docs(07-quick-add-library): create phase plan

This commit is contained in:
2026-03-12 13:24:58 +01:00
parent 51c9aa39d0
commit c57311adb4
3 changed files with 555 additions and 4 deletions

View File

@@ -0,0 +1,217 @@
---
phase: 07-quick-add-library
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- backend/migrations/003_quick_add_library.sql
- backend/internal/models/models.go
- backend/internal/db/queries.go
- backend/internal/api/handlers.go
- backend/internal/api/router.go
autonomous: true
requirements: [QADD-01, QADD-03]
must_haves:
truths:
- "A quick_add_items table exists with user_id, name, icon, and sort_order columns"
- "API returns a list of quick-add items for the authenticated user"
- "API can create, update, and delete quick-add items"
- "Quick-add items are user-scoped — one user cannot see another's items"
artifacts:
- path: "backend/migrations/003_quick_add_library.sql"
provides: "quick_add_items table DDL"
contains: "CREATE TABLE quick_add_items"
- path: "backend/internal/models/models.go"
provides: "QuickAddItem Go struct"
contains: "QuickAddItem"
- path: "backend/internal/db/queries.go"
provides: "CRUD query functions for quick-add items"
exports: ["ListQuickAddItems", "CreateQuickAddItem", "UpdateQuickAddItem", "DeleteQuickAddItem"]
- path: "backend/internal/api/handlers.go"
provides: "HTTP handlers for quick-add CRUD"
contains: "ListQuickAddItems"
- path: "backend/internal/api/router.go"
provides: "Route registrations under /api/quick-add"
contains: "/api/quick-add"
key_links:
- from: "backend/internal/api/router.go"
to: "backend/internal/api/handlers.go"
via: "handler method references"
pattern: "h\\..*QuickAdd"
- from: "backend/internal/api/handlers.go"
to: "backend/internal/db/queries.go"
via: "query function calls"
pattern: "q\\..*QuickAdd"
---
<objective>
Create the backend data model and REST API for the quick-add library feature.
Purpose: Users need a persistent library of saved one-off expense categories (name + icon) that they can reuse across months. This plan creates the database table, Go model, query functions, and HTTP endpoints.
Output: Migration file, QuickAddItem model, CRUD queries, REST handlers at /api/quick-add
</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
@backend/internal/models/models.go
@backend/internal/db/queries.go
@backend/internal/api/handlers.go
@backend/internal/api/router.go
@backend/migrations/002_templates.sql
<interfaces>
<!-- Existing patterns the executor must follow -->
From backend/internal/models/models.go:
```go
// Category struct pattern — QuickAddItem should follow same shape
type Category struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
Name string `json:"name"`
Type CategoryType `json:"type"`
Icon string `json:"icon"`
SortOrder int `json:"sort_order"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
From backend/internal/api/router.go:
```go
// Route group pattern — quick-add follows same structure
r.Route("/api/template", func(r chi.Router) {
r.Get("/", h.GetTemplate)
r.Put("/", h.UpdateTemplateName)
r.Post("/items", h.CreateTemplateItem)
// ...
})
```
From backend/internal/api/handlers.go:
```go
// Handler struct — all handlers are methods on this
type Handlers struct {
queries *db.Queries
sessionSecret string
}
// Helper functions available: writeJSON, writeError, auth.UserIDFromContext
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Migration, model, and query functions</name>
<files>backend/migrations/003_quick_add_library.sql, backend/internal/models/models.go, backend/internal/db/queries.go</files>
<action>
1. Create migration `backend/migrations/003_quick_add_library.sql`:
```sql
CREATE TABLE quick_add_items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
icon VARCHAR(50) NOT NULL DEFAULT '',
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_quick_add_items_user ON quick_add_items(user_id);
```
The table stores saved one-off category presets (name + icon). No FK to categories — these are independent presets the user can pick from when adding a one-off budget item.
2. Add `QuickAddItem` struct to `backend/internal/models/models.go`:
```go
type QuickAddItem struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
Name string `json:"name"`
Icon string `json:"icon"`
SortOrder int `json:"sort_order"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
3. Add four query functions to `backend/internal/db/queries.go` (append after template section):
- `ListQuickAddItems(ctx, userID) ([]QuickAddItem, error)` — SELECT ordered by sort_order, returns empty slice (not nil) when none exist
- `CreateQuickAddItem(ctx, userID, name, icon string) (*QuickAddItem, error)` — INSERT with sort_order = (SELECT COALESCE(MAX(sort_order),0)+1), RETURNING all columns
- `UpdateQuickAddItem(ctx, id, userID, name, icon string, sortOrder int) (*QuickAddItem, error)` — UPDATE with WHERE id=$1 AND user_id=$2, return error if no rows affected
- `DeleteQuickAddItem(ctx, id, userID) error` — DELETE with WHERE id=$1 AND user_id=$2
Follow existing query patterns: use context parameter, userID scoping in WHERE clause, fmt.Errorf wrapping, pgx row scanning.
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/backend && go vet ./...</automated>
</verify>
<done>QuickAddItem struct compiles, all four query functions compile, migration file exists with CREATE TABLE statement</done>
</task>
<task type="auto">
<name>Task 2: HTTP handlers and route registration</name>
<files>backend/internal/api/handlers.go, backend/internal/api/router.go</files>
<action>
1. Add four handler methods to `backend/internal/api/handlers.go`:
- `ListQuickAddItems(w, r)` — GET, extracts userID from context, calls queries.ListQuickAddItems, returns JSON array (200)
- `CreateQuickAddItem(w, r)` — POST, accepts JSON `{name: string, icon: string}`, validates name is non-empty (400 if missing), calls queries.CreateQuickAddItem, returns created item (201)
- `UpdateQuickAddItem(w, r)` — PUT, extracts itemId from chi URL param, accepts JSON `{name: string, icon: string, sort_order: int}`, validates name non-empty, calls queries.UpdateQuickAddItem, returns updated item (200). Return 404 if no rows affected.
- `DeleteQuickAddItem(w, r)` — DELETE, extracts itemId from chi URL param, calls queries.DeleteQuickAddItem, returns 204
Follow existing handler patterns:
- Use `auth.UserIDFromContext(r.Context())` for userID
- Use `chi.URLParam(r, "itemId")` for path params
- Use `writeJSON(w, status, data)` and `writeError(w, status, message)`
- Parse UUID with `uuid.Parse()`, return 400 on invalid
2. Register routes in `backend/internal/api/router.go` inside the authenticated group (after the template route block):
```go
r.Route("/api/quick-add", func(r chi.Router) {
r.Get("/", h.ListQuickAddItems)
r.Post("/", h.CreateQuickAddItem)
r.Put("/{itemId}", h.UpdateQuickAddItem)
r.Delete("/{itemId}", h.DeleteQuickAddItem)
})
```
</action>
<verify>
<automated>cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/backend && go vet ./... && go build ./cmd/server</automated>
</verify>
<done>All four handlers compile, routes registered under /api/quick-add, go build succeeds with no errors</done>
</task>
</tasks>
<verification>
- `go vet ./...` passes with no issues
- `go build ./cmd/server` produces binary without errors
- Migration file 003 exists and has valid SQL
- QuickAddItem struct has json tags matching API contract
- All handlers use userID scoping (no cross-user data leak)
</verification>
<success_criteria>
- Backend compiles and builds successfully
- Migration creates quick_add_items table with correct schema
- Four REST endpoints exist: GET/POST /api/quick-add, PUT/DELETE /api/quick-add/{itemId}
- All endpoints require authentication (inside authenticated route group)
- All queries scope by user_id
</success_criteria>
<output>
After completion, create `.planning/phases/07-quick-add-library/07-01-SUMMARY.md`
</output>