Consolidate the wealth Grafana dashboard 36 -> ~17 panels with zero metric loss: merge the 3 NW/contribution/growth timeseries into 1, the 11 returns/Δ stat cards into 1 returns table, the 2 yearly barcharts into 1 combo, and the 3 net-pay-vs-market-gain panels into 1 (grain dropdown); reorganize into collapsed rows. Also rebuild the projection as a Trend panel (numeric years-from-today x-axis) so it renders regardless of the dashboard time range (fixes empty-by-default). Philosophy: merge duplicates, keep every metric. [ci skip] Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.5 KiB
6.5 KiB
Wealth Dashboard Consolidation — Design (2026-06-01)
Goal
The wealth Grafana dashboard (UID wealth) has grown to 36 panels with
heavy duplication. Consolidate to ~17 panels with ZERO metric loss by
merging redundant panels, and fix the projection's empty-by-default problem.
Philosophy (user-locked): merge duplicates, keep every metric — no metric the
user tracks today is removed.
Current state — 36 panels, duplication clusters
| Cluster | Panels today | Issue |
|---|---|---|
| 1. NW/contribution/growth over time | "Net worth — total over time", "Net contribution vs market value", "Growth (market value − contribution) over time" | All restate NW = contribution + growth |
| 2. Returns/deltas stat cards | "12mo return/contrib/gain" (3) + "Δ 1d/7d/30d/90d" × (all/mkt) (8) = 11 cards | Same idea, many windows |
| 3. Net pay vs market gain | "…cumulative", "…per year", "…per month" (3) | Same comparison, 3 grains |
| 4. Yearly bars | "Yearly investment return %" + "Annual change decomposition" (2) | Same yearly data, two encodings |
| Projection row (5) | text + 3 stats + projection chart | Stats duplicate Overview; chart empty by default (shared time-range) |
Target layout — collapsed rows
Row: Overview (expanded by default)
- Keep 4 snapshot stats: Net worth · Net contribution · Growth · ROI%.
- NEW "Returns" table ← merges cluster 2 (11 cards).
tablepanel: one row per window (1d / 7d / 30d / 90d / 12mo), columns Δ all £ · Δ market £ · return %. Reuses the existing per-window latest-vs-N-days-ago SQL, UNION'd into 5 rows. Preserves every value (12mo contrib = Δall − Δmkt) and adds return-% for the short windows.
Row: Net worth over time
- NEW merged timeseries ← cluster 1: two lines —
net_contributionandtotal_value(market value) — with the growth gap shaded (fillBelowTo / area between). Optionally a 3rd faint "growth" line (= total_value − net_contribution). Reuses the "Net contribution vs market value" query. - Keep "Per-account stacked — total value" · "Cash vs invested (stacked)".
Row: Returns & contributions
- NEW yearly combo ← cluster 4: timeseries panel,
contributions+market_gainas bars (drawStyle=bars via per-series override) + areturn_pctline on a right Y-axis. One query returnsyear, contributions, market_gain, return_pct(merges the two existing yearly queries — both already share theyearly/epCTEs). - Keep "Monthly contributions vs market gain" · "Per-account ROI %".
Row: Income vs market
- NEW merged "Net pay vs market gain" ← cluster 3: one timeseries + a
$graincustom variable (cumulative/yearly/monthly). The rawSql switches bucketing on$grain. Defaultcumulative.
Row: Holdings — Keep Positions · Activity log
Row: RSUs (META) — Keep vest cadence · realized PNL
Row: Projections (rebuilt)
- Rebuild the projection chart as a Trend panel (
type: trend): numeric x-axis = years from today (0…$horizon_years), y = Low / Base / High / Historical / "Base, no new contributions". The Trend panel renders smooth multi-series lines on a numeric x — independent of the dashboard time range — so it is ALWAYS visible (fixes empty-by-default). SQL: same FV math as today, but emitm.n/12.0 AS years_from_nowinstead of a timestamp; formattable; panelxField = years_from_now. Carry over the dashed/dotted line overrides + GBP unit. - Drop the 3 projection-row stat cards (NW today / Historical return / Monthly contribution) — already in Overview (return table + snapshot). Keep the "How to view" text panel only if still useful (with Trend it's no longer needed — drop it too). Keep the 5 template vars (rate_low/base/high, monthly_contribution, horizon_years).
Panel count: 36 → ~17
4 snapshot + returns table + nw-over-time + per-account + cash-vs-invested + yearly-combo + monthly-contrib + per-account-ROI + net-pay(merged) + positions + activity-log + meta-cadence + meta-pnl + projection-trend = ~17.
Merge SQL notes (validate each against live wealth-pg before deploy)
- Returns table: 5
SELECTs (one per window) UNION ALL, each computingΔall = nw_now − nw_{ago},Δmkt = Δall − (contrib_now − contrib_{ago}),ret% = Δmkt / (nw_{ago} + 0.5·Δcontrib)·100(Modified Dietz, the existing formula). Window→interval: 1d/7d/30d/90d/12mo. - Yearly combo: extend the "Annual change decomposition" query (already has
contributions,market_gainper year) to also emitreturn_pct(the "Yearly investment return %" formula) — sameepCTE. - Net-pay
$grain: one query;cumulative= running sums,yearly/monthly= period-end deltas (reuse the month-end/year-end delta pattern shipped today).
Build / deploy / verify
- One-off Python builder (
/tmp, outside repo) loadswealth.json: removes the merged-away panels by title, adds the new merged panels +$grainvar, rebuilds the projection as a Trend panel, wraps everything in collapsed rows, assigns unique ids + clean gridPos. Clone existing panels for schema-39 fidelity where possible. - Validate:
json.load; unique ids; spot-run every new/merged target's SQL against livewealth-pg(the pg-sync sidecar) with default var values. - Deploy:
scripts/tg apply -target='module.monitoring.kubernetes_config_map.grafana_dashboards["wealth.json"]'(targeted — monitoring stack carries unrelated drift).git rebase --autostash forgejo/masterbefore push (shared repo). - Verify: ConfigMap == local file; user eyeballs each row in Grafana (esp. the Trend projection renders without touching the time picker, and the returns table + merged panels show the right numbers).
Risks
- Trend panel is flagged experimental (since v10.0) but available in v11.2;
confirm
xField+ queryformat=tableat build time. - Bars + line on one timeseries (yearly combo) needs per-series
drawStyleoverrides + a second Y-axis override — verify rendering. $grainnet-pay SQL is the fiddliest merge; validate all 3 grains.- Reorganizing into rows reshuffles gridPos for the whole dashboard — the builder must lay out rows top-to-bottom without overlaps.
- Keep the contribution-correctness fixes (LOCF view, month-end deltas) intact —
the merged panels read the same
dav_correctedview.
Out of scope
- The
dav_correctedview + the Fidelity growth-timing cosmetic (separate). - No new metrics — pure consolidation.