docs(20-02): complete tablo detail templ components plan summary

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arthur Belleville 2026-05-18 15:52:04 +02:00
parent a60de1fc7a
commit b05f280089
No known key found for this signature in database

View file

@ -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 `<div class="tab-coming-soon">...</div>`
**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