Goals are now funded entirely through tagged transactions — no more
manually-maintained saved_cents. Free cash waterfall (income → living →
goals → free cash) is the single source of truth for where money goes.
Core changes:
- Transaction.GoalID field links outflows to goals; SavedCents is derived
via MongoDB aggregation (getGoalFundedCentsAll) instead of stored
- Waterfall on dashboard and goals page splits outflows into living vs
goal-funded using GoalID presence
- ImpactOnDisposable fixed: uses income−living−monthlyCents instead of
waterfallFreeCash−monthlyCents (was double-subtracting goal spend)
- avgMonthlySavings fixed: divides by positive-saving months only, and
uses year+month key to avoid Dec cross-year collision
Interactive waterfall drill-down:
- Click Income / Living / Goals rows to expand category breakdown
- Click a category to reveal individual transactions inline
- All rendered server-side (instant, no extra API call)
- New WaterfallRow type + IncomeCats/LivingCats/IncomeCatTxns/LivingCatTxns
on DashboardData
Goals page:
- Summary cards switched from heuristic disposable/committed to waterfall
- Each goal card shows funding history (last 5 tagged transactions)
- "Fund this goal" button links to /transactions?fund_goal=<id>
Transactions page:
- Add Transaction modal has goal picker dropdown
- submitAdd() includes goal_id in POST body
- Auto-opens modal pre-selected when arriving from goals page
Seed:
- seedGoalTransactions() back-fills tagged contributions for all 4 demo
goals (Emergency fund, House down payment, Japan trip, MacBook Pro)
- Idempotent — skips if goal-tagged transactions already exist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a holding has no price (ISIN not in the built-in map and Yahoo
rejects the raw ISIN), the portfolio page now shows an amber banner
listing each missing ISIN with an inline text input and a "Look up"
link to Yahoo Finance symbol search.
Submitting the form POSTs to /portfolio/ticker which upserts the mapping
into a finance_ticker_mappings collection keyed by (user_id, ISIN).
On the next page load custom mappings are resolved first, before the
hardcoded isinToTicker table, so user overrides always win.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Tax Summary (/tax): annual gross income from Income transactions,
FIFO capital gains/losses from trades, expenses by category, CSV export
- Household Mode (/household): link a partner account, combined
income/expense/disposable view for current month, shared goals list
- Auto Import (/auto-import): schedule recurring CSV imports with
account, format and optional source URL; delete schedules; webhook docs
- New store methods for households and import_schedules collections
- storeIface extended; mockStore updated; all tests still pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Commit/uncommit button on each goal card
- Committed goals are deducted from disposable income on the dashboard
(Available to spend now reflects reserved goal contributions)
- Conflict detection: warning banner when committed goals exceed
disposable income, showing the shortfall
- Goals summary bar: disposable before goals, reserved per month,
free to spend after committed goals
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a Goals page where users can plan financial goals before committing
to them. Each goal shows:
- Required monthly contribution to hit the deadline
- Months remaining vs months at current savings rate
- Disposable income impact (what's left after the contribution)
- Feasibility banner (green if on track, red with month delta if not)
- Progress bar once savings are tracked
Goal types: one-off purchase, deposit/down-payment, emergency fund,
recurring investment — each with a description hint in the creation modal.
Data: Goal model + store CRUD in finance_goals collection.
Nav: Goals tab added between Portfolio and Sharing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>