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.

ReactViteExpressSQLitePlaidPlaywrightMCPWebAuthn
Household dashboard overview — net worth, cash flow, and trends (privacy mode on)

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.

Finance dashboard data pipeline

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.