Files
SimpleFinanceDash/.planning/research/SUMMARY.md

20 KiB

Project Research Summary

Project: SimpleFinanceDash v2.0 — Wizard Setup, Auto-Budget Creation, Sharp Pastel Design Domain: Personal finance dashboard — React SPA with Supabase backend Researched: 2026-04-02 Confidence: HIGH

Executive Summary

SimpleFinanceDash v2.0 is a UX simplification milestone on top of a fully working v1.0 app. All data infrastructure already exists — categories, templates, budget generation, charts, collapsible sections. The central problem is cognitive: new users land on a blank dashboard with no guidance, monthly budget creation requires a manual trigger, and the Quick Add feature lives on a disconnected page. The recommended approach is a three-part simplification: (1) a 3-step first-run wizard that seeds a usable template from curated defaults, (2) automatic monthly budget creation on dashboard visit when a template is populated, and (3) inline item-adding directly from the budget view to replace the isolated Quick Add page. Paired with a design system token rework (sharp radius, clearer pastels), these changes transform the app from a data entry tool into a coherent, guided experience.

The stack is locked and healthy. The only new dependencies are react-hook-form 7.72.0, zod 4.3.6, and @hookform/resolvers 5.2.2 for multi-step form validation in the wizard. Three additional shadcn/ui components are needed (progress, checkbox, scroll-area). All other work — the wizard stepper UI, design token changes, auto-budget triggering — is implemented through local code changes and SQL with no additional packages. Critically, no new DB migrations are required for features: all wizard and auto-budget writes go to existing categories, template_items, budgets, and budget_items tables via existing hooks and mutations. Two DB constraint migrations are required for safety (unique constraint on budgets(user_id, start_date) and categories(user_id, name)), and a one-time migration to set profiles.setup_completed = true for existing v1.0 users.

The primary risks are concurrency-related and data-integrity-related, not technical. Auto-budget creation via a client-side useEffect can fire multiple times (React StrictMode double-invocation, multi-tab, fast navigation), producing duplicate budget rows without a DB-level unique constraint. The wizard completion sequence is non-idempotent without explicit guards — a re-run creates duplicate categories and template items. The design token rework is a third systemic risk: changing global CSS variables (--radius, OKLCH color tokens) affects all 9 existing pages simultaneously. All three risks have clear, low-cost mitigations that must be applied before the relevant features ship, not after.

Key Findings

The project runs on React 19 + Vite 8 + TypeScript 5.9 + Tailwind CSS 4 + Recharts 2.15.4 + TanStack Query v5 + Supabase (PostgreSQL + Auth + RLS). These versions are locked and must not be changed in this milestone. Note: prior research incorrectly listed Recharts 3.x — the actual installed version is 2.15.4 per package.json, and upgrading to v3 is explicitly out of scope due to breaking changes. The backend is Supabase, not a Go service — there is no Go source code in the repository.

Core technologies (new additions only):

  • react-hook-form 7.72.0 + zod 4.3.6 + @hookform/resolvers 5.2.2 — multi-step wizard form validation; industry standard, 9.3kb bundle, handles per-step validation before advancing
  • shadcn checkbox, progress, scroll-area — three new shadcn components needed for wizard and inline add panel
  • Custom <WizardStepper> built from shadcn/ui Button + Badge + Tailwind — no external stepper library; none are dominant and all add bundle weight for 50 lines of local code
  • OKLCH two-tier pastel token system in src/index.css — surface tokens at L0.95 for backgrounds, accent tokens at L0.80 for borders/badges, existing text tokens at L~0.55 unchanged

Expected Features

Must have (table stakes — v2.0 launch):

  • 3-step first-run wizard: income → common items (pre-filled, editable, with live running balance) → review — skippable per step and as a whole
  • Pre-seeded library of ~15-20 curated items grouped by category type with static sensible default amounts
  • Auto-create current month's budget from template on dashboard visit — silent, no manual trigger
  • First-creation toast notification only ("Your April budget was created from your template"); silent for all subsequent months
  • Inline add-from-library on budget view as a shadcn Sheet panel — replaces the standalone Quick Add page
  • Quick Add removed from sidebar navigation; route kept with redirect to /budgets
  • Dashboard summary cards correctly reflecting current month budget data
  • Empty state CTAs for: empty template page, empty dashboard, empty budget view

Should have (competitive differentiators — v2.x):

  • "Edit template" shortcut link from budget view for quick access to change recurring items
  • Persistent "this month" summary widget on the dashboard sidebar
  • "Complete setup" banner for users who skipped the wizard but have an empty template
  • Running balance updating live during wizard item selection (income minus sum of selected items; frontend computation only)

