Files
SimpleFinanceDash/.planning/phases/07-setup-wizard/07-UI-SPEC.md
Jean-Luc Makiola 3c937e68bc docs(07): fix UI-SPEC typography to 2-weight contract
Collapse 3 font weights (400/500/600) to 2 (400/600) per checker
requirement. Labels now use semibold (600) instead of medium (500).
Also improves CTA labels and adds focal point declaration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-20 20:30:50 +02:00

15 KiB

phase, slug, status, shadcn_initialized, preset, created
phase slug status shadcn_initialized preset created
7 setup-wizard draft true new-york 2026-04-20

Phase 7 — UI Design Contract

Visual and interaction contract for the 3-step setup wizard. Generated by gsd-ui-researcher, verified by gsd-ui-checker.


Design System

Property Value
Tool shadcn (new-york style)
Preset new-york, baseColor neutral, cssVariables true
Component library Radix UI (via shadcn/ui)
Icon library Lucide
Font Inter, ui-sans-serif, system-ui, sans-serif

Spacing Scale

Declared values (must be multiples of 4):

Token Value Usage
xs 4px Icon gaps, inline padding
sm 8px Compact element spacing, checkbox-to-label gap
md 16px Default element spacing, card internal padding
lg 24px Section padding, stepper step gaps
xl 32px Layout gaps, card content vertical spacing
2xl 48px Step card top/bottom padding
3xl 64px Page-level vertical centering offset

Exceptions: Sticky allocation bar uses 12px vertical padding (py-3) for visual compactness within the card.


Typography

Role Size Weight Line Height
Body 14px 400 (regular) 1.5
Label 14px 600 (semibold) 1.4
Heading 20px 600 (semibold) 1.2
Display 28px 600 (semibold) 1.2

Only two weights are used: 400 (regular) for body text and 600 (semibold) for labels, headings, and display. No medium (500) weight exists in this contract.

Usage in wizard:

  • Display (28px/600): Wizard page title "Set up your budget" (step 1 heading area)
  • Heading (20px/600): Step card titles ("Monthly Income", "Recurring Items", "Review")
  • Label (14px/600): Category group headers (e.g., "Bills", "Variable Expenses"), stepper step labels, "Remaining to allocate" label, form field labels
  • Body (14px/400): Preset item names, amounts, helper text, step descriptions

Color

Role Value Usage
Dominant (60%) oklch(0.98 0.01 260) (--background) Page background behind wizard card
Secondary (30%) oklch(1 0 0) (--card) Wizard card surface, review summary card
Accent (10%) oklch(0.55 0.15 260) (--primary) Active stepper step indicator, primary CTA buttons, step number circles (active)
Destructive oklch(0.6 0.2 25) (--destructive) Negative "remaining to allocate" text, validation error text

Focal point: The primary CTA button ("Next Step" / "Complete Setup") in the bottom-right of the card is the single focal point on every step. It is the only large accent-colored element in the viewport, drawing the eye to the next action.

Accent reserved for:

  • Active step circle in the stepper (filled primary background)
  • "Next Step" and "Complete Setup" primary buttons
  • Income input focus ring
  • Completed step checkmark icon color

Additional semantic colors used (existing tokens):

  • --color-income (oklch(0.55 0.17 155)): Income category group header dot and badge
  • --color-bill (oklch(0.55 0.17 25)): Bill category group header dot and badge
  • --color-variable-expense (oklch(0.58 0.16 50)): Variable expense category group header dot and badge
  • --color-debt (oklch(0.52 0.18 355)): Debt category group header dot and badge
  • --color-saving (oklch(0.55 0.16 220)): Saving category group header dot and badge
  • --color-investment (oklch(0.55 0.16 285)): Investment category group header dot and badge
  • --color-on-budget (oklch(0.50 0.17 155)): Positive "remaining to allocate" text (green)

Component Inventory

New shadcn Components to Install

Component Purpose
checkbox Preset item selection in step 2

Existing Components Used

Component Where
Card, CardHeader, CardContent Wizard step container, review summary
Button Next Step, Go Back, Skip Step, Skip setup, Complete Setup
Input Income amount (step 1), per-item amount editing (step 2)
Badge Category type indicators next to preset items
Label Form field labels
Separator Between category groups in step 2 and review step

Custom Components to Build

Component Description
SetupWizard Page-level orchestrator: holds wizard state, renders stepper + active step
WizardStepper Horizontal numbered stepper bar (1-2-3) with clickable completed steps
IncomeStep Step 1: single income input with currency indicator
RecurringItemsStep Step 2: grouped checklist of 19 presets with editable amounts
ReviewStep Step 3: read-only summary of selections
AllocationBar Sticky bar showing "Remaining to allocate" with live calculation
PresetItemRow Single checklist row: checkbox + name + category badge + amount input
CategoryGroupHeader Section header with colored dot + category type label + item count

