docs(04): create phase plan

This commit is contained in:
2026-03-12 09:20:33 +01:00
parent e19d0b8ff7
commit 444baa5187
3 changed files with 327 additions and 2 deletions

View File

@@ -74,7 +74,10 @@ Plans:
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 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 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 **Plans:** 2 plans
Plans:
- [ ] 04-01-PLAN.md — TDD: formatCurrency locale parameter fix (FIX-01)
- [ ] 04-02-PLAN.md — Chart tooltip wiring and locale threading (IXTN-04)
## Progress ## Progress
@@ -86,4 +89,4 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4
| 1. Design Token Foundation | 2/2 | Complete | 2026-03-11 | | 1. Design Token Foundation | 2/2 | Complete | 2026-03-11 |
| 2. Layout and Brand Identity | 0/2 | In progress | - | | 2. Layout and Brand Identity | 0/2 | In progress | - |
| 3. Interaction Quality and Completeness | 0/4 | Not started | - | | 3. Interaction Quality and Completeness | 0/4 | Not started | - |
| 4. Chart Polish and Bug Fixes | 0/TBD | Not started | - | | 4. Chart Polish and Bug Fixes | 0/2 | Not started | - |

View File

@@ -0,0 +1,103 @@
---
phase: 04-chart-polish-and-bug-fixes
plan: 01
type: tdd
wave: 1
depends_on: []
files_modified:
- frontend/src/lib/format.ts
- frontend/src/lib/format.test.ts
autonomous: true
requirements:
- FIX-01
must_haves:
truths:
- "formatCurrency no longer hardcodes 'de-DE' — the default locale is 'en'"
- "formatCurrency accepts an optional third locale parameter"
- "Calling formatCurrency(1234.56, 'EUR', 'de') produces German-formatted output"
- "Calling formatCurrency(1234.56, 'USD', 'en') produces English-formatted output"
- "Calling formatCurrency(1234.56, 'EUR') without locale uses 'en' default, not 'de-DE'"
artifacts:
- path: "frontend/src/lib/format.ts"
provides: "Locale-aware formatCurrency function"
contains: "locale"
- path: "frontend/src/lib/format.test.ts"
provides: "Unit tests for formatCurrency locale behavior"
min_lines: 20
key_links:
- from: "frontend/src/lib/format.ts"
to: "Intl.NumberFormat"
via: "locale parameter passed as first arg"
pattern: "Intl\\.NumberFormat\\(locale"
---
<objective>
Fix the hardcoded `'de-DE'` locale in `formatCurrency` by adding an optional `locale` parameter with `'en'` as the default. This is the foundation for IXTN-04 (chart tooltips) and ensures all currency formatting respects the user's locale preference.
Purpose: FIX-01 — English-locale users currently see German number formatting everywhere
Output: Updated `format.ts` with locale parameter, comprehensive 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/phases/04-chart-polish-and-bug-fixes/04-RESEARCH.md
@frontend/src/lib/format.ts
</context>
<feature>
<name>Locale-aware formatCurrency</name>
<files>frontend/src/lib/format.ts, frontend/src/lib/format.test.ts</files>
<behavior>
- formatCurrency(1234.56, 'EUR', 'en') returns a string containing "1,234.56" (English grouping)
- formatCurrency(1234.56, 'EUR', 'de') returns a string containing "1.234,56" (German grouping)
- formatCurrency(1234.56, 'USD', 'en') returns a string containing "$" and "1,234.56"
- formatCurrency(1234.56, 'EUR') with NO locale arg uses 'en' default — does NOT produce German formatting
- formatCurrency(0, 'EUR', 'en') returns a string containing "0.00"
- formatCurrency(-500, 'EUR', 'en') returns a string containing "-" and "500.00"
- formatCurrency(1234.56, 'EUR', '') falls back gracefully (does not throw RangeError)
</behavior>
<implementation>
Update `frontend/src/lib/format.ts`:
```ts
export function formatCurrency(
amount: number,
currency: string = 'EUR',
locale: string = 'en'
): string {
return new Intl.NumberFormat(locale || 'en', {
style: 'currency',
currency,
}).format(amount)
}
```
Key points:
- Third parameter `locale` defaults to `'en'` (replacing hardcoded `'de-DE'`)
- Defensive `locale || 'en'` guards against empty string (which throws RangeError)
- All existing call sites pass only 2 args — they will now get English formatting instead of German
- This is intentional and correct per FIX-01
</implementation>
</feature>
<verification>
cd frontend && bun vitest run src/lib/format.test.ts
</verification>
<success_criteria>
- format.test.ts has at least 6 test cases covering locale variations, defaults, and edge cases
- All tests pass green
- formatCurrency signature has 3 parameters: amount, currency, locale
- No hardcoded 'de-DE' remains in format.ts
</success_criteria>
<output>
After completion, create `.planning/phases/04-chart-polish-and-bug-fixes/04-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,219 @@
---
phase: 04-chart-polish-and-bug-fixes
plan: 02
type: execute
wave: 2
depends_on:
- "04-01"
files_modified:
- frontend/src/pages/DashboardPage.tsx
- frontend/src/components/ExpenseBreakdown.tsx
- frontend/src/components/AvailableBalance.tsx
autonomous: true
requirements:
- IXTN-04
must_haves:
truths:
- "Hovering over an ExpenseBreakdown pie slice shows a tooltip with the category name and currency-formatted value"
- "Hovering over an AvailableBalance donut slice shows a tooltip with the segment name and currency-formatted value"
- "Chart tooltip values use the budget's currency code (not hardcoded EUR)"
- "Chart tooltip values use the user's preferred_locale for number formatting"
- "AvailableBalance center text also receives the user's locale for formatting"
artifacts:
- path: "frontend/src/components/ExpenseBreakdown.tsx"
provides: "Custom Recharts Tooltip with formatted currency"
contains: "formatCurrency"
- path: "frontend/src/components/AvailableBalance.tsx"
provides: "Custom Recharts Tooltip on donut chart + locale-aware center text"
contains: "Tooltip"
- path: "frontend/src/pages/DashboardPage.tsx"
provides: "Locale threading from useAuth to chart components"
contains: "useAuth"
key_links:
- from: "frontend/src/pages/DashboardPage.tsx"
to: "frontend/src/hooks/useAuth.ts"
via: "useAuth() hook call to get user.preferred_locale"
pattern: "useAuth\\(\\)"
- from: "frontend/src/pages/DashboardPage.tsx"
to: "frontend/src/components/ExpenseBreakdown.tsx"
via: "locale prop passed to ExpenseBreakdown"
pattern: "locale=.*userLocale"
- from: "frontend/src/pages/DashboardPage.tsx"
to: "frontend/src/components/AvailableBalance.tsx"
via: "locale prop passed to AvailableBalance"
pattern: "locale=.*userLocale"
- from: "frontend/src/components/ExpenseBreakdown.tsx"
to: "frontend/src/lib/format.ts"
via: "formatCurrency called inside Tooltip content renderer"
pattern: "formatCurrency.*budget\\.currency.*locale"
- from: "frontend/src/components/AvailableBalance.tsx"
to: "frontend/src/lib/format.ts"
via: "formatCurrency called inside Tooltip content renderer and center text"
pattern: "formatCurrency.*budget\\.currency.*locale"
---
<objective>
Wire custom currency-formatted tooltips into both chart components and thread the user's locale preference from `useAuth` through `DashboardPage` to the charts. After this plan, hovering over any chart segment shows a properly formatted currency value.
Purpose: IXTN-04 — chart tooltips currently show raw numbers without currency formatting
Output: Both charts have styled tooltips, locale flows from user settings to chart display
</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/phases/04-chart-polish-and-bug-fixes/04-RESEARCH.md
@.planning/phases/04-chart-polish-and-bug-fixes/04-01-SUMMARY.md
<interfaces>
<!-- Key types and contracts the executor needs -->
From frontend/src/lib/format.ts (after Plan 01):
```typescript
export function formatCurrency(amount: number, currency?: string, locale?: string): string
```
From frontend/src/lib/api.ts:
```typescript
export interface User {
// ...
preferred_locale: string
// ...
}
export interface BudgetDetail {
id: string
name: string
currency: string
// ...
totals: BudgetTotals
items: BudgetItem[]
}
```
From frontend/src/hooks/useAuth.ts:
```typescript
export function useAuth(): {
user: User | null
loading: boolean
login: (email: string, password: string) => Promise<void>
// ...
}
```
From frontend/src/components/ExpenseBreakdown.tsx (current):
```typescript
interface Props {
budget: BudgetDetail
}
// Needs locale prop added
```
From frontend/src/components/AvailableBalance.tsx (current):
```typescript
interface Props {
budget: BudgetDetail
}
// Needs locale prop added, also needs Tooltip import added
```
From frontend/src/lib/palette.ts:
```typescript
export type CategoryType = 'income' | 'bill' | 'variable_expense' | 'debt' | 'saving' | 'investment' | 'carryover'
export const palette: Record<CategoryType, { light: string; medium: string; base: string }>
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Add locale prop and custom Tooltip to both chart components</name>
<files>frontend/src/components/ExpenseBreakdown.tsx, frontend/src/components/AvailableBalance.tsx</files>
<action>
**ExpenseBreakdown.tsx:**
1. Add `locale?: string` to the `Props` interface
2. Import `formatCurrency` from `@/lib/format`
3. Replace bare `<Tooltip />` with a custom `content` renderer:
```tsx
<Tooltip
content={({ active, payload }) => {
if (!active || !payload?.length) return null
const item = payload[0]
return (
<div className="rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl">
<p className="font-medium text-foreground">{item.name}</p>
<p className="font-mono tabular-nums text-muted-foreground">
{formatCurrency(Number(item.value), budget.currency, locale)}
</p>
</div>
)
}}
/>
```
4. Destructure `locale = 'en'` from props with default
**AvailableBalance.tsx:**
1. Add `locale?: string` to the `Props` interface
2. Import `Tooltip` from `recharts` (add to existing import)
3. Add `<Tooltip>` with identical custom `content` renderer pattern inside the `<PieChart>` after the `<Pie>` element
4. Update the center text `formatCurrency(available, budget.currency)` call to include locale: `formatCurrency(available, budget.currency, locale)`
5. Destructure `locale = 'en'` from props with default
**Do NOT** use `ChartContainer` or `ChartTooltipContent` from shadcn — these charts use raw Recharts primitives and the project rule forbids editing shadcn ui source files.
**Tooltip styling** must match shadcn design system: `rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl` — this replicates the ChartTooltipContent styling without importing it.
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run</automated>
</verify>
<done>Both chart components accept an optional locale prop, render custom tooltips with formatCurrency, and AvailableBalance center text passes locale to formatCurrency</done>
</task>
<task type="auto">
<name>Task 2: Thread user locale from useAuth through DashboardPage to chart components</name>
<files>frontend/src/pages/DashboardPage.tsx</files>
<action>
1. Add `useAuth` import: `import { useAuth } from '@/hooks/useAuth'`
2. Inside `DashboardPage` function body, call: `const { user } = useAuth()`
3. Derive locale with defensive fallback: `const userLocale = user?.preferred_locale || 'en'`
4. Pass `locale={userLocale}` prop to both chart component instances:
- `<AvailableBalance budget={current} locale={userLocale} />`
- `<ExpenseBreakdown budget={current} locale={userLocale} />`
5. Do NOT pass locale to other components (BillsTracker, VariableExpenses, DebtTracker, FinancialOverview) — those components use formatCurrency with the new 'en' default which is correct. A full locale-threading pass across all table components is out of scope for this phase.
The `useAuth()` hook is idempotent — it reads from the same React state already initialized by `App.tsx`, so there is no double-fetch concern.
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && bun vitest run</automated>
</verify>
<done>DashboardPage calls useAuth(), derives userLocale, and passes it to both ExpenseBreakdown and AvailableBalance as a locale prop</done>
</task>
</tasks>
<verification>
1. `cd frontend && bun vitest run` — full test suite passes
2. `cd frontend && bun run build` — production build succeeds with no TypeScript errors
3. Manual: hover over ExpenseBreakdown pie slices — tooltip shows category name + formatted currency
4. Manual: hover over AvailableBalance donut slices — tooltip shows segment name + formatted currency
5. Manual: AvailableBalance center text formats using user's locale preference
</verification>
<success_criteria>
- ExpenseBreakdown shows formatted currency tooltip on hover (not raw numbers)
- AvailableBalance shows formatted currency tooltip on hover (previously had no tooltip)
- AvailableBalance center text uses the user's locale for formatting
- DashboardPage reads user.preferred_locale via useAuth and threads it to both chart components
- Full test suite and build pass with no errors
</success_criteria>
<output>
After completion, create `.planning/phases/04-chart-polish-and-bug-fixes/04-02-SUMMARY.md`
</output>