Defer (v3+):

  • AI-suggested amounts based on spending history — requires historical data and ML infrastructure; static defaults are sufficient
  • CSV/bank import for actuals — already noted as a future feature in PROJECT.md
  • Mandatory wizard / forced onboarding — explicitly an anti-feature; skippable is always correct
  • Complex 6+ step wizard — drop-off increases sharply beyond step 3; confirmed by YNAB's own Oct 2025 update to shorten their onboarding

Architecture Approach

The v2.0 architecture is additive, not structural. A new WizardRoute guard wraps the existing ProtectedRoute subtree in App.tsx. A new /setup route renders SetupWizardPage as a dedicated page (not a modal overlay — dedicated URL prevents broken refresh/back behavior). The wizard completes by writing to existing tables via existing hooks. Auto-budget creation is a useEffect trigger added to DashboardPage that calls the already-existing generateFromTemplate mutation. Inline add replaces QuickAddPicker with a new AddOneOffSheet component at both call sites. Dashboard simplification removes the 3-column chart grid from DashboardContent (charts stay in the codebase but are removed from the Dashboard layout). All existing hooks and mutations (useBudgets.ts, useTemplate.ts, useCategories.ts, etc.) are read-only for this milestone.

New files:

  1. src/hooks/useFirstRunState.ts — detects first-run: categories.length === 0 OR template_items.length === 0
  2. src/data/presets.ts — static preset category list with suggested amounts (compile-time data, no DB table)
  3. src/pages/SetupWizardPage.tsx — 3-step wizard, local useState only, localStorage persistence
  4. src/components/wizard/WizardStep.tsx, CategoryDefaults.tsx, TemplateDefaults.tsx — wizard UI pieces
  5. src/components/budget/AddOneOffSheet.tsx — Sheet-based one-off item adder (replaces QuickAddPicker)

Modified files: src/App.tsx, src/components/AppLayout.tsx, src/pages/DashboardPage.tsx, src/pages/BudgetDetailPage.tsx, src/index.css, src/i18n/en.json, src/i18n/de.json

Critical Pitfalls

  1. Duplicate budget creation on concurrent auto-create — Add UNIQUE (user_id, start_date) constraint to budgets table via migration AND use INSERT ... ON CONFLICT DO NOTHING in generateFromTemplate before any auto-create code ships. Use a useRef(false) guard in the useEffect to prevent double-fire from React StrictMode.

  2. Wizard creates duplicate categories on re-run — Add UNIQUE (user_id, name) constraint to categories table; use upsert for category creation. Add profiles.setup_completed boolean; set to true in onSuccess only. Write a migration to backfill setup_completed = true for all v1.0 users with existing template items before shipping.

  3. Design token rework breaks all 9 pages silently — Token changes must be one isolated commit followed immediately by a full visual regression pass on all pages before any component code is touched. Never mix token changes and component changes in the same commit.

  4. Auto-budget defaults to wrong currency — The generateFromTemplate mutation defaults to "EUR". Auto-create must read profile.currency first and chain via TanStack Query's enabled flag: only auto-create after both the budgets list and user profile are loaded.

  5. Wizard state lost on browser refresh — Persist wizard state to localStorage keyed by wizard_state_${userId} on every step change; read on mount; clear on completion or skip. Use URL search params (?step=2) for browser back/forward support.

Implications for Roadmap

Research points to a clear five-phase structure derived from the dependency chain in ARCHITECTURE.md, the feature dependency graph in FEATURES.md, and the phase-to-pitfall mapping in PITFALLS.md.

Phase 1: Design System Token Rework

Rationale: Token changes cascade globally to all 9 existing pages. This must land first, in isolation, establishing the visual baseline before any page component is built or modified. Mixing token changes with component changes makes regressions impossible to attribute. Delivers: --radius: 0.125rem (sharp edges), refined OKLCH pastel surface/accent tokens, warmer background, softer border — applied in src/index.css only, zero component-file changes. Addresses: Sharp minimal aesthetic direction; OKLCH two-tier pastel system for category colors Avoids: Pitfall 3 (token rework breaks pages silently) — full visual pass on all 9 pages is the acceptance criterion before this phase closes. Research flag: Standard pattern — CSS custom property overrides in Tailwind v4 @theme inline are fully documented. No deeper research needed.

Phase 2: Preset Data, First-Run Detection, and DB Safety Constraints

