Files
SimpleFinanceDash/.planning/phases/06-template-frontend-and-workflow-replacement/06-01-PLAN.md

13 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
06-template-frontend-and-workflow-replacement 01 execute 1
frontend/src/lib/api.ts
frontend/src/hooks/useTemplate.ts
frontend/src/pages/TemplatePage.tsx
frontend/src/components/AppLayout.tsx
frontend/src/App.tsx
frontend/src/i18n/en.json
frontend/src/i18n/de.json
true
TMPL-05
truths artifacts key_links
User can navigate to a Template page from the sidebar
Template page shows current template items grouped by tier (fixed items with amounts, variable items without)
User can add a new item to the template by selecting a category and tier
User can remove an item from the template
User can reorder template items via move-up/move-down buttons
One-off tier is not available when adding template items
path provides contains
frontend/src/lib/api.ts Template API functions (get, create item, update item, delete item, reorder, generate) template
path provides exports
frontend/src/hooks/useTemplate.ts useTemplate hook with CRUD operations
useTemplate
path provides exports
frontend/src/pages/TemplatePage.tsx Template management page component
TemplatePage
path provides contains
frontend/src/components/AppLayout.tsx Sidebar nav item for Template template
path provides contains
frontend/src/App.tsx Route for /template /template
from to via pattern
frontend/src/pages/TemplatePage.tsx /api/template useTemplate hook useTemplate
from to via pattern
frontend/src/components/AppLayout.tsx /template Link component in nav to.*template
from to via pattern
frontend/src/App.tsx TemplatePage Route element Route.*template
Create the template management page where users can add, remove, and reorder fixed and variable budget items in their monthly template.

Purpose: TMPL-05 requires a dedicated template page for managing the items that auto-populate new monthly budgets. This plan builds the full frontend: API client functions, data hook, page component, routing, and navigation.

Output: Working template management page accessible from sidebar, with full CRUD for template items.

<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>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/05-template-data-model-and-api/05-01-SUMMARY.md @.planning/phases/05-template-data-model-and-api/05-02-SUMMARY.md

From backend/internal/models/models.go:

type ItemTier string
const (
    ItemTierFixed    ItemTier = "fixed"
    ItemTierVariable ItemTier = "variable"
    ItemTierOneOff   ItemTier = "one_off"
)

type TemplateItem struct {
    ID             uuid.UUID        `json:"id"`
    TemplateID     uuid.UUID        `json:"template_id"`
    CategoryID     uuid.UUID        `json:"category_id"`
    CategoryName   string           `json:"category_name,omitempty"`
    CategoryType   CategoryType     `json:"category_type,omitempty"`
    CategoryIcon   string           `json:"category_icon,omitempty"`
    ItemTier       ItemTier         `json:"item_tier"`
    BudgetedAmount *decimal.Decimal `json:"budgeted_amount"`
    SortOrder      int              `json:"sort_order"`
}

type TemplateDetail struct {
    Template  // id, user_id, name, created_at, updated_at
    Items []TemplateItem `json:"items"`
}

API endpoints (from Phase 5 Plan 02):

  • GET /api/template -> TemplateDetail (empty items array when no template)
  • PUT /api/template -> update name
  • POST /api/template/items -> add item (auto-creates template if needed)
  • PUT /api/template/items/{itemId} -> update item
  • DELETE /api/template/items/{itemId} -> remove item (204)
  • PUT /api/template/items/reorder -> batch update sort_order (204)
  • POST /api/budgets/generate -> { month: "2026-04", currency: "EUR" } -> BudgetDetail or 409

From frontend/src/lib/api.ts:

export type CategoryType = 'bill' | 'variable_expense' | 'debt' | 'saving' | 'investment' | 'income'
export interface Category {
  id: string; name: string; type: CategoryType; icon: string; sort_order: number
}
export interface BudgetItem {
  id: string; budget_id: string; category_id: string; category_name: string;
  category_type: CategoryType; budgeted_amount: number; actual_amount: number; notes: string
}
export const categories = { list: () => request<Category[]>('/categories') }

