|
|
||
|---|---|---|
| .learnings | ||
| client | ||
| db | ||
| docs | ||
| img | ||
| legacy | ||
| middleware | ||
| public | ||
| routes | ||
| scripts | ||
| services | ||
| setup | ||
| tests | ||
| utils | ||
| workers | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .markdownlint.json | ||
| .rsyncignore | ||
| Dockerfile | ||
| HISTORY.md | ||
| NOTES.md | ||
| README.md | ||
| REVIEW.md | ||
| SECURITY_AUDIT.md | ||
| bill-tracker.code-workspace | ||
| components.json | ||
| deploy.sh | ||
| docker-compose.yml | ||
| docker-entrypoint.sh | ||
| index.html | ||
| jsconfig.json | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.js | ||
| run-functional-test.js | ||
| server.js | ||
| tailwind.config.js | ||
| test-functional.js | ||
| vite.config.mjs | ||
README.md
BillTracker
BillTracker is a private, self-hosted bill planning app for households and small personal setups. It tracks recurring bills, payments, monthly cash buckets, due dates, categories, debt payoff, imports, exports, backups, transactions, bank sync, and subscriptions from one local installation.
It runs as a Node/Express app with a React/Vite frontend and stores data in SQLite. It is designed for people who want their bill data under their own control instead of inside a third-party budgeting service.
Key features include:
- SimpleFIN bank sync integration (auto-sync, manual "Sync Now", 90-day backfill)
- Subscription catalog with recommendations from unmatched charges
- Advisory non-bill filter system (5k+ patterns, auto-matching)
- Transaction import, matching, and management
- Snowball and avalanche debt payoff planning
- Analytics, calendar, summary pages, and printable reports
- Dark mode and PWA support (offline-ready)
- Keyboard command palette (Ctrl+K)
Demo Server: https://t1.scheller.ltd/
Username: guest · Password: guest123
Highlights
- Private-by-design self-hosted bill tracking with local SQLite storage
- Tracker view with monthly buckets (
1st-14thand15th-31st) and period-aware balance - Bills, categories, payments, notes, skipped months, history ranges, and inactive bill handling
- Subscription catalog (v2 with 100+ services across categories, recommendations from unmatched charges)
- Advisory non-bill filter system (5k+ patterns, UI for confidence levels, lazy cache, auto-matching)
- Debt snowball page with payoff projections, avalanche comparison, APR math, and amortization schedules
- Analytics, calendar, summary pages, and printable reports
- XLSX and CSV import, user export/import, Excel export, import history, and admin backups
- Transaction import, matching, and management (Data page)
- Local username/password login with optional Authentik/OIDC SSO
- Admin panel for users, backups, cleanup, auth settings, status, and migrations
- Status page with health checks, bank sync card, daily worker card, and recent errors
- Compact tracker mode with side-by-side buckets, subscription/AP/2FA badges
- Background worker system (dailyWorker for autopay marking, notifications, session pruning, cleanup)
- Dark mode and theme support
- PWA support (service worker, offline-ready)
- Keyboard command palette (Ctrl+K)
- Monthly bill state (skip, notes per month), bill history and status tracking
- SimpleFIN bank sync integration (auto-sync, manual "Sync Now", 90-day backfill, config via admin)
- Two-factor authentication badges, autopay badges, subscription badges on bills
- Customizable display preferences per bill (toggle columns, badges)
- Public About, Privacy, and Release Notes pages
Screenshots
Additional Screenshots
The app includes many more screenshots in the docs:
- Analytics page: spending trends, category breakdowns, heatmaps
- Calendar page: due dates, payments, month progress
- Summary page: income, starting amounts, monthly planning
- Admin panel: user management, backups, status, migrations
- Worker status: dailyWorker activity, notifications, cleanup
- Status page: health checks, bank sync status, recent errors
- Compact tracker mode: side-by-side buckets, subscription/AP/2FA badges
See the docs directory for more details.
Who This Is For
BillTracker is built for self-hosters who want a practical bill dashboard without sending personal finance data to an outside service.
Good fit:
- Home servers, NAS boxes, small VPS deployments, Portainer, or Docker Compose
- Single-user or multi-user households
- People who split monthly cash around the 1st and 15th
- Users who want import/export and database backup control
- Authentik/OIDC users who want optional SSO
- Users who want SimpleFIN bank sync integration
- People managing subscriptions, debt, and transactions in one place
Not a full replacement for:
- Double-entry accounting
- Investment tracking
- Tax software
Note: Bank sync requires a SimpleFIN account. Direct bank connections are not supported.
Quick Start With Docker
The included Compose file runs the published image on host port 3030 and stores all persistent app data under /data inside the container.
docker compose up -d
Open:
http://localhost:3030
On first start, seed an admin account with:
environment:
INIT_ADMIN_USER: admin
INIT_ADMIN_PASS: change-this-password
Optional regular user seed:
environment:
INIT_REGULAR_USER: regularuser
INIT_REGULAR_PASS: changeme123
Passwords must be at least 8 characters. Remove or rotate first-run seed values after initial setup.
Persistent Data
For Docker, keep /data mounted. The container defaults to:
DB_PATH=/data/db/bills.db
BACKUP_PATH=/data/backups
Back up the mounted /data directory like you would any other sensitive financial data.
Background Workers
The app runs a daily worker (dailyWorker) for:
- Autopay marking
- Bill due notifications (3 days, 1 day, due today, overdue)
- Session cleanup
- Import history pruning
Worker status and recent activity are visible in the Status page admin panel.
Node Install
Install dependencies:
npm install
Run API and Vite UI for development:
npm run dev
Build and start production:
npm run build
npm start
The production server serves dist/ and listens on PORT, defaulting to 3000.
Useful scripts:
npm run dev:api
npm run dev:ui
npm run build
npm run check
npm start
npm run check runs backend CommonJS syntax checks and a Vite production build.
Product Map
Tracker
The Tracker is the main monthly view. It shows active bills for the selected month, grouped into:
1st-14th15th-31st
You can record payments, quick-pay bills, skip a bill for the month, add monthly notes, override monthly amounts, and navigate between months. The summary cards show starting cash, total paid, active period balance, overdue amount, previous month paid, and trend.
Compact tracker mode (available at 2xl+ screen width) adds:
- Side-by-side buckets for efficient viewing
- Subscription/AP/2FA badges for quick identification
- "S"/"AP"/"2FA" pill badges on bills
- Customizable column visibility per bill
Bills
Bills store the recurring source data:
- name, expected amount, due day, category
- active/inactive state and history visibility (default, all, ranges, none)
- billing cycle (monthly, weekly, biweekly, quarterly, annual)
- autopay status tracking (pending, assumed_paid, confirmed)
- subscription detection
- cycle type and cycle day configuration
Inactive bills support history ranges for past billing periods.
Optional Debt Fields
- balance, APR, and minimum payment
- snowball ordering and exclusion flags
- debt payoff tracking
Monthly Override State
- actual_amount per month
- is_skipped flag
- notes per month
SimpleFIN Bank Sync
SimpleFIN integration provides automated bank syncing:
- Auto-sync with configurable schedule
- Manual "Sync Now" button for immediate synchronization
- 90-day backfill support
- Configuration via Admin panel
- Recommendations subsystem for unmatched bank charges
Subscription Catalog
Track and manage recurring subscriptions:
- v2 catalog with 100+ services across categories
- Recommendations from unmatched bank charges
- Category-based organization
- Automatic subscription detection
Advisory Filter System
Non-bill filtering with machine learning patterns:
- 5000+ patterns for classification
- UI for high/medium confidence filtering
- Lazy caching for performance
- Auto-matching from bank sync
Snowball
The Snowball page focuses on debt payoff planning:
- snowball and avalanche ordering
- minimum-only baseline vs. full extra payment
- live payoff projections with APR snapshots
- amortization schedules
- drag ordering and debt exclusion
Calendar, Summary, And Analytics
- Calendar shows due dates, payments, and month progress
- Summary handles income, starting amounts, and monthly planning
- Analytics provides spending trends, category views, bill history, filters, heatmaps, and print output
Data Tools
BillTracker includes:
- XLSX and CSV spreadsheet import with preview
- Import by bill (manual entry)
- User SQLite import/export
- Excel workbook export
- Transaction import, matching, and management
- Import history with detailed stats
- Admin database backup, restore, download, cleanup, and retention tools
Data Page
The Data page manages transactions:
- Import from CSV/XLSX with field mapping
- Match transactions to bills
- Ignore unmatched transactions
- Transaction status tracking (matched, unmatched, ignored)
Status Page
System status at a glance:
- Health checks (database, SMTP, workers)
- SimpleFIN bank sync status
- Daily worker activity
- Degraded state indicators
- Recent errors list
Privacy Model
BillTracker is intended to run privately in your own environment.
- Bill data stays in your SQLite database.
- The app does not use third-party analytics, advertising, or telemetry.
- The public Privacy page explains the app’s local-first behavior.
- Login device details shown in Profile are visible to that user in the app UI, not exposed through the Admin UI.
- Optional update checks are for software update availability, not bill-data collection.
Admins can manage users, reset passwords, configure authentication, and manage backups, but normal bill data is scoped to the signed-in user.
Authentication
BillTracker supports local username/password login by default. Admins can create users, reset passwords, promote/demote users, and activate/deactivate accounts.
Optional Authentik/OIDC login can be enabled from Admin. OIDC uses authorization code flow with PKCE, state and nonce validation, and openid-client token validation.
Important behavior:
- Admin role is never granted by default through OIDC.
- OIDC admin access requires a configured admin group.
- Local login cannot be disabled unless OIDC is configured, enabled, and mapped to an admin group.
- The default seeded admin is restricted to admin routes and cannot access personal tracker data.
- OIDC provider name, issuer URL, client ID/secret, redirect URI, scopes, and admin group are configurable via Admin settings with environment variable fallbacks.
See Authentik-Integration.md for setup details.
Configuration
Most settings are configured in the web UI:
- User settings: Settings/Profile
- Server settings: Admin
- Authentication settings: Admin
- Backup and cleanup settings: Admin
Common environment variables:
PORT=3000
NODE_ENV=production
DB_PATH=/path/to/bills.db
BACKUP_PATH=/path/to/backups
INIT_ADMIN_USER=admin
INIT_ADMIN_PASS=change-this-password
INIT_REGULAR_USER=regularuser
INIT_REGULAR_PASS=changeme123
SESSION_CLEANUP_INTERVAL_MS=86400000
HTTPS=true
COOKIE_SECURE=true
CORS_ORIGIN=https://bills.example.com
CSRF_HTTP_ONLY=false
CSRF_SAME_SITE=strict
CSRF_SECURE=true
CSRF_COOKIE_NAME=bt_csrf_token
DATA_IMPORT_ENABLED=true
Worker settings:
WORKER_INTERVAL_MS=86400000
WORKER_AUTOPAY_ENABLED=true
WORKER_NOTIFICATIONS_ENABLED=true
WORKER_SESSION_CLEANUP_ENABLED=true
WORKER_IMPORT_CLEANUP_ENABLED=true
OIDC fallback environment variables are used when matching Admin database settings are blank:
OIDC_PROVIDER_NAME=authentik
OIDC_ISSUER_URL=https://auth.example.com/application/o/bills/.well-known/openid-configuration
OIDC_CLIENT_ID=<client-id>
OIDC_CLIENT_SECRET=<client-secret>
OIDC_TOKEN_AUTH_METHOD=client_secret_basic
OIDC_REDIRECT_URI=https://bills.example.com/api/auth/oidc/callback
OIDC_SCOPES="openid email profile groups"
OIDC_ADMIN_GROUP=bill-tracker-admins
OIDC_AUTO_PROVISION=true
Database-backed Admin settings take precedence over environment fallback values.
Reverse Proxy And HTTPS
Run BillTracker behind HTTPS for normal use. If TLS terminates at a reverse proxy, forward:
X-Forwarded-Proto: https
Recommended production posture:
HTTPS=true
COOKIE_SECURE=true
CSRF_SECURE=true
CSRF_SAME_SITE=strict
For plain HTTP development only, you may need:
CSRF_SECURE=false
COOKIE_SECURE=false
Leave CORS_ORIGIN unset for normal same-origin deployments. Set it only if the frontend and backend are intentionally served from different origins.
Security Notes
- Auth is required for user data routes.
- Admin routes require an admin session.
- User-owned bill, category, payment, import, export, and settings routes derive ownership from the authenticated session.
- CSRF uses a double-submit cookie pattern. The SPA reads
bt_csrf_tokenwithdocument.cookieand sends it asx-csrf-tokenon mutating requests. - Do not set
CSRF_HTTP_ONLY=truefor this SPA unless token delivery changes. - Session cookies are HTTP-only and SameSite-protected.
- Password changes rotate the current session and invalidate other sessions.
- Rate limits protect local login, password changes, imports, exports, admin actions, and OIDC routes.
- Security headers include CSP nonces and standard hardening headers.
- Audit logging records security-sensitive events such as login, logout, password changes, role changes, CSRF failures, and migration operations.
Backups and exports can contain sensitive financial data. The app writes SQLite backup files with restrictive permissions, but backup/export encryption is not implemented. Protect downloaded files and mounted volumes yourself.
Upgrading
For a Node install:
git pull
npm install
npm run build
npm start
Restart your process manager after building.
For Docker:
docker compose pull
docker compose up -d
If you build locally, rebuild the image and recreate the container.
The app initializes the schema and runs additive migrations on startup. The Docker entrypoint also runs scripts/migrate-db.js before starting unless:
RUN_DB_MIGRATIONS=false
Project Structure
bill-tracker/
├── client/ # React app, pages, layout, UI components
│ ├── components/ # Reusable React components
│ │ ├── layout/ # Layout components (Sidebar, etc.)
│ │ └── ui/ # UI components (buttons, inputs, etc.)
│ ├── pages/ # Page components (one per route)
│ │ ├── TrackerPage.jsx
│ │ ├── BillsPage.jsx
│ │ ├── CategoriesPage.jsx
│ │ ├── CalendarPage.jsx
│ │ ├── SummaryPage.jsx
│ │ ├── AnalyticsPage.jsx
│ │ ├── ProfilePage.jsx
│ │ ├── SettingsPage.jsx
│ │ ├── DataPage.jsx
│ │ ├── AdminPage.jsx
│ │ ├── LoginPage.jsx
│ │ └── AboutPage.jsx
│ ├── hooks/ # Custom React hooks (useAuth, etc.)
│ ├── api.js # API client functions
│ ├── App.jsx # React Router configuration
│ ├── main.jsx # React entry point
│ └── index.html # HTML template
├── server.js # Express backend entry
├── routes/ # API route handlers
- services/ # Business logic layer: auth, OIDC, backups, imports, cleanup, status, audit, workers, transactions, matches, data sources, snowball, analytics, notification, export, and transaction import logic
├── middleware/ # Express middleware
├── db/ # Database schemas/migrations
├── workers/ # Background job workers
├── scripts/ # Utility scripts
├── docs/ # Technical references and integration guides
├── dist/ # Build output (generated)
├── public/ # Static assets
├── Dockerfile # Container config
└── docker-compose.yml
Documentation
- HISTORY.md: release history
- CSRF-SPA-Setup.md: CSRF behavior for the SPA
- Authentik-Integration.md: authentik/OIDC setup
- SimpleFIN-Integration.md: SimpleFIN bank sync setup
- Engineering_Reference_Manual.md: deeper implementation reference
Known Limitations
- Admin backups and user exports are not encrypted by the app. Protect downloaded files and mounted volumes yourself.
- Bank sync via SimpleFIN is implemented, but direct bank connections are not supported (requires SimpleFIN account).
- OIDC single logout is not implemented; users must log out from each device separately.
- Rate limiting is in-memory, so counters reset on restart and are not shared across multiple app instances.
- Multiple OIDC providers are not currently supported.
- The XLSX parser dependency has known upstream security advisories; import routes are authenticated, file-size limited, and parse spreadsheet cells as data.
License
License: Not specified.