---
phase: 13-design-system-foundation
plan: 05
type: execute
wave: 5
depends_on:
  - 13-03
  - 13-04
files_modified:
  - backend/internal/web/ui/catalog/catalog.templ
  - backend/internal/web/ui/catalog/examples.go
  - backend/internal/web/catalog_route_catalog.go
  - backend/internal/web/catalog_route_stub.go
  - backend/internal/web/router.go
  - backend/justfile
autonomous: false
requirements: []

must_haves:
  truths:
    - "go run -tags catalog ./cmd/web serves GET /ui-catalog and returns HTTP 200"
    - "The catalog page renders all 11 component sections with section headings matching DS-XX requirement IDs"
    - "The default (no -tags catalog) build does not include the catalog route"
    - "The developer can visually verify all component variants before Phase 14 begins"
    - "go build ./... (without -tags catalog) succeeds — no undefined symbol linker errors"
    - "go test ./... passes — no regressions"
  artifacts:
    - path: "backend/internal/web/ui/catalog/catalog.templ"
      provides: "Single-page catalog layout with sidebar nav and component sections"
      contains: "Component Catalog"
    - path: "backend/internal/web/ui/catalog/examples.go"
      provides: "Typed Example structs for each component variant"
      contains: "buttonExamples"
    - path: "backend/internal/web/catalog_route_catalog.go"
      provides: "Build-tagged catalog route registration"
      contains: "//go:build catalog"
    - path: "backend/internal/web/catalog_route_stub.go"
      provides: "No-op stub for production builds"
      contains: "//go:build !catalog"
  key_links:
    - from: "backend/internal/web/router.go"
      to: "RegisterCatalogRoute"
      via: "unconditional call in NewRouter"
      pattern: "RegisterCatalogRoute"
    - from: "backend/internal/web/catalog_route_catalog.go"
      to: "backend/internal/web/ui/catalog/catalog.templ"
      via: "catalogPageHandler() templ.Handler render"
      pattern: "catalog"
---

## Phase Goal

**As a** developer, **I want to** run `just catalog` and view all 11 component types rendered with every variant on a single page, **so that** I can visually sign off on token values and component shapes before Phase 14 begins applying the design system to real app views.

<objective>
Create the build-tag-gated /ui-catalog route with a single-page component catalog.
The catalog shows all component variants with their templ call annotations.
A human checkpoint at the end gates progression to Phase 14.

Purpose: Visual sign-off is the final gate before Phases 14–17 apply the design system
to real app views. The catalog makes component shapes and token choices visible before
any per-view work begins.

