- Create 05-01-SUMMARY.md documenting migration, models, and query functions - Update STATE.md with decisions, metrics, and progress bar (92%) - Update ROADMAP.md phase 5 progress (1/2 plans complete) - Mark requirements TMPL-01, TMPL-02, TMPL-04 complete in REQUIREMENTS.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
6.2 KiB
Markdown
137 lines
6.2 KiB
Markdown
---
|
|
phase: 05-template-data-model-and-api
|
|
plan: 01
|
|
subsystem: database
|
|
tags: [postgres, go, pgx, migrations, templates, budget-items]
|
|
|
|
requires:
|
|
- phase: 01-foundation
|
|
provides: users/categories/budgets/budget_items tables and Go query layer
|
|
|
|
provides:
|
|
- item_tier enum (fixed, variable, one_off) on budget_items
|
|
- templates table (one-per-user via UNIQUE index)
|
|
- template_items table with CHECK constraint (no one_off allowed)
|
|
- Template, TemplateItem, TemplateDetail Go structs
|
|
- GetTemplate, UpdateTemplateName, CreateTemplateItem, UpdateTemplateItem, DeleteTemplateItem, ReorderTemplateItems query functions
|
|
- GenerateBudgetFromTemplate query function with duplicate-month detection and locale-aware naming
|
|
- Updated CreateBudgetItem, UpdateBudgetItem, GetBudgetWithItems, CopyBudgetItems with item_tier support
|
|
|
|
affects:
|
|
- 05-02 (template HTTP handlers will call these query functions)
|
|
- frontend template UI phases
|
|
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- Lazy template creation: CreateTemplateItem upserts template before inserting item
|
|
- BudgetExistsError struct wraps existing budget ID for 409 response
|
|
- Default itemTier to one_off at query layer when empty (new items default to one_off)
|
|
|
|
key-files:
|
|
created:
|
|
- backend/migrations/002_templates.sql
|
|
modified:
|
|
- backend/internal/models/models.go
|
|
- backend/internal/db/queries.go
|
|
- backend/internal/api/handlers.go
|
|
|
|
key-decisions:
|
|
- "New budget items created via API default to item_tier=one_off when not specified"
|
|
- "Existing budget_items rows get DEFAULT item_tier='fixed' (migration assumes all prior items were recurring)"
|
|
- "Template creation is lazy: CreateTemplateItem upserts template using ON CONFLICT DO UPDATE"
|
|
- "GetTemplate returns empty TemplateDetail (not error) when no template exists for user"
|
|
- "GenerateBudgetFromTemplate returns BudgetExistsError struct (not plain error) so handler can include existing budget ID in 409 response"
|
|
- "Variable template items use budgeted_amount=0 when generating budget (fixed items copy the template amount)"
|
|
|
|
patterns-established:
|
|
- "BudgetExistsError: typed error struct for domain-specific errors needing structured data in HTTP response"
|
|
- "Locale-aware month names via map[time.Month]string for EN and DE"
|
|
|
|
requirements-completed: [TMPL-01, TMPL-02, TMPL-04]
|
|
|
|
duration: 3min
|
|
completed: 2026-03-12
|
|
---
|
|
|
|
# Phase 5 Plan 1: Template Data Model and API Summary
|
|
|
|
**PostgreSQL migration and Go query layer for three-tier item model (fixed/variable/one_off), templates table with lazy creation, and GenerateBudgetFromTemplate with duplicate-month detection**
|
|
|
|
## Performance
|
|
|
|
- **Duration:** ~3 min
|
|
- **Started:** 2026-03-12T11:04:04Z
|
|
- **Completed:** 2026-03-12T11:06:52Z
|
|
- **Tasks:** 2
|
|
- **Files modified:** 4 (2 created, 2 updated, 1 auto-fixed)
|
|
|
|
## Accomplishments
|
|
|
|
- Migration 002 adds item_tier enum to budget_items, creates templates and template_items tables with DB-level CHECK constraint preventing one_off items in templates
|
|
- All 7 new template query functions implemented (GetTemplate, UpdateTemplateName, CreateTemplateItem, UpdateTemplateItem, DeleteTemplateItem, ReorderTemplateItems, GenerateBudgetFromTemplate)
|
|
- Existing budget item queries (CreateBudgetItem, UpdateBudgetItem, GetBudgetWithItems, CopyBudgetItems) updated to include item_tier
|
|
|
|
## Task Commits
|
|
|
|
Each task was committed atomically:
|
|
|
|
1. **Task 1: Migration SQL and Go model types** - `b3082ca` (feat)
|
|
2. **Task 2: Database query functions** - `f9dd409` (feat)
|
|
|
|
**Plan metadata:** (to be created next)
|
|
|
|
## Files Created/Modified
|
|
|
|
- `backend/migrations/002_templates.sql` - item_tier enum, ALTER budget_items, templates and template_items tables with CHECK constraint
|
|
- `backend/internal/models/models.go` - ItemTier type + constants, ItemTier field on BudgetItem, Template/TemplateItem/TemplateDetail structs
|
|
- `backend/internal/db/queries.go` - All template query functions, updated budget item queries, BudgetExistsError, locale-aware month name maps
|
|
- `backend/internal/api/handlers.go` - Updated CreateBudgetItem/UpdateBudgetItem calls to pass ItemTier from request body
|
|
|
|
## Decisions Made
|
|
|
|
- New API-created budget items default to `item_tier=one_off` (at the query layer) — new items created mid-month are one-offs unless specified
|
|
- Migration uses `DEFAULT 'fixed'` for existing rows — prior items came from copy-from-previous, treating them as recurring
|
|
- Template creation is lazy: `CreateTemplateItem` upserts the template via `ON CONFLICT (user_id) DO UPDATE`, no separate "create template" endpoint needed
|
|
- `GetTemplate` returns empty `TemplateDetail` (not an error) when no template exists, per context decision
|
|
- `GenerateBudgetFromTemplate` returns a typed `BudgetExistsError` struct so Plan 02 handler can extract the existing budget ID for a structured 409 response
|
|
|
|
## Deviations from Plan
|
|
|
|
### Auto-fixed Issues
|
|
|
|
**1. [Rule 3 - Blocking] Updated handlers.go to pass ItemTier parameter**
|
|
- **Found during:** Task 2 (query function updates)
|
|
- **Issue:** Changing `CreateBudgetItem` and `UpdateBudgetItem` signatures to include `itemTier` broke compilation of `handlers.go`, which calls both functions
|
|
- **Fix:** Added `ItemTier models.ItemTier` to both request structs and passed it to the query calls
|
|
- **Files modified:** `backend/internal/api/handlers.go`
|
|
- **Verification:** `go vet ./...` passes cleanly
|
|
- **Committed in:** `f9dd409` (Task 2 commit)
|
|
|
|
---
|
|
|
|
**Total deviations:** 1 auto-fixed (1 blocking compile fix)
|
|
**Impact on plan:** Necessary for correctness — handler was calling updated function with wrong arity. No scope creep.
|
|
|
|
## Issues Encountered
|
|
|
|
None — plan executed cleanly with one compile-blocking auto-fix handled inline.
|
|
|
|
## User Setup Required
|
|
|
|
None - no external service configuration required. Migration will be applied by the DB migration runner on next startup.
|
|
|
|
## Next Phase Readiness
|
|
|
|
- All query functions ready for Plan 02 HTTP handlers to consume
|
|
- `BudgetExistsError` struct available for 409 response in `GenerateBudgetFromTemplate` handler
|
|
- `GetTemplate` empty-return behavior documented for frontend to handle gracefully
|
|
|
|
## Self-Check: PASSED
|
|
|
|
All created files verified on disk. Both task commits (b3082ca, f9dd409) confirmed in git log.
|
|
|
|
---
|
|
*Phase: 05-template-data-model-and-api*
|
|
*Completed: 2026-03-12*
|