From b05f2800897231530d14031fbedc1baac539b428 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Mon, 18 May 2026 15:52:04 +0200 Subject: [PATCH] docs(20-02): complete tablo detail templ components plan summary Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../20-02-SUMMARY.md | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 .planning/phases/20-tablo-detail-kanban-restyle/20-02-SUMMARY.md diff --git a/.planning/phases/20-tablo-detail-kanban-restyle/20-02-SUMMARY.md b/.planning/phases/20-tablo-detail-kanban-restyle/20-02-SUMMARY.md new file mode 100644 index 0000000..56a8a6c --- /dev/null +++ b/.planning/phases/20-tablo-detail-kanban-restyle/20-02-SUMMARY.md @@ -0,0 +1,131 @@ +--- +phase: 20-tablo-detail-kanban-restyle +plan: "02" +subsystem: go-backend/views+handlers +tags: [tablo-detail, kanban, templ, htmx, sortable] +dependency_graph: + requires: + - 20-01 (TabloDetailViewModel, GetTabloDetailPage handler, GET /tablos/{tabloID} route) + provides: + - TabloDetailPage (real templ component, replaces Plan 01 stub) + - TabloDetailHeader (header with avatar, title, metadata row) + - TabloDetailTabBar (HTMX tab navigation with hx-get + hx-push-url) + - TabloDetailKanbanBoard (4-column flex container) + - TabloDetailKanbanColumn (column with header, task list, hidden reorder form) + - TabloDetailTaskCard (task card with drag handle + delete button) + - TabloDetailEtapesSection (etapes list below kanban) + - TabloDetailSortableScript (Sortable.js DOMContentLoaded + htmx:afterSettle init) + - GetTabloDetailTab handler (GET /tablos/{tabloID}/{tab}) + - GET /tablos/{tabloID}/{tab} route + affects: + - go-backend/router.go +tech_stack: + added: [] + patterns: + - templ component hierarchy (8 sub-components under TabloDetailPage) + - Hidden reorder form per column (id="reorder-form-{status}") for Sortable.js onEnd + - HTMX tab navigation (hx-get + hx-push-url="true") + - Tab handler pattern (tasks tab returns partial; other tabs return "coming soon" fragment) +key_files: + created: + - go-backend/internal/web/views/tablo_detail.templ + - go-backend/internal/web/views/tablo_detail_templ.go + - go-backend/internal/web/handlers/tablo_detail_tab.go + modified: + - go-backend/internal/web/views/tablo_detail_view.go + - go-backend/router.go +decisions: + - Tab links use hx-get + hx-push-url="true" targeting #tab-content per UI-SPEC locked interaction contract; plain href anchors explicitly forbidden + - TabloDetailKanbanBoard is a standalone component; TasksKanbanLayout from tasks.templ is not reused (separate surface per RESEARCH anti-patterns) + - TabloDetailSortableScript uses templ.Raw to emit raw script block; guard el._sortable prevents double-init after HTMX swap + - GetTabloDetailTab returns kanban board fragment only for tasks tab; other tabs return hardcoded "coming soon" text (tab slug never interpolated into HTML - T-20-07 mitigation) + - strconv.Itoa used for integer-to-string conversion in templ (not fmt.Sprintf) +metrics: + duration: "~15min" + completed_date: "2026-05-18" + tasks_completed: 2 + files_created: 3 + files_modified: 2 +--- + +# Phase 20 Plan 02: TabloDetailPage Templ Component + Tab Handler Summary + +Full HTML surface for the tablo detail page: templ components for header, HTMX tab bar, kanban board (4 columns each with hidden reorder form), task cards with drag handles, etapes section, and Sortable.js init script. Stub replaced with real templ component; tab route registered. + +## What Was Built + +**views/tablo_detail.templ** +- `TabloDetailPage(vm TabloDetailViewModel)` — outer wrapper calling all sub-components +- `TabloDetailHeader(vm TabloDetailViewModel)` — header with colored avatar, h1 title, metadata row (owner, due date, status badge, progress bar) +- `TabloDetailTabBar(tabloID string)` — 5-tab nav (Vue d'ensemble, Tâches, Fichiers, Discussion, Événements) using hx-get + hx-target="#tab-content" + hx-push-url="true"; Tâches always active +- `TabloDetailKanbanBoard(columns, tabloID)` — flex container iterating over 4 columns +- `TabloDetailKanbanColumn(col, tabloID)` — column with header (title, count, "+ Ajouter"), task list (.task-list.sortable-column), hidden reorder form id="reorder-form-{col.ID}", create zone +- `TabloDetailTaskCard(task, tabloID)` — article.task-card with .task-drag-handle, .task-card-title, ui.IconButton delete with hx-delete +- `TabloDetailEtapesSection(etapes)` — section.tablo-etapes-section with h2 "Étapes" and ul of li.tablo-etape-row items +- `TabloDetailSortableScript(tabloID)` — raw script block with initTabloDetailSortable() registered on DOMContentLoaded + htmx:afterSettle + +**views/tablo_detail_view.go** +- Stub `TabloDetailPage` function (templ.ComponentFunc) removed +- `context`, `io`, `templ` imports removed (no longer needed in .go file) +- All struct types and `NewTabloDetailViewModel` / `computeTabloProgress` functions retained + +**handlers/tablo_detail_tab.go** +- `GetTabloDetailTab()` handler for GET /tablos/{tabloID}/{tab} +- Auth check → UUID parse → tab slug switch +- tasks tab: fetches tablo + tasks → builds vm → renders TabloDetailKanbanBoard fragment +- Other tabs: returns hardcoded `
...
` + +**router.go** +- `mux.Get("/tablos/{tabloID}/{tab}", authHandler.GetTabloDetailTab())` registered after /tablos/{tabloID} + +## Security (Threat Model) + +| Threat | Mitigation | Status | +|--------|------------|--------| +| T-20-04: task.Title injected into HTML | templ auto-escapes all { expr } interpolations | Mitigated | +| T-20-05: data-status from user input | data-status comes from hardcoded column IDs only | Mitigated | +| T-20-07: {tab} slug reflected into HTML | Tab slug used only as switch key; "coming soon" text hardcoded | Mitigated | + +## Test Coverage + +All pre-existing handler tests pass with the real templ component: +- `TestGetTabloDetailPage_Returns200` — authenticated + owned tablo → 200 + tablo name in body +- `TestGetTabloDetailPage_Returns404` — unknown tablo → 404 +- `TestGetTabloDetailPage_Returns400` — invalid UUID → 400 +- `TestGetTabloDetailPage_Unauthenticated` — no cookie → 302 /login +- `TestTabloDetailKanbanColumns` — body contains todo/in_progress/in_review/done data-status values +- `TestGetTabloDetailPage_ContainsSortableScript` — body contains "initTabloDetailSortable" + +Full view model tests also pass (TestComputeTabloProgress_*, TestNewTabloDetailViewModel_*). + +## Commits + +| Hash | Type | Description | +|------|------|-------------| +| 4ae19fa | feat | TabloDetailPage templ component + GetTabloDetailTab handler | +| a60de1f | feat | Replace TabloDetailPage stub with templ component + register tab route | + +## Deviations from Plan + +None — plan executed exactly as written. + +## Known Stubs + +None. The TabloDetailPage stub from Plan 01 has been replaced. The "coming soon" tab content in GetTabloDetailTab is intentional scaffolding for Phase 21+ (overview, files, discussion, events), not an unresolved stub. + +## Self-Check + +Files created: +- go-backend/internal/web/views/tablo_detail.templ — FOUND +- go-backend/internal/web/views/tablo_detail_templ.go — FOUND +- go-backend/internal/web/handlers/tablo_detail_tab.go — FOUND + +Commits: +- 4ae19fa — FOUND +- a60de1f — FOUND + +just generate — PASSES (tablo_detail_templ.go generated) +go build ./... — PASSES +go test ./... -count=1 — ALL PASS (13 packages) + +## Self-Check: PASSED