Skip to content

heezy-finance Roadmap

Phase 1 — Fix the Data ✅ Complete (2026-06-18)

Item Status
receipts.date_ts migration + backfill ✅
merchant_normalized on receipts ✅
category + merchant_normalized on bank_transactions ✅
Bank transactions integrated into dashboard ✅
Gas spend fixed: $140.52 (was $36) ✅
Bank source filter + 🏦 badge in Purchases ✅
Bank page with category cards + monthly chart ✅
BoA parser: CC detection ✅
Cap1 parser: fixed stmt_id bug ✅
Statement NFS ingest pipeline (end-to-end) ✅
Ingest pipeline: auto-category + merchant on insert ✅
docs.heezy.info live on Cloudflare Pages ✅

Phase 2 — Complete Bank Coverage ✅ Complete (2026-06-20)

Item Status Notes
Bank page deployment ✅ Category breakdown, monthly trends, top merchants
Bank integration into all views ✅ Overview, Purchases, Categories all include bank data
payment_type on receipts ✅ Dropdown UI added: cash / credit / debit / check / other
Purchases table sortable ✅ Date, Source, Vendor, Item, Total, Category columns sortable
Purchases date defaults ✅ Start Date = 1st of month, End Date = today
Rule-based bank categorization ✅ Ollama too slow on CPU; keyword rules working well
More BoA monthly statements ✅ Jan–Jul 2026 checking loaded
CC statements (BoA Visa, Cap1, Chase) ✅ BoA CC 14 statements, Chase CC 14 back to Oct 2025
Historical statement backfill 🔲 Nothing pre-Oct 2025 loaded on any account
Blocked: June 2026 statements ✅ Loaded

Gmail auto-fetch is not viable

BoA and Capital One send notification-only emails with no PDF attachments. Manual workflow: download from bank portal → drop to /nfs/heezy/ingest/raw/statements/new/ → picked up within 5 min.

CI/CD Lesson: Push to Gitea, Not GitHub

Issue: Pushing to GitHub origin instead of Gitea canonical repo breaks deployments.

Root Cause: GitHub is a mirrored backup only; act-runner watches Gitea. Pushing to origin (GitHub) doesn't trigger the pipeline.

Fix: Always push to Gitea remote first, then origin.

# ❌ Wrong — GitHub doesn't trigger act-runner
git push origin main

# ✅ Correct — Push to Gitea first, then GitHub
git push gitea main
git push origin main

Deployment Pipeline: 1. Push → Gitea main 2. Gitea webhook → act-runner triggers .gitea/workflows/deploy-heezy-finance.yml 3. Workflow builds Docker image, pushes to ECR 4. Workflow writes .deploy-trigger file to heezy-k8s repo 5. heezy-k8s auto-deploy workflow: kubectl apply -k, rollout restart, rollout status 6. Pod updates with new image

See CI/CD for full details.

Phase 3 — Global Date Range + Lookback ✅ Complete (2026-06-20)

Item Status Notes
Global date range selector ✅ Utilities/Mortgage historical lookback working
Utilities category drill-down ✅ Monthly breakdown with per-vendor trends
Mortgage payment tracking ✅ Historical payment records by date range
Category drill-down modal ✅ Click category cards to view monthly detail
Feature verification ✅ All 4 phases verified live on finance.heezy.info

Phase 4 — Hockey Holdem Receipt ✅ Complete (2026-06-20)

Item Status Notes
Receipt categorization ✅ Hockey Holdem vendor recognized + categorized
Line item detail modal ✅ Click receipt to view itemized breakdown
Payment type tracking ✅ Cash, credit, debit payment types recorded
Full integration ✅ Receipt appears in all views (Overview, Purchases, Hockey category)

Phase 5 — Parser Fixes & Account Coverage ✅ Complete (2026-07-07)

Item Status Notes
Fix Cap1 false-detected as EDJ ✅ Cap1 PDFs contain "EDWARD JONES" in txn descriptions; moved Cap1 check before EDJ in detect_bank()
Fix Chase Amazon closing date ✅ Opening/Closing Date X - Y regex now captures second (closing) date
Add missing accounts (BoA 7503, Chase 2609) ✅ Both inserted with display_group='debt'
Clean up bad statement rows from failed uploads ✅ Deleted edjbrok0000_2026-06-30, chasecrd2609_2026-05-20, stale account_balances row
Fix boacrdNone ghost rows ✅ Guard added in scan_statements.py: skip insert_bank_statement when account_last4=None and type is credit_card. 12 existing rows deleted. Now 0

