Add savings goals tracking - #52
Merged
Merged
Conversation
Adds the "actually improves finances" feature the review flagged as missing beyond budgets — a savings goal (target amount, optional target date) with a manually-tracked contribution total, separate from expense/ income math on purpose: the household's net cash flow can go negative some months, which would make goal progress swing negative too and mean nothing to someone who never touched that money. Ships the same phased shape income tracking used: chat-driven creation and contribution (create_savings_goal, contribute_to_savings_goal, delete_savings_goal, get_savings_goals), a read-only progress section in the Expenses view for now, no edit dialog yet. savings_goals is household-shared like budgets (no user_id). Two real bugs caught in verification, not design gaps: - tests/conftest.py's TRUNCATE list didn't include the new table, so goals leaked across tests until the first run's failures pointed at it. - vite.config.js's dev proxy is an explicit path allowlist and /savings-goals was missing from it — the frontend fetch was silently hitting Vite itself instead of the backend, so the section never rendered in dev/e2e despite the API working correctly on its own. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qz6JBNFwhgem5GY3i2BEMY
main moved forward with PRs #50 (usage instrumentation + session persistence) and #51 (proactive nudges) since this branch was cut. Conflicts were both cases of two features adding adjacent schema/config blocks — resolved by keeping both sides, not choosing one: - agent/db.py: usage_events + chat_sessions table creation (from main) alongside savings_goals (from this branch). - tests/conftest.py and scripts/seed_e2e_data.py: TRUNCATE lists needed every new table name from both sides, not just one. No logic changes beyond the merge itself.
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
Adds the "actually improves finances" feature flagged as missing beyond budgets — a savings goal (target amount, optional target date) with a manually-tracked contribution total, separate from expense/income math on purpose: the household's net cash flow can go negative some months, which would make goal progress swing negative too and mean nothing to someone who never touched that money.
create_savings_goal,contribute_to_savings_goal,delete_savings_goal,get_savings_goals), a read-only progress section in the Expenses view for now, no edit dialog yet.savings_goalsis household-shared likebudgets(nouser_id).GET /savings-goalsendpoint + aSavingsGoalsSectioncomponent mirroringCategoryBreakdown/RecurringSection's visual style.Two real bugs caught in verification, not design gaps:
tests/conftest.py's TRUNCATE list didn't include the new table, so goals leaked across tests until the first run's failures pointed at it.vite.config.js's dev proxy is an explicit path allowlist and/savings-goalswas missing from it — the frontend fetch was silently hitting Vite itself instead of the backend, so the section never rendered in dev/e2e despite the API working correctly on its own (confirmed via direct curl against the backend).Test plan
uv run pytest tests/— 182 passed (newdb/api/toolscoverage: CRUD, contribution clipping at 0, soft-delete, pct-complete capping at 100%)uv run ruff check .— cleannpm run build/npm run lint— cleannpx playwright test— 82 passed, mobile + desktop, including a newsavings-goals.spec.js🤖 Generated with Claude Code
https://claude.ai/code/session_01Qz6JBNFwhgem5GY3i2BEMY
Generated by Claude Code