---
phase: 15-dashboard-tablos
plan: 01
type: execute
wave: 0
depends_on: []
files_modified:
  - backend/internal/web/handlers_tablos_test.go
autonomous: true
requirements:
  - DASH-01
  - DASH-02
  - DASH-03
must_haves:
  truths:
    - "TestTablosDashboard_Sidebar fails RED until AppLayout is implemented"
    - "TestTablosDashboard_ProjectCards fails RED until project-card template is implemented"
    - "TestTablosDashboard_EmptyState fails RED until empty state is wired to ui.EmptyState"
  artifacts:
    - path: "backend/internal/web/handlers_tablos_test.go"
      provides: "Wave 0 test stubs for DASH-01/02/03"
      contains: "TestTablosDashboard_Sidebar"
  key_links:
    - from: "TestTablosDashboard_Sidebar"
      to: "GET / handler response body"
      via: "httptest.ResponseRecorder"
      pattern: "strings.Contains.*dashboard-sidebar"
---

## Phase Goal

**As a** signed-in user, **I want to** see a sidebar-based dashboard with project cards for my tablos, **so that** the app matches the go-backend visual design and I can navigate my work efficiently.

<objective>
Create failing integration test stubs for DASH-01, DASH-02, and DASH-03 in the existing handlers_tablos_test.go file. These tests define the acceptance target for Plans 02 and 03 — they MUST fail (RED) when this plan is complete.

Purpose: Nyquist compliance requires automated tests for every requirement ID before implementation begins. Wave 0 plants the tests that Plans 02 and 03 will turn green.

Output: Three new test functions added to handlers_tablos_test.go, all failing at runtime until the AppLayout and project-card templates are implemented.
</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/ROADMAP.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/15-dashboard-tablos/15-VALIDATION.md
</context>

<tasks>

<task type="auto" tdd="true">
  <name>Task 1: Add Wave 0 RED test stubs for DASH-01, DASH-02, DASH-03</name>
  <files>backend/internal/web/handlers_tablos_test.go</files>

  <read_first>
    - backend/internal/web/handlers_tablos_test.go — read the full file to understand: package name, existing test helper signatures (loginUser, newTabloTestRouter, getCSRFToken), how existing tests issue GET / and check response body via strings.Contains, and how tablos are pre-inserted (look for helper that inserts a tablo row).
    - backend/internal/web/handlers_auth_test.go — read to understand setupTestDB, preInsertUser, and the newTestRouter pattern used across test files.
  </read_first>

  <behavior>
    - TestTablosDashboard_Sidebar: authenticated GET / must contain "dashboard-sidebar" in the response body. Fails RED until AppLayout renders the sidebar.
    - TestTablosDashboard_ProjectCards: authenticated GET / with at least one pre-inserted tablo must contain "project-card" in the response body. Fails RED until TabloProjectCard is implemented.
    - TestTablosDashboard_EmptyState: authenticated GET / with zero tablos must contain "ui-empty-state" in the response body. Fails RED until TablosEmptyState uses @ui.EmptyState.
  </behavior>

  <action>
    Append three new test functions at the end of handlers_tablos_test.go. Each follows the exact same httptest pattern already used by the file's existing tests: call loginUser to get session cookies, issue GET / with those cookies, check rec.Code == 200, call strings.Contains on rec.Body.String() for the target string.

    TestTablosDashboard_Sidebar: after login (no tablo pre-insert needed), GET /, assert strings.Contains(body, "dashboard-sidebar"). The test should also assert strings.Contains(body, "sidebar-nav-shell") as a secondary structural check.

    TestTablosDashboard_ProjectCards: pre-insert one tablo for the user (use whatever helper function the file already uses for tablo insertion, or insert directly via deps.Queries.CreateTablo if available), then GET /, assert strings.Contains(body, "project-card"). If no tablo-insert helper exists yet, use a direct sqlc query call matching the CreateTablo pattern visible elsewhere in the test file.

    TestTablosDashboard_EmptyState: after login with zero tablos, GET /, assert strings.Contains(body, "ui-empty-state").

    All three functions must be inside a TEST_DATABASE_URL guard (same pattern used by the existing integration tests in the file — check how they skip when no DB is configured). Follow the package-level skip pattern exactly as seen in handlers_tablos_test.go.

    Do NOT implement: any template changes, any CSS, any handler changes. This task is test-only.
  </action>

  <verify>
    <automated>cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend && go build ./internal/web/... 2>&amp;1</automated>
  </verify>

  <acceptance_criteria>
    - handlers_tablos_test.go compiles without error: `go build ./internal/web/...` exits 0
    - File contains func TestTablosDashboard_Sidebar: `grep -c "func TestTablosDashboard_Sidebar" backend/internal/web/handlers_tablos_test.go` returns 1
    - File contains func TestTablosDashboard_ProjectCards: `grep -c "func TestTablosDashboard_ProjectCards" backend/internal/web/handlers_tablos_test.go` returns 1
    - File contains func TestTablosDashboard_EmptyState: `grep -c "func TestTablosDashboard_EmptyState" backend/internal/web/handlers_tablos_test.go` returns 1
    - Each test asserts "dashboard-sidebar", "project-card", and "ui-empty-state" respectively via strings.Contains
    - Without TEST_DATABASE_URL set, `go test ./internal/web/... -run "TestTablosDashboard_Sidebar|TestTablosDashboard_ProjectCards|TestTablosDashboard_EmptyState" -count=1` exits 0 (tests skip rather than fail)
    - The existing TestTablos* tests still pass: `go test ./internal/web/... -run TestTablos -count=1` exits 0 (skips count as pass when no DB configured)
  </acceptance_criteria>

  <done>Three test stubs exist, compile cleanly, and skip when TEST_DATABASE_URL is absent. They will turn RED when a DB is wired and AppLayout is not yet implemented — that is the expected Wave 0 state.</done>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| test harness → handler | httptest requests carry session cookies issued by the test login helper |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-15-01-01 | Information Disclosure | test DB | accept | Tests skip without TEST_DATABASE_URL; no production secrets in test code |
</threat_model>

<verification>
`cd /Users/arthur.belleville/Documents/perso/projects/xtablo-source/backend && go build ./internal/web/... && go test ./internal/web/... -run TestTablos -count=1`

All existing Tablos tests pass (skip without DB). Three new stubs compile and skip without DB.
</verification>

<success_criteria>
- handlers_tablos_test.go contains TestTablosDashboard_Sidebar, TestTablosDashboard_ProjectCards, TestTablosDashboard_EmptyState
- `go build ./internal/web/...` exits 0
- No existing tests broken
</success_criteria>

<output>
After completion, create `.planning/phases/15-dashboard-tablos/15-01-SUMMARY.md`
</output>
