xtablo-source/.planning/phases/03-tablos-crud/03-02-SUMMARY.md
Arthur Belleville c4406cf16c
docs(03-02): plan 02 SUMMARY + STATE update — checkpoint at Task 3
- 03-02-SUMMARY.md: TablosDeps, handler contracts, template contracts,
  4/10 tests green, 6 RED for Plan 03, known stubs documented
- STATE.md: 2 new decisions, plan 02 metrics row added, notes updated
- ROADMAP.md: phase 3 progress updated (2/3 summaries)
2026-05-15 00:22:16 +02:00

7.5 KiB


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

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

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 <div class="tablo-delete-zone"> — Plan 03 wires /delete-confirm to swap outerHTML
  • TabloCard renders "View" link to /tablos/{id} — Plan 03 implements that route
  • All 5 template components in tablos.templ are callable by Plan 03

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] Deleted stale index_templ.go after emptying index.templ

  • Found during: Task 2 (after reducing index.templ to bare package declaration)
  • Issue: templ generate regenerated index_templ.go with import "github.com/a-h/templ" even though the file has no templ components, causing go build to fail with "imported and not used".
  • Fix: Deleted backend/templates/index_templ.go manually after just generate; build passes.
  • Files modified: backend/templates/index_templ.go (deleted)
  • Committed in: 5db9215 (Task 2)

Known Stubs

  • TabloCard Delete button fires hx-get="/tablos/{id}/delete-confirm" — the /delete-confirm route does not exist yet (Plan 03 implements it). The button is visible on the dashboard but clicking it returns a 404 until Plan 03.
  • TabloCard "View" link points to /tablos/{id} — route not yet registered (Plan 03). Navigating returns chi's default 404 until Plan 03.

These stubs are intentional per plan design — Plan 02 establishes the zone and link shapes that Plan 03 will wire.

Checkpoint Status

Task 3 (human-verify) reached — execution paused awaiting manual browser verification of:

  1. Dashboard "Your Tablos" heading + tablo cards or empty state
  2. "New tablo" button HTMX fetch of inline form
  3. HTMX create: form clears, card prepends, no full reload
  4. Validation: empty title shows "Title is required." inline
  5. Non-JS POST → 303 redirect to /, tablo in list
  6. CSRF token present in form _csrf hidden field

Next Phase Readiness

  • Plan 03 can implement TabloDetail, TabloUpdate, TabloDeleteConfirm, TabloDelete, and TabloDeleteCancel handlers and routes.
  • TablosDeps available, NewRouter signature stable.
  • .tablo-delete-zone class on TabloCard wired for Plan 03's delete-confirm OOB swap.

Phase: 03-tablos-crud Completed (partial — checkpoint): 2026-05-14