diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 563486f..5bbfcc7 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -14,7 +14,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 | 1/3 | In Progress| | +| 3 | 2/3 | In Progress| | | 4 | Tasks (Kanban) | A user can run a kanban board inside a tablo | TASK-01..07 | | 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 | @@ -82,10 +82,10 @@ Plans: **User-in-loop:** Approve the `tablos` table schema (ownership model, soft-delete vs hard-delete, slug strategy). -**Plans:** 1/3 plans executed +**Plans:** 2/3 plans executed Plans: - [x] 03-01-PLAN.md — Wave 0: migration 0003_tablos + sqlc queries + handlers_tablos_test.go RED scaffold + button.css danger/neutral variants -- [ ] 03-02-PLAN.md — Vertical slice 1: dashboard list + inline-form create (HTMX OOB swap; TABLO-01, TABLO-02, TABLO-06) +- [x] 03-02-PLAN.md — Vertical slice 1: dashboard list + inline-form create (HTMX OOB swap; TABLO-01, TABLO-02, TABLO-06) - [ ] 03-03-PLAN.md — Vertical slice 2: detail + inline edit (title/description) + inline-confirmation delete (TABLO-03, TABLO-04, TABLO-05, TABLO-06) ### Phase 4: Tasks (Kanban) diff --git a/.planning/STATE.md b/.planning/STATE.md index c62196c..926f3b7 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: in_progress -last_updated: "2026-05-14T22:15:00.679Z" +last_updated: "2026-05-14T22:21:35.039Z" progress: total_phases: 7 completed_phases: 2 total_plans: 14 - completed_plans: 12 - percent: 86 + completed_plans: 13 + percent: 93 --- # STATE @@ -68,6 +68,8 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) - **trustedOrigins variadic arg in auth.Mount + NewRouter** — test routers pass "localhost"; production passes none - **sqlc-generated files not committed** — backend/.gitignore excludes internal/db/sqlc/*.go; just generate reproduces them (03-01) - **NewRouter extended with TablosDeps parameter** — second explicit deps param before csrfKey; all call sites updated (03-01) +- **index_templ.go deleted manually after emptying index.templ** — templ generates broken import when .templ has no components (03-02) +- **Non-HTMX validation error re-fetches tablos and renders full dashboard** — no form state threading; simpler than threading form through full page (03-02) ## Performance Metrics @@ -81,6 +83,7 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) | 02-authentication | 06 | ~12min | 1 | 9 | | 02-authentication | 07 | ~25min | 1 | 18 | | 03-tablos-crud | 01 | ~15min | 3 | 10 | +| 03-tablos-crud | 02 | ~4min | 2 | 7 | ## Notes @@ -102,6 +105,9 @@ See: `.planning/PROJECT.md` (updated 2026-05-14) - Phase 2 Plan 07 SUMMARY: `.planning/phases/02-authentication/02-07-SUMMARY.md` - Phase 3 Plan 01 SUMMARY: `.planning/phases/03-tablos-crud/03-01-SUMMARY.md` - Commits (03-01): f1b8d6e (migration + queries), c8f44b1 (TablosDeps stub + test scaffold), 2c1b186 (button CSS variants) +- Phase 3 Plan 02 SUMMARY: `.planning/phases/03-tablos-crud/03-02-SUMMARY.md` +- Commits (03-02): 43ddf25 (tablos templates + layout footer), 5db9215 (tablo handlers + router wiring) +- 03-02 stopped at Task 3 checkpoint:human-verify --- -*Last updated: 2026-05-14 after Phase 3 Plan 01 completion* +*Last updated: 2026-05-14 after Phase 3 Plan 02 Tasks 1+2 (checkpoint at Task 3)* diff --git a/.planning/phases/03-tablos-crud/03-02-SUMMARY.md b/.planning/phases/03-tablos-crud/03-02-SUMMARY.md new file mode 100644 index 0000000..cdcf57e --- /dev/null +++ b/.planning/phases/03-tablos-crud/03-02-SUMMARY.md @@ -0,0 +1,175 @@ +--- +phase: 03-tablos-crud +plan: 02 +subsystem: web-handlers + templates +tags: [go, htmx, templ, chi, csrf, tablo-crud] + +# Dependency graph +requires: + - phase: 03-tablos-crud + plan: 01 + provides: tablos table migration, sqlc queries, TablosDeps stub, RED test scaffold, button CSS variants +provides: + - TablosDashboard template (full page): heading, New-tablo button, create-form slot, card list + - TablosEmptyState template: "No tablos yet" + CTA with exact UI-SPEC copy + - TabloCard template: title, optional description/color dot, View link, .tablo-delete-zone wrapper + - TabloCreateFormFragment template: inline HTMX form with CSRF, field errors, Cancel link + - TabloCardWithOOBFormClear template: card + top-level OOB div clearing #create-form-slot + - TabloCreateForm + TabloCreateErrors form types (tablos_forms.go) + - TablosListHandler — GET / lists user tablos newest-first + - TablosNewHandler — GET /tablos/new returns create form fragment + - TablosCreateHandler — POST /tablos validates, inserts, dual-target HTMX swap or 303 redirect + - router.go: GET / → TablosListHandler, GET /tablos/new, POST /tablos registered + - layout.templ footer updated: "Phase 3 · Tablos" + - TestTabloList, TestTabloList_Empty, TestTabloCreate, TestTabloCreate_Validation: GREEN (4/10) +affects: [03-03] + +# Tech tracking +tech-stack: + added: [] + patterns: + - Dual-target HTMX swap: HX-Retarget + hx-swap-oob sibling in single response (Pattern 4) + - OOB div as top-level sibling in templ component (Pitfall 5 handled) + - r.PostFormValue only — gorilla/csrf body consumption guard (Pitfall 2) + - pgtype.Text{String: s, Valid: s != ""} for nullable insert params + - renderTabloCreateError helper mirrors renderSignupError pattern + +key-files: + created: + - backend/templates/tablos.templ + - backend/templates/tablos_forms.go + modified: + - backend/internal/web/handlers_tablos.go + - backend/internal/web/handlers.go + - backend/internal/web/router.go + - backend/templates/layout.templ + - backend/templates/index.templ + +key-decisions: + - "index_templ.go deleted manually — templ generates broken import when .templ has no components" + - "IndexHandler removed from handlers.go; auth/csrf imports removed (now unused)" + - "index.templ reduced to bare package declaration rather than deleted — keeps file discoverable" + - "Non-HTMX validation error re-fetches tablos and renders full dashboard (no form state threading)" + +patterns-established: + - "Pattern: TabloCardWithOOBFormClear emits OOB div as top-level sibling (Pitfall 5)" + - "Pattern: dual-target HTMX create swap via HX-Retarget + HX-Reswap headers" + - "Pattern: nullable pgtype.Text insert via Valid: s != '' guard" + +requirements-completed: + - TABLO-01 + - TABLO-02 + - TABLO-06 + +# Metrics +duration: ~4min +completed: 2026-05-14 +--- + +# Phase 03 Plan 02: Tablos Dashboard + Create Slice Summary + +**tablos.templ dashboard/card/form components + TablosListHandler/NewHandler/CreateHandler wiring 4/10 integration tests green; HTMX dual-target create and non-HTMX 303 fallback both verified** + +## Performance + +- **Duration:** ~4 min +- **Started:** 2026-05-14T22:16:47Z +- **Completed:** 2026-05-14T22:20:30Z (pre-checkpoint — Tasks 1+2 only) +- **Tasks:** 2 of 3 (Task 3 is human-verify checkpoint) +- **Files modified:** 7 + +## Accomplishments + +- `tablos.templ` created with 5 components: TablosDashboard, TablosEmptyState, TabloCard, TabloCreateFormFragment, TabloCardWithOOBFormClear +- `tablos_forms.go` with TabloCreateForm + TabloCreateErrors types (mirrors auth_forms.go) +- `layout.templ` footer updated from "Phase 2 · Authentication" to "Phase 3 · Tablos" +- `handlers_tablos.go` filled from stub to full implementation (List/New/Create handlers) +- `router.go` protected group updated: GET / → TablosListHandler, + GET /tablos/new, POST /tablos +- `handlers.go` IndexHandler removed; `index.templ` emptied; `index_templ.go` deleted +- TestTabloList, TestTabloList_Empty, TestTabloCreate (HTMX + non-HTMX), TestTabloCreate_Validation all PASS +- Phase 1/2 tests (TestSignup/TestLogin/TestLogout/TestCSRF) still pass — no regression + +## Task Commits + +1. **Task 1: tablos templates + layout footer** - `43ddf25` (feat) +2. **Task 2: tablo handlers + router wiring** - `5db9215` (feat) + +## Tests: 4 of 10 Green, 6 Remain RED for Plan 03 + +| Test | Status | +|------|--------| +| TestTabloList | GREEN | +| TestTabloList_Empty | GREEN | +| TestTabloCreate/HTMX_create | GREEN | +| TestTabloCreate/non-HTMX_create | GREEN | +| TestTabloCreate_Validation | GREEN | +| TestTabloDetail_Owner | RED (Plan 03) | +| TestTabloDetail_NonOwner | RED (Plan 03) | +| TestTabloDetail_InvalidID | RED (Plan 03) | +| TestTabloUpdate | RED (Plan 03) | +| TestTabloDeleteConfirm | RED (Plan 03) | +| TestTabloDelete/HTMX_delete | RED (Plan 03) | +| TestTabloDelete/non-HTMX_delete | RED (Plan 03) | + +## Handler Contracts Established + +**TablosDeps** (unchanged from Plan 01): +```go +type TablosDeps struct { + Queries *sqlc.Queries +} +``` + +**Handler signatures:** +- `TablosListHandler(deps TablosDeps) http.HandlerFunc` — GET / +- `TablosNewHandler(deps TablosDeps) http.HandlerFunc` — GET /tablos/new +- `TablosCreateHandler(deps TablosDeps) http.HandlerFunc` — POST /tablos + +**NewRouter signature** (unchanged from Plan 01): +```go +func NewRouter(pinger Pinger, staticDir string, deps AuthDeps, tabloDeps TablosDeps, csrfKey []byte, env string, trustedOrigins ...string) http.Handler +``` + +## Template Contracts for Plan 03 + +- `TabloCard` wraps Delete button in `