---
phase: 03-tablos-crud
plan: 01
subsystem: database
tags: [go, postgres, sqlc, goose, integration-tests, css]

# Dependency graph
requires:
  - phase: 02-authentication
    provides: users table, migrations pattern, sqlc pattern, test harness (setupTestDB, handlers_auth_test patterns)
provides:
  - tablos table migration (0003_tablos.sql) with user_id FK + ON DELETE CASCADE + index
  - 5 sqlc queries: ListTablosByUser, GetTabloByID, InsertTablo, UpdateTablo, DeleteTablo
  - Tablo struct with pgtype.Text for nullable description/color
  - TablosDeps struct + updated NewRouter signature accepting TablosDeps
  - RED integration test scaffold (10 tests, all FAIL until Plans 02/03)
  - button.css danger + neutral-soft variants for Plan 02 templates
affects: [03-02, 03-03]

# Tech tracking
tech-stack:
  added: []
  patterns:
    - TablosDeps constructor pattern mirroring AuthDeps
    - pgtype.Text for nullable text columns in sqlc + pgx/v5
    - NewRouter extended with second deps argument (TablosDeps)

key-files:
  created:
    - backend/migrations/0003_tablos.sql
    - backend/internal/db/queries/tablos.sql
    - backend/internal/web/handlers_tablos.go
    - backend/internal/web/handlers_tablos_test.go
  modified:
    - backend/internal/web/router.go
    - backend/internal/web/handlers_auth_test.go
    - backend/internal/web/handlers_test.go
    - backend/internal/web/csrf_test.go
    - backend/cmd/web/main.go
    - backend/internal/web/ui/button.css

key-decisions:
  - "sqlc-generated files (.go) not committed per backend/.gitignore convention — regenerated by just generate"
  - "NewRouter signature extended to accept TablosDeps as second deps param (before csrfKey)"
  - "handlers_tablos.go created as stub to allow test file to compile before Plan 02 adds handlers"

patterns-established:
  - "Pattern: TablosDeps struct holds *sqlc.Queries, passed to handlers via constructor"
  - "Pattern: test scaffold uses preInsertUser + store.Create for session without going through signup"

requirements-completed:
  - TABLO-01
  - TABLO-02
  - TABLO-03
  - TABLO-04
  - TABLO-05
  - TABLO-06

# Metrics
duration: ~15min
completed: 2026-05-14
---

# Phase 03 Plan 01: Schema Foundation + Test Scaffold Summary

**goose migration for tablos table, 5 sqlc queries with pgtype.Text nullable columns, RED test scaffold covering all 10 TABLO-01..06 paths, and danger/neutral-soft button CSS variants**

## Performance

- **Duration:** ~15 min
- **Started:** 2026-05-14T22:05:00Z
- **Completed:** 2026-05-14T22:13:59Z
- **Tasks:** 3
- **Files modified:** 10

## Accomplishments

- tablos table migration (0003_tablos.sql) with user_id FK → ON DELETE CASCADE, tablos_user_id_idx, goose Up/Down
- 5 named sqlc queries (ListTablosByUser, GetTabloByID, InsertTablo, UpdateTablo, DeleteTablo) — UpdateTablo explicitly sets updated_at = now(), color not editable in Phase 3
- 10 RED integration tests in handlers_tablos_test.go covering all TABLO-01..06 paths; file compiles and go vet passes
- TablosDeps struct + NewRouter extended to accept it; all existing call sites updated
- .ui-button-solid-danger-md and .ui-button-soft-neutral-md CSS classes added to button.css, emitted in static/tailwind.css

## Task Commits

1. **Task 1: Migration + sqlc queries** - `f1b8d6e` (feat)
2. **Task 2: TablosDeps stub + RED test scaffold** - `c8f44b1` (test)
3. **Task 3: Button CSS danger + neutral-soft variants** - `2c1b186` (feat)

## Files Created/Modified

- `backend/migrations/0003_tablos.sql` - tablos table schema, ON DELETE CASCADE FK, index
- `backend/internal/db/queries/tablos.sql` - 5 sqlc queries; UpdateTablo sets updated_at explicitly
- `backend/internal/web/handlers_tablos.go` - TablosDeps struct stub (Plans 02/03 add handlers)
- `backend/internal/web/handlers_tablos_test.go` - 10 integration tests in RED state
- `backend/internal/web/router.go` - NewRouter signature extended: `(pinger, staticDir, AuthDeps, TablosDeps, csrfKey, env, origins...)`
- `backend/internal/web/handlers_auth_test.go` - updated newTestRouter + newTestRouterWithLimiter calls
- `backend/internal/web/handlers_test.go` - updated 3 inline NewRouter calls
- `backend/internal/web/csrf_test.go` - updated newTestRouterWithCSRF call
- `backend/cmd/web/main.go` - constructs TablosDeps{Queries: q}, passes to NewRouter
- `backend/internal/web/ui/button.css` - added danger + neutral-soft variants with WCAG 44px min-height

## Decisions Made

- sqlc-generated `.go` files not committed — `backend/.gitignore` explicitly excludes `internal/db/sqlc/*.go`; `just generate` reproduces them. Plan said "committed" but project convention takes precedence.
- NewRouter receives TablosDeps as a second explicit parameter (before csrfKey) rather than merging into AuthDeps — mirrors the Phase 2 pattern and keeps concerns separate.
- handlers_tablos.go created as a thin stub (just the TablosDeps struct) so the test file compiles without any handler implementation — exactly as plan acceptance criteria specified.

## Deviations from Plan

### Auto-fixed Issues

**1. [Rule 1 - Bug] Updated all NewRouter call sites to match new signature**
- **Found during:** Task 2 (TablosDeps stub + router signature change)
- **Issue:** router.go signature changed from `(pinger, staticDir, AuthDeps, csrfKey, env, origins...)` to `(pinger, staticDir, AuthDeps, TablosDeps, csrfKey, env, origins...)`. Three test files (csrf_test.go, handlers_test.go, handlers_auth_test.go) and main.go used the old signature — would not compile.
- **Fix:** Updated all call sites to pass `TablosDeps{}` or `TablosDeps{Queries: q}` as the new second deps argument.
- **Files modified:** backend/internal/web/csrf_test.go, backend/internal/web/handlers_test.go, backend/internal/web/handlers_auth_test.go, backend/cmd/web/main.go
- **Verification:** `go build ./...` and `go vet ./internal/web/...` exit 0
- **Committed in:** c8f44b1 (Task 2 commit)

---

**Total deviations:** 1 auto-fixed (Rule 1 - call site update)
**Impact on plan:** Necessary to keep all existing tests compilable. No scope creep.

## Known Stubs

- `handlers_tablos.go` — intentional stub (TablosDeps struct only, no handlers). Plans 02 and 03 implement the handlers. All 10 tests in handlers_tablos_test.go are RED until then.

## Issues Encountered

None — plan executed cleanly. sqlc-generated files gitignored per project convention; acknowledged as deviation from plan wording.

## Next Phase Readiness

- Plan 02 can implement tablo handlers by filling out handlers_tablos.go and adding routes to router.go, using the TablosDeps type already in place.
- All 10 RED tests provide exact behavioral contracts (status codes, headers, body substrings, DB assertions) for Plan 02/03 to satisfy.
- button.css danger + neutral-soft variants are ready for template work in Plan 02.
- `go build ./...` clean, `go vet ./internal/web/...` clean.

---
*Phase: 03-tablos-crud*
*Completed: 2026-05-14*