Phase 6 — Infrastructure Resilience ✅ Mostly Complete

Focus: Remove node affinity pinning, fix PVC pattern for multi-node resilience.

Item Status Notes
Remove nodeSelector / nodeAffinity ✅ Gone from the deployment and from heezy-statement-scanner / heezy-budget-alerts. The pod currently runs on nebula-4, having moved off nebula-5 on its own
Implement & test failover ✅ Verified by real reschedules across nodes
Audit PVC necessity 🔲 /data is still mounted but app state lives in Postgres. Unclear the volume is needed at all
Design storage solution 🔲 PVC is still 2Gi RWO Longhorn. Strategy is Recreate to avoid a multi-attach deadlock, which costs a few seconds of downtime per deploy

Phase 7 — Reconciliation ✅ Complete

Shipped inside the dashboard, not as the separate heezy-finance-reconcile service originally sketched. A dedicated service was not worth the operational cost for matching that runs in milliseconds at request time.

Item Status Notes
Reconcile page ✅ /reconcile, see Reconcile Tab
Receipt to transaction matching ✅ Exact (date, amount) key, done in Python at request time
Manual link and override ✅ POST /api/reconcile/link, receipts.bank_transaction_id
Inline category reassignment ✅ POST /api/reconcile/update-category, feeds spending and budget analytics
Acknowledge / hide rows ✅ bank_transactions.reconcile_acknowledged
Orphaned receipt surfacing ✅ Receipts in range with no matching transaction
Fuzzy matching (date ±2 days, amount within 1%, merchant similarity) 🔲 Match is still exact-only. Confidence scoring never built
Order to transaction matching 🔲 orders.bank_transaction_id exists but nothing populates it

Phase 8 — Budgeting & Targets ✅ Complete

Item Status Notes
Monthly per-category budgets ✅ spend_budgets, Budget page
Annual per-category budgets ✅ annual_budgets, keyed on (category, year), for lumpy categories
Fixed vs variable cost split ✅ FIXED_COST_CATS in categories.py
Daily Discord budget alerts ✅ heezy-budget-alerts CronJob, 14:00 UTC
Financial targets page ✅ Emergency fund, 529s, investments, mortgage payoff, retirement/FIRE. See Targets Tab
Mortgage statement ingest ✅ mortgage_statements table, 9 statements

Phase 9 — Classification Quality ✅ Complete

Item Status Notes
Taxonomy moved to categories.py ✅ app.py and item_classifier.py share one list
Rules → cache → LLM pipeline ✅ item_category_cache, 135 entries. LLM is last resort, answers are stable across re-runs
real to numeric migration ✅ Every money column is numeric
Merchant rules split one per chain ✅ Was rendering every Meijer, Costco and Aldi debit as a vendor named "grocery"

Open Work

Item Priority Notes
Backfill 12 receipts with NULL date_ts Medium They are invisible to every date-filtered query
Surface the silent balance-skip Medium upsert_account_balance() logs WARN when no account matches; the upload response says nothing
Add liveness / readiness probes Medium A pod that cannot reach Postgres still reports Running
Fuzzy reconcile matching Low Exact (date, amount) misses pending-vs-posted date drift
FK from statements to accounts Low Still matched by institution + last4 + type string
Normalize bank_statements.statement_period_start/end Low Raw PDF text
Capital One and Edward Jones backfill Low Cap1 stops at 2026-06, EDJ starts at 2026-05

Current DB State

Counts as of 2026-08-11.

Table Count Notes
orders 284 25 distinct vendors, 7 without a grand_total
order_items 367 Rule, cache, or LLM categorized
receipts 155 12 without date_ts
receipt_items 821
bank_statements 80 BoA, Cap1, Chase, EDJ, one manual Venmo row
bank_transactions 1,582 Dashboard shows debits only
mortgage_statements 9 Fifth Third
accounts 27 17 active
account_balances 84
spend_budgets / annual_budgets 13 / 5
item_category_cache 135

Last updated: 2026-08-11