← Projects
LiveRailway · SQLite (Railway is the source of truth)

Joint Venture

Household finance dashboard that ingests every statement we get, in any format, from any bank.

PythonFlaskSQLiteOCRAnthropic SDK
●●●
Net Worth↑ 8.4%
JanAprJulOct
Allocation
Recent Transactions

The problem

Between the two of us, our family has accounts spread across a long list of local and international banks, credit cards, e-wallets, brokerages and retirement accounts, and each of those institutions sends statements in its own quirky format. Spreadsheets stop being honest somewhere around the third account, off-the-shelf personal finance tools never really supported Philippine banks in the first place, and any picture of our net worth that we trust has to come from actually opening every PDF, every CSV and every emailed receipt and reconciling them against each other. That is not a thing a busy household will do by hand for very long.

The solution

Joint Venture is a single Flask app that quietly does all of that work for us. Nineteen parsers handle everything from EBCDIC-garbled credit card statements that only OCR can read, to encrypted bank PDFs that need decrypting with PyMuPDF before anything else can touch them, to 401k quarterly factsheets that arrive with UUID filenames. Once the data is in, it powers the things we actually care about: categorized spending, merchant rules, multi-currency net worth, look-through ETF allocation across sectors and geographies, a clean retirement-account chain across providers, and a forecast that we can play with. A mail-to-webhook pipeline pipes in merchant receipts and banking emails so the dashboard stays close to real time, and time-weighted return done properly (Modified Dietz, chain-linked quarterly) gives us a growth number across the USD accounts and the PHP funds that we can actually believe.

Features

  • Drop new statements into an inbox folder, run one command, everything lands in the right place
  • Net worth dashboard across PHP and USD with quarterly time-weighted return
  • Look-through ETF allocation by sector and geography
  • Monthly forecast and budget vs. actual
  • Merchant rules and automatic categorization
  • Asset inventory with photos
  • Medicine and supplement tracking with expiry alerts
  • Household-staff payroll built right into the same app

Architecture

  • Six domains in one app: Expenses, Investments and Net Worth, Forecast, Asset Inventory, Pharmacy, and Staff Payroll
  • `db_pkg/` holds seventeen domain modules, broken out of what used to be a single monolithic db.py
  • `routes/` holds ten Flask blueprints, which leaves `app.py` as a slim 137-line core
  • `parsers/` holds nineteen parser classes, with content-based detection as a fallback, atomic writes, an inbox workflow, and automatic backups before every run
  • 184 tests run automatically on every commit via a pre-commit hook
  • Inbound email webhook hands PDFs to a background thread so the gunicorn worker never blocks, with the parsed result landing in a statement_review staging table that you approve, edit, or discard from Telegram
  • Every monetary amount is stored as integer cents, FX rates from the BSP go back to 2016, and SGD is handled as a cross-rate from USD via open.er-api.com
  • Look-through allocation uses twenty-three fund factsheets to break ETFs into GICS sectors and six geographic regions
  • Sync safety: Railway is the source of truth for any data a human touches, and the local app only ever pushes parse-owned tables back, through the REST API