21 KiB
Project Research Summary
Project: SimpleFinanceDash — UI/UX Overhaul Milestone Domain: Personal finance budget dashboard (React SPA, UI-only redesign) Researched: 2026-03-16 Confidence: HIGH
Executive Summary
This milestone is a pure UI/UX overhaul of an existing working application. The backend (Supabase schema, hooks, queries) is frozen. The stack is already in place — React 19, Vite 8, Tailwind CSS 4, Recharts 3.8.0, shadcn/ui, TanStack Query — and no new framework dependencies are needed. The overhaul adds three shadcn/ui primitives (chart, accordion/collapsible), extends the existing OKLCH color system, and introduces a structured component hierarchy for the dashboard. The core transformation is from a flat single-chart dashboard to a rich hybrid layout: summary KPI cards, three chart types (donut, vertical bar, horizontal bar), and collapsible per-category line-item sections.
The recommended approach is to establish design foundations first (tokens, shared components, build order primitives) before touching any page. Every visual decision — color, spacing, card style — must originate from index.css @theme inline tokens and a small set of shared components (PageShell, StatCard, CategorySection). Without this discipline, a multi-page overhaul will produce "island redesign" inconsistency: each page looks polished individually but the app feels fragmented during navigation. The dashboard phase comes second, followed by extending the design system to all remaining pages.
The highest-risk technical area is the Recharts + shadcn chart.tsx integration: the official shadcn PR for Recharts v3 is not yet merged, so the generated chart.tsx requires a known manual patch (add initialDimension to ResponsiveContainer). A close second risk is collapsible section layout shift — Recharts ResponsiveContainer instances react to parent height changes, and multiple instances on one page require debounce={50} and Radix Collapsible (not raw display:none toggle) to prevent ResizeObserver cascade errors. Both risks have documented fixes and are LOW recovery cost if addressed proactively.
Key Findings
Recommended Stack
The stack is locked; no new npm packages are required. Three shadcn/ui components must be installed via CLI: chart (Recharts theme-aware wrappers), collapsible (Radix primitive for category sections), and optionally accordion. After running npx shadcn@latest add chart, a manual one-line fix to chart.tsx is required: add initialDimension={{ width: 320, height: 200 }} to the inner ResponsiveContainer (see shadcn-ui/ui issue #9892). The existing OKLCH color palette in index.css needs only two additions: richer chroma on category colors (bump from ~0.14 to ~0.18+) and semantic status tokens (--color-over-budget, --color-on-budget, --color-budget-bar-bg).
Core technologies and their roles for this milestone:
- Recharts 3.8.0 — all three chart types (donut, bar, horizontal bar) are supported natively; stay on current version, do not introduce alternative chart libraries
- shadcn
chart.tsx—ChartContainer+ChartTooltipContentwrappers provide CSS-variable-aware theming for all Recharts instances; required patch documented in issue #9892 - shadcn
Collapsible— Radix UI primitive that animates height via CSS custom property--radix-collapsible-content-height; the correct tool for per-category collapsible sections - Tailwind CSS 4
@theme inline— single source of truth for all color tokens; all component color values must reference CSS variables, never hardcoded hex useMemoin DashboardContent — all chart data derivations must be memoized centrally; child chart components receive pre-computed data arrays and render only
Critical version note: Recharts 3 deprecated Cell in favor of shape prop, and removed blendStroke — use stroke="none" instead. Existing Cell usage still works but should not be extended.
Expected Features
Research grounded in competitor analysis (YNAB, Empower) and fintech UX standards. The full feature list lives in FEATURES.md.
Must have (table stakes — users expect these):
- Summary KPI cards (income / expenses / balance) with colored semantics and variance badges
- Donut chart with center total label and active hover expand
- Horizontal bar chart: budget vs actual per category type
- Grouped bar chart: income budgeted vs actual
- Collapsible per-category sections with line items and group totals
- Skeleton loading states that mirror the real layout structure
- Month navigation control on the dashboard (currently locked to current month)
- Consistent design language across all pages — the dashboard sets the pattern, all other pages must inherit it
Should have (differentiators, high value for low cost):
- Variance indicators (delta arrows/badges) on summary cards and section headers
- Accent-colored category section borders (
border-l-4with category CSS variable) - Empty state with actionable CTA for new months
- Carryover amount surfaced on the dashboard balance card
- Section collapse state preserved in localStorage (P3 polish)
Defer to v2+:
- Trend / multi-month charts — requires new query shape and chart layout; explicitly out of scope
- Dark mode — OKLCH infrastructure is ready but requires full contrast audit; doubles testing surface
- AI-derived insights — backend dependency; no scope here
- Drag-to-reorder categories — requires
sort_ordermutation support
Architecture Approach
The existing three-tier architecture (Pages → Hooks → Supabase) is preserved intact. The overhaul introduces a View Components layer that sits between pages and shadcn/ui primitives, and a small Shared Components layer for cross-page patterns. Hooks and library files are read-only during this milestone; all computation lives in the presentation layer via useMemo.
New components and their responsibilities:
| Component | Location | Responsibility |
|---|---|---|
DashboardContent |
components/dashboard/ |
Orchestrator: owns useMemo derivations, passes typed props to all children |
SummaryStrip + StatCard |
components/dashboard/ |
KPI cards row with semantic color and variance badge |
ChartPanel |
components/dashboard/ |
Two-column responsive grid containing all three chart instances |
IncomeBarChart |
components/dashboard/ |
Budgeted vs actual income vertical bar, wrapped in ChartContainer |
ExpenseDonutChart |
components/dashboard/ |
Expense breakdown donut with center total and custom legend |
SpendBarChart |
components/dashboard/ |
Horizontal budget vs actual by category type |
CategorySection |
components/dashboard/ |
Radix Collapsible wrapping header row + BudgetLineItems |
BudgetLineItems |
components/dashboard/ |
Line-item table reusing existing InlineEditCell / DifferenceCell atoms |
PageShell |
components/shared/ |
Cross-page consistent header with title, optional description, CTA slot |
Build order is strictly dependency-driven (see Architecture section for full sequence): install shadcn primitives first, then PageShell and StatCard, then chart components, then CategorySection, then DashboardContent as final orchestrator, then all remaining page refreshes.
Critical Pitfalls
All six pitfalls in PITFALLS.md are rated HIGH confidence with verified fixes. The top five to actively prevent:
-
Unmemoized chart data triggers triple re-renders — every
items.filter().reduce()inDashboardContentmust be wrapped inuseMemo. Adding three chart instances to a non-memoized render body multiplies re-render cost 3x and causes tooltip hover lag. Recovery cost is LOW but disrupts delivered work if caught late. -
shadcn
chart.tsxincompatibility with Recharts 3 — the generatedchart.tsxfromnpx shadcn@latest add chartwill producewidth(-1) and height(-1)warnings and potential layout failures. Apply theinitialDimensionfix toChartContainerimmediately after generation. This is a one-line fix with a documented workaround (issue #9892), but if skipped it causes all charts to silently render at zero dimensions. -
Collapsible sections trigger ResizeObserver cascade on charts — using
display:nonetoggle or rawheightanimation on category sections causes RechartsResponsiveContainerinstances above/below to rapidly resize. Fix: use RadixCollapsiblewith CSS@keyframeson--radix-collapsible-content-height, and adddebounce={50}to allResponsiveContainerinstances. -
Color accessibility regression during "rich visual" overhaul — the redesign goal of rich colors is a direct risk factor for WCAG contrast failures. The existing
text-green-600/text-red-600pattern must be audited (green-600 is borderline). All six category pie slice colors cluster at similar OKLCH lightness (~0.65–0.72) — vary lightness as well as hue. Supplement color with icons for status indicators; color alone is never sufficient. -
i18n key regressions —
i18nextsilently falls back to English when German keys are missing (fallbackLng: 'en'). Every new UI text key must be added to bothen.jsonandde.jsonin the same commit. Runi18next-scanneror manually switch to German locale before marking any phase complete.
Sixth pitfall to prevent at the outset: Design inconsistency across page refreshes. If shared components (StatCard, CategorySection header pattern, card border accents) are not extracted before page work begins, each page will develop subtle visual drift that is expensive to correct retroactively.
Implications for Roadmap
Research points to a clear four-phase structure. The ordering is driven by: (1) the build dependency chain in ARCHITECTURE.md, (2) the "design foundation before page work" principle from PITFALLS.md, and (3) the feature dependency graph in FEATURES.md.
Phase 1: Design Foundation and Primitives
Rationale: Multiple pitfalls converge on the same root cause — design tokens and shared components must exist before any page work begins. Design drift (Pitfall 6) and color accessibility failures (Pitfall 4) both require the palette and shared component abstractions to be established first. This phase has no external dependencies and produces the building blocks every subsequent phase consumes.
Delivers: Extended index.css color tokens (richer chroma, semantic status tokens), installed shadcn primitives (chart.tsx with Recharts v3 patch applied, collapsible.tsx), PageShell, StatCard / SummaryStrip components.
Addresses: Summary KPI cards (table stakes), accent-colored category borders, semantic color system, skeleton components
Avoids: Design inconsistency pitfall, color accessibility regression, CSS variable scope issues
Research flag: Standard patterns — no additional research needed. Tailwind v4 @theme inline and WCAG contrast requirements are well-documented.
Phase 2: Dashboard Charts and Layout
Rationale: Charts depend on chart.tsx from Phase 1. The dashboard is the highest-value page and establishes the full visual language for all subsequent pages. Month navigation must be included here (not deferred) because it changes how DashboardContent holds state — retrofitting it after collapsible sections are built is more disruptive than including it upfront.
Delivers: DashboardContent orchestrator with useMemo data derivations, ChartPanel with all three chart types (IncomeBarChart, ExpenseDonutChart, SpendBarChart), month navigation control, skeleton loading for charts and cards.
Addresses: Donut chart (table stakes), horizontal bar chart (P1), grouped income bar chart (P1), skeleton loading (P1), month navigation (P1)
Avoids: Unmemoized chart data pitfall (use useMemo from the start), chart.tsx Recharts v3 patch (apply in Phase 1 before this phase begins)
Research flag: Standard patterns — Recharts 3.8.0 chart implementations are fully documented. The specific chart.tsx fix is documented in issue #9892.
Phase 3: Collapsible Dashboard Sections
Rationale: CategorySection depends on Collapsible primitive (Phase 1) and BudgetLineItems (which reuses existing InlineEditCell atoms). This phase brings the dashboard to full feature completeness. Separating it from Phase 2 keeps each phase focused and ensures chart layout is stable before section collapse animations interact with chart resize behavior.
Delivers: CategorySection components with Radix Collapsible, BudgetLineItems table, group totals row, variance indicators in section headers, carryover amount on balance card.
Addresses: Collapsible sections with line items (P1), totals per section (table stakes), variance indicators (P2), carryover amount (P2)
Avoids: Collapsible layout shift pitfall — use Radix Collapsible with CSS keyframe animation and debounce={50} on all ResponsiveContainer instances; never display:none toggle
Research flag: Standard patterns — Radix Collapsible API is well-documented. The --radix-collapsible-content-height animation pattern is the established approach.
Phase 4: Full-App Design Consistency
Rationale: The dashboard establishes the design token application patterns. All other pages inherit from it. This phase is sequenced last because it depends on PageShell and the card/color patterns being proven on the dashboard first. FEATURES.md dependency graph makes this explicit: "all-pages redesign depends on dashboard being finished first."
Delivers: PageShell applied to all 9 pages, consistent card/color/typography treatment on BudgetDetailPage (highest urgency — users navigate here directly from dashboard), BudgetListPage, CategoriesPage, TemplatePage, LoginPage, RegisterPage, QuickAddPage, SettingsPage. Empty state pattern for new months.
Addresses: Consistent design language (table stakes), BudgetDetailPage polish (P1), remaining page polish (P2), empty states (P2)
Avoids: i18n key regressions — switch to German locale and run key parity check before completing each sub-page
Research flag: Standard patterns — PageShell wrapper is straightforward. The main risk is thoroughness (9 pages), not technical complexity.
Phase Ordering Rationale
- Foundation before features: Pitfall 6 (design inconsistency) has a HIGH recovery cost. Establishing
index.csstokens and shared components in Phase 1 prevents the most expensive failure mode. - Dashboard before other pages: FEATURES.md dependency graph is explicit — the dashboard establishes the patterns all pages inherit. Building it second (after foundation) lets Phase 4 apply proven patterns.
- Charts before collapsibles:
ChartPanellayout must be stable before collapsible sections are added beneath it. The ResizeObserver pitfall (Pitfall 3) is easiest to test and fix when charts are the only moving part. - Sections in their own phase: The collapsible + ResizeObserver interaction is the trickiest technical integration. Isolating it in Phase 3 limits blast radius if issues arise.
Research Flags
Phases with standard, well-documented patterns (skip /gsd:research-phase):
- Phase 1: Tailwind v4
@theme inline, OKLCH color tokens, and WCAG contrast requirements are all from official documentation with no ambiguity. - Phase 2: Recharts 3.8.0 chart implementations and the
chart.tsxfix are fully documented. Month navigation viauseBudgetshook is a straightforward state change inDashboardContent. - Phase 3: Radix Collapsible primitive is well-documented. The animation pattern with
--radix-collapsible-content-heightis the standard approach. - Phase 4:
PageShellapplication and page-by-page refresh are repetitive pattern application, not novel implementation.
No phases require pre-execution research. All major decisions are resolved by this research.
Confidence Assessment
| Area | Confidence | Notes |
|---|---|---|
| Stack | HIGH | Stack is locked and fully inspected. The one uncertainty (shadcn chart.tsx + Recharts v3 compatibility) has a documented fix in issue #9892. |
| Features | HIGH | Grounded in competitor analysis (YNAB, Empower) and fintech UX standards. Feature prioritization is opinionated and defensible. |
| Architecture | HIGH | Based on full codebase inspection. Component boundaries and build order are derived from actual file structure and import dependencies. |
| Pitfalls | HIGH | Most pitfalls verified against official docs and open Recharts/shadcn issues. Recovery strategies and warning signs documented for each. |
Overall confidence: HIGH
Gaps to Address
- shadcn
chart.tsxpatch (issue #9892): TheinitialDimensionfix is community-verified but not yet merged into the official shadcn CLI output. Apply manually after generation and verify with a smoke test (render one chart, confirm nowidth(-1)warnings in console) before proceeding with Phase 2. - WCAG contrast on category colors: The recommended OKLCH values in STACK.md (chroma bumped to ~0.18+) have not been run through a contrast checker. During Phase 1, verify each category color pair against its background at the target luminance levels. Adjust chroma or lightness if any pair fails 3:1 (non-text) or 4.5:1 (text) thresholds.
- i18n key count baseline: Before starting the overhaul, run
i18next-scanner(or manually auditen.jsonvsde.json) to establish a baseline parity count. This makes regression detection in each subsequent phase mechanical rather than manual. BudgetListPagedata shape: Research did not inspectBudgetListPageimplementation in detail. Phase 4 may uncover layout decisions that conflict with the dashboard's card pattern. Plan for one iteration pass onBudgetListPagespecifically.
Sources
Primary (HIGH confidence — official documentation)
- Recharts 3.0 Migration Guide — v3 breaking changes,
Celldeprecation,blendStrokeremoval - Recharts API: ResponsiveContainer —
debounceprop, dimension requirements - shadcn/ui Chart Docs —
ChartContainer,ChartConfig,ChartTooltipContent - shadcn/ui Accordion + Collapsible Docs — component API,
type="multiple", independent state - Radix UI Collapsible —
--radix-collapsible-content-heightanimation pattern - Tailwind CSS v4 Theme Docs —
@theme inline, CSS variable scoping, dark mode class strategy - WCAG 2.1 SC 1.4.11 Non-text Contrast — 3:1 minimum for UI components and chart elements
- WCAG SC 1.4.3 Contrast Minimum — 4.5:1 for normal text
- React useMemo — memoization patterns for derived state
- Existing codebase: full inspection of
src/pages/,src/components/,src/hooks/,src/lib/,src/index.css
Secondary (MEDIUM confidence — community sources, multiple corroborating)
- shadcn-ui/ui PR #8486 — Recharts v3 chart.tsx upgrade (open as of March 2026)
- shadcn-ui/ui Issue #9892 — Community-verified
initialDimensionfix for Recharts v3 - Recharts performance guide — memoization guidance
- Recharts ResizeObserver loop issue #1770 — confirmed bug and
debounceworkaround - YNAB / Empower competitor analysis — feature comparison basis
- Fintech dashboard design best practices — Eleken, Merge Rocks, F9 Finance — visual design conventions
- shadcn/ui Charts examples — Donut with center text, bar chart patterns
Tertiary (informing but not authoritative)
- Skeleton loading UX — LogRocket — skeleton mirrors real layout
- Empty state UX — Eleken — CTA pattern for empty states
- Color theory in finance dashboards — Extej/Medium — palette chroma recommendations
Research completed: 2026-03-16 Ready for roadmap: yes