feat(persistence): SQLite layer, persistent budgets/goals, and UI edit retention#7
Open
pranaymodukuru wants to merge 3 commits into
Open
feat(persistence): SQLite layer, persistent budgets/goals, and UI edit retention#7pranaymodukuru wants to merge 3 commits into
pranaymodukuru wants to merge 3 commits into
Conversation
…n dashboard Introduces Phase 1 of the personal finance platform upgrade — giving the app a persistent memory so nothing is lost between sessions. - src/db.py: new SQLite schema (transactions, user_edits, budgets, goals) with full CRUD helpers, stable content-addressed tx_id, and a context manager that auto-commits/rollbacks - src/cleaner.py: after writing cleaned CSV, upsert all rows to SQLite; db_rows_written added to cleaning report - scripts/gen-dashboard-data.py: reads from SQLite first (with user_edits applied), falls back to CSV if DB not yet populated - dashboard/pages-1.jsx: useLocalStorage hook persists budget limits and goals across page reloads; goals now fully CRUD (add, edit, delete) with icon/colour picker - pyproject.toml: add fastapi + uvicorn for upcoming API layer (Phase 2) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaced INSERT OR REPLACE (which always deleted+reinserted) with an INSERT ... ON CONFLICT DO UPDATE WHERE clause that only writes when receiver, amount, category, subcategory, or description actually differ. Unchanged rows keep their original imported_at. User edits in the user_edits table are never touched by upsert_transactions regardless. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Transaction category/subcategory edits made via the inline dropdowns in
the Transactions view now survive page reloads (stored in localStorage
under pf_tx_edits). Previously they were plain useState and evaporated
on every reload.
Also brings the Vite app (src/) up to parity with the fix that
previously only landed on the legacy Babel file (pages-1.jsx):
- Budgets: slider limits persist via useLocalStorage('pf_budgets')
- Goals: full CRUD (add/edit/delete) persisted via useLocalStorage('pf_goals');
icon + colour picker; replaces the hardcoded static array
useLocalStorage hook added to src/helpers.jsx and exported for reuse.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
src/db.py): 4-table schema —transactions,user_edits,budgets,goals. Content-addressed transaction IDs (SHA256 of identity columns) ensure idempotent upserts. Theuser_editsoverlay is applied at read time, keeping base rows immutable.src/db.py,src/cleaner.py): UsesINSERT ... ON CONFLICT DO UPDATE SET ... WHERE <fields differ>so unchanged transactions are a true no-op —imported_atis preserved across re-cleans.src/cleaner.py): After writing CSV,clean()now also calls_write_to_db()so the DB stays in sync with every/clean-datarun.scripts/gen-dashboard-data.py):gen-dashboard-data.pynow prefers SQLite (with user_edits applied) and falls back to CSV when no DB exists.dashboard/src/):useLocalStoragehook tohelpers.jsxpf_tx_editsin localStorage)pf_budgets)GoalFormcomponent — icon picker, colour picker, target/progress/deadline fields (pf_goals)pyproject.toml): Addedfastapianduvicornfor the upcoming Phase 2 API layer.Architecture notes
The
user_editspattern keeps source data clean while allowing UI-driven corrections. When Phase 2 (FastAPI) lands, edits will write directly to SQLite viaPATCH /transactions/:idrather than localStorage, fixing the current array-index staleness risk.Test plan
/clean-datatwice — verifyimported_atis unchanged on second run for unmodified transactionspython scripts/gen-dashboard-data.pywith a populateddata/ledger.db— verify DB path is used🤖 Generated with Claude Code