Rationale: Both the wizard and auto-budget creation depend on knowing whether this is a first-run user and on DB constraints that prevent duplicate data. Static data and detection hook have no UI dependencies and can be built and tested in isolation. The DB constraints must exist before any write mutations are triggered. Delivers: src/data/presets.ts, src/hooks/useFirstRunState.ts, DB migration for UNIQUE (user_id, start_date) on budgets, DB migration for UNIQUE (user_id, name) on categories, DB migration for profiles.setup_completed flag with backfill for v1.0 users. Addresses: Accurate first-run detection; protection against duplicate data at the DB layer Avoids: Pitfall 1 (duplicate budgets), Pitfall 6 (duplicate categories), Pitfall 8 (first-run gate triggers for existing users) Research flag: Standard pattern. The setup_completed backfill migration needs a SQL audit of the profiles table structure before writing — low-effort verification.

Phase 3: Setup Wizard

Rationale: Depends on Phase 2 (presets data, first-run hook, DB constraints). The wizard is the core new-user experience. Building it after the data layer and constraints ensures the completion flow has correct idempotency guards from the start rather than retrofitting them later. Delivers: /setup route, SetupWizardPage (3 steps: income → items → review), wizard components, WizardRoute guard in App.tsx, localStorage state persistence, bilingual i18n keys for all wizard text. Addresses: Wizard-style first-run setup, pre-filled category items, skippable steps, running balance display Avoids: Pitfall 2 (wizard state lost on refresh) and Pitfall 6 (duplicate categories on re-run via idempotency guards) Uses: react-hook-form + zod + @hookform/resolvers (new dependencies), checkbox shadcn component Research flag: react-hook-form + zod integration is the standard shadcn/ui documented form pattern. Custom WizardStepper using shadcn primitives is a copy-paste block. No deeper research needed.

Phase 4: Auto-Budget Creation

Rationale: Depends on Phase 3 — a populated template must be possible before auto-creation is meaningful. Also depends on Phase 2 DB constraints being in place. The profile currency dependency must be resolved here, not deferred. Delivers: Auto-create useEffect in DashboardPage (with useRef guard), profile currency read (verify profiles table schema), upsert-based budget creation, first-creation toast notification via sonner. Addresses: Auto-created budget on first month visit, correct currency denomination for all users, silent creation for all subsequent months Avoids: Pitfall 1 (concurrent duplicate creation — DB constraint + ON CONFLICT guard) and Pitfall 5 (wrong currency — profile dependency resolved before mutation fires) Research flag: Verify the profiles table schema for the currency column name before writing the auto-create code. STACK.md flags this as needing confirmation. Low-effort: check supabase/migrations/ directly.

Phase 5: Inline Add-from-Library and Dashboard Simplification

Rationale: Depends on Phase 4 — inline add is only meaningful when a budget exists for the current month. Dashboard simplification (removing the chart grid) is deferred until auto-creation is working so there is no regression window where the dashboard shows only empty state. Quick Add deprecation with redirect belongs in the same phase as the replacement being functional. Delivers: AddOneOffSheet component replacing QuickAddPicker at both call sites, removal of QuickAdd from sidebar nav, redirect from /quick-add to /budgets, removal of 3-column chart grid from DashboardContent, scroll-area shadcn component. Addresses: Inline add-from-library on budget view, Quick Add page consolidation, dashboard "at a glance" simplification, empty state for removed chart area Avoids: Pitfall 4 (Quick Add removal breaks nav/bookmarks — redirect added in same commit as nav removal) Research flag: Standard component replacement pattern. No deeper research needed.

Phase Ordering Rationale

  • Tokens first because they are global-scope — any token change touches all pages. Establishing them before page work begins means every page built afterward is already on the correct visual foundation.
  • Data + constraints before UI because the wizard's correctness depends on DB-level deduplication and accurate first-run detection. Building the wizard UI first and adding guards later is the most common cause of data corruption in this pattern.
  • Wizard before auto-budget because auto-budget is only meaningful when there is a template to generate from. The wizard is the mechanism that creates the template. E2E testing of auto-budget requires a wizard-populated template.
  • Auto-budget before inline add because inline add requires a current-month budget to exist. The auto-creation flow provides that guarantee.
  • This ordering satisfies all 9 pitfall prevention phases documented in PITFALLS.md.

Research Flags

Phases needing specific verification at planning time:

  • Phase 4 (Auto-Budget Creation): Verify the profiles table schema — specifically the currency column name and whether useProfile or useAuth is the correct hook to read it from. STACK.md flags this as a "verify in planning" item. Action: check supabase/migrations/001_profiles.sql before writing the auto-create spec.