From frontend/src/components/AppLayout.tsx:

const navItems = [
  { path: '/', label: t('nav.dashboard'), icon: LayoutDashboard },
  { path: '/categories', label: t('nav.categories'), icon: Tags },
  { path: '/settings', label: t('nav.settings'), icon: Settings },
]
Task 1: API client extensions and useTemplate hook frontend/src/lib/api.ts, frontend/src/hooks/useTemplate.ts 1. In `frontend/src/lib/api.ts`: - Add `item_tier` field to existing `BudgetItem` interface: `item_tier: 'fixed' | 'variable' | 'one_off'` - Add `ItemTier` type alias: `export type ItemTier = 'fixed' | 'variable' | 'one_off'` - Add `TemplateItem` interface: `{ id: string, template_id: string, category_id: string, category_name: string, category_type: CategoryType, category_icon: string, item_tier: ItemTier, budgeted_amount: number | null, sort_order: number }` - Add `TemplateDetail` interface: `{ id: string | null, name: string, items: TemplateItem[] }` - Add `template` API object: ``` get: () => request('/template') updateName: (name: string) => request('/template', { method: 'PUT', body: JSON.stringify({ name }) }) addItem: (data: { category_id: string, item_tier: ItemTier, budgeted_amount?: number }) => request('/template/items', { method: 'POST', body: JSON.stringify(data) }) updateItem: (itemId: string, data: { item_tier?: ItemTier, budgeted_amount?: number }) => request(`/template/items/${itemId}`, { method: 'PUT', body: JSON.stringify(data) }) deleteItem: (itemId: string) => request(`/template/items/${itemId}`, { method: 'DELETE' }) reorder: (items: { id: string, sort_order: number }[]) => request('/template/items/reorder', { method: 'PUT', body: JSON.stringify({ items }) }) ``` - Add `generate` function to `budgets` object: `generate: (data: { month: string, currency: string }) => request('/budgets/generate', { method: 'POST', body: JSON.stringify(data) })`
2. Create `frontend/src/hooks/useTemplate.ts`:
   - Import `template as templateApi, categories as categoriesApi` from api.ts
   - State: `templateDetail` (TemplateDetail | null), `categories` (Category[]), `loading` (boolean)
   - `fetchTemplate`: calls templateApi.get(), sets state
   - `fetchCategories`: calls categoriesApi.list(), sets state
   - `addItem(data)`: calls templateApi.addItem(data), then refetches template
   - `removeItem(itemId)`: calls templateApi.deleteItem(itemId), then refetches template
   - `moveItem(itemId, direction: 'up' | 'down')`: compute new sort_order values for the swapped pair, call templateApi.reorder with full item list's updated sort_orders, then refetch
   - `updateItem(itemId, data)`: calls templateApi.updateItem(itemId, data), then refetches
   - useEffect on mount: fetch both template and categories
   - Return: `{ template: templateDetail, categories, loading, addItem, removeItem, moveItem, updateItem, refetch: fetchTemplate }`
cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && npx tsc --noEmit 2>&1 | head -30 api.ts has template and generate API functions, BudgetItem includes item_tier, useTemplate hook compiles without errors Task 2: TemplatePage component, routing, navigation, and i18n frontend/src/pages/TemplatePage.tsx, frontend/src/components/AppLayout.tsx, frontend/src/App.tsx, frontend/src/i18n/en.json, frontend/src/i18n/de.json 1. Create `frontend/src/pages/TemplatePage.tsx`: - Import useTemplate hook, useTranslation, shadcn components (Card, CardHeader, CardTitle, CardContent, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Input, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Badge), EmptyState, lucide icons (FileText, Plus, Trash2, ArrowUp, ArrowDown, GripVertical) - Use `useTemplate()` to get template, categories, and CRUD functions - Layout: Card with pastel gradient header (use `headerGradient` pattern from palette.ts -- pick a suitable palette key or use inline violet/indigo gradient similar to BudgetSetup) - **Add item form** at top of card content: - Row with: Category select (filtered to exclude categories already in template), Item tier select (only "fixed" and "variable" -- NOT "one_off"), budgeted_amount Input (only shown when tier is "fixed"), Add button (Plus icon) - On add: call `addItem({ category_id, item_tier, budgeted_amount })`, clear form - Disable Add button when category not selected or (tier is fixed and amount is empty) - **Template items table** below the add form: - Columns: Reorder (up/down arrow buttons), Category (name + icon), Tier (Badge showing "Fixed" or "Variable"), Amount (show formatted amount for fixed, dash for variable), Actions (Trash2 delete button) - Items displayed in sort_order - Move up disabled on first item, move down disabled on last item - Delete button calls `removeItem(itemId)` - **Empty state** when template has no items: use EmptyState component with FileText icon, heading like "No template items", subtext explaining to add fixed and variable items - Show loading skeleton while data loads (use Skeleton component with pastel tint) - Use `useTranslation()` for all visible text via `t('template.*')` keys
2. Update `frontend/src/components/AppLayout.tsx`:
   - Import `FileText` icon from lucide-react
   - Add template nav item to `navItems` array after categories: `{ path: '/template', label: t('nav.template'), icon: FileText }`

3. Update `frontend/src/App.tsx`:
   - Import `TemplatePage` from pages
   - Add route: `<Route path="/template" element={<TemplatePage />} />`

4. Update `frontend/src/i18n/en.json`:
   - Add `"nav.template": "Template"` (inside nav object)
   - Add `"template"` object with keys:
     ```
     "title": "Monthly Template",
     "addItem": "Add Item",
     "category": "Category",
     "tier": "Tier",
     "fixed": "Fixed",
     "variable": "Variable",
     "oneOff": "One-off",
     "amount": "Amount",
     "actions": "Actions",
     "noItems": "No template items yet",
     "noItemsHint": "Add fixed and variable items to define your monthly budget template.",
     "selectCategory": "Select category",
     "selectTier": "Select tier"
     ```

5. Update `frontend/src/i18n/de.json`:
   - Add `"nav.template": "Vorlage"` (inside nav object)
   - Add `"template"` object with German translations:
     ```
     "title": "Monatliche Vorlage",
     "addItem": "Eintrag hinzufuegen",
     "category": "Kategorie",
     "tier": "Typ",
     "fixed": "Fest",
     "variable": "Variabel",
     "oneOff": "Einmalig",
     "amount": "Betrag",
     "actions": "Aktionen",
     "noItems": "Noch keine Vorlageneintraege",
     "noItemsHint": "Fuegen Sie feste und variable Eintraege hinzu, um Ihre monatliche Budgetvorlage zu definieren.",
     "selectCategory": "Kategorie auswaehlen",
     "selectTier": "Typ auswaehlen"
     ```
cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/frontend && npx tsc --noEmit 2>&1 | head -30 && bun run build 2>&1 | tail -5 Template page renders with add/remove/reorder functionality, accessible via sidebar nav item at /template, all text uses i18n keys in both EN and DE - TypeScript compiles without errors: `cd frontend && npx tsc --noEmit` - Production build succeeds: `cd frontend && bun run build` - Template page is reachable at /template route - Sidebar shows Template nav item between Categories and Settings - Template API functions exist in api.ts and have correct method/path

<success_criteria>

  • TemplatePage shows add form with category select, tier select (fixed/variable only), and conditional amount input
  • Existing template items display in a table with tier badges and delete buttons
  • Reorder arrows move items up/down and persist via API
  • Empty state shown when no template items exist
  • Sidebar navigation includes Template link
  • All UI text is i18n-translated (EN + DE) </success_criteria>
After completion, create `.planning/phases/06-template-frontend-and-workflow-replacement/06-01-SUMMARY.md`