diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 40f270a..5957652 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -15,7 +15,7 @@ | 1 | Foundation | Fresh `backend/` Go package boots, renders HTMX, talks to Postgres | FOUND-01..05 | | 2 | Authentication | Complete (7/7) | AUTH-01..07 | | 3 | Tablos CRUD | Complete (3/3) | TABLO-01..06 | -| 4 | 1/4 | In Progress| | +| 4 | 2/4 | In Progress| | | 5 | Files | A user can attach, list, download, delete files on a tablo | FILE-01..06 | | 6 | Background Worker | A second binary runs jobs against the same Postgres | WORK-01..04 | | 7 | Deploy v1 | The product runs in production on a single host | DEPLOY-01..05 | @@ -103,10 +103,10 @@ Plans: **User-in-loop:** Approve the `task_columns` (or fixed-column) schema and the ordering strategy (fractional indices, gaps-of-100, linked list — to be decided with research). Approve whether reorder is drag-and-drop or button-driven. -**Plans:** 1/4 plans executed +**Plans:** 2/4 plans executed Plans: - [x] 04-01-PLAN.md — Wave 0: migration 0004_tasks + sqlc queries + handlers_tasks_test.go RED scaffold + soft-danger button CSS + Sortable.js bootstrap -- [ ] 04-02-PLAN.md — Vertical slice 1: kanban board render + task create + task delete (TASK-01, TASK-02, TASK-06) +- [x] 04-02-PLAN.md — Vertical slice 1: kanban board render + task create + task delete (TASK-01, TASK-02, TASK-06) - [ ] 04-03-PLAN.md — Vertical slice 2: task inline edit + Sortable.js drag reorder/move (TASK-03, TASK-04, TASK-05, TASK-07) - [ ] 04-04-PLAN.md — Human-verify checkpoint: full kanban board browser verification diff --git a/.planning/STATE.md b/.planning/STATE.md index 5d55a26..4505e57 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,13 +3,13 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: ready_to_execute -last_updated: "2026-05-15T07:25:45.316Z" +last_updated: "2026-05-15T07:34:10.554Z" progress: total_phases: 7 completed_phases: 3 total_plans: 18 - completed_plans: 15 - percent: 83 + completed_plans: 16 + percent: 89 --- # STATE @@ -32,14 +32,14 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) | 1 | Foundation | ✓ Complete | | 2 | Authentication | ✓ Complete — VERIFIED PASS (2026-05-14) | | 3 | Tablos CRUD | ✓ Complete — All 3 plans done, TABLO-01..06 closed, verified 2026-05-15 | -| 4 | Tasks (Kanban) | ◷ In Progress — Plan 01 done | +| 4 | Tasks (Kanban) | ◷ In Progress — Plans 01-02 done | | 5 | Files | ○ Pending | | 6 | Background Worker | ○ Pending | | 7 | Deploy v1 | ○ Pending | ## Active Phase -**Phase 4: Tasks (Kanban)** — In progress. Plan 01 done (Wave 0 foundation). Plans 02-04 pending. +**Phase 4: Tasks (Kanban)** — In progress. Plans 01-02 done (Wave 0 foundation + Wave 1 vertical slice). Plans 03-04 pending. ## Verification Record @@ -76,6 +76,8 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) - **task_status ENUM order matches visual column order** (todo, in_progress, in_review, done) — ENUM ordinal sorting aligns with kanban column display order per Pitfall 6 (04-01) - **Down migration drops TABLE before TYPE** — tasks table dropped before task_status type per Pitfall 3; type cannot be dropped while still referenced (04-01) - **TasksDeps stub in test file** — declared in handlers_tasks_test.go; moved to handlers_tasks.go in Plan 02 to avoid file dependency before handlers exist (04-01) +- **TaskColumns/TaskColumnLabels in templates package** — moved from web package to templates to avoid web↔templates import cycle; handlers reference via templates.TaskColumns (04-02) +- **TabloDetailPage accepts tasks []sqlc.Task** — kanban board embedded below tablo header; TabloDetailHandler fetches tasks via ListTasksByTablo before rendering (04-02) ## Performance Metrics @@ -92,6 +94,7 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) | 03-tablos-crud | 02 | ~4min | 3 | 8 | | 03-tablos-crud | 03 | ~30min | 3 | 5 | | 04-tasks-kanban | 01 | ~4min | 3 | 7 | +| 04-tasks-kanban | 02 | ~20min | 3 | 12 | ## Notes @@ -121,6 +124,8 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) - **Phase 3 complete** — All 3 plans done; TABLO-01..06 closed; 10/10 TABLO tests green; full browser verify passed 2026-05-15 - Phase 4 Plan 01 SUMMARY: `.planning/phases/04-tasks-kanban/04-01-SUMMARY.md` - Commits (04-01): c9c8262 (migration + sqlc queries), 8b9543d (RED test scaffold + form structs), 55fb32f (Sortable.js + soft-danger CSS) +- Phase 4 Plan 02 SUMMARY: `.planning/phases/04-tasks-kanban/04-02-SUMMARY.md` +- Commits (04-02): 181ae79 (handlers + router + main.go), 889164b (templates + tablos.templ + layout.templ), 92ebb5f (activate task tests) --- -*Last updated: 2026-05-15 after Phase 4 Plan 01 complete (Wave 0 foundation)* +*Last updated: 2026-05-15 after Phase 4 Plan 02 complete (Wave 1 vertical slice — kanban board + create + delete)* diff --git a/.planning/phases/04-tasks-kanban/04-02-SUMMARY.md b/.planning/phases/04-tasks-kanban/04-02-SUMMARY.md new file mode 100644 index 0000000..c26a4d8 --- /dev/null +++ b/.planning/phases/04-tasks-kanban/04-02-SUMMARY.md @@ -0,0 +1,121 @@ +--- +phase: 04-tasks-kanban +plan: "02" +subsystem: backend/tasks +tags: [kanban, htmx, handlers, templ, tdd-green] +dependency_graph: + requires: [04-tasks-kanban/04-01] + provides: [kanban-board-ui, task-create, task-delete, task-handlers, task-routes] + affects: [backend/internal/web, backend/templates, backend/cmd/web] +tech_stack: + added: [] + patterns: [htmx-oob-swap, chi-route-ordering, templ-components, ownership-guard] +key_files: + created: + - backend/internal/web/handlers_tasks.go + - backend/templates/tasks.templ + modified: + - backend/internal/web/router.go + - backend/cmd/web/main.go + - backend/templates/tablos.templ + - backend/templates/layout.templ + - backend/templates/tasks_forms.go + - backend/internal/web/handlers_tablos.go + - backend/internal/web/handlers_tasks_test.go + - backend/internal/web/handlers_test.go + - backend/internal/web/handlers_tablos_test.go + - backend/internal/web/handlers_auth_test.go + - backend/internal/web/csrf_test.go +decisions: + - "TaskColumns/TaskColumnLabels moved to templates package to avoid web↔templates import cycle" + - "TabloDetailPage updated to accept tasks []sqlc.Task; handlers_tablos.go fetches tasks via ListTasksByTablo before rendering" + - "Non-HTMX validation error in TabloUpdateHandler also fetches tasks for kanban board rendering" + - "AddTaskTrigger and TaskCard use raw CSS class string for soft-danger button (not ui.Button) per plan spec" + - "Column labels match tasks_forms.go TaskColumnLabels; test scaffold updated from incorrect capitalization" +metrics: + duration: ~20min + completed: "2026-05-15" + tasks: 3 + files: 12 +--- + +# Phase 4 Plan 02: Kanban Board Vertical Slice (Wave 1) Summary + +Vertical slice 1 of the kanban workflow: renders the kanban board on tablo detail page with 4 columns, implements task creation via inline column form with HTMX, and task deletion with inline confirmation. Users can now open a tablo, see 4 columns (To do, In progress, In review, Done), create tasks, and delete them. + +## Tasks Completed + +| Task | Name | Commit | Files | +|------|------|--------|-------| +| 1 | handlers_tasks.go + router + main.go | 181ae79 | backend/internal/web/handlers_tasks.go, router.go, main.go, 5 test files | +| 2 | tasks.templ + tablos.templ + layout.templ | 889164b | backend/templates/tasks.templ, tablos.templ, layout.templ, tasks_forms.go, handlers_tablos.go | +| 3 | Activate task integration tests | 92ebb5f | backend/internal/web/handlers_tasks_test.go | + +## Verification Results + +- `go build ./...` exits 0 +- `go test ./...` exits 0 (all tests pass or skip correctly) +- `go test ./internal/web/ -run TestTask -v`: 9 SKIP total — 5 skip due to no TEST_DATABASE_URL (activated, awaiting DB), 4 skip with "handlers_tasks not yet implemented" (Plan 03) +- `grep -c 'KanbanBoard' templates/tasks.templ` returns 2 +- `grep -c 'TaskCreateHandler' internal/web/router.go` returns 1 +- `grep -c 'sortable.min.js' templates/layout.templ` returns 1 + +## Decisions Made + +1. **TaskColumns/TaskColumnLabels moved to templates package** — `handlers_tasks.go` imports `templates`, and `tasks.templ` needs the column definitions. Putting them in `web` package would create a cycle (`templates` → `web` → ... → `templates`). Moving to `templates/tasks_forms.go` breaks the cycle cleanly. + +2. **TabloDetailPage signature updated** — Added `tasks []sqlc.Task` parameter. All callers updated: `TabloDetailHandler` fetches tasks via `ListTasksByTablo`; `TabloUpdateHandler` non-HTMX error path also fetches tasks for correct rendering. + +3. **Task column header strings corrected** — The Plan 01 test scaffold used `"Todo"`, `"In Progress"`, `"In Review"` which didn't match the plan spec `"To do"`, `"In progress"`, `"In review"`. Updated test to use correct labels from `TaskColumnLabels`. + +4. **Integration tests skip on missing TEST_DATABASE_URL** — Tests are activated (no t.Skip), but the test helper `setupTestDB` skips when no database is configured. This is the correct behavior per the existing test pattern. + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 2 - Import cycle prevention] TaskColumns/TaskColumnLabels moved from web to templates package** +- **Found during:** Task 2 (templ generation, go build cycle check) +- **Issue:** `tasks.templ` needs `web.TaskColumns` and `web.TaskColumnLabels`. But `templates` package imports `web/ui` (not `web`), and `web` imports `templates` — adding `web` as a direct import to `templates` would create `web → templates → web` cycle. +- **Fix:** Moved `TaskColumns` and `TaskColumnLabels` to `backend/templates/tasks_forms.go`. Handlers reference `templates.TaskColumns` via the already-existing `templates` import. No structural change — just a different home for the constants. +- **Files modified:** backend/templates/tasks_forms.go, backend/internal/web/handlers_tasks.go +- **Commit:** 181ae79 + +**2. [Rule 1 - Bug] Column header test strings corrected** +- **Found during:** Task 3 (activating tests) +- **Issue:** Plan 01 scaffold used `"Todo"`, `"In Progress"`, `"In Review"` but TaskColumnLabels defines `"To do"`, `"In progress"`, `"In review"`. +- **Fix:** Updated `TestTasksKanbanRenders` to use the correct label strings. +- **Files modified:** backend/internal/web/handlers_tasks_test.go +- **Commit:** 92ebb5f + +**3. [Rule 3 - Router update] All NewRouter call sites updated** +- **Found during:** Task 1 (adding TasksDeps param to NewRouter) +- **Issue:** 5 test helper functions across 4 test files called `NewRouter` without `TasksDeps`. +- **Fix:** Updated all callers: `handlers_test.go`, `handlers_tablos_test.go`, `handlers_auth_test.go`, `csrf_test.go`. +- **Files modified:** 4 test files +- **Commit:** 181ae79 + +## Known Stubs + +- `TaskEditHandler` returns 501 — Plan 03 implements task editing +- `TaskUpdateHandler` returns 501 — Plan 03 implements task update +- `TaskReorderHandler` returns 501 — Plan 03 implements drag-and-drop reorder + +These stubs are intentional per the plan spec; routes are registered so route resolution tests work. + +## Threat Flags + +None — all threat mitigations from the plan's threat register are implemented: +- T-04-03: loadOwnedTabloForTask uses `GetTaskByID(WHERE id=$1 AND tablo_id=$2)` with ownership-verified tablo_id +- T-04-04: title validated non-empty, max 255 chars +- T-04-05: status validated against validTaskStatuses map before DB insert +- T-04-07: TabloDetailPage only renders after loadOwnedTablo passes ownership check + +## Self-Check: PASSED + +- backend/internal/web/handlers_tasks.go: FOUND +- backend/templates/tasks.templ: FOUND +- backend/internal/web/router.go (TaskCreateHandler): FOUND +- backend/templates/layout.templ (sortable.min.js): FOUND +- backend/templates/tablos.templ (tasks param): FOUND +- Commits 181ae79, 889164b, 92ebb5f: FOUND