# Budget Analytics & Dashboard v2: page separation pattern

Use this reference when the FinanceManager Budget/Cashflow dashboard pages start collapsing into the same view or the user asks for clearer Budget Analytics.

## Core lesson

`Budget Übersicht`, `Budgetstatus`, and `Budget vs Ist` must be three different surfaces, not the same component with different route titles.

- **Budget Übersicht** = monthly cockpit answering: “How am I doing this month?”
  - KPI cards: current-month income, expenses, net cashflow, budget consumption, savings rate, open review items.
  - Main content: monthly cashflow, top expense categories, critical category lights, latest confirmed expenses, open todos.
- **Budgetstatus nach Kategorie** = operational category control answering: “Which category is on plan?”
  - Category table/cards with month budget, year budget, current-month actual, YTD actual, average month, forecast year, year deviation, traffic-light status.
  - Row click opens per-category monthly chart and confirmed transactions filtered to that category.
- **Budget vs Ist** = analysis page answering: “How do plan and reality differ across categories/time?”
  - Category budget-vs-actual bars, top overruns, top under-budget categories, income/expense per month, net-cashflow trend, category shares.

## Backend pattern

Add separated DTO/viewmodel functions instead of stretching `get_budget_overview`:

- `get_budget_dashboard_cockpit(conn, month='YYYY-MM')` with `purpose='monthly_cockpit'`.
- `get_budget_status_by_category(conn, year='YYYY')` with row-level `purpose='category_control'`, `actual_current_month`, `monthly_analysis`.
- `get_budget_vs_actual_analysis(conn, year='YYYY')` with `purpose='plan_vs_reality_analysis'`.

API shape used successfully:

- `/api/budget/dashboard/cockpit?month=2026-05`
- `/api/budget/status/categories?year=2026`
- `/api/budget/analysis/budget-vs-actual?year=2026`

## Data correctness rules

- Only confirmed `budget_transactions` count as actuals.
- Candidates do not count as actuals.
- Transfers do not count as income/expense actuals.
- `covered_by_migros` candidates must not double count.
- Filter 2025 and 2026 separately; default active budget year remains 2026 when requested.
- Current-month category alarms should consider both full-year forecast deviation and current-month over-budget conditions; a category can be operationally critical this month even if full-year forecast is still under budget.

## Frontend pattern

Create separate Vue pages/components:

- `BudgetOverviewPage.vue` for the monthly cockpit.
- `BudgetStatusPage.vue` for category control and row-click monthly detail.
- `BudgetVsActualPage.vue` for plan-vs-reality analysis.

Router must map the routes to distinct pages:

- `/planning/budget` → overview/cockpit.
- `/planning/budget/status` → category status/control.
- `/planning/budget/analysis/budget-vs-actual` → analysis.

When refactoring, update legacy tests that expected Budgetstatus mobile cards or Budget-vs-Ist content on the old overview page; those expectations should move to the correct separated page.

## Chart approach

Native SVG worked well for this sprint and avoided adding a dependency/license surface:

- Cockpit: monthly cashflow bars and top-category share bars.
- Status: per-category Jan–Dec actual bars with budget-line concept.
- Analysis: horizontal category budget-vs-actual bars, monthly income/expense bars, category share/donut-inspired block, net trend line.

Document the decision in `docs/budget/budget-analytics-dashboard-v2-chart-approach.md` if implementing in-repo. ECharts remains a later option if real tooltips/zoom/complex interactions become necessary.

## Verification checklist

- RED tests first for separated DTO `purpose` values and page-specific selectors.
- Backend tests for candidate/transfer/covered-by-Migros exclusion and year separation.
- Frontend tests for three distinct routes/pages, filters, mobile cards, and chart selectors.
- Full gate: `python -m compileall src tests`, `pytest -q`, `npm test -- --run`, `npm run build`, source/build secret scans, Git-safety, `git diff --check`, commit, push, remote-hash verification.
- Restart backend/frontend from the current checkout and verify both local API and Tailscale/Vite proxy routes.
