---
phase: 01-foundation
plan: 04
type: execute
wave: 4
depends_on: ["01-01", "01-02", "01-03"]
files_modified:
  - backend/README.md
autonomous: false
requirements:
  - FOUND-05
tags:
  - documentation
  - onboarding

must_haves:
  truths:
    - "A new dev with Go ≥ 1.22, just, podman (or docker), and curl on their PATH can clone the repo, follow `backend/README.md`, and see the HTMX-driven root page within ~5 minutes"
    - "The README documents exactly the recipes shipped in Plan 01's justfile — no aspirational or yet-to-exist commands"
    - "The README spells out the docker compose fallback for contributors who don't use podman (D-11)"
    - "The README documents the two-terminal dev workflow (`just dev` + `just styles-watch`) per RESEARCH Open Question 2"
    - "The README documents the bootstrap order: `just bootstrap` → `just db-up` → `just migrate up` → `just dev` (in 1st terminal) + `just styles-watch` (in 2nd terminal) → open localhost:8080"
    - "D-11: podman compose chosen for local Postgres; README documents docker compose as the fallback for contributors who do not use podman"
    - "D-14: README documents the two-terminal dev workflow — just dev in terminal 1 and just styles-watch in terminal 2 — per the locked Tailwind watch decision"
  artifacts:
    - path: backend/README.md
      provides: Five-minute onboarding doc covering prereqs, bootstrap, dev workflow, common commands, troubleshooting pointers
      contains: "Quickstart"
  key_links:
    - from: backend/README.md
      to: backend/justfile (recipes)
      via: documented command names match recipe names exactly
      pattern: "just bootstrap"
    - from: backend/README.md
      to: backend/compose.yaml (podman alternative)
      via: documented docker fallback
      pattern: "docker compose"
---

<objective>
Ship the README that closes FOUND-05: a new dev can clone, follow it, and see the page in ~5 minutes. This is the final piece of the Walking Skeleton — without it, the success criterion "A new dev can clone the repo, run `compose up -d` + `just dev`, and see the page within ~5 minutes following `backend/README.md`" is unverified.

Purpose: Documentation IS the deliverable for FOUND-05. The checkpoint at the end of this plan is the manual onboarding walkthrough that closes the requirement.

Output: One file (`backend/README.md`) and a successful clean-clone walkthrough.
</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/01-foundation/01-CONTEXT.md
@.planning/phases/01-foundation/01-RESEARCH.md
@.planning/phases/01-foundation/01-VALIDATION.md
@.planning/phases/01-foundation/SKELETON.md
@.planning/phases/01-foundation/01-01-SUMMARY.md
@.planning/phases/01-foundation/01-03-SUMMARY.md
@backend/justfile
@backend/compose.yaml
@backend/.env.example
</context>

<tasks>

