From 72fb62635da890351690a71c54d8082f83cd185e Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Wed, 11 Mar 2026 22:27:07 +0100 Subject: [PATCH] fix(03): revise plans based on checker feedback --- .planning/ROADMAP.md | 11 +- .../03-00-PLAN.md | 161 ++++++++++++++++++ .../03-01-PLAN.md | 11 +- .../03-02-PLAN.md | 9 +- .../03-03-PLAN.md | 6 +- .../03-VALIDATION.md | 38 ++--- 6 files changed, 202 insertions(+), 34 deletions(-) create mode 100644 .planning/phases/03-interaction-quality-and-completeness/03-00-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index b4225e6..d557ef0 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -54,13 +54,14 @@ Plans: **Depends on**: Phase 2 **Requirements**: IXTN-01, IXTN-02, IXTN-03, IXTN-05, STATE-01, STATE-02, STATE-03 **Success Criteria** (what must be TRUE): - 1. Submitting a login, register, budget create, or budget edit form shows a spinner on the button — the user knows the request is in flight + 1. Submitting a login, register, budget create, or budget edit form shows a spinner on the button — the user knows the request is in flight (Note: Budget Edit form does not exist yet; spinner covers 3 existing forms — Login, Register, Budget Create) 2. Hovering over an inline-editable row reveals a pencil icon, making the edit affordance discoverable before clicking 3. After saving an inline edit, the row briefly flashes a confirmation color, confirming the save completed 4. Attempting to delete a category triggers a confirmation dialog before the deletion executes 5. A user with no budgets sees a designed empty state with a clear CTA on the dashboard; a user with no categories sees the same on the categories page; loading skeletons use pastel-tinted backgrounds matching their section -**Plans:** 3 plans +**Plans:** 4 plans Plans: +- [ ] 03-00-PLAN.md — Wave 0 test stub files (BudgetSetup, CategoriesPage, DashboardPage, BillsTracker) - [ ] 03-01-PLAN.md — InlineEditCell pencil icon + save callbacks, form submit spinners - [ ] 03-02-PLAN.md — Delete confirmation dialog, empty states for Dashboard and Categories - [ ] 03-03-PLAN.md — Row flash wiring in trackers, pastel-tinted loading skeletons @@ -71,18 +72,18 @@ Plans: **Requirements**: IXTN-04, FIX-01 **Success Criteria** (what must be TRUE): 1. All chart fills (donut slices, bar segments) use the semantic category colors from `lib/palette.ts` — "Bills" is the same color in the donut chart as it is in the FinancialOverview table - 2. Chart tooltips display values formatted with the budget's currency (e.g., "€1,234.56" not "1234.56") + 2. Chart tooltips display values formatted with the budget's currency (e.g., "1,234.56" not "1234.56") 3. The `formatCurrency` function uses the user's locale preference from their settings instead of the hardcoded `de-DE` — an English-locale user sees their numbers formatted correctly **Plans**: TBD ## Progress **Execution Order:** -Phases execute in numeric order: 1 → 2 → 3 → 4 +Phases execute in numeric order: 1 -> 2 -> 3 -> 4 | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| | 1. Design Token Foundation | 2/2 | Complete | 2026-03-11 | | 2. Layout and Brand Identity | 0/2 | In progress | - | -| 3. Interaction Quality and Completeness | 0/3 | Not started | - | +| 3. Interaction Quality and Completeness | 0/4 | Not started | - | | 4. Chart Polish and Bug Fixes | 0/TBD | Not started | - | diff --git a/.planning/phases/03-interaction-quality-and-completeness/03-00-PLAN.md b/.planning/phases/03-interaction-quality-and-completeness/03-00-PLAN.md new file mode 100644 index 0000000..b31cd53 --- /dev/null +++ b/.planning/phases/03-interaction-quality-and-completeness/03-00-PLAN.md @@ -0,0 +1,161 @@ +--- +phase: 03-interaction-quality-and-completeness +plan: 00 +type: execute +wave: 0 +depends_on: [] +files_modified: + - frontend/src/components/BudgetSetup.test.tsx + - frontend/src/pages/CategoriesPage.test.tsx + - frontend/src/pages/DashboardPage.test.tsx + - frontend/src/components/BillsTracker.test.tsx +autonomous: true +requirements: [IXTN-01, IXTN-05, STATE-01, STATE-02, STATE-03] + +must_haves: + truths: + - "All 4 test stub files exist and can be loaded by vitest" + - "Each stub contains at least one pending/skipped test describing the target behavior" + artifacts: + - path: "frontend/src/components/BudgetSetup.test.tsx" + provides: "Test stub for budget form spinner (IXTN-01)" + contains: "BudgetSetup" + - path: "frontend/src/pages/CategoriesPage.test.tsx" + provides: "Test stubs for delete confirmation (IXTN-05) and empty state (STATE-02)" + contains: "CategoriesPage" + - path: "frontend/src/pages/DashboardPage.test.tsx" + provides: "Test stub for dashboard empty state (STATE-01)" + contains: "DashboardPage" + - path: "frontend/src/components/BillsTracker.test.tsx" + provides: "Test stub for tinted skeleton (STATE-03)" + contains: "BillsTracker" + key_links: [] +--- + + +Create Wave 0 test stub files for the 4 components that lack test coverage. Each stub imports the component, renders it with minimal props, and contains skipped (it.skip) test cases describing the behaviors that Plans 01-03 will implement. + +Purpose: Satisfy Nyquist compliance — every task in Plans 01-03 must have a runnable test file in its verify command. Wave 0 ensures those files exist before execution begins. +Output: 4 new test files with pending test stubs. + + + +@/home/jean-luc-makiola/.claude/get-shit-done/workflows/execute-plan.md +@/home/jean-luc-makiola/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/03-interaction-quality-and-completeness/03-CONTEXT.md +@.planning/phases/03-interaction-quality-and-completeness/03-VALIDATION.md + + +From frontend/src/components/BudgetSetup.tsx: +```typescript +interface Props { + existingBudgets: Budget[] + onCreated: () => void + onCancel: () => void +} +export function BudgetSetup({ existingBudgets, onCreated, onCancel }: Props) +``` + +From frontend/src/pages/CategoriesPage.tsx: +```typescript +// Default export, no props — uses hooks internally (useTranslation, etc.) +export default function CategoriesPage() +``` + +From frontend/src/pages/DashboardPage.tsx: +```typescript +// Default export, no props — uses hooks internally +export default function DashboardPage() +``` + +From frontend/src/components/BillsTracker.tsx: +```typescript +interface Props { + budget: BudgetDetail + onUpdate: (itemId: string, data: { actual_amount?: number; budgeted_amount?: number }) => Promise +} +export function BillsTracker({ budget, onUpdate }: Props) +``` + + + + + + + Task 1: Create 4 test stub files with pending test cases + frontend/src/components/BudgetSetup.test.tsx, frontend/src/pages/CategoriesPage.test.tsx, frontend/src/pages/DashboardPage.test.tsx, frontend/src/components/BillsTracker.test.tsx + + Create each test file with the following structure: import vitest globals (describe, it, expect), import @testing-library/react (render, screen), import the component, wrap tests in a describe block, and add `it.skip` stubs for the behaviors that will be implemented in Plans 01-03. + + **BudgetSetup.test.tsx:** + - Import `BudgetSetup` from `@/components/BudgetSetup` + - Mock `@/lib/api` (budgets.create) and `react-i18next` (useTranslation returns t = key passthrough) + - `it.skip('shows spinner in create button when saving')` — IXTN-01 + - `it.skip('disables create button when saving')` — IXTN-01 + - Add one basic `it('renders without crashing')` test that renders BudgetSetup with minimal props: `existingBudgets: [], onCreated: vi.fn(), onCancel: vi.fn()` — this validates the stub file works. + + **CategoriesPage.test.tsx:** + - Import `CategoriesPage` from `@/pages/CategoriesPage` + - Mock `@/lib/api` (categories.list returns [], categories.delete) and `react-i18next` + - `it.skip('opens confirmation dialog when delete button clicked')` — IXTN-05 + - `it.skip('executes delete on confirm and shows spinner')` — IXTN-05 + - `it.skip('shows error inline when delete fails')` — IXTN-05 + - `it.skip('shows empty state when no categories exist')` — STATE-02 + - Add one basic `it('renders without crashing')` that renders CategoriesPage inside a MemoryRouter (it uses routing). + + **DashboardPage.test.tsx:** + - Import `DashboardPage` from `@/pages/DashboardPage` + - Mock `@/lib/api` (budgets.list returns []) and `react-i18next` + - `it.skip('shows empty state with CTA when no budgets')` — STATE-01 + - `it.skip('shows loading skeleton while fetching')` — STATE-03 + - Add one basic `it('renders without crashing')` that renders DashboardPage inside a MemoryRouter. + + **BillsTracker.test.tsx:** + - Import `BillsTracker` from `@/components/BillsTracker` + - Mock `react-i18next` + - `it.skip('shows tinted skeleton when no bill items')` — STATE-03 + - `it.skip('flashes row green on successful inline save')` — IXTN-03 + - `it.skip('flashes row red on failed inline save')` — IXTN-03 + - Add one basic `it('renders without crashing')` that renders BillsTracker with a minimal budget fixture (empty items array) and `onUpdate: vi.fn()`. + + For components needing MemoryRouter (page-level components with routing), wrap in `` from `react-router-dom`. + + Pattern for all mocks: + ```typescript + vi.mock('react-i18next', () => ({ + useTranslation: () => ({ t: (key: string) => key, i18n: { language: 'en' } }), + })) + ``` + + Each file MUST have at least one non-skipped test that passes to confirm the stub is valid. + + + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/BudgetSetup.test.tsx src/pages/CategoriesPage.test.tsx src/pages/DashboardPage.test.tsx src/components/BillsTracker.test.tsx + + All 4 test stub files exist, each has at least one passing basic test and multiple it.skip stubs describing target behaviors. Vitest runs all 4 files without errors. + + + + + +- `cd frontend && bun vitest run` — full test suite passes (new stubs + existing tests) +- All 4 files importable by vitest +- Each file has at least one non-skipped passing test + + + +- BudgetSetup.test.tsx, CategoriesPage.test.tsx, DashboardPage.test.tsx, BillsTracker.test.tsx all exist +- Each file has skip-marked stubs for the behaviors Plans 01-03 will implement +- Each file has at least one passing smoke test +- Full test suite remains green + + + +After completion, create `.planning/phases/03-interaction-quality-and-completeness/03-00-SUMMARY.md` + diff --git a/.planning/phases/03-interaction-quality-and-completeness/03-01-PLAN.md b/.planning/phases/03-interaction-quality-and-completeness/03-01-PLAN.md index 6c00641..4c563c0 100644 --- a/.planning/phases/03-interaction-quality-and-completeness/03-01-PLAN.md +++ b/.planning/phases/03-interaction-quality-and-completeness/03-01-PLAN.md @@ -3,7 +3,7 @@ phase: 03-interaction-quality-and-completeness plan: 01 type: execute wave: 1 -depends_on: [] +depends_on: ["03-00"] files_modified: - frontend/src/components/InlineEditCell.tsx - frontend/src/components/InlineEditCell.test.tsx @@ -49,10 +49,12 @@ must_haves: --- -Add pencil icon hover affordance and save/error callbacks to InlineEditCell, plus loading spinners to all four form submit buttons. +Add pencil icon hover affordance and save/error callbacks to InlineEditCell, plus loading spinners to three form submit buttons (Login, Register, Budget Create). Purpose: Make inline editing discoverable (pencil icon on hover) and prepare the callback interface for row-level flash feedback in downstream plans. Make form submissions feel responsive with spinner indicators. Output: Enhanced InlineEditCell with pencil + callbacks, spinner-enabled Login/Register/BudgetSetup forms. + +Note: CONTEXT.md specifies spinners on "all four forms: Login, Register, Budget Create, Budget Edit." No Budget Edit form component exists in the codebase — only BudgetSetup (create-only). Budget Edit spinner is deferred until that form is built. This plan covers the 3 existing forms. @@ -151,10 +153,12 @@ export function formatCurrency(value: number, currency: string): string - Add `className="min-w-[120px]"` to Button. - Replace button text with: `{saving ? : t('budget.create')}` + Note: CONTEXT.md mentions "Budget Edit" as a fourth form, but no Budget Edit component exists in the codebase (BudgetSetup is create-only). Spinner for Budget Edit is deferred until that form is created. + Do NOT modify any other logic in these files — only the Button content and className. - cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/LoginPage.test.tsx src/pages/RegisterPage.test.tsx && bun run build + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/LoginPage.test.tsx src/pages/RegisterPage.test.tsx src/components/BudgetSetup.test.tsx && bun run build All three form submit buttons show Spinner component when loading/saving state is true, buttons are disabled during loading, min-width prevents layout shift. Build passes with zero errors. @@ -171,6 +175,7 @@ export function formatCurrency(value: number, currency: string): string - Pencil icon renders in InlineEditCell display mode (opacity-0, visible on hover via CSS) - onSaveSuccess fires after successful save; onSaveError fires and reverts value on failure - Login, Register, BudgetSetup buttons show Spinner when loading, disabled to prevent double-submit +- Budget Edit spinner is explicitly deferred (no form component exists yet) - All existing tests continue to pass; new tests cover the added behaviors diff --git a/.planning/phases/03-interaction-quality-and-completeness/03-02-PLAN.md b/.planning/phases/03-interaction-quality-and-completeness/03-02-PLAN.md index 42b876f..37eb0fe 100644 --- a/.planning/phases/03-interaction-quality-and-completeness/03-02-PLAN.md +++ b/.planning/phases/03-interaction-quality-and-completeness/03-02-PLAN.md @@ -3,7 +3,7 @@ phase: 03-interaction-quality-and-completeness plan: 02 type: execute wave: 1 -depends_on: [] +depends_on: ["03-00"] files_modified: - frontend/src/pages/CategoriesPage.tsx - frontend/src/pages/DashboardPage.tsx @@ -105,6 +105,9 @@ export { Spinner } Task 1: Create shared EmptyState component and wire into Dashboard and Categories pages frontend/src/components/EmptyState.tsx, frontend/src/pages/DashboardPage.tsx, frontend/src/pages/CategoriesPage.tsx + **Step 0 — Check shadcn registry first (per project skill rules):** + Run `bunx --bun shadcn@latest search -q empty` in the frontend directory. If shadcn provides an EmptyState or similar component, use it instead of creating a custom one. If nothing relevant is found (expected), proceed with custom component below. + **Create `frontend/src/components/EmptyState.tsx`:** ```typescript interface EmptyStateProps { @@ -128,7 +131,7 @@ export { Spinner } - Guard the grouped cards render with `{grouped.length > 0 && grouped.map(...)}` so both empty state and cards don't show simultaneously. - cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/DashboardPage.test.tsx src/pages/CategoriesPage.test.tsx && bun run build EmptyState component exists and is used in DashboardPage (no-budgets case) and CategoriesPage (no-categories case). CategoriesPage has loading state to prevent empty-state flash. Build passes. @@ -190,7 +193,7 @@ export { Spinner } **CRITICAL:** The ON DELETE RESTRICT constraint means deleting a category with budget items returns 500. The catch block handles this — the error message displays inline in the dialog. The dialog does NOT auto-close on error, letting the user read the message and dismiss manually. - cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/pages/CategoriesPage.test.tsx && bun run build Delete button opens confirmation dialog. Confirm executes delete with spinner. Error from ON DELETE RESTRICT shows inline. Cancel closes dialog. Build passes with zero errors. diff --git a/.planning/phases/03-interaction-quality-and-completeness/03-03-PLAN.md b/.planning/phases/03-interaction-quality-and-completeness/03-03-PLAN.md index 389624b..07f1f9b 100644 --- a/.planning/phases/03-interaction-quality-and-completeness/03-03-PLAN.md +++ b/.planning/phases/03-interaction-quality-and-completeness/03-03-PLAN.md @@ -3,7 +3,7 @@ phase: 03-interaction-quality-and-completeness plan: 03 type: execute wave: 2 -depends_on: ["03-01"] +depends_on: ["03-01", "03-00"] files_modified: - frontend/src/components/BillsTracker.tsx - frontend/src/components/VariableExpenses.tsx @@ -171,7 +171,7 @@ From frontend/src/components/ui/skeleton.tsx: **Do NOT modify** the totals row or the CardHeader — only add flash state and wire callbacks. - cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun run build + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/BillsTracker.test.tsx && bun run build All three tracker components have flash state, triggerFlash helper, inline style on data rows, and onSaveSuccess/onSaveError wired to InlineEditCell. Build passes. @@ -234,7 +234,7 @@ From frontend/src/components/ui/skeleton.tsx: **Note:** These skeletons show when a budget exists but has no items of that type — they serve as visual placeholders indicating the section exists. This is distinct from the DashboardPage loading skeleton (which shows before any data loads). - cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run && bun run build + cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run src/components/BillsTracker.test.tsx src/pages/DashboardPage.test.tsx && bun run build Dashboard loading skeleton uses palette-tinted backgrounds per section. Each tracker shows tinted skeletons when no items of its type exist. All tests pass, build succeeds. diff --git a/.planning/phases/03-interaction-quality-and-completeness/03-VALIDATION.md b/.planning/phases/03-interaction-quality-and-completeness/03-VALIDATION.md index bcb1aa0..c44d064 100644 --- a/.planning/phases/03-interaction-quality-and-completeness/03-VALIDATION.md +++ b/.planning/phases/03-interaction-quality-and-completeness/03-VALIDATION.md @@ -2,7 +2,7 @@ phase: 3 slug: interaction-quality-and-completeness status: draft -nyquist_compliant: false +nyquist_compliant: true wave_0_complete: false created: 2026-03-11 --- @@ -38,24 +38,22 @@ created: 2026-03-11 | Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status | |---------|------|------|-------------|-----------|-------------------|-------------|--------| -| 03-00-01 | 00 | 0 | IXTN-01 | unit stub | `bun vitest run src/components/BudgetSetup.test.tsx` | ❌ W0 | ⬜ pending | -| 03-00-02 | 00 | 0 | IXTN-05, STATE-02 | unit stub | `bun vitest run src/pages/CategoriesPage.test.tsx` | ❌ W0 | ⬜ pending | -| 03-00-03 | 00 | 0 | STATE-01 | unit stub | `bun vitest run src/pages/DashboardPage.test.tsx` | ❌ W0 | ⬜ pending | -| 03-00-04 | 00 | 0 | STATE-03 | unit stub | `bun vitest run src/components/BillsTracker.test.tsx` | ❌ W0 | ⬜ pending | -| 03-01-01 | 01 | 1 | IXTN-02, IXTN-03 | unit | `bun vitest run src/components/InlineEditCell.test.tsx` | ✅ extend | ⬜ pending | -| 03-01-02 | 01 | 1 | IXTN-01 | unit | `bun vitest run src/pages/LoginPage.test.tsx src/pages/RegisterPage.test.tsx` | ✅ extend | ⬜ pending | -| 03-01-03 | 01 | 1 | IXTN-01 | unit | `bun vitest run src/components/BudgetSetup.test.tsx` | ❌ W0 | ⬜ pending | -| 03-02-01 | 02 | 1 | IXTN-05 | unit | `bun vitest run src/pages/CategoriesPage.test.tsx` | ❌ W0 | ⬜ pending | -| 03-02-02 | 02 | 1 | STATE-01 | unit | `bun vitest run src/pages/DashboardPage.test.tsx` | ❌ W0 | ⬜ pending | -| 03-02-03 | 02 | 1 | STATE-02 | unit | `bun vitest run src/pages/CategoriesPage.test.tsx` | ❌ W0 | ⬜ pending | -| 03-02-04 | 02 | 1 | STATE-03 | unit | `bun vitest run src/components/BillsTracker.test.tsx` | ❌ W0 | ⬜ pending | +| 03-00-01 | 00 | 0 | IXTN-01, IXTN-05, STATE-01, STATE-02, STATE-03 | unit stub | `bun vitest run src/components/BudgetSetup.test.tsx src/pages/CategoriesPage.test.tsx src/pages/DashboardPage.test.tsx src/components/BillsTracker.test.tsx` | Created by 03-00 | pending | +| 03-01-01 | 01 | 1 | IXTN-02, IXTN-03 | unit | `bun vitest run src/components/InlineEditCell.test.tsx` | extend | pending | +| 03-01-02 | 01 | 1 | IXTN-01 | unit | `bun vitest run src/pages/LoginPage.test.tsx src/pages/RegisterPage.test.tsx src/components/BudgetSetup.test.tsx` | extend + W0 | pending | +| 03-02-01 | 02 | 1 | STATE-01, STATE-02 | unit | `bun vitest run src/pages/DashboardPage.test.tsx src/pages/CategoriesPage.test.tsx` | W0 | pending | +| 03-02-02 | 02 | 1 | IXTN-05 | unit | `bun vitest run src/pages/CategoriesPage.test.tsx` | W0 | pending | +| 03-03-01 | 03 | 2 | IXTN-03 | unit | `bun vitest run src/components/BillsTracker.test.tsx` | W0 | pending | +| 03-03-02 | 03 | 2 | STATE-03 | unit | `bun vitest run src/components/BillsTracker.test.tsx src/pages/DashboardPage.test.tsx` | W0 | pending | -*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* +*Status: pending / green / red / flaky* --- ## Wave 0 Requirements +Plan 03-00-PLAN.md creates all 4 stub files: + - [ ] `frontend/src/components/BudgetSetup.test.tsx` — stubs for IXTN-01 (budget form spinner) - [ ] `frontend/src/pages/CategoriesPage.test.tsx` — stubs for IXTN-05 (delete confirmation), STATE-02 (empty state) - [ ] `frontend/src/pages/DashboardPage.test.tsx` — stubs for STATE-01 (dashboard empty state) @@ -82,11 +80,11 @@ created: 2026-03-11 ## Validation Sign-Off -- [ ] All tasks have `` verify or Wave 0 dependencies -- [ ] Sampling continuity: no 3 consecutive tasks without automated verify -- [ ] Wave 0 covers all MISSING references -- [ ] No watch-mode flags -- [ ] Feedback latency < 20s -- [ ] `nyquist_compliant: true` set in frontmatter +- [x] All tasks have `` verify or Wave 0 dependencies +- [x] Sampling continuity: no 3 consecutive tasks without automated verify +- [x] Wave 0 covers all MISSING references (03-00-PLAN.md) +- [x] No watch-mode flags +- [x] Feedback latency < 20s +- [ ] `wave_0_complete: true` set after 03-00 executes -**Approval:** pending +**Approval:** pending execution