xtablo-source/.planning/phases/20-tablo-detail-kanban-restyle/20-03-PLAN.md
Arthur Belleville f24e1c4d35
test(20-01): add failing tests for TabloDetailViewModel + GetTabloDetailPage handler
- TestComputeTabloProgress_{Empty,AllDone,Half,EtapesIgnored}
- TestNewTabloDetailViewModel_{GroupsTasksByStatus,EtapesExcludedFromColumns,EtapesPopulated}
- TestGetTabloDetailPage_{Returns200,Returns404,Returns400,Unauthenticated}
- TestTabloDetailKanbanColumns
- TestGetTabloDetailPage_ContainsSortableScript
2026-05-18 15:44:53 +02:00

402 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
phase: 20-tablo-detail-kanban-restyle
plan: 03
type: execute
wave: 2
depends_on:
- 20-01
files_modified:
- go-backend/internal/web/ui/app.css
autonomous: true
requirements:
- DETAIL-01
- TASK-01
must_haves:
truths:
- "app.css contains a .tablo-detail-header rule with flex-direction, padding, and border-bottom"
- "app.css contains a .tablo-detail-title rule with font-size 1.75rem and font-weight 600"
- "app.css contains a .tablo-metadata-row rule with display flex and gap 24px"
- "app.css contains a .tablo-kanban-board rule with display flex, gap 16px, and overflow-x auto"
- "app.css contains a .tablo-kanban-column rule with width 18rem, border-radius 0.75rem, and border"
- "app.css contains a .task-card rule with flex-direction column, border-radius 8px, and gap 8px"
- "app.css contains a .task-drag-handle rule with opacity 0 and a .task-card:hover .task-drag-handle rule with opacity 1"
- "app.css contains a .task-card-delete rule with opacity 0 at rest and visible on .task-card:hover"
- "app.css contains a .tablo-progress-bar rule with background var(--color-brand-primary) — NOT var(--project-color)"
- "app.css contains a .tablo-files-table-wrapper rule with border-radius 12px"
- "app.css .task-list rule is updated to include gap 8px and padding 8px"
- "app.css contains a .tablo-etapes-section rule and a .tablo-etape-row rule"
artifacts:
- path: "go-backend/internal/web/ui/app.css"
provides: "All tablo detail + kanban restyle + etapes section CSS rules"
contains: ".tablo-detail-header"
key_links:
- from: "go-backend/internal/web/views/tablo_detail.templ"
to: "go-backend/internal/web/ui/app.css"
via: "CSS class names applied to HTML elements"
pattern: ".tablo-kanban-board"
---
<objective>
Apply all CSS changes from the UI-SPEC to app.css: new tablo detail header styles, kanban board layout, task card restyle (column-flex, hover shadow, opacity-based drag handle), progress bar fill fix, files table wrapper, etapes section, and updated task-list gap. This plan runs in parallel with Plan 02 since CSS class names are already locked in the UI-SPEC.
Purpose: Without these CSS rules, the templ components from Plan 02 render unstyled. This plan is the visual half of the restyle.
Output: Updated app.css with all new and modified CSS blocks from UI-SPEC.
</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>
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/20-tablo-detail-kanban-restyle/20-UI-SPEC.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/20-tablo-detail-kanban-restyle/20-RESEARCH.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.claude/skills/sketch-findings-xtablo-source/SKILL.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Tablo detail header and metadata CSS</name>
<files>go-backend/internal/web/ui/app.css</files>
<read_first>
- go-backend/internal/web/ui/app.css (read lines 1040-1080 — existing .project-progress-track, .project-progress-bar, .project-progress-label rules to understand context before modifying)
- go-backend/internal/web/ui/app.css (read lines 880-920 — existing .tab-nav, .tab-nav-item rules to confirm no tab changes needed)
- go-backend/internal/web/ui/base.css (read first 60 lines — confirm --color-brand-primary, --color-border-default, --color-surface-muted, --color-text-primary token names)
</read_first>
<action>
Edit go-backend/internal/web/ui/app.css. Append a new section at the end of the file titled "/* === Tablo Detail Page === */". Add the following CSS blocks in this order. Use exact property values from the UI-SPEC — do not approximate or simplify.
BLOCK 1: .tablo-detail-page — outer container
padding: 24px 32px;
BLOCK 2: .tablo-detail-header — header element
border-bottom: 1px solid var(--color-border-muted);
display: flex;
flex-direction: column;
gap: 0;
padding-bottom: 0;
BLOCK 3: .tablo-detail-title-row — flex row with avatar + h1
align-items: center;
display: flex;
gap: 16px;
margin-bottom: 0;
padding-bottom: 16px;
BLOCK 4: .tablo-detail-avatar — 48×48 colored circle
align-items: center;
border-radius: 12px;
color: #ffffff;
display: flex;
flex-shrink: 0;
font-size: 1rem;
font-weight: 700;
height: 48px;
justify-content: center;
width: 48px;
BLOCK 5: .tablo-detail-title — h1 tablo name
color: var(--color-text-primary);
font-size: 1.75rem;
font-weight: 600;
line-height: 1.2;
margin: 0;
BLOCK 6: .tablo-metadata-row — metadata flex row
align-items: center;
border-bottom: 1px solid var(--color-border-muted);
display: flex;
flex-wrap: wrap;
gap: 24px;
padding-block: 16px;
BLOCK 7: .tablo-meta-segment — each segment in metadata row
align-items: center;
color: var(--color-text-secondary);
display: flex;
font-size: 0.875rem;
gap: 8px;
BLOCK 8: .tablo-meta-progress — progress segment override
align-items: center;
display: flex;
gap: 8px;
BLOCK 9: .tablo-progress-bar — detail page progress bar fill (MUST use brand-primary, NOT project-color — Pitfall 5)
background: var(--color-brand-primary);
border-radius: 9999px;
height: 5px;
BLOCK 10: .tablo-tab-bar — tab navigation below header
border-bottom: 1px solid var(--color-border-muted);
display: flex;
gap: 24px;
margin-top: 0;
padding-top: 8px;
BLOCK 11: .tablo-tab-bar .tab-nav-item — override for tabs within tablo detail
font-size: 0.875rem;
padding-bottom: 12px;
Do NOT modify the existing .project-progress-bar rule (it is used by tablo cards on the list page which keep var(--project-color)). The tablo detail page uses .tablo-progress-bar (different class) to avoid the conflict.
Do NOT modify .tab-nav or .tab-nav-item globally — only scope changes to .tablo-tab-bar context if any override is needed.
</action>
<verify>
<automated>grep -c "tablo-detail-header\|tablo-detail-title\|tablo-metadata-row\|tablo-progress-bar\|tablo-tab-bar" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/go-backend/internal/web/ui/app.css</automated>
</verify>
<done>grep count returns 5 or more (one match per class block); .tablo-progress-bar uses var(--color-brand-primary) not var(--project-color); grep for "tablo-progress-bar" returns a rule with "background: var(--color-brand-primary)".</done>
</task>
<task type="auto">
<name>Task 2: Kanban board, task card, etapes section, files table, and task-list gap CSS</name>
<files>go-backend/internal/web/ui/app.css</files>
<read_first>
- go-backend/internal/web/ui/app.css (read lines 1283-1350 — existing .task-list, .task-row, .task-body, .task-check rules; understand what to modify vs what to add)
- go-backend/internal/web/ui/app.css (read lines 1254-1268 — existing .tasks-section rule with border-radius: 1rem — do NOT change this; kanban column gets its own rule)
- go-backend/internal/web/ui/base.css (confirm --color-surface-default, --color-border-default, --color-border-strong, --color-surface-muted token names)
</read_first>
<action>
Edit go-backend/internal/web/ui/app.css. Continue the "/* === Tablo Detail Page === */" section from Task 1 (or append after it). Add the following blocks:
BLOCK 12: .tablo-kanban-board — flex container for the kanban columns
display: flex;
gap: 16px;
overflow-x: auto;
padding-bottom: 16px;
padding-top: 24px;
BLOCK 13: .tablo-kanban-column — each column card
background: var(--color-surface-default);
border: 1px solid var(--color-border-default);
border-radius: 0.75rem;
flex-shrink: 0;
overflow: hidden;
width: 18rem;
BLOCK 14: .tablo-kanban-column-header — column header area
align-items: center;
background: var(--color-surface-muted);
display: flex;
gap: 8px;
justify-content: space-between;
padding: 12px 16px;
BLOCK 15: .tablo-kanban-column-title — column h3 label
color: var(--color-text-primary);
font-size: 0.875rem;
font-weight: 600;
margin: 0;
BLOCK 16: .tablo-kanban-task-count — task count pill
background: var(--color-surface-default);
border: 1px solid var(--color-border-muted);
border-radius: 9999px;
color: var(--color-text-secondary);
font-size: 0.75rem;
padding: 0 8px;
BLOCK 17: .tablo-kanban-add-link — "+ Ajouter" link
color: var(--color-text-brand);
font-size: 0.875rem;
font-weight: 400;
margin-left: auto;
text-decoration: none;
BLOCK 18: .tablo-kanban-empty — empty column state
color: var(--color-text-faint);
font-size: 0.875rem;
padding: 24px 16px;
text-align: center;
BLOCK 19: .task-card — new card layout (replaces/supplements .task-row for tablo detail)
background: var(--color-surface-default);
border: 1px solid var(--color-border-default);
border-radius: 8px;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 8px;
padding-block: 8px;
padding-inline: 12px;
transition: box-shadow 0.12s ease, border-color 0.12s ease;
BLOCK 20: .task-card:hover
border-color: var(--color-border-strong);
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
BLOCK 21: .task-card-top-row — row with drag handle, title, delete icon
align-items: flex-start;
display: flex;
gap: 6px;
BLOCK 22: .task-drag-handle — drag handle (Braille pattern)
color: var(--color-text-faint);
cursor: grab;
flex-shrink: 0;
font-size: 1rem;
opacity: 0;
transition: opacity 0.12s ease;
BLOCK 23: .task-card:hover .task-drag-handle — reveal on card hover
opacity: 1;
BLOCK 24: .task-card-title — task title text
color: var(--color-text-primary);
flex: 1;
font-size: 0.875rem;
font-weight: 400;
line-height: 1.4;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
BLOCK 25: .task-card-delete — delete icon wrapper (opacity hidden at rest)
flex-shrink: 0;
opacity: 0;
transition: opacity 0.12s ease;
BLOCK 26: .task-card:hover .task-card-delete — reveal on card hover
opacity: 1;
Now modify the EXISTING .task-list rule (around line 1283 in app.css):
Find the current rule:
.task-list {
display: flex;
flex-direction: column;
}
Change it to add gap and padding:
.task-list {
display: flex;
flex-direction: column;
gap: 8px;
padding: 8px;
}
This change affects both the global tasks page and the tablo detail page equally — gap between cards is desired everywhere.
Add etapes section CSS:
BLOCK 27: .tablo-etapes-section — etapes list below kanban board
border-top: 1px solid var(--color-border-muted);
margin-top: 24px;
padding-top: 24px;
BLOCK 28: .tablo-etapes-section h2, .tablo-etapes-section h3 — section heading
color: var(--color-text-primary);
font-size: 1rem;
font-weight: 600;
margin: 0 0 12px 0;
BLOCK 29: .tablo-etapes-section ul — list reset
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 8px;
BLOCK 30: .tablo-etape-row — each etape row
align-items: center;
background: var(--color-surface-default);
border: 1px solid var(--color-border-default);
border-radius: 8px;
display: flex;
gap: 12px;
justify-content: space-between;
padding: 10px 16px;
BLOCK 31: .tablo-etape-name — etape stage name
color: var(--color-text-primary);
font-size: 0.875rem;
font-weight: 500;
BLOCK 32: .tablo-etape-count — task count label
color: var(--color-text-secondary);
font-size: 0.75rem;
Add files table wrapper CSS:
BLOCK 33: .tablo-files-table-wrapper — wrapper for the files table
border: 1px solid var(--color-border-default);
border-radius: 12px;
overflow: hidden;
BLOCK 34: .tablo-files-table-wrapper thead tr
background: var(--color-surface-muted);
BLOCK 35: .tablo-files-table-wrapper thead th
color: var(--color-text-muted);
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
BLOCK 36: .tablo-files-table-wrapper tbody tr
border-bottom: 1px solid var(--color-border-default);
BLOCK 37: .tablo-files-table-wrapper tbody tr:hover
background: var(--color-surface-subtle);
CRITICAL checks before saving:
- .tablo-progress-bar uses "background: var(--color-brand-primary)" — verify with grep after writing
- .task-card and .task-row are SEPARATE rules — .task-row must NOT be removed (it is used by the global tasks page)
- .tasks-section border-radius (1rem) must NOT be changed — only .tablo-kanban-column gets 0.75rem
- All opacity transitions use "0.12s ease" consistent with design system
</action>
<verify>
<automated>grep "background: var(--color-brand-primary)" /Users/arthur.belleville/Documents/perso/projects/xtablo-source/go-backend/internal/web/ui/app.css</automated>
</verify>
<done>grep returns at least one line containing "background: var(--color-brand-primary)" (the .tablo-progress-bar rule); .task-card block exists with flex-direction: column; .task-drag-handle exists with opacity: 0; .task-card:hover .task-drag-handle exists with opacity: 1; .tablo-kanban-board exists with overflow-x: auto; .task-list updated to include gap: 8px; .task-row unchanged; .tablo-etapes-section and .tablo-etape-row rules present.</done>
</task>
</tasks>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| CSS cascade | New .task-card rules must not override or break .task-row rules used on global /tasks page |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-20-06 | Tampering | CSS cascade — .task-card vs .task-row collision | mitigate | .task-card is a new separate selector; .task-row selector is unchanged; they do not overlap since tablo-detail uses task-card and global tasks page uses task-row |
| T-20-SC | Tampering | npm/pip/cargo installs | accept | No package installs — CSS file edit only |
</threat_model>
<verification>
After Plan 03:
- grep for "tablo-kanban-board" in app.css returns at least one match with "overflow-x: auto"
- grep for ".tablo-progress-bar" in app.css returns a match with "background: var(--color-brand-primary)"
- grep for "tablo-progress-bar" does NOT return "var(--project-color)"
- grep for ".task-card" in app.css returns the column-flex card rule (flex-direction: column)
- grep for ".task-drag-handle" returns opacity: 0 rule
- grep for ".task-card:hover .task-drag-handle" returns opacity: 1 rule
- grep for ".task-row" still returns the original horizontal rule (not removed)
- grep for ".tasks-section" still has border-radius: 1rem (not changed to 0.75rem)
- grep for ".task-list" returns updated rule with gap: 8px
- grep for ".tablo-etapes-section" returns a CSS rule
- grep for ".tablo-etape-row" returns a CSS rule
- go build ./... still exits 0 (CSS is static — no compilation risk, but verify Go still compiles cleanly)
</verification>
<success_criteria>
- Visual: tablo detail header shows tablo name in large font, metadata row, and progress bar with purple fill
- Visual: kanban columns are 18rem wide with rounded corners, muted header background
- Visual: task cards are white box with column layout, subtle border, hover shadow
- Visual: drag handle appears on card hover (opacity transition, not display toggle)
- Visual: delete icon appears on card hover
- Visual: empty columns show "Aucune tâche" centered
- Visual: etapes section renders below kanban board with stage names and task counts
- CSS regression: global /tasks kanban page still renders correctly (task-row unchanged)
</success_criteria>
<output>
Create `.planning/phases/20-tablo-detail-kanban-restyle/20-03-SUMMARY.md` when done.
</output>