Skip to content

heezy-finance

Last Updated: 2026-08-11 Status: Active Owner: trash


What Is This?

heezy-finance is a household spending analytics platform. It is not an accounting tool, it is a visibility tool. The goal is a single dashboard showing where money goes, with accurate data from every spending channel.

Several loosely coupled services write to the same Postgres database (heezy on big-boi, 192.168.1.21:5432), and one Flask app reads from all of them.


Services

Service Repo Path URL Role
heezy-finance (dashboard) heezy-containers/dockerfiles/heezy-finance/ finance.heezy.info The web app. 9 pages, ~60 API endpoints
heezy-finance-sync (CronJob) same image, amazon_orders.py none Hourly at :00, --hours 2. Gmail order ingest
heezy-statement-scanner (CronJob) same image, scan_statements.py none Hourly at :30. Parses PDFs dropped on NFS
heezy-budget-alerts (CronJob) same image, budget_alerts.py none Daily 14:00 UTC (9am ET). Discord budget warnings
statements (upload service) heezy-containers/dockerfiles/statements/ statements.heezy.info Lands statement files on NFS. No parsing
receipts heezy-containers/dockerfiles/receipts/ receipts.heezy.info Receipt OCR and line-item extraction

The three CronJobs run the same heezy-finance image with a different command. A dashboard deploy updates all four at once.


Data Sources

Counts as of 2026-08-11.

1. orders / order_items (email-parsed orders)

  • Source: Amazon and other vendor order confirmation emails
  • Populated by: amazon_orders.py, Gmail API plus Ollama llama3.2:3b on big-boi
  • Current state: 284 orders, 367 line items, 25 distinct vendors
  • Classification: rules, then ASIN/title cache, then LLM. See Data Sources
  • Open issue: 7 orders have a NULL or zero grand_total. Current Amazon HTML does not expose a parseable total on roughly a third of confirmations; line items usually rescue it

2. receipts / receipt_items (scanned receipts)

  • Source: photos uploaded to receipts.heezy.info
  • Populated by: the receipts service, AWS Textract AnalyzeExpense by default
  • Current state: 155 receipts, 821 line items
  • Open issue: 12 receipts have a NULL date_ts and are invisible to any date-filtered query

3. bank_statements / bank_transactions (statement parser)

  • Source: BoA, Capital One, Chase, Edward Jones, Fifth Third PDFs plus Chase CSV/OFX
  • Populated by: parse.py, driven by scan_statements.py (NFS) or POST /api/statements/upload
  • Current state: 80 statements, 1,582 transactions
Institution Type Statements Coverage
Bank of America checking 7 2026-01 to 2026-07
Bank of America credit_card 14 2026-01 to 2026-07
Capital One checking 10 2025-11 to 2026-06
Capital One savings 10 2025-11 to 2026-06
Chase credit_card 14 2025-10 to 2026-07
Edward Jones 529, brokerage, ira, roth_ira, money_market 24 2026-05 to 2026-07
Venmo venmo 1 manual row, no parser

Fifth Third mortgage statements land in mortgage_statements, not bank_statements. 9 rows.

See Data Sources for parser detail and quirks.


Dashboard

  • Stack: Flask, vanilla JS, Jinja templates, Plotly for charts
  • Live URL: finance.heezy.info
  • k8s: heezy namespace, deployment heezy-finance, NodePort 30860
  • Source: heezy-containers/dockerfiles/heezy-finance/app.py (~4,000 lines)

Pages

Nav order comes from templates/_nav.html.

Route Nav label Doc
/ Spending Overview Tab
/reconcile Reconcile Reconcile Tab
/money Net Worth Net Worth Tab
/targets Targets Targets Tab
/mortgage Mortgage Mortgage Tab
/budget Budget Budget Tab
/statements Statements Statements Tab
/maintenance Maintenance Toilet paper inventory. Unrelated to spending, and unrelated to the separate heezy-maintenance service

/bank, /purchases, and /trends are 302s to / (they are tabs inside the Spending SPA). /sankey is a 302 to /money. /record-balances still renders its own template but is no longer linked from the nav; the Statements page replaced it.

API Endpoints

Grouped. See each page doc for request and response shapes.

Group Endpoints
Period discovery /api/available-periods, /api/latest-data-period
Spending /api/overview, /api/transactions, /api/comparison, /api/trends, /api/purchases, /api/bank-overview, /api/category-drilldown, /api/category-transactions/<category>, /api/uncategorized-items
Cash flow /api/sankey
Reconcile /api/reconcile/ + page-data, summary, unmatched-bank, unmatched-receipts, auto-match, link, update-category, acknowledge, unreconciled-summary, unreconciled-by-category
Receipts /api/receipt-detail/<id>, /api/receipts/<id>/items, /api/receipts/<id>/category, /api/receipt-items/<id>, /api/bank-transactions/<id>/stub-receipt
Categories /api/categories, /api/bank-transactions/<id>/category
Accounts and net worth /api/accounts, /api/accounts/<id>/nickname, /api/account-balances/<id>, /api/net-worth, /api/money-history
Statements /api/statements/upload, /api/upload-statement, /api/statements/audit
Mortgage /api/mortgage-latest, /api/mortgage-history, /api/mortgage-calc
Targets /api/targets-summary
Budget /api/budget, /api/budget/<category>, /api/budget/annual, /api/budget/annual/<category>, /api/ytd-by-category
Sync /api/sync
Maintenance /api/tp/bathrooms, /api/tp/inventory, /api/tp/restock, /api/tp/log, /api/tp/stats

Database

All tables in the heezy database on big-boi (192.168.1.21:5432). Schema source of truth: ansible-heezy/roles/heezy-postgres-schema/files/schema.sql

Table Purpose
orders, order_items Order and line-item data from email confirmations
receipts, receipt_items Scanned receipt metadata and line items
bank_statements, bank_transactions Statement metadata and individual transactions
accounts Tracked accounts. Required for balance upsert to succeed
account_balances Point-in-time balance snapshots per account
mortgage_statements Fifth Third statements: balance, rate, principal/interest/escrow split
spend_budgets Monthly per-category budget targets
annual_budgets Yearly per-category budget targets, keyed on (category, year)
item_category_cache ASIN or title-hash to category, so a product classifies once
statement_files_processed Upload dedupe by file hash
amazon_returns Return initiations and acceptances
home_maintenance Home task log with forecasted and actual cost
tp_bathrooms, tp_inventory, tp_change_log Toilet paper tracker behind /maintenance
vw_sankey_income, vw_sankey_transfers, vw_sankey_spend Views. See Sankey Architecture

Known Issues

Issue Severity Notes
12 receipts with NULL date_ts Medium Dropped by every date-filtered query. Backfill SQL in Data Standards
Missing account causes silent balance skip Medium upsert_account_balance() logs WARN only, no error in the upload response
7 orders with no grand_total Low Amazon HTML has no parseable total. repair_order_data.py --backfill-totals recovers most from line items
No FK from statements to accounts Low Matched by institution + last4 + type string at ingest. Renaming an account orphans its history
bank_statements.statement_period_start/end are text Low Raw PDF strings. period_end_date is the normalized one
PVC is RWO on Longhorn Low Deploy strategy is Recreate to work around it. Node affinity is gone, so the pod does reschedule

Resolved since the last revision of this page: the 12 boacrdNone ghost statement rows (now 0), and the real money-column tech debt (every money column is numeric).