Layout Contract

Page Shell

Full viewport height, centered content:
- Container: flex min-h-screen items-center justify-center bg-background p-4
- No sidebar, no app nav — standalone page like login/register
- Content wrapper: w-full max-w-2xl (672px) with vertical flex layout

Stepper Bar

Position: Above the card, inside the content wrapper
Layout: flex items-center justify-center gap-8
Each step: 
  - Circle: 32px (w-8 h-8), centered number text (14px/600)
  - Active: bg-primary text-primary-foreground
  - Completed: bg-primary text-primary-foreground with Check icon (16px)
  - Upcoming: bg-muted text-muted-foreground border border-border
  - Connector line between steps: h-px w-16 bg-border (completed: bg-primary)
  - Step label below circle: text-xs font-semibold text-muted-foreground (active: text-foreground)
Clickable: Completed steps and current step only (not future steps)
Margin below stepper: 24px (mb-6) before the card

Step Card

Card: w-full border border-border shadow-sm
CardHeader: pb-2
  - Step title: heading (20px/600)
  - Step description: body (14px/400) text-muted-foreground, 1 line
CardContent: space-y-6

Bottom navigation row (inside CardContent, at the bottom):
  - flex justify-between items-center pt-4 border-t border-border
  - Left: Go Back button (variant="ghost", hidden on step 1) + Skip Step button (variant="ghost", text-muted-foreground)
  - Right: Next Step button (variant="default", primary) or Complete Setup button (step 3)

Step 1 — Income

Card content:
  - Label: "Monthly net income" (14px/600)
  - Input row: flex items-center gap-2
    - Input: type="number", w-full, text-right, text-lg (18px), pre-filled "3000"
    - Currency suffix: text-muted-foreground text-sm, shows profile currency (e.g., "EUR")
  - Helper text below: "Enter your total monthly take-home pay" (14px/400, text-muted-foreground)
  - Validation: if empty or <= 0 on Next Step click, show destructive text below input: "Please enter a positive income amount"

Step 2 — Recurring Items

Allocation bar (sticky):
  - Position: sticky top-0 z-10, inside the card content area
  - Layout: flex justify-between items-center py-3 px-4 bg-muted border-b border-border
  - Left: "Remaining to allocate" (14px/600)
  - Right: formatted amount (16px/600)
    - Positive or zero: text-on-budget (green)
    - Negative: text-destructive (red)
  - Updates live on every check/uncheck and amount edit

Category groups (6 groups, ordered: income, bill, variable_expense, debt, saving, investment):
  - CategoryGroupHeader: flex items-center gap-2 pt-4 pb-2
    - Colored dot: w-2.5 h-2.5 (10px) circle using category color token
    - Group label: label (14px/600) using categoryLabels from palette.ts
    - Item count badge: text-xs text-muted-foreground "(4 items)"
  - Separator below header: border-border

  PresetItemRow (per item):
    - Layout: flex items-center gap-3 py-2.5 px-1
    - Checkbox: shadcn checkbox (16px square, sharp corners via radius-0)
    - Item name: body (14px/400), flex-1
      - Uses i18n key: t(`presets.${type}.${slug}`)
    - Category badge: Badge variant="outline", text-xs, styled with category color border-left (3px)
    - Amount input: w-24 text-right, type="number"
      - Enabled only when checkbox is checked
      - Disabled state: bg-muted text-muted-foreground opacity-50
      - Pre-filled with preset defaultAmount

Default checked state:
  - bill (4 items): ALL checked
  - variable_expense (5 items): ALL checked
  - income, debt, saving, investment: ALL unchecked

Step 3 — Review

Card content:
  - Read-only summary, no editable fields
  - Income row: flex justify-between py-2
    - "Monthly income" (14px/600)
    - Formatted amount (14px/600)
  - Separator
  - Selected items grouped by category type (same order as step 2)
    - CategoryGroupHeader (same component, no checkbox)
    - Per item: flex justify-between py-1.5 px-1
      - Item name (14px/400)
      - Amount (14px/400, text-right)
  - Separator
  - Totals section: space-y-1 pt-2
    - "Total expenses" row: flex justify-between, 14px/600
    - "Remaining" row: flex justify-between, 16px/600
      - Positive: text-on-budget
      - Negative: text-destructive
  
  - If no items selected: show muted message "No items selected. You can add items to your template later."

Skip Controls

Per-step skip: Ghost button "Skip Step" in the bottom-left nav area
  - Advances to next step without saving current step data
  - On step 3 skip: same as "Skip setup" (exits wizard)

Global skip: "Skip setup" link/button
  - Position: below the card, centered, text-sm text-muted-foreground underline
  - Margin top: 16px below card
  - Action: clears localStorage, sets profiles.setup_completed = true, redirects to dashboard
  - No confirmation dialog (non-destructive — user can still manually set up template)

