- 04-03-SUMMARY.md created with full execution details
- STATE.md updated: decisions, metrics, notes for plan 03
- ROADMAP.md updated with plan progress (3/4 summaries for phase 4)
- Remove t.Skip("handlers_tasks not yet implemented") from TestTaskOrderPersists
- Full test suite green: go test ./... exits 0, no FAIL lines
- All 9 TestTask* tests active (skip on missing TEST_DATABASE_URL per existing pattern)
- TaskReorderHandler: POST /tablos/{id}/tasks/reorder updates status+position
- Fetches existing task via GetTaskByID before UpdateTask (T-04-08 mass assignment guard)
- Supports both array form (task_id[]/task_col[]) and single-value form (task_id/status/position)
- Invalid UUIDs silently skipped (D-05); tasks from other tablos skipped (T-04-10)
- Returns updated KanbanBoard outerHTML for HTMX swap
- Remove t.Skip from TestTaskReorderCrossColumn and TestTaskReorderSameColumn
- Add handlers_tasks.go: TasksDeps, TaskNewFormHandler, TaskCancelNewHandler, TaskCreateHandler, TaskShowHandler, TaskDeleteConfirmHandler, TaskDeleteHandler, plus stub Edit/Update/Reorder handlers
- Add task routes to router.go (static before parametric per Pitfall 1)
- Add TasksDeps param to NewRouter; update main.go and all test callers
- Move TaskColumns/TaskColumnLabels to templates package to avoid import cycle
- handlers_tasks_test.go: 9 TestTask* functions (TASK-01..07 + IDOR) all skip
- TasksDeps stub struct declared in test file for Plan 02 wiring
- tasks_forms.go: TaskCreateForm, TaskCreateErrors, TaskUpdateForm, TaskUpdateErrors structs
- go build ./... passes; go test -run TestTask exits 0 with all 9 SKIP
- TabloCreateErrors: add Color field for server-side hex validation error
- TabloCreateFormFragment: render FieldError for color field and update
placeholder to hex-only hint (#6366f1) matching the validation constraint
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- TabloUpdateHandler: capture user from loadOwnedTablo (was discarded with _)
- Pass captured user to TabloDetailPage on non-HTMX validation error path
instead of nil, preventing broken layout (no logout button/email shown)
- TabloUpdateHandler: pass tablo.Color to UpdateTablo to preserve color on update (CR-01)
- loadOwnedTablo: pass GetTabloByIDParams{ID, UserID} to DB query (WR-01 call site)
- TabloDeleteHandler: pass DeleteTabloParams{ID, UserID} to DB query (WR-02 call site)
- TabloDeleteHandler: on DB error with HX-Request, render TabloDeleteConfirmFragment
instead of plain http.Error to avoid broken HTMX DOM state (CR-03)
- renderTabloCreateError: log secondary ListTablosByUser fetch failure (WR-03)
- TablosCreateHandler: validate color with isValidCSSColor (hex only) and surface
TabloCreateErrors.Color field error to prevent CSS injection (WR-04)
- Add isValidCSSColor helper using ^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$ regex
- Update test call sites for GetTabloByID and DeleteTablo new param types
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- UpdateTablo SQL: add color = \$4 so color is preserved across title/description edits
- GetTabloByID SQL: add AND user_id = \$2 to push ownership enforcement into the DB layer
- DeleteTablo SQL: add AND user_id = \$2 to push authorization into the DB layer
- sqlc bindings regenerated (UpdateTabloParams+Color, GetTabloByIDParams, DeleteTabloParams)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- loadOwnedTablo helper: uuid.Parse, GetTabloByID, ownership check (D-04: 404 not 403)
- TabloDetailHandler: GET /tablos/{id} renders detail page
- TabloEditTitleHandler/ShowTitleHandler: GET /tablos/{id}/edit-title|show-title fragments
- TabloEditDescHandler/ShowDescHandler: GET /tablos/{id}/edit-desc|show-desc fragments
- TabloUpdateHandler: POST /tablos/{id} — validates, updates DB, renders matching zone fragment
- TabloDeleteConfirmHandler/CancelHandler: GET /tablos/{id}/delete-confirm|delete-cancel
- TabloDeleteHandler: POST /tablos/{id}/delete — deletes row, HX-Redirect:/ or 303
- router.go: 9 new routes in RequireAuth group, static-before-parametric order preserved
- Fix [Rule 1 - Bug]: test title "Owner's Tablo" caused HTML entity mismatch — changed to "Owners Detail Tablo"
- go test ./internal/web/... -run TestTablo: 10/10 PASS; full suite: all PASS
- TabloDetailPage: full detail layout with title/desc/delete zones
- TabloTitleDisplay/EditFragment: outerHTML-swappable title zone with _zone=title hidden field
- TabloDescDisplay/EditFragment: outerHTML-swappable desc zone with _zone=desc hidden field
- TabloDeleteButtonFragment: canonical single-source delete zone (TabloCard now delegates here)
- TabloDeleteConfirmFragment: inline confirm with "Delete tablo?", "Yes, delete", "Keep tablo"
- TabloNotFoundPage: 404 page with UI-SPEC copy
- TabloUpdateErrors struct added to tablos_forms.go
- just generate + go build ./... both exit 0
Plans cover TABLO-01..06 via MVP vertical slices: foundation (migration
+ sqlc + test scaffold + button CSS), list+create (dashboard, inline
form, OOB swap), and detail+edit+delete (ownership 404, inline edit
fragments, inline confirm delete). Includes Nyquist VALIDATION.md and
PATTERNS.md with real analog excerpts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace generic "Save"/"Cancel" with specific labels: "Save changes",
"Discard changes", "Keep tablo" throughout spec, component inventory,
interaction contracts, and HTMX reference table
- Remove 500 (medium) weight; form labels now use font-semibold (600),
consistent with Button convention — 2 declared weights total
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- TestLoadCSRFKey_* in internal/auth for env key loading
- TestCSRF_*MissingToken / TestCSRF_*ValidToken for all three POST routes
- TestForms_ContainCSRFField for hidden _csrf input in rendered HTML
- TestRouter_CSRFMountedAfterResolveSession for middleware order (D-24)
- TestCSRF_HeaderFallback for X-CSRF-Token header support
- Add gorilla/csrf v1.7.3 dependency