Skip to content

Handoff: Finances Phase D, surface rebuild passes (start 2026-07-06)

For: a fresh agent working WITH Justin, live on a dev slot. Plan: finances-native-rebuild-2026-07-05, Tasks 20-32. Module reference: reference_creatortrack_finance_module (read this first). Boundary + design contract: creatortrack/docs/FINANCES-APP-SPEC.md (eslint enforces the import boundary).

State you inherit (do NOT redo)

Phases A-C shipped and pushed (origin/main a19e1dc, 2026-07-05 night). finance.* Postgres is the source of truth; all ingest jobs are TypeScript (lib/finance-jobs/), all writes are native routes, the Flask app + finance.db are retired (archived), the timers are forge-creatortrack-finance-*. Prod is live and healthy: check select job, ok, detail from finance.job_runs order by id desc limit 10.

The actual job: rebuild each surface WITH Justin, one pass = one commit

The 13 surfaces in app/finances/* are 1:1 ports of the old Flask app (its CSS, Outfit font, dark Material markup). Justin explicitly does NOT want a polished port; he wants each surface rebuilt in CreatorTrack's native design system with him driving scope and look:

  • components/ui primitives + workspace shell patterns (study how Habits/Tasks render in .ws-appsurface)
  • Geist / Geist Mono, CreatorTrack tokens; NO finances.css, NO Outfit
  • Recharts is in the deps (Food Log trends use it) for charts
  • Data layer stays: lib/finance.ts loaders are ported and correct; restyle/rethink the presentation, reuse the queries (extend where Justin wants new views)

Order (Justin approves each on the dev slot before commit; commit feat(finances): <surface> iteration pass): Dashboard, Net Worth, Investments, Spending, Budget, Business, Recurring, Cash Flow, Accounts, Transactions, Categorize, Receipts, Alerts. Task 32 (Alerts, last) also deletes app/finances/finances.css + the Outfit import.

Fold these into the relevant passes

  • Receipts (Task 31): the old phone-upload capture surface died with Flask. Build native capture (upload -> finance.receipts + image store); the reconcile job (lib/finance-jobs/receipts.ts) already matches + attaches to ERPNext. Zero receipts exist, clean slate.
  • Transactions (Task 29): wire the edit/bulk-edit UI to POST /api/finance/transactions (route exists, has no UI yet).
  • Budget (Task 24): wire targets/autoset to POST /api/finance/budgets (route exists).
  • Net Worth / Accounts: manual value edits -> POST /api/finance/manual-values (route exists).
  • Investments (Task 22): SSGA as_of sometimes lands empty (xlsx date-serial parse in lib/finance-jobs/holdings.ts consSsga); fix while restyling.
  • Alerts (Task 32): render finance.alert_feed at the top (table exists, feed is live).

Dev-slot workflow

  • Bootstrap per reference_creatortrack_dev_testing: branch feat/finances-surfaces (or per-surface), worktree at forge-suite-wt/<branch>, clone DB ct_<branch> from creatortrack_dev_base (template already has the 3 finance migrations; seed user_rules if the pass needs them: scratch seed lives only in prod now, re-derive from finance.user_rules in lifeos).
  • Worktree needs ln -s /home/justinwieb/forge-suite/node_modules <wt>/node_modules and next dev --webpack / next build --webpack (Turbopack rejects the cross-root symlink).
  • NO new npm deps on the branch: the shared node_modules gets pruned by other agents' npm runs (fflate lesson). Merge ONCE at the end.
  • tsx testing: env -u PGPASSWORD PGDATABASE=ct_<branch> npx tsx <file>.mts; server-only imports need lazy import. Drizzle: in ${arr}, never = any(${arr}).
  • Icons: ALWAYS key by iconKey from lib/finance-icons.ts, never raw merchant_norm.

Open reminders for Justin

  • PNC Bank needs re-auth at bridge.simplefin.org (SimpleFIN warns every sync).
  • Post-confidence cleanup (not urgent): delete legacy forge-finance-* unit files, retire the 8096 tunnel ingress entries, remove finance.db from the active tree.

[Claude Code, 2026-07-05 night]