<task type="auto">
  <name>Task 1: Write backend/README.md — quickstart, prereqs, dev workflow, troubleshooting</name>
  <files>backend/README.md</files>
  <read_first>
    - backend/justfile (just-shipped — recipe names must match exactly)
    - backend/.env.example (env var names must match exactly)
    - backend/compose.yaml (service name + port must match)
    - .planning/phases/01-foundation/01-RESEARCH.md (Common Pitfalls section — surface the top 3 in a troubleshooting subsection)
    - .planning/phases/01-foundation/01-CONTEXT.md (D-11 — document docker fallback; deferred ideas — do NOT document /readyz or single-binary subcommands)
  </read_first>
  <action>
    Write `backend/README.md` with the following structure (use `##` headers, GitHub-flavored markdown, keep terse):

    1. **Title + one-line description.** "Xtablo backend — Go + HTMX + Postgres. Phase 1: Walking Skeleton."

    2. **Prerequisites.** Bulleted list of what must already be installed on the dev machine:
       - Go ≥ 1.22 (existing project uses 1.26)
       - `just` task runner
       - `podman` with `podman compose` (preferred per D-11) OR `docker` with `docker compose`
       - `curl`
       - Git
       Note: `goose`, `templ`, `sqlc`, `air`, the Tailwind CLI, and `htmx.min.js` are auto-installed/vendored by `just bootstrap` — do NOT list them as prereqs.

    3. **Quickstart (5-minute clone-to-page).** Numbered list of commands, in order:
       ```
       cd backend
       cp .env.example .env       # adjust DATABASE_URL if Postgres is not on localhost:5432
       just bootstrap             # installs goose/templ/sqlc/air; vendors tailwindcss + htmx.min.js
       just db-up                 # starts postgres via podman compose (or docker compose — see below)
       just migrate up            # applies migrations from ./migrations
       just dev                   # in terminal 1: builds, runs air watcher on :8080
       # in a SECOND terminal:
       just styles-watch          # rebuilds static/tailwind.css on .templ / .go change
       # open http://localhost:8080
       ```
       State explicitly: clicking "Fetch server time" should swap an ISO-8601 timestamp into the page. If you see "No time fetched yet." and nothing happens on click, see Troubleshooting.

    4. **docker compose fallback.** One paragraph: if you use docker instead of podman, replace `podman compose` with `docker compose` everywhere (the `compose.yaml` is portable). Reference `just db-up` calls `podman compose up -d postgres` — if you don't have podman, run `docker compose up -d postgres` directly instead of `just db-up`. (D-11)

    5. **Project layout.** Reproduce the directory layout from SKELETON.md (or the abbreviated form from CONTEXT D-01). Brief annotations next to each top-level dir.

    6. **Environment variables.** Table of the three keys from `.env.example`: `DATABASE_URL`, `PORT`, `ENV` — with one-line descriptions and default values. Note `.env` is gitignored; `.env.example` is committed.

    7. **Common commands.** Table mapping recipe → what it does → when to use it:
       - `just bootstrap` — install dev tools + bootstrap-downloaded assets (one-time per clone)
       - `just db-up` / `just db-down` — start/stop local Postgres
       - `just migrate up` / `migrate down` / `migrate status` — apply / revert / inspect migrations
       - `just generate` — runs `templ generate`, `sqlc generate`, Tailwind compile (one-shot)
       - `just styles-watch` — Tailwind in watch mode (run in a 2nd terminal alongside `just dev`)
       - `just dev` — Postgres up + initial generate + air live-reload on `:8080`
       - `just test` — `go test ./...` (after `templ generate`)
       - `just lint` — `go vet` + `gofmt` check
       - `just build` — compile both `bin/web` and `bin/worker`

    8. **Worker (skeleton — Phase 1 only).** Note that `cmd/worker` in Phase 1 boots, logs "worker ready", and idles on signal. Real job runtime lands in Phase 6 (D-03). To run it manually: `DATABASE_URL=... go run ./cmd/worker` (Ctrl-C to exit).

    9. **Troubleshooting.** Subsection covering the top 3 Pitfalls from RESEARCH:
       - "Fresh clone fails to build with `undefined: templates.Index`" → run `just generate` first; templ-generated files are not committed (Pitfall 1).
       - "First request to `/healthz` returns 503 right after `just db-up`" → wait ~5–10s for the container to become healthy; check `podman compose ps`. Subsequent calls succeed (Pitfall 2).
       - "Tailwind classes used in `.templ` files don't appear in the compiled CSS" → confirm `tailwind.input.css` has `@source "../templates/**/*.templ"` and re-run `just styles-watch` (Pitfall 3).

    10. **What Phase 1 ships (and doesn't).** Two short lists.
        - Ships: project scaffold, local Postgres via compose, goose migration pipeline, chi router, slog logging, RequestID middleware, graceful shutdown, /healthz, templ + HTMX demo, ui design-system package (Button/Card/Badge), live-reload dev loop.
        - Does NOT ship (deferred to listed phase): auth (Phase 2), tablos (Phase 3), tasks (Phase 4), files (Phase 5), real worker jobs (Phase 6), production deploy / Dockerfile / `/readyz` (Phase 7).

    Hard constraints:
    - Keep the file under ~300 lines. README is a quickstart, not an architecture doc.
    - Every command shown must match a recipe that actually exists in `backend/justfile` — no aspirational commands (Codex concern #6 — `generate`, `test`, `build`, `dev` are scaffolded in Plan 01-01 but become end-to-end runnable only after Plan 01-03; the README quickstart sequence is the order in which they first become useful and is correct as written).
    - Use "bootstrap-downloaded" wording (NOT "vendored") for `bin/tailwindcss` and `static/htmx.min.js` — both are reproduced by `just bootstrap` from pinned URLs in the justfile and are gitignored, not committed (Codex concern #4).
    - When discussing HTMX hosting, clarify: "HTMX is served from `/static/htmx.min.js` at runtime — no CDN. The justfile's bootstrap-time `unpkg.com` URL is the single authoritative version pin." (Codex concern #5).
    - `just clean` IS a real recipe (added in Plan 01-01 per Codex concern #10); Method B in the onboarding checkpoint references it.
    - No emoji. No marketing voice (UI-SPEC tone rules — "friendly, declarative, no marketing").
    - No screenshots in Phase 1. Plain text + code blocks only.
  </action>
  <verify>
    <automated>test -f backend/README.md && grep -q '^## Prerequisites' backend/README.md && grep -q '^## Quickstart' backend/README.md && grep -q 'just bootstrap' backend/README.md && grep -q 'just db-up' backend/README.md && grep -q 'just migrate up' backend/README.md && grep -q 'just dev' backend/README.md && grep -q 'just styles-watch' backend/README.md && grep -q 'docker compose' backend/README.md && grep -q 'DATABASE_URL' backend/README.md && grep -q 'PORT' backend/README.md && grep -q 'ENV' backend/README.md && grep -q 'Troubleshooting' backend/README.md && wc -l backend/README.md | awk '$1<=350{exit 0} {exit 1}'</automated>
  </verify>
  <acceptance_criteria>
    - README has ≥10 distinct `##` sections per the action plan
    - Every `just ...` command mentioned matches a recipe in `backend/justfile` (verifiable by cross-grep)
    - docker compose fallback is documented (D-11)
    - Two-terminal workflow (`just dev` + `just styles-watch`) is explicitly called out
    - Troubleshooting surfaces ≥3 Pitfalls from RESEARCH.md
    - Total length ≤ 350 lines
    - No emoji (`grep -P '[\x{1F300}-\x{1F9FF}]' backend/README.md` returns empty)
    - No references to features deferred to Phases 2–7 except in the explicit "What Phase 1 ships (and doesn't)" section
  </acceptance_criteria>
  <done>README exists and matches the structure above; quickstart is internally consistent with the actual justfile.</done>
</task>

<task type="checkpoint:human-verify" gate="blocking">
  <name>Task 2 (checkpoint): Clean-clone onboarding walkthrough — closes FOUND-05</name>
  <what-built>
    Task 1 wrote `backend/README.md`. This checkpoint exercises FOUND-05's success criterion 5 ("A new dev can clone the repo, run `compose up -d` + `just dev`, and see the page within ~5 minutes following `backend/README.md`") via a real walkthrough.
  </what-built>
  <files>backend/README.md (read by the developer being onboarded), fresh clone directory (Method A) or cleaned local backend/ (Method B)</files>
  <action>Human runs the onboarding walkthrough — agent cannot do this autonomously because the test is "does a human reading the README succeed?" The agent's job ends with Task 1 (writing the README); this checkpoint is the literal contract test for FOUND-05 success criterion 5.</action>
  <how-to-verify>
    Choose ONE of the two methods below:

    **Method A — Fresh checkout in a sibling directory (preferred):**
    1. `cd ..` to the parent of this repo.
    2. `git clone <this repo path> xtablo-source-onboarding-test` (or shallow clone if disk space is a concern).
    3. `cd xtablo-source-onboarding-test/backend`.
    4. Open `README.md` and follow the Quickstart numbered list LITERALLY. Do not skip steps. Do not read other docs. Start a stopwatch.
    5. Confirm `http://localhost:8080/` loads, the page renders, the "Fetch server time" button works.
    6. Note total elapsed time. Target: ≤ 5 minutes wall-clock (including `just bootstrap` downloads — which is the slowest step).
    7. Note any step in the README that was ambiguous, missing, or wrong.
    8. Stop here. Do not commit to the sibling clone. `cd ..` and `rm -rf xtablo-source-onboarding-test`.

    **Method B — In-place dry run (acceptable fallback):**
    1. From a clean working tree in `backend/`, run `just clean` (the recipe was added to the justfile in Plan 01-01 per Codex concern #10; it removes `bin/`, `tmp/`, `static/tailwind.css`, `static/htmx.min.js`, and `*_templ.go` files — leaves the Postgres volume intact, run `just db-down` separately if a DB reset is needed).
    2. Open `README.md` and follow the Quickstart literally.
    3. Same time + ambiguity checks as Method A.

    Acceptance:
    - Page renders within 5 minutes from step 1.
    - No step in the README requires guessing or out-of-band knowledge.
    - HTMX demo button works.
    - `/healthz` returns 200 with `{"status":"ok","db":"ok"}`.

    If any step fails or is ambiguous: edit README, re-run.
  </how-to-verify>
  <verify>Human follows the README from a clean state; the running page is reached within 5 minutes; HTMX demo works; /healthz returns 200.</verify>
  <done>User responds "approved" with elapsed time noted; any README edits made during the walkthrough are committed.</done>
  <resume-signal>Type "approved" (with elapsed time and any minor README tweaks made) or describe blocking issues.</resume-signal>
</task>

</tasks>

<threat_model>
## Trust Boundaries

| Boundary | Description |
|----------|-------------|
| README ↔ developer | README is the contract — wrong commands cause silent failure |

## STRIDE Threat Register

| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-01-14 | I (Information disclosure) | README example DSN | accept | The example DSN uses the dev-only `xtablo:xtablo` credentials documented in compose.yaml. README explicitly states "adjust DATABASE_URL if Postgres is not on localhost:5432" but does NOT instruct devs to commit secrets. `.env` remains gitignored. |
| T-01-15 | (process) | Onboarding ambiguity → wasted time | mitigate | Checkpoint Task 2 is the contractual test — the README must produce a working page in one pass with no out-of-band knowledge. |
</threat_model>

<verification>
- `backend/README.md` exists and passes Task 1 automated checks
- Task 2 checkpoint completes (clean-clone walkthrough succeeds, time ≤ 5 minutes)
</verification>

<success_criteria>
1. README documents every required step of the Phase 1 dev loop exactly once
2. Commands in the README match recipes in the justfile name-for-name
3. docker compose fallback documented (D-11)
4. Two-terminal workflow documented (RESEARCH Open Question 2)
5. Top 3 pitfalls from RESEARCH surfaced in a Troubleshooting section
6. A fresh clone reaches the running page in ~5 minutes following README only — closes FOUND-05 success criterion 5
</success_criteria>

<output>
After completion, create `.planning/phases/01-foundation/01-04-SUMMARY.md` documenting:
- Final README line count and section count
- Elapsed time of the clean-clone walkthrough
- Any README edits made after the walkthrough (commit references)
- Phase 1 completion status — all of FOUND-01..05 closed
</output>
