xtablo-source/docs/superpowers/plans/2026-05-09-go-backend-design-system.md
2026-05-09 20:18:24 +02:00

14 KiB

Go Backend Design System Implementation Plan

For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Build a repo-owned templ design system for go-backend, generate a static catalog outside the app, and migrate /tablos to the new shared primitives.

Architecture: Keep Tailwind as the styling/token foundation, but move reusable UI into go-backend/internal/web/ui/ as templ primitives plus small Go helpers. Add a Go-driven static catalog generator that renders documentation and previews from the same component implementations, then migrate /tablos to consume those primitives instead of ad hoc view markup.

Tech Stack: Go, templ, HTMX, Tailwind CSS v4, Go net/http tests, standard library filesystem APIs


File Structure

Existing files to modify

  • go-backend/tailwind.input.css
    • Add design token definitions and any shared theme aliases needed by the primitives.
  • go-backend/static/styles.css
    • Keep only app-shell styles, semantic shared component classes, and any small non-Tailwind glue that the primitives require.
  • go-backend/internal/web/views/tablos.templ
    • Replace ad hoc button/badge/modal/table markup with ui primitives.
  • go-backend/internal/web/views/tablos_view.go
    • Adapt the tablos view models to feed the new shared component APIs.
  • go-backend/internal/web/views/dashboard_components.templ
    • Replace any reused button or badge markup that should be shared in the first migration pass.
  • go-backend/internal/web/views/home.go
    • Adjust any overview helper data needed to feed shared UI primitives.
  • go-backend/internal/web/handlers/tablos_test.go
    • Update assertions to check shared component contracts.
  • go-backend/router_test.go
    • Add or update full-page assertions proving shared primitives appear in rendered pages.
  • go-backend/justfile
    • Add a command for generating the design-system catalog.

New files to create

  • go-backend/internal/web/ui/variants.go
    • Shared enums/constants/helpers for variants and sizes.
  • go-backend/internal/web/ui/tokens.go
    • Token names, semantic aliases, and any helper mappings needed by components.
  • go-backend/internal/web/ui/button.templ
    • Shared button primitive.
  • go-backend/internal/web/ui/icon_button.templ
    • Shared icon-only button primitive, including destructive/borderless cases.
  • go-backend/internal/web/ui/badge.templ
    • Shared badge primitive for statuses.
  • go-backend/internal/web/ui/input.templ
    • Shared text input primitive.
  • go-backend/internal/web/ui/textarea.templ
    • Shared textarea primitive.
  • go-backend/internal/web/ui/form_field.templ
    • Shared labeled field wrapper with error state.
  • go-backend/internal/web/ui/card.templ
    • Shared card shell and subregions where justified.
  • go-backend/internal/web/ui/modal.templ
    • Shared modal shell and actions.
  • go-backend/internal/web/ui/table.templ
    • Shared table wrappers/helpers for headers and row actions.
  • go-backend/internal/web/ui/empty_state.templ
    • Shared empty-state primitive.
  • go-backend/internal/web/ui/ui_test.go
    • Rendering tests for core primitive contracts.
  • go-backend/internal/web/ui/catalog/pages.go
    • Catalog page registry and page metadata.
  • go-backend/internal/web/ui/catalog/examples.go
    • Rendered example fixtures used by the catalog.
  • go-backend/internal/web/ui/catalog/catalog.templ
    • Shared catalog page templates.
  • go-backend/internal/web/ui/catalog/catalog_test.go
    • Catalog rendering and registration tests.
  • go-backend/cmd/designsystem/main.go
    • Static catalog generator entrypoint.
  • go-backend/cmd/designsystem/main_test.go
    • Generator output tests.