Output:
- backend/internal/web/ui/catalog/catalog.templ (layout + section rendering)
- backend/internal/web/ui/catalog/examples.go (typed examples per component)
- backend/internal/web/catalog_route_catalog.go (//go:build catalog)
- backend/internal/web/catalog_route_stub.go (//go:build !catalog)
- router.go wired with unconditional RegisterCatalogRoute call
- justfile catalog target added
</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/phases/13-design-system-foundation/13-CONTEXT.md
@.planning/phases/13-design-system-foundation/13-RESEARCH.md
@.planning/phases/13-design-system-foundation/13-PATTERNS.md
@.planning/phases/13-design-system-foundation/13-UI-SPEC.md
@.planning/phases/13-design-system-foundation/13-03-SUMMARY.md
@.planning/phases/13-design-system-foundation/13-04-SUMMARY.md
</context>

<interfaces>
From backend/internal/web/router.go:
  func NewRouter(pinger Pinger, staticFS fs.FS, deps AuthDeps, tabloDeps TablosDeps,
    taskDeps TasksDeps, etapeDeps EtapesDeps, eventDeps EventsDeps,
    discussionDeps DiscussionDeps, planningDeps PlanningDeps, fileDeps FilesDeps,
    csrfKey []byte, env string, trustedOrigins ...string) (http.Handler, error)
  // Add RegisterCatalogRoute(r) call inside this function, after all protected routes.

Build tag file pair pattern:
  catalog_route_catalog.go — //go:build catalog — defines RegisterCatalogRoute(r chi.Router) that mounts handler
  catalog_route_stub.go   — //go:build !catalog — defines RegisterCatalogRoute(r chi.Router) {} no-op

Catalog layout (from 13-UI-SPEC.md):
  Sidebar 240px fixed, right: main content fluid
  Section order: alphabetical — badge, button, card, empty-state, form-field, icon-button, input, modal, select, table, textarea
  Each section heading: "{ComponentName} — {DS-req}" (e.g. "Button — DS-02")
  Modal section renders panel-only (no backdrop wrapper — Pitfall 7)

Catalog copywriting (from 13-UI-SPEC.md):
  Page title: "Component Catalog"
  Nav heading: "Components"
  Empty state demo title: "Nothing here yet"
  Empty state demo body: "Add your first item to get started."
  Modal demo title: "Confirm action"
  Form error demo: "This field is required."
  Form hint demo: "Enter a value between 1 and 100."
</interfaces>

<tasks>

<task type="auto">
  <name>Task 1: Create catalog package (catalog.templ + examples.go + route files + router wiring)</name>
  <files>
    backend/internal/web/ui/catalog/catalog.templ,
    backend/internal/web/ui/catalog/examples.go,
    backend/internal/web/catalog_route_catalog.go,
    backend/internal/web/catalog_route_stub.go,
    backend/internal/web/router.go
  </files>
  <read_first>
    - go-backend/internal/web/ui/catalog/catalog.templ (structure reference — go-backend uses static file generation but the templ layout structure is the model)
    - go-backend/internal/web/ui/catalog/examples.go (Example struct pattern and per-component example functions)
    - backend/internal/web/router.go (find where to insert RegisterCatalogRoute call — after all protected routes, before healthz handler if any)
    - 13-PATTERNS.md (catalog.templ, examples.go, catalog_route_catalog.go + stub sections)
    - 13-RESEARCH.md (Catalog Route — Build Tag Pattern section, Pitfall 4, Pitfall 7)
    - 13-UI-SPEC.md (Catalog Page Contract section — layout, section order, copywriting)
  </read_first>
  <action>
    Step 1 — Create backend/internal/web/ui/catalog/ directory and catalog.templ:
    Package declaration: "package catalog".
    The catalog page uses a fake shell with Tailwind utilities (flex, min-h-screen, w-60, etc.)
    — no import of real app.css (per D-A04).
    Layout: two-column flex with sidebar (w-60, fixed, border-r) and main content area (flex-1, p-8).
    Sidebar nav: heading "Components" + anchor links in alphabetical order:
    #badge, #button, #card, #empty-state, #form-field, #icon-button, #input, #modal, #select, #table, #textarea.
    Each section in main content: <section id="{slug}"> with <h2>{ComponentName} — {DS-req}</h2>
    followed by the component examples from the examples list.
    Each example: rendered component + <pre><code> block showing the Snippet string.
    Modal section: render the ui-modal-panel div directly without the ui-modal-backdrop wrapper
    (Pitfall 7 — backdrop position:fixed would overlay the page).
    Page title: <title>Component Catalog</title>.
    Import path for ui components: "backend/internal/web/ui".

    Step 2 — Create backend/internal/web/ui/catalog/examples.go:
    Package declaration: "package catalog".
    Define type Example struct { Title string; Preview templ.Component; Snippet string }.
    Define example functions for each component:
    - badgeExamples() — returns examples for info, warning, success, danger, primary variants
    - buttonExamples() — returns examples for solid/default, solid/danger, soft/neutral, ghost variants (all size MD)
    - cardExamples() — returns one example with body content using textBody helper
    - emptyStateExamples() — returns one example with title "Nothing here yet", description "Add your first item to get started."
    - formFieldExamples() — returns example with Label, Hint, Error using "This field is required." and "Enter a value between 1 and 100."
    - iconButtonExamples() — returns examples for ghost/neutral (plus icon) and solid/danger (trash icon)
    - inputExamples() — returns examples for text type, email type, with placeholder
    - modalExamples() — returns one example rendering ModalProps{Title: "Confirm action"} BUT wraps it to render only the ui-modal-panel (not the backdrop)
    - selectExamples() — returns one example with a few options
    - tableExamples() — returns one example with a simple head/body
    - textareaExamples() — returns one example with placeholder and rows

    Add a componentFunc helper (adapted from go-backend examples.go):
    func componentFunc(f func(ctx context.Context, w io.Writer) error) templ.Component.
    Imports: "context", "io", "github.com/a-h/templ", "backend/internal/web/ui".

    Step 3 — Create backend/internal/web/catalog_route_catalog.go:
    First line: //go:build catalog
    Package declaration: package web
    Import: "github.com/go-chi/chi/v5"
    Define RegisterCatalogRoute(r chi.Router) that calls r.Get("/ui-catalog", catalogPageHandler()).
    Define catalogPageHandler() http.HandlerFunc that renders catalog.templ using templ.Handler.
    Import path for catalog: "backend/internal/web/ui/catalog".

    Step 4 — Create backend/internal/web/catalog_route_stub.go:
    First line: //go:build !catalog
    Package declaration: package web
    Import: "github.com/go-chi/chi/v5"
    Define RegisterCatalogRoute(r chi.Router) {} // no-op in production builds.

    Step 5 — Update backend/internal/web/router.go:
    Add a single unconditional call RegisterCatalogRoute(r) inside NewRouter, after all authenticated
    routes are registered and before the function returns. In the non-catalog build, the stub's
    no-op satisfies the symbol — no linker error.

    Run: cd backend && go build ./... — must succeed (without -tags catalog — stub satisfies symbol).
    Run: cd backend && go build -tags catalog ./... — must succeed (catalog build).
    Run: cd backend && just generate && go test ./... -count=1 — must be green.
  </action>
  <verify>
    <automated>cd backend && go build ./... && go build -tags catalog ./... && just generate && go test ./... -count=1 && grep 'RegisterCatalogRoute' internal/web/router.go && grep '^//go:build catalog' internal/web/catalog_route_catalog.go && grep 'Component Catalog' internal/web/ui/catalog/catalog.templ</automated>
  </verify>
  <acceptance_criteria>
    - go build ./... (without catalog tag) succeeds — no linker errors
    - go build -tags catalog ./... succeeds
    - just generate && go test ./... -count=1 is green
    - backend/internal/web/catalog_route_catalog.go starts with "//go:build catalog"
    - backend/internal/web/catalog_route_stub.go starts with "//go:build !catalog"
    - router.go contains "RegisterCatalogRoute(r)"
    - catalog.templ contains "Component Catalog"
    - catalog.templ contains each section anchor: "#badge", "#button", "#card", "#input"
    - examples.go contains "func buttonExamples()"
    - examples.go contains "func modalExamples()"
    - The modal example does NOT use "ui-modal-backdrop" as a wrapper (renders panel-only)
  </acceptance_criteria>
  <done>Catalog package created; route files registered; router wired; build succeeds with and without catalog tag; tests green</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2: Visual sign-off — run catalog and verify all 11 component sections</name>
  <what-built>
    A dev-only catalog route at /ui-catalog that renders all 11 component types with all variants.
    The catalog is gated by //go:build catalog so it never ships in production.
    The justfile has a "catalog" target that runs: just generate && go run -tags catalog ./cmd/web
    Developer visits http://localhost:8080/ui-catalog to review all components.
  </what-built>
  <how-to-verify>
    1. Run the catalog server:
       cd backend && just generate && go run -tags catalog ./cmd/web
       (or: just catalog if the target is wired)

    2. Visit http://localhost:8080/ui-catalog in a browser.

    3. Verify the sidebar shows all 11 section links in alphabetical order:
       badge, button, card, empty-state, form-field, icon-button, input, modal, select, table, textarea

    4. For each section, verify:
       - Section heading includes the DS requirement number (e.g. "Button — DS-02")
       - All declared variants are rendered (e.g. button: solid/default, solid/danger, soft/neutral, ghost)
       - Each variant shows a templ call annotation below the rendered component

    5. Verify specific components:
       - Button: ghost variant renders with transparent background (no colored fill)
       - Badge: primary variant renders with purple-tinted background (different from info blue)
       - Card: header and body regions render as separate bordered sections
       - Modal: modal panel is visible (no full-page backdrop overlay)
       - EmptyState: icon circle + title + description render correctly
       - Select: dropdown control renders with chevron indicator
       - IconButton: ghost variant has no background, solid variant has filled background

    6. Check browser console — no JavaScript errors.

    7. Confirm token values look correct:
       - Brand purple (#804eec) on primary buttons and ghost button text
       - Pill-shaped badges with subtle colored borders
       - Cards with rounded corners and shadow

    8. Type "approved" if all 11 sections look correct, or describe any issues to address.
  </how-to-verify>
  <resume-signal>
    Type "approved" to proceed to Phase 14, or describe specific visual issues (component,
    variant, observed vs expected appearance) so they can be fixed before Phase 14 begins.
  </resume-signal>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| Catalog route → production binary | //go:build catalog tag ensures the route is never compiled into production; production binary built without -tags catalog |
| Catalog page → browser | All catalog content is developer-authored static data (no user input rendered on catalog page) |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-13-05-01 | Information Disclosure | /ui-catalog route in production | mitigate | //go:build catalog + //go:build !catalog stub ensures the route symbol is a no-op in default builds. Production deployment uses go build ./... (no catalog tag). Verify with: go build ./... followed by strings ./cmd/web/main-binary | grep ui-catalog — must return nothing. |
| T-13-05-02 | Elevation of Privilege | catalog route in dev | accept | Catalog is dev-only; no auth required is intentional for a local development tool; serves static component previews only, no user data |
| T-13-05-03 | Information Disclosure | examples.go static strings | accept | Demo strings ("Nothing here yet", "Confirm action", etc.) are hard-coded display text; no secrets, no user data |
</threat_model>

<verification>
After this plan completes (pre-checkpoint):
- cd backend && go build ./... — must succeed (no catalog tag, stub satisfies symbol)
- cd backend && go build -tags catalog ./... — must succeed
- cd backend && go test ./... -count=1 — must be green
- grep 'RegisterCatalogRoute' backend/internal/web/router.go — must match
- grep '^//go:build catalog$' backend/internal/web/catalog_route_catalog.go — must match
- grep '^//go:build !catalog$' backend/internal/web/catalog_route_stub.go — must match

After checkpoint approval:
- Developer has visually confirmed all 11 component sections on /ui-catalog
- Token values (brand purple, badge tones, card shadow) match expectations
- Phase 14 can begin
</verification>

<success_criteria>
1. go build ./... and go build -tags catalog ./... both succeed
2. go test ./... is green with no regressions
3. /ui-catalog serves all 11 component sections with variants and templ annotations
4. Production build (no -tags catalog) excludes catalog route — RegisterCatalogRoute is a no-op
5. Developer has approved the visual output via the checkpoint — all 11 sections confirmed correct
</success_criteria>

<output>
After completion, create `.planning/phases/13-design-system-foundation/13-05-SUMMARY.md`
</output>
