Personal · privacy-focused

Household Finance

A self-hosted app that turns uploaded bank statements into a verified transaction ledger, organises incoming financial documents by what they are for, and highlights missing statement periods — without sending our history to someone else’s cloud.

← Back to projects

Why I built it

I wanted one combined view across personal, business and multiple bank accounts, while keeping each account identifiable. I also got tired of guessing whether every statement had been uploaded — and of spreadsheets that quietly invent zeros for missing months.

What it does today

Upload statements, parse bank-specific layouts, and check opening/closing balances and transaction totals before anything becomes ledger truth. Failures go to manual review.

From there: browse transactions with the original PDF as evidence, categorise spend with rules (manual corrections stay put), exclude transfers between our own accounts, associate income and costs with properties, keep tax certificates and bank letters off the ledger, and export CSV. Currencies stay separate.

It currently understands Yuh, UBS (including scanned pages via OCR), and Santander UK. Partner and Accountant roles keep access limited.

Where I used AI — and where I didn’t

Bank statement layouts are predictable, so I wrote normal parsers in code for those. Scanned UBS PDFs need OCR (Tesseract) — that’s a tool, not a chat prompt. I don’t use an LLM to invent balances: failed checks stay in review until I promote or reject them. AI helped me build and iterate the app itself; it doesn’t get to rewrite our ledger.

Features

Spending analytics

Money in and out by month, per currency — never mixed into misleading totals. If a month has no statement, I leave it blank instead of drawing a fake zero, and averages skip the gap. Categories come from explicit rules; transfers between our own accounts stay out of spend analysis.

Household Finance Analytics Trends view showing spending chart with blank months where statements are missing
Trends: in and out by month, gaps left blank on purpose

Letters vs statements

Incoming documents are classified by purpose. Bank letters and notices go to Mail as correspondence, not ledger facts. Tax certificates, interest summaries and similar files stay as evidence — readable and linked to the original PDF, never turned into transactions.

Household Finance Mail view listing bank letters with dates, extracted summaries, and source PDF filenames
Mail: useful to read, kept off the spending totals

Missing statement coverage

The coverage grid shows which statement periods are present and which still need to be obtained from the bank. Green means I have a statement; red means there’s a gap. If OCR couldn’t read a file cleanly, I flag it for review — having the PDF is not the same as trusting the numbers.

Household Finance Document library statement coverage grid with green covered months and red missing months
Coverage grid plus review warnings for unclear reads

Properties & tax claims

Where it’s relevant, income and expenditure can be associated with individual properties — without collapsing a mortgage, tax and fees into one vague “housing” bucket. Tax-deductible amounts are only what we’ve claimed, never inferred from a category label.

Where I want to take it

These ideas are planned or possible later work — not features that exist today.

Longer term, I’d like Household Finance to process more of our incoming household mail automatically — filing tax documents, ignoring irrelevant correspondence, extracting useful information, and eventually helping with actions such as appointments. Possible later helpers could include plain-English explanations, DE→EN translation, and spend investigation prompts.

Those would be advisory or administrative helpers. The ledger itself would still rely on deterministic parsing and validation, not an LLM inventing financial facts.

Architecture

Household Finance architecture overview Browser to Next.js web app, FastAPI and worker services, PostgreSQL for trusted data, MinIO for documents, with OCR and parsers on the worker path. Web UI API Worker PostgreSQL MinIO OCR / parsers
Runs at home via Docker Compose. Private repo — no public demo link.
  • Postgres stores trusted transactions; original PDFs stay in MinIO as immutable evidence.
  • Flow: upload → extract → classify → parse → validate balances/totals → auto-promote when checks pass, or review → promote / reject / replace.

Technology

  • Docker Compose
  • Next.js
  • FastAPI
  • PostgreSQL
  • MinIO
  • Tesseract OCR
  • JWT auth / roles