Generated files expected to change

  • go-backend/internal/web/ui/*_templ.go
    • Generated from the new templ primitives.
  • go-backend/internal/web/ui/catalog/*_templ.go
    • Generated from catalog templates.
  • go-backend/internal/web/views/*_templ.go
    • Regenerated after migrating views to shared primitives.
  • docs/design-system/*.html
    • Generated static catalog output.
  • go-backend/static/tailwind.css
    • Regenerated compiled Tailwind output.

Verification commands

  • cd go-backend && go test ./internal/web/ui -v
  • cd go-backend && go test ./cmd/designsystem -v
  • cd go-backend && go test ./internal/web/handlers -run 'Tablos|HomePage'
  • cd go-backend && just generate
  • cd go-backend && go test ./...
  • cd go-backend && just build

Chunk 1: UI Foundation

Task 1: Introduce failing tests for shared variant and primitive contracts

Files:

  • Create: go-backend/internal/web/ui/ui_test.go

  • Step 1: Write failing rendering tests for the first primitive contracts

Add focused tests for:

  • button variants and sizes
  • icon button destructive variant
  • badge variant rendering
  • modal shell structure

Example starter shape:

func TestIconButtonRendersBorderlessDestructiveMarkup(t *testing.T) {
	component := IconButton(IconButtonProps{
		Label:   "Supprimer le projet",
		Icon:    "trash",
		Variant: IconButtonVariantDangerGhost,
	})

	html := renderToString(t, component)

	for _, want := range []string{
		`class="borderless-icon-button"`,
		`aria-label="Supprimer le projet"`,
	} {
		if !strings.Contains(html, want) {
			t.Fatalf("expected %q in %q", want, html)
		}
	}
}
  • Step 2: Run the focused UI tests to verify they fail

Run: cd go-backend && go test ./internal/web/ui -v

Expected: FAIL because the ui package or primitives do not exist yet.

  • Step 3: Add the minimal ui package structure

Create:

  • variants.go
  • tokens.go
  • empty templ primitive files for the first component set

Keep the first implementation minimal: just enough types and entrypoints to satisfy the tests.

  • Step 4: Re-run the focused UI tests to verify the first primitives compile and pass

Run: cd go-backend && just generate && go test ./internal/web/ui -v

Expected: PASS for the initial primitive contract tests.

  • Step 5: Commit
git add go-backend/internal/web/ui go-backend/tailwind.input.css go-backend/static/styles.css
git commit -m "feat: add design system ui foundation"

Task 2: Add design tokens and shared semantic class rules

Files:

  • Modify: go-backend/tailwind.input.css

  • Modify: go-backend/static/styles.css

  • Test: go-backend/internal/web/ui/ui_test.go

  • Step 1: Write a failing token-level test

Add a test that renders a primitive and proves semantic classes/tokens are in use rather than page-local class strings.

  • Step 2: Run the focused test to verify it fails

Run: cd go-backend && go test ./internal/web/ui -run 'Token|Button|Badge' -v

Expected: FAIL due to missing token-backed class behavior.

  • Step 3: Define shared tokens and semantic CSS

Add:

  • semantic token aliases in tailwind.input.css
  • shared borderless/destructive button styles
  • any tiny semantic CSS hooks the primitives need

Do not add page-specific classes here.

  • Step 4: Re-run the focused UI tests

Run: cd go-backend && just generate && go test ./internal/web/ui -run 'Token|Button|Badge' -v

Expected: PASS.

  • Step 5: Commit
git add go-backend/tailwind.input.css go-backend/static/styles.css go-backend/internal/web/ui
git commit -m "feat: add design system tokens"

Chunk 2: Primitive Components

Task 3: Build the first reusable primitives

Files:

  • Create/Modify: go-backend/internal/web/ui/button.templ

  • Create/Modify: go-backend/internal/web/ui/icon_button.templ

  • Create/Modify: go-backend/internal/web/ui/badge.templ

  • Create/Modify: go-backend/internal/web/ui/input.templ

  • Create/Modify: go-backend/internal/web/ui/textarea.templ

  • Create/Modify: go-backend/internal/web/ui/form_field.templ

  • Create/Modify: go-backend/internal/web/ui/card.templ

  • Create/Modify: go-backend/internal/web/ui/modal.templ

  • Create/Modify: go-backend/internal/web/ui/table.templ

  • Create/Modify: go-backend/internal/web/ui/empty_state.templ

  • Modify: go-backend/internal/web/ui/ui_test.go

  • Step 1: Expand the test suite with one failing test per primitive

Add one focused contract test per primitive. Examples:

  • Button renders primary, ghost, and danger

  • IconButton renders icon-only action buttons

  • Badge renders status-like visual variants

  • FormField renders label + error text

  • Modal renders shell/body/actions

  • Table renders shared header/body wrappers

  • Step 2: Run the primitive tests to verify they fail

Run: cd go-backend && go test ./internal/web/ui -run 'Button|IconButton|Badge|Modal|Table|FormField' -v

Expected: FAIL due to missing or incomplete primitive implementations.

  • Step 3: Implement the minimal primitives to satisfy the tests

Keep APIs tight:

  • semantic variants

  • sm, md, lg sizes

  • pass-through HTMX attrs only where needed

  • no arbitrary class-first API

  • Step 4: Re-run the primitive tests

Run: cd go-backend && just generate && go test ./internal/web/ui -run 'Button|IconButton|Badge|Modal|Table|FormField' -v

Expected: PASS.

  • Step 5: Commit
git add go-backend/internal/web/ui
git commit -m "feat: add initial design system primitives"

Chunk 3: Static Catalog Generator

Task 4: Build the catalog registry and page templates

Files:

  • Create: go-backend/internal/web/ui/catalog/pages.go

  • Create: go-backend/internal/web/ui/catalog/examples.go

  • Create: go-backend/internal/web/ui/catalog/catalog.templ

  • Create: go-backend/internal/web/ui/catalog/catalog_test.go

  • Step 1: Write failing catalog tests

Add tests for:

  • component pages are registered

  • a tokens page exists

  • component examples render through the real primitives

  • Step 2: Run the focused catalog tests to verify they fail

Run: cd go-backend && go test ./internal/web/ui/catalog -v

Expected: FAIL because catalog registry/templates do not exist yet.

  • Step 3: Implement the catalog registry and page templates

Add:

  • page metadata
  • component examples
  • shared catalog layout
  • snippet sections

Use the real primitives from internal/web/ui/.

  • Step 4: Re-run the focused catalog tests

Run: cd go-backend && just generate && go test ./internal/web/ui/catalog -v

Expected: PASS.

  • Step 5: Commit
git add go-backend/internal/web/ui/catalog
git commit -m "feat: add design system catalog pages"

Task 5: Add the static generator command and generated output

Files:

  • Create: go-backend/cmd/designsystem/main.go

  • Create: go-backend/cmd/designsystem/main_test.go

  • Modify: go-backend/justfile

  • Generated: docs/design-system/*.html

  • Step 1: Write failing generator tests

Add tests that:

  • create a temp output dir

  • run the generator

  • assert index.html, tokens.html, and at least one component page exist

  • Step 2: Run the generator tests to verify they fail

Run: cd go-backend && go test ./cmd/designsystem -v

Expected: FAIL because the generator command does not exist yet.

  • Step 3: Implement the generator and just entrypoint

Add:

  • generator command

  • output directory creation

  • page rendering loop

  • just design-system recipe

  • Step 4: Generate the static catalog and verify tests pass

Run:

  • cd go-backend && go test ./cmd/designsystem -v
  • cd go-backend && just design-system

Expected:

  • tests PASS

  • docs/design-system/ contains generated HTML pages

  • Step 5: Commit

git add go-backend/cmd/designsystem go-backend/justfile docs/design-system
git commit -m "feat: add static design system generator"

Chunk 4: Migrate /tablos

Task 6: Replace ad hoc /tablos UI markup with shared primitives

Files:

  • Modify: go-backend/internal/web/views/tablos.templ

  • Modify: go-backend/internal/web/views/tablos_view.go

  • Modify: go-backend/internal/web/views/dashboard_components.templ

  • Modify: go-backend/internal/web/views/home.go

  • Modify: go-backend/internal/web/handlers/tablos_test.go

  • Modify: go-backend/router_test.go

  • Step 1: Add failing migration tests

Add or update tests so they explicitly expect shared component contracts in /tablos, for example:

  • shared Button class contract in toolbar or modal

  • shared IconButton contract for delete actions

  • shared Badge contract for statuses

  • shared Modal shell contract

  • shared Table wrapper contract

  • Step 2: Run the focused /tablos tests to verify they fail

Run: cd go-backend && go test ./internal/web/handlers -run 'Tablos|HomePage' -v

Expected: FAIL because views still render ad hoc markup.

  • Step 3: Migrate /tablos to ui primitives

Replace local markup with shared components:

  • primary actions -> Button
  • delete actions -> IconButton
  • statuses -> Badge
  • create form shell -> Modal + FormField + Input
  • list view shell -> Table
  • empty state -> EmptyState

Keep the page-specific layout, filters, and HTMX flows intact.

  • Step 4: Re-run focused /tablos tests

Run: cd go-backend && just generate && go test ./internal/web/handlers -run 'Tablos|HomePage' -v

Expected: PASS.

  • Step 5: Commit
git add go-backend/internal/web/views go-backend/internal/web/handlers/tablos_test.go go-backend/router_test.go
git commit -m "refactor: migrate tablos to design system primitives"

Chunk 5: Final Verification And Docs Output

Task 7: Regenerate docs, verify the full app, and lock in usage rules

Files:

  • Modify if needed: docs/design-system/*.html

  • Modify if needed: go-backend/internal/web/ui/catalog/*

  • Modify if needed: go-backend/internal/web/ui/ui_test.go

  • Step 1: Generate the final catalog output

Run: cd go-backend && just design-system

Expected: refreshed static catalog pages under docs/design-system/.

  • Step 2: Run the full verification suite

Run:

  • cd go-backend && just generate
  • cd go-backend && go test ./...
  • cd go-backend && just build

Expected:

  • all tests PASS

  • app builds cleanly

  • Step 3: Do a final plan-vs-spec review pass

Check:

  • primitives exist

  • catalog exists and is generated outside the app

  • /tablos uses shared primitives

  • no duplicate delete button implementation remains

  • Step 4: Commit

git add go-backend docs/design-system
git commit -m "feat: add go-backend design system"