Files
SimpleFinanceDash/.planning/phases/07-quick-add-library/07-01-PLAN.md

8.6 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
07-quick-add-library 01 execute 1
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
true
QADD-01
QADD-03
truths artifacts key_links
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
path provides contains
backend/migrations/003_quick_add_library.sql quick_add_items table DDL CREATE TABLE quick_add_items
path provides contains
backend/internal/models/models.go QuickAddItem Go struct QuickAddItem
path provides exports
backend/internal/db/queries.go CRUD query functions for quick-add items
ListQuickAddItems
CreateQuickAddItem
UpdateQuickAddItem
DeleteQuickAddItem
path provides contains
backend/internal/api/handlers.go HTTP handlers for quick-add CRUD ListQuickAddItems
path provides contains
backend/internal/api/router.go Route registrations under /api/quick-add /api/quick-add
from to via pattern
backend/internal/api/router.go backend/internal/api/handlers.go handler method references h..*QuickAdd
from to via pattern
backend/internal/api/handlers.go backend/internal/db/queries.go query function calls q..*QuickAdd
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

<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

@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

From backend/internal/models/models.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:

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

// Handler struct — all handlers are methods on this
type Handlers struct {
	queries       *db.Queries
	sessionSecret string
}

// Helper functions available: writeJSON, writeError, auth.UserIDFromContext
Task 1: Migration, model, and query functions backend/migrations/003_quick_add_library.sql, backend/internal/models/models.go, backend/internal/db/queries.go 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.
  1. Add QuickAddItem struct to backend/internal/models/models.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"`
    }
    
  2. 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. cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/backend && go vet ./... QuickAddItem struct compiles, all four query functions compile, migration file exists with CREATE TABLE statement

Task 2: HTTP handlers and route registration backend/internal/api/handlers.go, backend/internal/api/router.go 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
  1. Register routes in backend/internal/api/router.go inside the authenticated group (after the template route block):
    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)
    })
    
cd /home/jean-luc-makiola/Development/projects/SimpleFinanceDash/backend && go vet ./... && go build ./cmd/server All four handlers compile, routes registered under /api/quick-add, go build succeeds with no errors - `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)

<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>
After completion, create `.planning/phases/07-quick-add-library/07-01-SUMMARY.md`