Home Finance Dashboard
A private, local-first dashboard for our household finances — every account, transaction, and net-worth trend on one page, on the home network only.

Our household money lives across a dozen places — banks, credit cards, brokerages, payroll, a mortgage. This app pulls all of it into one read-only dashboard that never leaves the house.

How it works
The core idea is a one-way pipeline: raw exports go in one side, a single static JSON file comes out the other, and the dashboard just reads that file.
- Getting the data. Each institution gets its own importer: fixed-width text statements, card CSVs, payroll exports, RSU spreadsheets from the brokerage (vested and unvested buckets tracked separately), even itemized Amazon order history. Where a bank has no export worth automating, a Playwright script drives a real browser through the download flow — with credentials injected from the macOS Keychain so they never touch a file or shell history. Plaid covers the accounts that allow aggregation.
- Making sense of it. A rules engine categorizes every transaction and dedupes across sources, then folds in manual balances, home equity (estimated value minus the live mortgage principal), and tax configuration. Everything lands in a SQLite build artifact.
- Serving it. The build emits one static
dashboard.json; the React frontend renders its charts from that file alone. There is no live database behind the web server and no write path at all — the dashboard is read-only by construction. - Asking questions. An MCP server exposes the same SQLite data to AI agents, so "how much did we spend on groceries last quarter?" is a question in a chat instead of an hour in a spreadsheet.
Why it's not on the internet
On purpose, this app has no public URL, no cloud database, and no tunnel. It's only reachable on the home LAN or over WireGuard, behind passkey login, from a DNS name that doesn't resolve outside the house. It holds every account and transaction we have, so the simplest defense felt right: don't be reachable in the first place.