Finances -> lifeos Migration Plan (first real Suite module)¶
URL: https://mkdocs.justinsforge.com/memory/plans/finances-to-lifeos-migration-2026-06-17/
Date: 2026-06-17. Author: [Claude Code], with Justin. Status: plan, pending one decision (FIN Bridge transition).
Reads alongside the Suite plan: memory/plans/workspace-suite-architecture-and-rebuild-plan-2026-06-17.md.
Goal: make finances the first real module of The Suite, by migrating the live finance data
into lifeos Postgres (workspace-scoped + RLS) and rebuilding the UI in forge-suite, WITHOUT
breaking the live money pipeline. Be thoughtful: money data + a scheduled ingest.
1. Current state (verified 2026-06-17)¶
- Data store: SQLite
data/finance/finance.db. Tables (rows): accounts (62), transactions (8611), balances (1132), budgets (37), recurring (86), holdings (23), manual_values (37), merchant_icons (63), nw_history_grid (6040), weekly_snapshots (644), etf_constituents (827), receipts (0). - Idempotency keys: transactions UNIQUE(source, external_id); SimpleFIN ids
simplefin_txn_id(txns) andsimplefin_id(accounts). - Live pipeline (timers, all write finance.db today):
forge-finance-sync.timer->forge_finance_ingest.py= the FIN Bridge (SimpleFIN).forge-finance-snapshot.timer-> balances/weekly snapshots.forge-erpnext-post.timer-> posts to ERPNext (downstream, unaffected by where we read).forge-finance-receipt-reconcile.timer.- UI: Flask
forge-finances.service(port 8096), 14 feature blueprints: dashboard, transactions, accounts, budget, spending, cashflow, investments, networth, recurring, categorize, alerts, business, receipts, icons.
2. Target: a finance schema in lifeos¶
A new finance schema in lifeos Postgres (CT 109), workspace-scoped + RLS via
core.apply_workspace_rls(), in Justin's workspace (multi-tenant-ready for future creators).
Mirror finance.db table-for-table, adding workspace_id to every table, keeping the same natural
keys for idempotency:
| finance.db table | lifeos finance.
DDL lives as a numbered SQL migration (the Python migration runner owns lifeos DDL; Drizzle in
3. One-time backfill (SQLite -> Postgres)¶A Python script (reuse the existing finance env + psycopg admin) that reads finance.db and bulk
-inserts into lifeos 4. DECIDED (2026-06-17): full clean-slate migration, lifeos is the single source of truth¶Per Justin's standing rule ([[feedback_suite_clean_slate_rebuild]]): full migration, no mirror, no clinging. lifeos Postgres becomes the one source of truth. The SimpleFIN FIN Bridge and all finance writers are repointed to write Postgres directly; finance.db and the Flask finances app are retired once the Suite module is verified. A SQLite->Postgres mirror was explicitly rejected as bloat (two stores, a sync layer). Anti-bloat in the schema: migrate only the source data (accounts, transactions, balances, holdings, manual_values, budgets, recurring, merchant_icons). Treat derived/cache tables (nw_history_grid, weekly_snapshots, etf_constituents) as things the Python jobs regenerate against Postgres, not historical baggage to import. Reference the old code for logic; do not copy its architecture. 5. Build order¶
6. Guardrails¶
7. Decision: RESOLVED¶Full clean-slate migration (C2). lifeos single source of truth; FIN Bridge + writers repointed to Postgres; finance.db + Flask app retired after verification. No mirror. [Claude Code] |
|---|