Interaction Contract

Step Navigation

Action Behavior
Click "Next Step" (step 1) Validate income > 0. If valid, transition to step 2. If invalid, show inline error.
Click "Next Step" (step 2) No validation required (0 items selected is valid). Transition to step 3.
Click "Go Back" Return to previous step. Preserve all entered data.
Click stepper circle (completed) Navigate to that step. Preserve all data.
Click stepper circle (future) No action. Cursor: default.
Click "Complete Setup" (step 3) Create categories + template items via API. On success: clear localStorage, set setup_completed=true, redirect to dashboard with toast.
Click "Skip Step" (per-step) Advance to next step without current step data. Step 1 skip: income stays at default or last entered value. Step 2 skip: uncheck all items.
Click "Skip setup" (global) Exit wizard entirely. Clear localStorage. Mark setup_completed=true. Redirect to dashboard. No toast.
Page refresh mid-wizard Restore wizard at the same step with all entered data from localStorage.

State Persistence (localStorage)

Key: `setup-wizard-${userId}`
Value: JSON object
{
  currentStep: 1 | 2 | 3,
  income: number,
  selectedItems: Record<string, { checked: boolean, amount: number }>,
  // keyed by preset slug
}
Cleared on: wizard completion OR skip setup

Loading & Error States

State Behavior
Wizard loading (useFirstRunState pending) Show centered Skeleton matching card dimensions (max-w-2xl, h-64)
Completion API in progress "Complete Setup" button shows spinner + disabled. Go Back/Skip Step also disabled.
Completion API failure Toast (sonner, variant destructive): "Could not save your template. Please try again." Button re-enables. Data preserved.
Partial completion failure If categories created but template items fail: toast with "Some items could not be saved. Check your template page." Redirect to dashboard anyway.

Transitions Between Steps

No animated transitions between steps. Instant swap of step content within the card. The stepper bar updates synchronously.


Copywriting Contract

All copy must have i18n keys in both en.json and de.json. Keys live under a setup namespace.

Element EN Copy i18n Key
Page title (step 1) Set up your budget setup.title
Step 1 title Monthly Income setup.step1.title
Step 1 description How much do you earn each month? setup.step1.description
Step 1 label Monthly net income setup.step1.incomeLabel
Step 1 helper Enter your total monthly take-home pay setup.step1.helper
Step 1 validation Please enter a positive income amount setup.step1.validation
Step 2 title Recurring Items setup.step2.title
Step 2 description Select your regular monthly expenses setup.step2.description
Allocation bar label Remaining to allocate setup.step2.remaining
Step 3 title Review setup.step3.title
Step 3 description Confirm your budget template setup.step3.description
Step 3 income label Monthly income setup.step3.incomeLabel
Step 3 total label Total expenses setup.step3.totalLabel
Step 3 remaining label Remaining setup.step3.remainingLabel
Step 3 empty No items selected. You can add items to your template later. setup.step3.empty
Stepper labels Income / Items / Review setup.steps.1 / setup.steps.2 / setup.steps.3
Next button Next Step setup.next
Back button Go Back setup.back
Skip button Skip Step setup.skip
Skip setup link Skip setup setup.skipSetup
Complete button Complete Setup setup.complete
Success toast Template created! Your first budget will appear automatically. setup.toast.success
Error toast Could not save your template. Please try again. setup.toast.error
Partial error toast Some items could not be saved. Check your template page. setup.toast.partialError

Registry Safety

Registry Blocks Used Safety Gate
shadcn official checkbox not required

No third-party registries declared.


Accessibility Contract

Concern Implementation
Stepper semantics role="navigation" with aria-label="Setup progress". Each step: role="tab", aria-selected for active, aria-disabled for future.
Step content role="tabpanel" with aria-labelledby pointing to the active step tab.
Checkbox group Each category group is a fieldset with legend (visually styled as CategoryGroupHeader).
Income input aria-describedby pointing to helper text and validation error (when shown).
Allocation bar aria-live="polite" so screen readers announce remaining amount changes.
Skip links Visible, keyboard-focusable. Not hidden behind hover.
Focus management On step transition, focus moves to the step card heading.

Responsive Behavior

Breakpoint Behavior
>= 768px (md) max-w-2xl card centered, stepper horizontal with labels below circles
< 768px (sm) Card becomes full-width (mx-4). Stepper collapses: show circles only, hide step labels. Amount inputs remain w-24.
< 480px (xs) PresetItemRow: badge hidden, amount input w-20. Category group headers wrap naturally.

Checker Sign-Off

  • Dimension 1 Copywriting: PASS
  • Dimension 2 Visuals: PASS
  • Dimension 3 Color: PASS
  • Dimension 4 Typography: PASS
  • Dimension 5 Spacing: PASS
  • Dimension 6 Registry Safety: PASS

Approval: pending