docs(01): create phase plan

This commit is contained in:
2026-03-11 19:26:25 +01:00
parent 5aa64ab178
commit d9e65a43c2
3 changed files with 594 additions and 2 deletions

View File

@@ -0,0 +1,254 @@
---
phase: 01-design-token-foundation
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- frontend/src/index.css
- frontend/src/lib/palette.ts
- frontend/src/lib/palette.test.ts
- frontend/src/test-setup.ts
- frontend/vite.config.ts
- frontend/package.json
autonomous: true
requirements:
- DSGN-01
- DSGN-02
- DSGN-05
must_haves:
truths:
- "All shadcn CSS variables in :root use pastel oklch values with non-zero chroma (no oklch(L 0 0) neutrals remain except --card which stays pure white)"
- "palette.ts exports typed color objects for all 7 category types with 3 shades each (light, medium, base)"
- "headerGradient() returns a valid CSSProperties object with a linear-gradient background"
- "amountColorClass() returns text-success for positive income, text-warning for over-budget expenses, text-destructive for negative available"
- "Custom --success and --warning CSS tokens exist in :root and are registered in @theme inline"
artifacts:
- path: "frontend/src/index.css"
provides: "Pastel oklch CSS variables for all shadcn tokens, plus --success and --warning semantic tokens"
contains: "--success"
- path: "frontend/src/lib/palette.ts"
provides: "Single source of truth for category colors with typed exports"
exports: ["palette", "CategoryType", "CategoryShades", "headerGradient", "overviewHeaderGradient", "amountColorClass"]
- path: "frontend/src/lib/palette.test.ts"
provides: "Unit tests for palette exports, headerGradient, and amountColorClass"
min_lines: 40
key_links:
- from: "frontend/src/index.css"
to: "frontend/src/lib/palette.ts"
via: "--chart-* CSS vars synced with palette base colors"
pattern: "chart-[1-5]"
- from: "frontend/src/lib/palette.ts"
to: "@/lib/utils"
via: "amountColorClass returns Tailwind utility classes that reference CSS variables"
pattern: "text-success|text-warning|text-destructive"
---
<objective>
Establish the pastel CSS variable system and palette.ts module that all subsequent visual work depends on.
Purpose: This is the foundation layer. Every component change in Plan 02 references the tokens and palette created here. Without this, component wiring would hardcode new values instead of referencing a single source of truth.
Output: Pastel-tinted index.css, typed palette.ts with helpers, passing unit tests.
</objective>
<execution_context>
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-design-token-foundation/01-CONTEXT.md
@.planning/phases/01-design-token-foundation/01-RESEARCH.md
@.planning/phases/01-design-token-foundation/01-VALIDATION.md
@frontend/src/index.css
@frontend/vite.config.ts
@frontend/package.json
</context>
<tasks>
<task type="auto">
<name>Task 1: Install test infrastructure and set up vitest</name>
<files>frontend/package.json, frontend/vite.config.ts, frontend/src/test-setup.ts</files>
<action>
1. Install test dependencies:
`cd frontend && bun add -d vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom`
2. Update `frontend/vite.config.ts` — add a `test` block inside `defineConfig`:
```
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./src/test-setup.ts'],
}
```
Import `/// <reference types="vitest" />` at the top of the file.
3. Create `frontend/src/test-setup.ts`:
```typescript
import '@testing-library/jest-dom'
```
4. Verify the test runner starts: `cd frontend && bun vitest run --reporter=verbose` (should exit 0 with "no test files found" or similar).
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run --reporter=verbose 2>&1 | tail -5</automated>
</verify>
<done>vitest runs successfully with zero failures. test-setup.ts imports jest-dom matchers. vite.config.ts has test block with jsdom environment.</done>
</task>
<task type="auto" tdd="true">
<name>Task 2: Replace CSS tokens with pastel oklch values and add success/warning tokens</name>
<files>frontend/src/index.css</files>
<behavior>
- Manual verification: every oklch value in :root has chroma > 0 (except --card which stays oklch(1 0 0) per locked decision "cards stay pure white")
- --success and --warning tokens exist in :root
- --color-success and --color-warning are registered in @theme inline
- --chart-1 through --chart-5 map to category base colors (bill, variable_expense, debt, saving, investment)
</behavior>
<action>
Replace ALL zero-chroma oklch values in the `:root` block of `frontend/src/index.css` with pastel-tinted equivalents. Follow these locked decisions:
**Background and surface tokens (lavender tint, hue ~290):**
- `--background: oklch(0.98 0.005 290)` — very subtle lavender tint
- `--card: oklch(1 0 0)` — KEEP pure white (cards float on tinted bg)
- `--card-foreground: oklch(0.145 0.005 290)` — near-black with slight tint
- `--popover: oklch(1 0 0)` — pure white like cards
- `--popover-foreground: oklch(0.145 0.005 290)`
- `--foreground: oklch(0.145 0.005 290)`
**Primary/accent tokens (soft lavender-blue, hue ~260-280):**
- `--primary: oklch(0.50 0.12 260)` — soft lavender-blue
- `--primary-foreground: oklch(0.99 0.005 290)`
- `--secondary: oklch(0.95 0.015 280)`
- `--secondary-foreground: oklch(0.25 0.01 280)`
- `--muted: oklch(0.95 0.010 280)`
- `--muted-foreground: oklch(0.50 0.01 280)`
- `--accent: oklch(0.94 0.020 280)`
- `--accent-foreground: oklch(0.25 0.01 280)`
- `--ring: oklch(0.65 0.08 260)` — tinted focus ring
- `--border: oklch(0.91 0.008 280)` — subtle lavender border
- `--input: oklch(0.91 0.008 280)`
**Sidebar tokens (slightly more distinct lavender):**
- `--sidebar: oklch(0.97 0.012 280)`
- `--sidebar-foreground: oklch(0.20 0.01 280)`
- `--sidebar-primary: oklch(0.50 0.12 260)`
- `--sidebar-primary-foreground: oklch(0.99 0.005 290)`
- `--sidebar-accent: oklch(0.93 0.020 280)`
- `--sidebar-accent-foreground: oklch(0.25 0.01 280)`
- `--sidebar-border: oklch(0.90 0.010 280)`
- `--sidebar-ring: oklch(0.65 0.08 260)`
**Chart tokens (mapped to category base colors — synced with palette.ts):**
- `--chart-1: oklch(0.76 0.12 250)` — bill (blue)
- `--chart-2: oklch(0.80 0.14 85)` — variable_expense (amber)
- `--chart-3: oklch(0.76 0.13 15)` — debt (rose)
- `--chart-4: oklch(0.75 0.13 280)` — saving (violet)
- `--chart-5: oklch(0.76 0.12 320)` — investment (pink)
**NEW semantic tokens — add to :root block:**
- `--success: oklch(0.55 0.15 145)` — green for positive amounts
- `--success-foreground: oklch(0.99 0 0)`
- `--warning: oklch(0.70 0.14 75)` — amber for over-budget
- `--warning-foreground: oklch(0.99 0 0)`
**NEW @theme inline additions — add these lines:**
```css
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
```
Do NOT modify the `.dark` block (dark mode is out of scope). Do NOT touch the `@layer base` block.
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash && grep -c "oklch.*0 0)" frontend/src/index.css | head -1</automated>
</verify>
<done>The :root block has zero remaining zero-chroma neutral tokens (except --card and --popover which are intentionally pure white). --success and --warning tokens exist in :root and are registered in @theme inline. All chart tokens map to category base colors. The .dark block is unchanged.</done>
</task>
<task type="auto" tdd="true">
<name>Task 3: Create palette.ts and palette.test.ts</name>
<files>frontend/src/lib/palette.ts, frontend/src/lib/palette.test.ts</files>
<behavior>
- palette exports all 7 CategoryType values: income, bill, variable_expense, debt, saving, investment, carryover
- Each category has 3 shades: light, medium, base — all non-empty oklch strings
- headerGradient('bill') returns { background: 'linear-gradient(to right, ...)' }
- overviewHeaderGradient() returns a multi-stop gradient for FinancialOverview
- amountColorClass({ type: 'income', actual: 100, budgeted: 0, isIncome: true }) returns 'text-success'
- amountColorClass({ type: 'income', actual: 0, budgeted: 0, isIncome: true }) returns ''
- amountColorClass({ type: 'bill', actual: 200, budgeted: 100 }) returns 'text-warning'
- amountColorClass({ type: 'bill', actual: 100, budgeted: 100 }) returns '' (exactly on budget = normal)
- amountColorClass({ type: 'bill', actual: 50, budgeted: 100 }) returns '' (under budget = normal)
- amountColorClass({ type: 'bill', actual: 0, budgeted: 0, isAvailable: true }) returns ''
- amountColorClass({ type: 'bill', actual: 500, budgeted: 0, isAvailable: true }) returns 'text-success'
- amountColorClass({ type: 'bill', actual: -100, budgeted: 0, isAvailable: true }) returns 'text-destructive'
</behavior>
<action>
**Write tests first (RED):**
Create `frontend/src/lib/palette.test.ts` with tests covering all behaviors listed above. Group into describe blocks: "palette exports", "headerGradient", "overviewHeaderGradient", "amountColorClass".
Run tests — they must FAIL (module not found).
**Write implementation (GREEN):**
Create `frontend/src/lib/palette.ts` with these exports:
1. `CategoryType` — union type of all 7 category strings
2. `CategoryShades` — interface with `light`, `medium`, `base` string fields
3. `palette` — `Record<CategoryType, CategoryShades>` with oklch values per locked decisions:
- income: hue 145 (green), light L=0.96 C=0.04, medium L=0.88 C=0.08, base L=0.76 C=0.14
- bill: hue 250 (blue), light L=0.96 C=0.03, medium L=0.88 C=0.07, base L=0.76 C=0.12
- variable_expense: hue 85 (amber), light L=0.97 C=0.04, medium L=0.90 C=0.08, base L=0.80 C=0.14
- debt: hue 15 (rose), light L=0.96 C=0.04, medium L=0.88 C=0.08, base L=0.76 C=0.13
- saving: hue 280 (violet), light L=0.95 C=0.04, medium L=0.87 C=0.08, base L=0.75 C=0.13
- investment: hue 320 (pink), light L=0.96 C=0.04, medium L=0.88 C=0.07, base L=0.76 C=0.12
- carryover: hue 210 (sky), light L=0.96 C=0.03, medium L=0.88 C=0.06, base L=0.76 C=0.11
4. `headerGradient(type: CategoryType): React.CSSProperties` — returns `{ background: 'linear-gradient(to right, ${light}, ${medium})' }`
5. `overviewHeaderGradient(): React.CSSProperties` — returns a multi-stop gradient using carryover.light, saving.light, and income.light (sky via lavender to green) for the FinancialOverview header
6. `amountColorClass(opts)` — implements the locked amount coloring rules:
- `isAvailable` or `isIncome` path: positive → 'text-success', negative → 'text-destructive', zero → ''
- Expense path: actual > budgeted → 'text-warning', else → ''
**IMPORTANT:** The base colors for bill, variable_expense, debt, saving, investment MUST match the --chart-1 through --chart-5 values set in Task 2's index.css. These are the same oklch strings.
Run tests — they must PASS.
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/lib/palette.test.ts --reporter=verbose</automated>
</verify>
<done>All palette.test.ts tests pass. palette.ts exports all 7 categories with 3 shades each. headerGradient returns valid gradient CSSProperties. amountColorClass correctly returns text-success/text-warning/text-destructive/empty string per the locked rules.</done>
</task>
</tasks>
<verification>
1. `cd frontend && bun vitest run --reporter=verbose` — all tests pass
2. `grep -c "oklch.*0 0)" frontend/src/index.css` — returns a small number (only --card and --popover intentionally white)
3. `grep "success\|warning" frontend/src/index.css` — shows the new semantic tokens
4. palette.ts exports are importable: `cd frontend && bun -e "import { palette } from './src/lib/palette'; console.log(Object.keys(palette).length)"` — prints 7
</verification>
<success_criteria>
- Zero zero-chroma neutrals remain in :root (except intentional pure white on --card/--popover)
- palette.ts is the single source of truth for 7 category types x 3 shades
- headerGradient and amountColorClass helpers work correctly per unit tests
- --success and --warning CSS variables are usable as Tailwind utilities (text-success, text-warning)
- --chart-1 through --chart-5 values match palette.ts base colors
- vitest runs with all tests green
</success_criteria>
<output>
After completion, create `.planning/phases/01-design-token-foundation/01-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,335 @@
---
phase: 01-design-token-foundation
plan: 02
type: execute
wave: 2
depends_on: ["01-01"]
files_modified:
- frontend/src/components/BillsTracker.tsx
- frontend/src/components/VariableExpenses.tsx
- frontend/src/components/DebtTracker.tsx
- frontend/src/components/AvailableBalance.tsx
- frontend/src/components/ExpenseBreakdown.tsx
- frontend/src/components/FinancialOverview.tsx
- frontend/src/components/InlineEditCell.tsx
- frontend/src/components/InlineEditCell.test.tsx
autonomous: false
requirements:
- DSGN-03
- DSGN-04
- DSGN-05
- FIX-02
must_haves:
truths:
- "Card headers on BillsTracker, VariableExpenses, DebtTracker, AvailableBalance, ExpenseBreakdown use palette-driven gradients — no hardcoded Tailwind color classes remain"
- "FinancialOverview header uses a multi-pastel gradient from overviewHeaderGradient()"
- "FinancialOverview and AvailableBalance have hero typography (text-2xl titles, p-6 padding) while other cards have regular typography (text-base titles, px-4 py-3 padding)"
- "AvailableBalance center amount is text-3xl font-bold with green/red color coding"
- "Actual amount columns show green for positive income, amber for over-budget expenses, red for negative available — budget column stays neutral"
- "InlineEditCell.tsx is a shared component replacing three duplicate InlineEditRow functions"
- "FinancialOverview rows are tinted with their category's light shade"
artifacts:
- path: "frontend/src/components/InlineEditCell.tsx"
provides: "Shared inline edit cell component"
exports: ["InlineEditCell"]
min_lines: 25
- path: "frontend/src/components/InlineEditCell.test.tsx"
provides: "Unit tests for InlineEditCell"
min_lines: 30
- path: "frontend/src/components/BillsTracker.tsx"
provides: "Bills section with palette gradient header and InlineEditCell"
contains: "headerGradient"
- path: "frontend/src/components/FinancialOverview.tsx"
provides: "Hero overview with multi-gradient header and category-tinted rows"
contains: "overviewHeaderGradient"
key_links:
- from: "frontend/src/components/BillsTracker.tsx"
to: "frontend/src/lib/palette.ts"
via: "import headerGradient and amountColorClass"
pattern: "import.*palette"
- from: "frontend/src/components/InlineEditCell.tsx"
to: "frontend/src/components/BillsTracker.tsx"
via: "BillsTracker imports and uses InlineEditCell instead of local InlineEditRow"
pattern: "InlineEditCell"
- from: "frontend/src/components/AvailableBalance.tsx"
to: "frontend/src/lib/palette.ts"
via: "Chart Cell fill uses palette[type].base instead of PASTEL_COLORS array"
pattern: "palette.*base"
---
<objective>
Wire the palette.ts module into all dashboard components — replace hardcoded gradients, apply hero typography, add amount coloring, and extract InlineEditCell.
Purpose: This transforms the visual appearance of the dashboard from generic neutrals to a cohesive pastel-themed experience. Every component now reads from the token system established in Plan 01.
Output: All 6 dashboard components updated, InlineEditCell extracted and tested.
</objective>
<execution_context>
@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md
@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-design-token-foundation/01-CONTEXT.md
@.planning/phases/01-design-token-foundation/01-RESEARCH.md
@.planning/phases/01-design-token-foundation/01-01-SUMMARY.md
@frontend/src/lib/palette.ts
@frontend/src/index.css
@frontend/src/components/BillsTracker.tsx
@frontend/src/components/VariableExpenses.tsx
@frontend/src/components/DebtTracker.tsx
@frontend/src/components/AvailableBalance.tsx
@frontend/src/components/ExpenseBreakdown.tsx
@frontend/src/components/FinancialOverview.tsx
<interfaces>
<!-- Key types and contracts from Plan 01 that this plan uses directly. -->
From src/lib/palette.ts (created in Plan 01):
```typescript
export type CategoryType = 'income' | 'bill' | 'variable_expense' | 'debt' | 'saving' | 'investment' | 'carryover'
export interface CategoryShades {
light: string // oklch — row backgrounds, tinted surfaces
medium: string // oklch — header gradient to-color, badges
base: string // oklch — chart fills, text accents
}
export const palette: Record<CategoryType, CategoryShades>
export function headerGradient(type: CategoryType): React.CSSProperties
export function overviewHeaderGradient(): React.CSSProperties
export function amountColorClass(opts: {
type: CategoryType
actual: number
budgeted: number
isIncome?: boolean
isAvailable?: boolean
}): string
```
From src/lib/utils.ts:
```typescript
export function cn(...inputs: ClassValue[]): string
```
From src/lib/format.ts:
```typescript
export function formatCurrency(value: number, currency: string): string
```
</interfaces>
</context>
<tasks>
<task type="auto" tdd="true">
<name>Task 1: Extract InlineEditCell and wire palette into all components</name>
<files>
frontend/src/components/InlineEditCell.tsx,
frontend/src/components/InlineEditCell.test.tsx,
frontend/src/components/BillsTracker.tsx,
frontend/src/components/VariableExpenses.tsx,
frontend/src/components/DebtTracker.tsx,
frontend/src/components/AvailableBalance.tsx,
frontend/src/components/ExpenseBreakdown.tsx,
frontend/src/components/FinancialOverview.tsx
</files>
<behavior>
- InlineEditCell renders formatted currency in display mode
- InlineEditCell shows an Input on click (enters edit mode)
- InlineEditCell calls onSave with parsed number on blur/Enter
- InlineEditCell does NOT call onSave if value unchanged or NaN
</behavior>
<action>
**Part A — Write InlineEditCell tests (RED):**
Create `frontend/src/components/InlineEditCell.test.tsx` with tests:
- "renders formatted currency value in display mode"
- "enters edit mode on click"
- "calls onSave with parsed number on blur"
- "does not call onSave when value unchanged"
- "calls onSave on Enter key"
Use `@testing-library/react` render + `@testing-library/user-event`. Mock `formatCurrency` from `@/lib/format` if needed, or just test the DOM output.
Run tests — they must FAIL.
**Part B — Create InlineEditCell (GREEN):**
Create `frontend/src/components/InlineEditCell.tsx` following the pattern from RESEARCH.md Pattern 5. Props interface:
```typescript
interface InlineEditCellProps {
value: number
currency: string
onSave: (value: number) => Promise<void>
className?: string
}
```
The component renders a `<TableCell>` that:
- In display mode: shows a `<span>` with `formatCurrency(value, currency)`, `cursor-pointer rounded px-2 py-1 hover:bg-muted`
- On click: switches to edit mode with `<Input type="number" step="0.01">`, autofocused
- On blur or Enter: parses the input, calls `onSave` if value changed and is a valid number, then returns to display mode
Run tests — they must PASS.
**Part C — Wire palette into all 6 dashboard components:**
For each component, apply these changes:
**BillsTracker.tsx:**
1. Remove the private `InlineEditRow` function (lines ~59-110)
2. Add imports: `import { headerGradient, amountColorClass } from '@/lib/palette'` and `import { InlineEditCell } from '@/components/InlineEditCell'`
3. Replace `<CardHeader className="bg-gradient-to-r from-blue-50 to-indigo-50">` with `<CardHeader style={headerGradient('bill')}>`
4. Replace the `<InlineEditRow>` usage with `<InlineEditCell>` inside the existing `<TableRow>`. The caller keeps the label and budget cells; InlineEditCell replaces only the actual amount cell.
5. Add `amountColorClass({ type: 'bill', actual, budgeted })` as `className` on the InlineEditCell for amount coloring. Budget column stays neutral (no color class).
**VariableExpenses.tsx:**
1. Remove the private `InlineEditRow` function (lines ~86-142)
2. Add same imports as BillsTracker
3. Replace `<CardHeader className="bg-gradient-to-r from-amber-50 to-yellow-50">` with `<CardHeader style={headerGradient('variable_expense')}>`
4. Replace `<InlineEditRow>` with `<InlineEditCell>` for the actual cell. Keep the "remaining" cell in VariableExpenses — it's NOT part of InlineEditCell.
5. Add amount coloring to the InlineEditCell className.
**DebtTracker.tsx:**
1. Remove the private `InlineEditRow` function (lines ~61-112)
2. Add same imports
3. Replace `<CardHeader className="bg-gradient-to-r from-orange-50 to-red-50">` with `<CardHeader style={headerGradient('debt')}>`
4. Replace `<InlineEditRow>` with `<InlineEditCell>` for the actual cell
5. Add amount coloring
**AvailableBalance.tsx:**
1. Remove the `PASTEL_COLORS` array constant
2. Add imports: `import { palette, headerGradient, type CategoryType } from '@/lib/palette'`
3. Replace `<CardHeader className="bg-gradient-to-r from-sky-50 to-cyan-50">` with `<CardHeader style={headerGradient('saving')} className="px-6 py-5">` (hero padding per locked decision)
4. Update `<CardTitle>` to `className="text-2xl font-semibold"` (hero typography)
5. Replace `<Cell fill={PASTEL_COLORS[index % ...]}` with `<Cell fill={palette[entry.categoryType as CategoryType]?.base ?? palette.carryover.base}>`
6. Style the center donut amount: `text-3xl font-bold tabular-nums` with `cn()` applying `text-success` when available >= 0, `text-destructive` when negative
7. Add small `text-xs text-muted-foreground` label "Available" (or translated equivalent) below the center amount
**ExpenseBreakdown.tsx:**
1. Remove the `PASTEL_COLORS` array constant
2. Add imports: `import { palette, type CategoryType } from '@/lib/palette'`
3. Replace `<CardHeader className="bg-gradient-to-r from-pink-50 to-rose-50">` with `<CardHeader style={headerGradient('debt')}>`
4. Replace `<Cell fill={PASTEL_COLORS[index % ...]}` with `<Cell fill={palette[entry.categoryType as CategoryType]?.base ?? palette.carryover.base}>`
**FinancialOverview.tsx:**
1. Add imports: `import { palette, overviewHeaderGradient, amountColorClass, type CategoryType } from '@/lib/palette'`
2. Replace `<CardHeader className="bg-gradient-to-r from-sky-50 to-indigo-50">` with `<CardHeader style={overviewHeaderGradient()} className="px-6 py-5">` (hero padding)
3. Update `<CardTitle>` to `className="text-2xl font-semibold"` (hero typography)
4. Tint each summary row with its category's light shade: add `style={{ backgroundColor: palette[categoryType].light }}` to each `<TableRow>` that represents a category
5. Apply `amountColorClass()` to actual amount cells. For the income row, pass `isIncome: true`. For the remaining/available summary row, pass `isAvailable: true`. Budget column stays neutral.
**CRITICAL anti-patterns to avoid:**
- Do NOT add `style` to `<Card>` — only to `<CardHeader>` for gradients
- Do NOT color the budget column — only actual gets colored
- Do NOT use raw Tailwind color classes like `text-green-600` — use `text-success` from the semantic token
- Do NOT edit any files in `src/components/ui/`
- Do NOT use Tailwind v3 bracket syntax `bg-[--var]` — use v4 parenthesis syntax `bg-(--var)` if needed
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run --reporter=verbose</automated>
</verify>
<done>
- InlineEditCell.test.tsx passes all tests
- palette.test.ts still passes (no regressions)
- No `InlineEditRow` private function exists in BillsTracker, VariableExpenses, or DebtTracker
- No `PASTEL_COLORS` array exists in AvailableBalance or ExpenseBreakdown
- No `bg-gradient-to-r from-blue-50` or similar hardcoded gradient classes exist in any dashboard component
- All 6 dashboard components import from `@/lib/palette`
- FinancialOverview and AvailableBalance use hero sizing (text-2xl, p-6/px-6 py-5)
- Amount coloring uses amountColorClass() — only on actual column
</done>
</task>
<task type="auto">
<name>Task 2: Build verification — ensure app compiles and no hardcoded colors remain</name>
<files>frontend/src/components/BillsTracker.tsx, frontend/src/components/VariableExpenses.tsx, frontend/src/components/DebtTracker.tsx, frontend/src/components/AvailableBalance.tsx, frontend/src/components/ExpenseBreakdown.tsx, frontend/src/components/FinancialOverview.tsx</files>
<action>
1. Run the Vite build to confirm no TypeScript errors:
`cd frontend && bun run build`
2. Run the full test suite:
`cd frontend && bun vitest run`
3. Verify no hardcoded gradient color classes remain in dashboard components:
`grep -rn "from-blue-50\|from-amber-50\|from-orange-50\|from-sky-50\|from-pink-50\|from-sky-50 to-indigo-50\|PASTEL_COLORS" frontend/src/components/`
This should return zero results.
4. Verify no raw Tailwind color utilities for amount coloring:
`grep -rn "text-green-\|text-red-\|text-amber-" frontend/src/components/`
This should return zero results (all amount colors use text-success, text-warning, text-destructive).
5. Verify InlineEditRow is fully removed:
`grep -rn "InlineEditRow" frontend/src/components/`
This should return zero results.
If any issues are found, fix them before proceeding.
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build 2>&1 | tail -5 && bun vitest run 2>&1 | tail -5</automated>
</verify>
<done>Vite production build succeeds with zero errors. All tests pass. No hardcoded gradient classes, PASTEL_COLORS arrays, InlineEditRow functions, or raw Tailwind color utilities exist in dashboard components.</done>
</task>
<task type="checkpoint:human-verify" gate="blocking">
<name>Task 3: Visual verification of pastel design token system</name>
<action>
Human verifies the complete pastel design token system and visual dashboard overhaul.
What was built:
- All shadcn components display in pastel tones (lavender-tinted backgrounds, borders, and surfaces)
- Card headers have category-specific pastel gradients (blue for bills, amber for variable expenses, rose for debt, etc.)
- FinancialOverview and AvailableBalance are visually dominant hero elements with larger text and more padding
- AvailableBalance donut center shows the amount in green (positive) or red (negative)
- Amount coloring: green for positive income, amber for over-budget expenses, red for negative available
- FinancialOverview rows are tinted with their category's pastel shade
- Charts use category colors from palette.ts (same colors as table headers)
- InlineEditCell is extracted as a shared component (click to edit actual amounts)
How to verify:
1. Start the app: `cd frontend && bun run dev` (ensure backend is running or use `docker compose up db` for database)
2. Open http://localhost:5173 in browser
3. Check these specific items:
a. Background tint: The page background should have a very subtle lavender tint; cards should be pure white floating on it
b. Card headers: Each section (Bills, Variable Expenses, Debt) should have a distinct pastel gradient header color — blue, amber, rose respectively
c. Hero elements: FinancialOverview and AvailableBalance should look visually larger/more prominent than other cards
d. Donut center: The available amount in the donut chart should be large text, colored green if positive or red if negative
e. Amount coloring: In any tracker, if an actual amount exceeds budget, it should show amber. Income actual amounts should be green. Remaining/available should be green (positive) or red (negative)
f. Row tinting: FinancialOverview summary rows should each have a subtle category-colored background
g. Inline editing: Click any actual amount in Bills/Variable Expenses/Debt — it should enter edit mode with an input field
h. Chart colors: Donut/bar chart segments should use the same colors as their corresponding card headers
</action>
<verify>Human visual inspection of dashboard at http://localhost:5173</verify>
<done>User confirms pastel theme, hero hierarchy, amount coloring, row tinting, inline editing, and chart colors all look correct.</done>
</task>
</tasks>
<verification>
1. `cd frontend && bun run build` — zero TypeScript errors
2. `cd frontend && bun vitest run` — all tests pass
3. `grep -rn "PASTEL_COLORS\|InlineEditRow\|from-blue-50\|from-amber-50\|from-orange-50\|from-sky-50\|from-pink-50" frontend/src/components/` — zero results
4. `grep -rn "text-green-\|text-red-\|text-amber-" frontend/src/components/` — zero results
5. Visual inspection confirms pastel theme, hero hierarchy, amount coloring, and inline editing
</verification>
<success_criteria>
- All 6 dashboard components use palette.ts for gradients (no hardcoded Tailwind color classes)
- FinancialOverview and AvailableBalance have hero typography and padding
- Amount coloring follows locked rules: green income, amber over-budget, red negative
- InlineEditCell is the single shared component for inline editing (3 duplicates removed)
- Charts use palette.ts base colors matching their card header categories
- Vite build succeeds, all tests pass
- User approves visual result at checkpoint
</success_criteria>
<output>
After completion, create `.planning/phases/01-design-token-foundation/01-02-SUMMARY.md`
</output>