* infra(terraform): manage finance session secret via random_password
Replace the hand-rolled variable (with insecure hardcoded default) with a
random_password resource so Terraform auto-generates a 48-char secret and
owns the finance-api-secrets k8s Secret lifecycle.
To rotate: terraform taint random_password.finance_session_secret && terraform apply
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(finance): active sessions panel + account deletion with full data purge
Sessions panel (/account):
- AuthSession now stores IPAddress and Device (browser + OS hint)
populated from X-Forwarded-For / User-Agent on every login
- Lists all active sessions with device icon, IP, sign-in time
- Current session badge ("This device") — cannot be self-revoked
- DELETE /sessions/:id revokes any other session (user-scoped)
Account deletion (POST /account/delete):
- Password accounts require password confirmation
- OAuth accounts require typing email address to confirm
- deleteAllUserData purges all 12 finance collections + user record
in a single call: accounts, categories, transactions, trades,
ticker_mappings, goals, import_schedules, properties, loans,
permissions, households, sessions → then the user itself
- Clears session cookie and redirects to login with success message
Infrastructure:
- findAuthUserByID added to store + storeIface
- getSessionsByUserID, deleteSessionForUser added to store + storeIface
- contains() added to template FuncMap
- accountTmpl registered; GET /account, POST /account/delete,
DELETE /sessions/:id routes wired
- 🔐 nav icon links to /account page
- Full EN + PT i18n coverage for all new strings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(finance): expand unit test coverage from ~55% to 64.7%
- Add handler_coverage_test.go (~3300 lines) covering auth flows,
org request lifecycle, CSV bank import, property/loan views,
fiscal year operations, session management, and cross-handler
consistency (values shown on one page match actions on others)
- Add handler_org_test.go (~1800 lines) covering the full org
handler surface: teams, members, invites, events, budget lines,
tx requests (all status transitions), ledger, analysis, and reports
- Extend handler_test.go mockStore with: properties/loans slice fields,
authUsers map with session-aware lookup, household field, org maps,
and updateFiscalYearStatusErr for error-path testing
- Fix nav bar: Business and Account links now show active state and
use i18n keys (removes hardcoded emoji); add account key to en/pt locales
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Waterfall now drills down: click Income/Living/Goals to expand
category breakdown, click a category to see its transactions
- Goal contributions are now transaction-backed (GoalID on Transaction,
SavedCents derived from MongoDB aggregation)
- Dashboard goals widget shows this-month funding status per goal
- Goals page lists funding history transactions per goal
- Transactions modal accepts a goal pre-selection (?fund_goal=<id>)
- Categories can auto-tag a linked goal on expense creation
- Settings → categories shows linked goal column and edit modal
- Free cash "what now?" section lists underfunded committed goals
with shortfall and Fund → links; shows success state when all met
- i18n: full EN/PT coverage for all new keys
- Seed data includes goal-tagged transactions so progress is non-zero
- Bug fixes: ImpactOnDisposable double-subtraction, avgMonthlySavings
denominator using only positive-savings months, cross-year month key
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
Adds a full translation layer (English + European Portuguese) using
BurntSushi/toml with go:embed. Locale detection reads the lang cookie,
falls back to Accept-Language, then defaults to "en". A language switcher
in the nav writes the cookie and redirects back. All 20 personal finance
templates now use {{.T.Get "key"}} for every UI string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(dashboard): committed goals widget
Shows all committed goals on the dashboard with progress bars,
months remaining, saved vs target, and monthly required (green
when on track, red when not). Links to /goals for the full view.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(auth): enable TLS on ingress so Secure session cookie is honoured
BASE_URL was https:// but the ingress had no TLS block, causing the
browser to silently drop the Secure cookie after login. Adding tls: to
the Traefik ingress makes the site serve HTTPS via Traefik's default
cert so cookie and scheme match.
Also adds SeedExtras to seed goals and property/loan data independently
of the transaction-based idempotency guard in SeedAdmin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(property): Layer 3 — Dream House Simulator
Add /dream page with a four-phase simulation engine:
Phase 1 — Save the down payment (uses current property equity)
Phase 2 — Construction period (both loans running simultaneously)
Phase 3 — Sell current house, apply proceeds to construction loan
Phase 4 — Final state: just the construction loan remaining
Inputs: dream cost, down payment %, construction loan rate/term,
build duration, monthly savings, expected sale price. All pre-filled
from existing property/loan data when available.
Output: per-phase timeline cards, monthly cost bar chart, total
interest, final payoff date, and a key levers section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(plan): rename Dream House to Goal Planner at /plan
- Route /dream → /plan
- Nav label "Dream House" → "Goal Planner"
- Template dream.html → plan.html
- All user-facing labels generalised (construction loan → new loan,
build duration → acquisition/build period, current property →
current asset, dream house cost → new goal cost, etc.)
- Empty state updated with generic copy and 🎯 icon
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(goals): merge Goal Planner into /goals as a second tab
- /goals now has two tabs: "Committed goals" and "Goal Planner"
- Goal creation only happens from the Planner tab (simulate first,
then "Save as goal" → creates an uncommitted goal)
- Commitment, deadline adjustment, and deletion stay on the Goals tab
- Off-track goals show an "Adjust deadline →" button that pushes the
deadline to the realistic date based on current savings rate
- /plan and /dream both redirect to /goals?tab=planner (301)
- "Goal Planner" nav link removed; plan.html kept for redirect compat
- GoalsData gains Tab, PlanProperties, PlanLoans, HasPlanResult,
PlanResult, PlanForm fields
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(goals): type-driven planner — Save for a purchase vs Sell & upgrade
Goal Planner tab now opens with two goal type cards:
🛒 Save for a purchase — name, target, monthly savings, optional
deadline. Shows time-to-reach at current rate, monthly needed
to hit the deadline, and a feasibility banner.
🔄 Sell & upgrade — the full four-phase transition simulator
(existing asset + loan → acquire new → sell old → payoff).
Each type has its own focused form and result section. Selecting a
type highlights the card and loads the matching form. Results include
a "Save as goal" action that drops an uncommitted goal into the
Goals tab.
Also adds runPurchaseSim() and PurchaseSimResult model.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(finance): Layer 2 — property equity flows into Net Worth
- NetWorthData gains PropertyValueCents, LoanBalanceCents, PropertyEquityCents
- NetWorth handler fetches properties + loans; adds equity to current snapshot
and uses amortisation formula to compute historical loan balances per month,
so the chart reflects how equity grew as loans were paid down
- Dashboard NetWorthCents now includes property equity
- loanBalanceAt() helper: B_n = P*(1+r)^n - (M/r)*((1+r)^n - 1)
- networth.html: inline breakdown row in hero card (cash / portfolio / equity),
new "Property equity" breakdown card (value − loans), chart gains a dashed
red "Loans outstanding" line when properties are present
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(property): resolve template, image pull, and build issues
- Fix parseTmpl missing base.html causing "base.html is undefined" error
- Change imagePullPolicy to IfNotPresent for local k3d dev workflow
- Add SERVICE_NAME to Makefile so make build-deploy uses correct image name
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
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>
- Merge Sharing + Household → /people (tab switcher: sharing | household)
- Merge Accounts + Categories → /settings (tab switcher: accounts | categories)
- Add Analysis dropdown in nav: Reports, Projections, Tax, Net Worth, What If
- Add Settings dropdown in nav: Accounts & Categories, Import CSV, Import Guide
- Legacy GET /sharing, /household, /accounts, /categories redirect 301 to new URLs
- Remove Import and Import Guide as standalone nav links
- New People handler consolidates all people-related mutations (_action field)
- New Settings handler renders both account and category lists in one page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Compute a sha256 fingerprint (date|description|amount|account_id, first
16 hex chars) for every CSV row and store it as bank_ref. At preview
time, existing fingerprints are fetched and matching rows are shown
greyed out with a "duplicate" label. At confirm time, those rows are
silently skipped — only truly new transactions are inserted.
If every row is a duplicate the user is redirected with ?notice=all_duplicates
instead of inserting an empty batch.
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>
Adds server-computed alert banners to the dashboard:
- Budget exceeded (red): when a category spend is over 100% of budget
- Budget pace warning (amber): 80%+ of budget used but <80% of month elapsed
- Goal deadline risk (amber): avg savings rate too low to hit a goal on time
- Spend pace warning (amber): disposable spending is 20%+ ahead of month progress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds /simulator page with live sliders for income change, one-off
expenses, and fixed cost shifts. Goal timelines update in real time
showing months gained/lost. Includes a savings rate bar chart from
historical monthly data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds /networth page with hero total, cash/portfolio breakdown cards,
and a month-by-month historical chart. Also shows net worth as a
value card on the dashboard with a link to the full breakdown.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Committed goals now appear in the Fixed Costs panel on the dashboard
with a "committed goal" label, and the total line uses TotalCommittedCents
(fixed costs + goal contributions) instead of total monthly expenses.
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>
- Exclude FixedCategories (Housing, Utilities, Subscriptions, Investments)
from budget health panel — they are committed costs, not variable spend
- Portfolio card and stocks panel now degrade gracefully to cost basis
when Yahoo Finance prices are unavailable, instead of showing €0
- Stocks panel shows "cost basis" label per holding when live prices
are not available
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the old KPI/chart dashboard with a focused layout that
answers the three key questions immediately:
- Hero block: "Available to spend" = income − fixed costs − spent so far,
with a progress bar showing % of disposable used vs month elapsed
- Bank math panel: detects recurring fixed expenses (Housing, Utilities,
Subscriptions, Investments) from last 3 months and shows the minimum
bank balance needed right now including a 2-week safety buffer
- Savings rate card with month-over-month delta
- Portfolio snapshot card with total value and P&L
- Stocks at a glance panel: per-holding value and P&L inline
- Budget health: thin bars per category, red when over limit
- Recent activity: last 5 transactions with category color dots
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>