xtablo-source/.planning/phases/16-tablo-detail/16-01-PLAN.md

203 lines
12 KiB
Markdown
Raw Normal View History

---
phase: 16-tablo-detail
plan: 01
type: execute
wave: 1
depends_on: []
files_modified:
- backend/internal/web/ui/icon_button.templ
- backend/internal/web/ui/app.css
autonomous: true
requirements:
- DETAIL-01
- DETAIL-02
- DETAIL-03
- DETAIL-04
must_haves:
truths:
- "icon_button.templ UIIcon switch contains a case for 'download' that emits a download SVG arrow"
- "icon_button.templ UIIcon switch contains a case for 'chat' that emits a speech-bubble SVG"
- "app.css contains .tasks-section, .task-row, .task-check, .task-list, .task-body, .task-meta, .tasks-add-button CSS rules using var(--...) tokens"
- "app.css contains .project-progress-track and .project-progress-bar CSS rules"
- "app.css contains .tab-nav, .tab-nav-item, .tab-nav-item.is-active, .tab-nav-item:hover CSS rules"
- "app.css contains .tablo-metadata-row and .tablo-metadata-date CSS rules"
- "app.css contains .kanban-column and scoped .kanban-column .tasks-section-header h3 { font-size: 1rem } override"
- "app.css contains .etape-group-header, .etape-group-color-dot, .etape-group-label CSS rules"
- "app.css contains .task-list-empty CSS rule"
- "templ generate && go build ./... exits 0 after changes"
artifacts:
- path: backend/internal/web/ui/icon_button.templ
provides: Download and chat icon SVG cases in UIIcon switch
contains: "case \"download\":"
- path: backend/internal/web/ui/app.css
provides: All new CSS sections for Phase 16 (1925)
contains: ".tasks-section {"
key_links:
- from: backend/internal/web/ui/icon_button.templ
to: backend/internal/web/ui/icon_button_templ.go
via: templ generate
pattern: "case \"download\""
- from: backend/internal/web/ui/app.css
to: browser render
via: static asset embed
pattern: ".tab-nav-item.is-active"
---
## Phase Goal
**As a** tablo owner, **I want to** see a fully restyled tablo detail page — header, kanban, etapes, and files — **so that** the detail view looks visually consistent with the design system established in Phases 1315.
<objective>
Add the two missing icon SVG cases (`download`, `chat`) to `UIIcon` in `icon_button.templ`, and append all Phase 16 CSS sections (1925) to `app.css`. This is the shared substrate that plans 0204 build on — without it, `@ui.IconButton` with `Icon: "download"` or `Icon: "chat"` renders the icon name as raw text.
Purpose: Unblock header restyling (Discussion/Download IconButtons), kanban restyling (task-row CSS), and files restyling (table + icons).
Output: Updated `icon_button.templ` with `download` and `chat` cases; `app.css` with Sections 1925 appended.
</objective>
<execution_context>
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/get-shit-done/workflows/execute-plan.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/ROADMAP.md
@.planning/phases/16-tablo-detail/16-CONTEXT.md
@.planning/phases/16-tablo-detail/16-RESEARCH.md
@.planning/phases/16-tablo-detail/16-PATTERNS.md
@.planning/phases/16-tablo-detail/16-UI-SPEC.md
<interfaces>
<!-- Key patterns the executor needs. No exploration required. -->
From backend/internal/web/ui/icon_button.templ (current UIIcon switch structure):
- Package: `package ui`
- Switch starts at line ~18, cases: "plus", "grid3x3", "list", "filter", "search", "calendar", "pencil", "trash"
- `default:` case emits `<span>{kind}</span>` (renders icon name as text — this is the bug)
- Insert `case "download":` and `case "chat":` BEFORE the `default:` case
From backend/internal/web/ui/app.css (current state):
- File is 450 lines; ends after Section 18 (project-card-top, project-avatar)
- Line 355-361: `.overview-section-heading h3, .tasks-section-header h3` shared rule exists (do NOT add a second `.tasks-section-header h3` rule; add only the scoped `.kanban-column .tasks-section-header h3 { font-size: 1rem; }` override)
- Sections to append: 19 (tasks-section block), 20 (progress bar), 21 (tab nav), 22 (metadata row), 23 (kanban-column wrapper), 24 (etape group), 25 (task-list-empty)
- All token names: `var(--color-surface-default)`, `var(--color-border-subtle)`, `var(--color-border-muted)`, `var(--color-border-strong)`, `var(--color-text-secondary)`, `var(--color-text-muted)`, `var(--color-text-faint)`, `var(--color-text-primary)`, `var(--color-text-brand)`, `var(--color-text-brand-strong)`, `var(--color-text-inverse)`, `var(--color-surface-muted)`, `var(--color-surface-neutral-hover)`, `var(--color-brand-primary)`, `var(--color-project-fallback)`, `var(--project-color, var(--color-project-fallback))`
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Add `download` and `chat` icon cases to UIIcon switch</name>
<files>backend/internal/web/ui/icon_button.templ</files>
<read_first>
- backend/internal/web/ui/icon_button.templ (read entire file — ~80 lines — before editing; understand the full switch structure and the `default:` position)
</read_first>
<action>
Read the full `icon_button.templ` file. Find the UIIcon switch's `default:` case. Insert two new cases immediately before `default:`:
Case "download": emit an SVG with `viewBox="0 0 24 24"`, `fill="none"`, `stroke="currentColor"`, `stroke-width="2"`, `stroke-linecap="round"`, `stroke-linejoin="round"`, `aria-hidden="true"`. Contents: `path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"`, `polyline points="7 10 12 15 17 10"`, `line x1="12" x2="12" y1="15" y2="3"`.
Case "chat": emit an SVG with same attributes. Contents: `path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"`.
Do NOT modify any other part of the file. Do NOT change the `default:` case or any existing cases.
After editing, run: `just generate` (or `templ generate ./backend/...`) to regenerate `icon_button_templ.go`.
</action>
<verify>
<automated>grep -c 'case "download"' /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/icon_button.templ && grep -c 'case "chat"' /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/icon_button.templ && cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source && go build ./backend/...</automated>
</verify>
<acceptance_criteria>
- `icon_button.templ` contains `case "download":` with a polyline + line SVG body
- `icon_button.templ` contains `case "chat":` with a path SVG body
- Both new cases appear before the `default:` case in the switch
- `go build ./backend/...` exits 0 (templ-generated file updated, no compile errors)
- The `default:` case and all 8 existing cases are unchanged
</acceptance_criteria>
<done>UIIcon switch contains "download" and "chat" cases; project compiles cleanly.</done>
</task>
<task type="auto">
<name>Task 2: Append CSS Sections 1925 to app.css</name>
<files>backend/internal/web/ui/app.css</files>
<read_first>
- backend/internal/web/ui/app.css (read lines 340450 to confirm the end of the file and the existing shared `.tasks-section-header h3` rule at lines 355361; verify no duplication before appending)
- .planning/phases/16-tablo-detail/16-PATTERNS.md (Pattern Assignments section: "New CSS blocks to append — Blocks 1, 2, 3" — these are the verbatim CSS blocks to append)
- .planning/phases/16-tablo-detail/16-UI-SPEC.md (New CSS Classes Required section — additional property values that refine the blocks)
</read_first>
<action>
Append the following seven CSS sections to the END of `backend/internal/web/ui/app.css`. Do NOT modify any existing rules. The shared `.tasks-section-header h3` rule at lines ~355-361 already exists — do NOT add another one; only add the scoped `.kanban-column .tasks-section-header h3 { font-size: 1rem; }` override.
Append in order:
Section 19 — Tasks section (ported from go-backend): `.tasks-section`, `.tasks-section-header`, `.tasks-add-button`, `.task-list`, `.task-row`, `.task-row:hover`, `.task-check`, `.task-check.is-complete`, `.task-body`, `.task-body p`, `.task-row.is-complete .task-body p`, `.task-meta`. All values from PATTERNS.md Block 1 verbatim.
Section 20 — Progress bar: `.project-progress-track`, `.project-progress-bar`. All values from PATTERNS.md Block 2 verbatim.
Section 21 — Tab nav: `.tab-nav`, `.tab-nav-item`, `.tab-nav-item.is-active`, `.tab-nav-item:hover:not(.is-active)`. Values from PATTERNS.md Block 3 / UI-SPEC.
Section 22 — Tablo detail metadata row: `.tablo-metadata-row`, `.tablo-metadata-date`, `.tablo-metadata-date svg`. Values from PATTERNS.md Block 3 / UI-SPEC.
Section 23 — Kanban column wrapper: `.kanban-column { flex-shrink: 0; width: 18rem; }` and `.kanban-column .tasks-section-header h3 { font-size: 1rem; }`.
Section 24 — Etape group sub-headings: `.etape-group-header`, `.etape-group-color-dot`, `.etape-group-label`, `.etape-group-label.is-unassigned`. Values from PATTERNS.md Block 3 / UI-SPEC.
Section 25 — Empty task list: `.task-list-empty { color: var(--color-text-faint); font-size: 0.875rem; font-style: italic; padding: 0.75rem 1rem; }`.
Every CSS value must use `var(--...)` tokens. No hardcoded hex values. No Tailwind utility classes.
</action>
<verify>
<automated>grep -c "\.tasks-section {" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.tab-nav-item\.is-active" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.kanban-column" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.etape-group-header" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css && grep -c "\.task-list-empty" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend/internal/web/ui/app.css</automated>
</verify>
<acceptance_criteria>
- `app.css` contains exactly one `.tasks-section {` rule (no duplication)
- `app.css` contains `.tab-nav-item.is-active` with `border-bottom-color: var(--color-brand-primary)` and `color: var(--color-text-brand)`
- `app.css` contains `.kanban-column` with `width: 18rem`
- `app.css` contains `.kanban-column .tasks-section-header h3` with `font-size: 1rem`
- `app.css` contains `.etape-group-header` with `background: var(--color-surface-muted)`
- `app.css` contains `.task-list-empty` with `font-style: italic`
- `app.css` contains `.project-progress-track` and `.project-progress-bar`
- `grep -c "#[0-9a-fA-F]\{3,6\}" app.css` returns 0 for newly appended lines (no hardcoded hex in new rules)
- `go build ./backend/...` exits 0 (CSS is a static asset, build verifies no templ regressions)
</acceptance_criteria>
<done>app.css has all Phase 16 CSS sections appended; no hardcoded hex values; project compiles cleanly.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| Static asset → browser | CSS and templ-generated HTML served as static embed; no user input processed |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-16-01-01 | Tampering | app.css static embed | accept | CSS is embedded at build time; no runtime user modification possible; existing CSP controls unchanged |
| T-16-01-02 | Information Disclosure | SVG icon markup | accept | SVG icons are decorative, contain no user data; aria-hidden="true" on all decorative SVGs |
No new trust boundaries. No user input, no authentication changes, no handler changes.
</threat_model>
<verification>
After both tasks complete:
```bash
cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source
go test ./backend/internal/web/... -count=1
```
All existing tests must pass. The CSS and icon changes do not affect test behavior (tests verify handler output, not CSS class names in most cases).
</verification>
<success_criteria>
- `icon_button.templ` has `case "download":` and `case "chat":` before `default:`
- `app.css` has 7 new sections (1925) appended with no hardcoded hex values
- `go test ./backend/internal/web/... -count=1` passes with no new failures
- `go build ./backend/...` exits 0
</success_criteria>
<output>
After completion, create `.planning/phases/16-tablo-detail/16-01-SUMMARY.md` using the summary template.
</output>