Phases with standard patterns (skip research-phase):

  • Phase 1: Tailwind v4 @theme inline and OKLCH token overrides — fully documented, established pattern in this codebase.
  • Phase 2: Static data file, boolean flag migration, unique constraint migrations — no novel patterns.
  • Phase 3: react-hook-form + zod is the standard shadcn/ui form pattern; wizard stepper is a shadcn/ui blocks copy-paste.
  • Phase 5: Component replacement using existing hooks and shadcn Sheet — established pattern within this codebase.

Confidence Assessment

Area Confidence Notes
Stack HIGH Verified against package.json and supabase/migrations/; actual installed versions confirmed; new dependencies verified via npm (April 2026); prior research's Recharts 3.x claim corrected
Features MEDIUM Grounded in competitor analysis (YNAB, Monarch, EveryDollar, Quicken Simplifi) and UX onboarding literature; no first-party user testing data for this specific app's users
Architecture HIGH Based on full codebase inspection; all hook names, mutation signatures, component locations, and file paths verified against source files
Pitfalls HIGH Direct codebase analysis for each pitfall; React StrictMode double-invocation and TanStack Query mutation patterns are well-understood; DB constraint behaviors are standard PostgreSQL

Overall confidence: HIGH

Gaps to Address

  • profiles table currency column: STACK.md's RPC SQL assumes a currency column on profiles. PITFALLS.md flags that auto-create defaults to EUR without reading it. Verify column name before Phase 4 begins — check supabase/migrations/001_profiles.sql. Low-effort, one-minute check.

  • setup_completed backfill migration: This migration must ship before or simultaneously with Phase 3 to prevent existing v1.0 users from hitting the wizard on their first v2.0 login. Write and test it in Phase 2; it is a prerequisite for Phase 3 deployment.

  • i18n for pre-filled wizard item names: The ~15-20 preset items in presets.ts have English names (Rent, Groceries, Car Insurance, etc.). German translations must exist in de.json before the wizard ships. Define translation keys directly in presets.ts at data-definition time to make the i18n requirement explicit and auditable.

  • quick_add_items user data consideration: Existing users may have data in quick_add_items that no longer surfaces in the UI after Phase 5. The new inline add uses categories, not quick_add_items. No migration is planned to bridge these. Acceptable risk for a personal/single-user app, but worth noting in user-facing release notes if the app has multiple users.

  • TanStack Query v5 useEffect mutation pattern: PITFALLS.md recommends against firing mutations inside useEffect with data dependencies. ARCHITECTURE.md uses exactly this pattern (with a useRef guard). Verify the useRef(false) guard is sufficient for TanStack Query v5's mutation lifecycle — specifically that mutate called on an already-pending mutation is silently ignored (it is, per TQ v5 docs, but confirm in implementation).

Sources

Primary (HIGH confidence)

  • package.json (project root) — authoritative installed versions; confirmed Recharts 2.15.4 not 3.x
  • supabase/migrations/002_categories.sql through 005_quick_add.sql — authoritative schema
  • src/App.tsx, src/components/AppLayout.tsx, src/pages/DashboardPage.tsx, src/pages/BudgetDetailPage.tsx — confirmed existing routing, nav items, hook usage patterns
  • src/hooks/useBudgets.ts, src/hooks/useTemplate.ts, src/hooks/useCategories.ts — confirmed existing mutation signatures
  • src/index.css, src/lib/palette.ts, src/lib/types.ts — confirmed token structure and CSS variable names
  • npm search results (April 2026) — react-hook-form 7.72.0, zod 4.3.6, @hookform/resolvers 5.2.2
  • shadcn/ui blocks page — stepper patterns available as copy-paste blocks, no npm dependency

Secondary (MEDIUM confidence)

  • YNAB, Monarch Money, EveryDollar, Quicken Simplifi — competitor feature patterns for wizard setup, auto-budget creation, and inline item adding
  • zod.dev/v4 — Zod 4 stable release notes and versioning strategy
  • Evil Martians OKLCH guide — lightness/chroma values for pastel system design
  • UX onboarding literature (UX Design Institute, UXCam, UXDA, Smashing Magazine) — wizard step count drop-off data, sheet vs. modal UX rationale
  • Recharts 3.0 migration guide — confirmed breaking changes; basis for "do not upgrade" recommendation

Tertiary (LOW confidence — informing but not authoritative)

  • TanStack Query v5 Strict Mode double-invocation behavior — inferred from known React 18/19 useEffect patterns; verify against TQ v5 mutation docs if unexpected behavior appears during implementation
  • PostgreSQL ON CONFLICT DO NOTHING behavior on Supabase PostgREST layer — standard DB behavior but confirm the exact upsert syntax works via the @supabase/supabase-js v2 client

Research completed: 2026-04-02 Ready for roadmap: yes