Chris Olson a68c343647 Milestone 3: launch (20261008.05)
Backup and restore: restore from Settings (any backup in the folder, or an
uploaded file) or from the command line with scripts/restore.sh. Each restore
checks the file first, saves a copy of the current data so it can be undone,
and keeps the person restoring signed in. Backups are now single
self-contained files. Drilled end to end: last night's backup brings
everything back exactly, including onto an empty new machine.

Speed: a phone's first load is 147 KB compressed (target 150). The ideas box,
account menu and sign-in screens load on demand, a small built-in toast
replaces sonner, the Inter font is trimmed to the characters used, and files
and API answers are served compressed. Every screen's data comes back in
under 100 ms with 50,000 transactions (server/bench).

Accessibility: no WCAG 2.2 AA issues on any screen in either theme. Darker
status text colors, 44 px touch targets on phones, reduced motion honoured,
and focus returns after dialogs close.

Also: an in-app guide ("How Spendlight works"), OFX/QFX/QBO import, and tags
on individual parts of a split purchase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:23:45 -04:00
2026-10-08 12:23:45 -04:00
2026-10-08 12:23:45 -04:00
2026-10-08 12:23:45 -04:00
2026-10-08 12:23:45 -04:00
2026-10-08 12:23:45 -04:00
2026-10-08 12:23:45 -04:00

Spendlight

A private, self-hosted household budgeting app: import bank and card statements, categorize in a tap, budget by month, and keep an eye on subscriptions. Runs as a single container on arm64 or amd64.

Status: milestones 0 to 3 are built: foundation, money in, the full picture, and launch (accessibility, speed, backup and restore, an in-app guide).

What it does

  • Import CSV statements from Bank of America, Discover, Chase, Capital One, Citi and Apple Card, plus any other bank through a one-time column mapper. OFX, QFX and QBO files (Quicken, Money, Web Connect) work too. Duplicates are skipped, card payments and transfers are paired, and any import can be undone.
  • Review new transactions with one-tap category suggestions that learn from every choice. Splits, tags, notes and cash entries are built in.
  • Budget one amount per category for every month, with any month set on its own. Fill a year from recent spending in one step; copy it into the next.
  • Home shows what's left to spend, how the year is pacing, insights, balances and the charges coming up.
  • Insights: year pacing, money in and out, budget against actual, categories by month, merchants, balances over time and tags.
  • Subscriptions and bills are found automatically across every account, confirmed with one tap, and watched for price changes, missed charges, charges after cancelling, double billing, renewals and trials ending.
  • Export everything to Excel or CSV.
  • AI features are designed in and switched off; no provider ships with the app and it makes no outside calls.

Running it

cp .env.example .env      # adjust the port, time zone and paths
scripts/deploy.sh         # builds a versioned image and starts it

HTTPS comes from your own reverse proxy (see deploy/nginx.conf.example). The API is documented at /api/docs on a running instance.

Backups and restoring

Every night at 02:30 (BACKUP_TIME) a complete copy of the database lands in the backups folder, plus one before every upgrade and every restore. Point any backup tool at that folder to keep copies off the server.

  • Everyday restore: Settings → Backups → Restore, as an admin. Spendlight checks the file, saves a "before restore" copy of the current data, and switches over. Restoring that copy undoes it. "Restore from a file" takes a backup from somewhere else, such as another machine.
  • When the app can't be used: put the backup file in the backups folder and run scripts/restore.sh spendlight-nightly-20261007-023000.db. It stops the app, restores, and starts it again.
  • Moving to a new machine: copy the data folder, or start with an empty one and run the restore script before the first sign-in.

Developing

The host only needs Docker; Node 24 runs in a container.

scripts/dev.sh npm install
scripts/dev.sh npm test
scripts/dev.sh npm run typecheck

Statement files never belong in this repository: samples/ is ignored and a pre-commit hook blocks statement and database files. Tests use made-up data in server/test/fixtures/synthetic and server/test/synthetic.ts.

Description
No description provided
Readme 345 KiB
Languages
TypeScript 97.2%
JavaScript 1.4%
CSS 0.6%
Shell 0.5%
Dockerfile 0.2%
Other 0.1%