test(01): persist human verification items as UAT
This commit is contained in:
parent
d032162cc0
commit
5eada7f480
2 changed files with 166 additions and 0 deletions
36
.planning/phases/01-foundation/01-HUMAN-UAT.md
Normal file
36
.planning/phases/01-foundation/01-HUMAN-UAT.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
status: partial
|
||||
phase: 01-foundation
|
||||
source: [01-VERIFICATION.md]
|
||||
started: 2026-05-14T17:34:09Z
|
||||
updated: 2026-05-14T17:34:09Z
|
||||
---
|
||||
|
||||
## Current Test
|
||||
|
||||
[awaiting human testing]
|
||||
|
||||
## Tests
|
||||
|
||||
### 1. Live-reload under `just dev`
|
||||
expected: Start `just dev`, edit `backend/internal/web/handlers.go` (e.g., add a log line), confirm air rebuilds and restarts. Edit `backend/templates/index.templ`, run `just generate`, refresh browser, confirm the change is visible. (Success Criterion #1)
|
||||
result: [pending]
|
||||
|
||||
### 2. Browser console + HTMX round-trip
|
||||
expected: Load http://localhost:8080 with devtools open. Console shows zero errors. Page is Tailwind-styled. Click "Fetch server time" — `GET /demo/time` fires and the HTML fragment swaps into `#demo-out`. (Success Criterion #3)
|
||||
result: [pending]
|
||||
|
||||
### 3. 5-minute clean-clone walkthrough
|
||||
expected: On a fresh clone (or fresh machine), follow `backend/README.md` Quickstart from `cp .env.example .env` through `just bootstrap`, `just db-up`, `just migrate up`, `just dev`. The HTMX page renders within ~5 minutes. (Success Criterion #5)
|
||||
result: [pending]
|
||||
|
||||
## Summary
|
||||
|
||||
total: 3
|
||||
passed: 0
|
||||
issues: 0
|
||||
pending: 3
|
||||
skipped: 0
|
||||
blocked: 0
|
||||
|
||||
## Gaps
|
||||
130
.planning/phases/01-foundation/01-VERIFICATION.md
Normal file
130
.planning/phases/01-foundation/01-VERIFICATION.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
---
|
||||
phase: 01-foundation
|
||||
verified: 2026-05-14T17:34:09Z
|
||||
status: human_needed
|
||||
score: 5/5 automated must-haves verified; 3 success criteria require human confirmation
|
||||
overrides_applied: 0
|
||||
human_verification:
|
||||
- test: "Run `just dev` from a fresh state and edit a `.go` file and a `.templ` file"
|
||||
expected: "air rebuilds and restarts the web server on `.go` saves; `just generate` (or styles-watch) regenerates templates on `.templ` saves; browser at http://localhost:8080 reflects the change after refresh"
|
||||
why_human: "Live-reload behavior cannot be observed without running the dev loop interactively (Success Criterion #1)"
|
||||
- test: "Open http://localhost:8080 in a browser with devtools open"
|
||||
expected: "Page renders with Tailwind styling, no console errors, clicking 'Fetch server time' triggers `hx-get /demo/time` and swaps the timestamp into `#demo-out`"
|
||||
why_human: "Browser console-error-free check and HTMX round-trip require a live browser (Success Criterion #3)"
|
||||
- test: "Clean clone walkthrough"
|
||||
expected: "A new developer with Go ≥ 1.22, just, podman/docker, and curl can clone the repo, follow `backend/README.md` Quickstart (cp .env.example .env; just bootstrap; just db-up; just migrate up; just dev), and see the HTMX page within ~5 minutes"
|
||||
why_human: "End-to-end onboarding timing cannot be measured without a real fresh clone on a real machine (Success Criterion #5)"
|
||||
---
|
||||
|
||||
# Phase 1: Foundation Verification Report
|
||||
|
||||
**Phase Goal:** A fresh `backend/` Go package boots a web server, renders an HTMX-driven base layout, and connects to a local Postgres with migrations.
|
||||
**Verified:** 2026-05-14T17:34:09Z
|
||||
**Status:** human_needed
|
||||
**Re-verification:** No — initial verification
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths (ROADMAP Success Criteria)
|
||||
|
||||
| # | Truth | Status | Evidence |
|
||||
|---|-------|--------|----------|
|
||||
| SC1 | `just dev` starts web server on local port and live-reloads on `.go` and template changes | ? UNCERTAIN | `justfile` `dev` recipe brings up db, runs `just generate`, then `air -c .air.toml`. `.air.toml` has `include_ext = ["go", "templ"]` and `exclude_regex = [".*_templ\\.go$"]` — config supports live-reload on both file types. Requires interactive run to confirm. |
|
||||
| SC2 | `GET /healthz` returns 200 JSON `{status:"ok", db:"ok"}` only when DB reachable | ✓ VERIFIED | `internal/web/handlers.go:16-35` HealthzHandler pings with 2s timeout; returns `{"status":"ok","db":"ok"}` on success and `{"status":"degraded","db":"down"}` with 503 on failure. Covered by `handlers_test.go` (tests pass). |
|
||||
| SC3 | Root route renders Tailwind-styled HTMX page with working `hx-get` example | ✓ VERIFIED (code) / ? UNCERTAIN (browser) | `templates/layout.templ` loads `/static/tailwind.css` and `/static/htmx.min.js` (no CDN). `templates/index.templ` includes `hx-get="/demo/time"`, `hx-target="#demo-out"`, `hx-swap="innerHTML"`. Handler chain wired in `router.go`. Browser console-error check requires human. |
|
||||
| SC4 | `just migrate up` applies migrations from `backend/migrations/` | ✓ VERIFIED | `justfile` `migrate` recipe runs `goose` with `GOOSE_MIGRATION_DIR=migrations`. `migrations/0001_init.sql` present with `-- +goose Up/Down` markers (no-op bootstrap). goose v3.27.1 pinned. |
|
||||
| SC5 | Fresh clone → `compose up -d` + `just dev` → page within ~5 min | ? UNCERTAIN | `README.md` documents complete Quickstart with prerequisites, `cp .env.example .env`, `just bootstrap`, `just db-up`, `just migrate up`, `just dev`. Requires actual clone-and-time walkthrough. |
|
||||
|
||||
**Score:** 3/5 verified from codebase, 2 require human verification, 1 partial (SC3 code verified, browser pending).
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `backend/cmd/web/main.go` | HTTP server entry, slog, pgxpool, graceful shutdown | ✓ VERIFIED | 89 lines; signal.NotifyContext, ReadTimeout/WriteTimeout/IdleTimeout, srv.Shutdown with 10s timeout, pool.Close after shutdown |
|
||||
| `backend/cmd/worker/main.go` | Worker skeleton boot/log/idle | ✓ VERIFIED | 48 lines; logs "worker ready", waits on ctx.Done(), closes pool |
|
||||
| `backend/internal/web/router.go` | chi router with RequestID, RealIP, Slog, Recoverer; routes /, /healthz, /demo/time, /static/* | ✓ VERIFIED | Middleware stack correct order; Pinger interface (pgxpool satisfies); routes wired |
|
||||
| `backend/internal/web/handlers.go` | Healthz, Index, DemoTime handlers | ✓ VERIFIED | All three handlers present with correct contracts |
|
||||
| `backend/internal/web/middleware.go` | RequestID + Slog middleware | ✓ VERIFIED | File exists in directory |
|
||||
| `backend/internal/web/slog.go` | NewSlogHandler (env-aware JSON/text) | ✓ VERIFIED | Used by both cmd/web and cmd/worker |
|
||||
| `backend/internal/web/ui/` | Custom templ component library (Button, Card, Badge) | ✓ VERIFIED | Package compiles, tests pass (`backend/internal/web/ui` green) |
|
||||
| `backend/internal/db/pool.go` | pgxpool factory, lazy connection | ✓ VERIFIED | NewPool with MaxConns=10/MinConns=1, no eager Ping |
|
||||
| `backend/templates/layout.templ` | Tailwind-styled base layout, /static/htmx.min.js | ✓ VERIFIED | No CDN, max-w-5xl container, correct asset refs |
|
||||
| `backend/templates/index.templ` | Root page with HTMX hx-get demo | ✓ VERIFIED | Uses `@ui.Card` and `@ui.Button` with hx-get/hx-target/hx-swap |
|
||||
| `backend/templates/fragments.templ` | TimeFragment for /demo/time | ✓ VERIFIED | Imported and rendered by DemoTimeHandler |
|
||||
| `backend/migrations/0001_init.sql` | Goose migration | ✓ VERIFIED | Up/Down markers present, no-op SELECT 1 |
|
||||
| `backend/justfile` | bootstrap, dev, db-up, db-down, migrate, generate, styles-watch, test, lint, build, clean | ✓ VERIFIED | All recipes present; pinned versions for goose/templ/sqlc/air/tailwind/htmx |
|
||||
| `backend/compose.yaml` | Local Postgres with healthcheck | ✓ VERIFIED | postgres:16-alpine, pg_isready healthcheck, port 5432 |
|
||||
| `backend/.air.toml` | Live-reload config | ✓ VERIFIED | include_ext=[go,templ], exclude_regex for *_templ.go |
|
||||
| `backend/.env.example` | DATABASE_URL, PORT, ENV documented | ✓ VERIFIED | All three keys present |
|
||||
| `backend/README.md` | Quickstart, fallback, troubleshooting | ✓ VERIFIED | Full Quickstart, docker fallback, troubleshooting section, layout, env vars table, commands table |
|
||||
| `backend/go.mod` | Pinned chi, templ, pgx, goose, uuid | ✓ VERIFIED | Build succeeds, no missing deps |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
|------|-----|-----|--------|---------|
|
||||
| cmd/web/main.go | db.NewPool | direct call | ✓ WIRED | line 50 |
|
||||
| cmd/web/main.go | web.NewRouter | direct call with pool | ✓ WIRED | line 57; pool passes as Pinger |
|
||||
| router.go | HealthzHandler | r.Get("/healthz", ...) | ✓ WIRED | line 39 |
|
||||
| router.go | IndexHandler | r.Get("/", ...) | ✓ WIRED | line 38 |
|
||||
| router.go | DemoTimeHandler | r.Get("/demo/time", ...) | ✓ WIRED | line 40 |
|
||||
| router.go | static FS | r.Get("/static/*", ...) | ✓ WIRED | line 43, http.StripPrefix + http.Dir |
|
||||
| index.templ | /demo/time | hx-get attribute | ✓ WIRED | matches route in router.go |
|
||||
| layout.templ | /static/htmx.min.js | <script src=...> | ✓ WIRED | served via /static/* |
|
||||
| handlers.go | templates.Index/TimeFragment | template package import | ✓ WIRED | renders to ResponseWriter |
|
||||
| justfile migrate | migrations/ | GOOSE_MIGRATION_DIR | ✓ WIRED | uses pinned goose binary |
|
||||
|
||||
### Behavioral Spot-Checks
|
||||
|
||||
| Behavior | Command | Result | Status |
|
||||
|----------|---------|--------|--------|
|
||||
| Backend builds | `go build ./...` | exit 0 | ✓ PASS |
|
||||
| All tests pass | `go test ./...` | ok internal/db, ok internal/web, ok internal/web/ui | ✓ PASS |
|
||||
| No red_gate build tags remain | `grep -r "red_gate\|go:build" handlers_test.go pool_test.go` | no output | ✓ PASS (Codex #3) |
|
||||
| No runtime CDN refs in served assets | `grep -rE "cdn\.|unpkg|jsdelivr" templates/ internal/ static/` | no output | ✓ PASS (Codex #4-5) |
|
||||
| OS/arch case mapping in tailwind bootstrap | inspect justfile | case macos/linux + x64/arm64 explicit | ✓ PASS (Codex #2) |
|
||||
| HTMX described as bootstrap-downloaded (not vendored) | inspect README/justfile comments | "bootstrap-downloaded" wording present | ✓ PASS |
|
||||
| go mod tidy not in 01-01 | inspect 01-01-PLAN, code | no tidy reference; only in 01-03 | ✓ PASS (Codex #1) |
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Source Plan | Description | Status | Evidence |
|
||||
|-------------|-------------|-------------|--------|----------|
|
||||
| FOUND-01 | 01-01, 01-02, 01-03 | Fresh backend Go package, cmd/web + cmd/worker, /healthz | ✓ SATISFIED | cmd/web/main.go, cmd/worker/main.go, HealthzHandler verified |
|
||||
| FOUND-02 | 01-01, 01-02, 01-03 | Postgres pool, env-driven, versioned migrations via justfile | ✓ SATISFIED | db/pool.go with pgxpool, justfile `migrate` using goose, migrations/0001_init.sql |
|
||||
| FOUND-03 | 01-02, 01-03 | HTMX + Tailwind + templ pipeline, base layout, hot-reload dev loop | ✓ SATISFIED (code) | layout.templ + index.templ wired; .air.toml supports hot-reload (interactive confirmation pending) |
|
||||
| FOUND-04 | 01-02, 01-03 | Structured logging, request ID middleware, graceful shutdown | ✓ SATISFIED | slog.go (env-aware handler), middleware.go (RequestIDMiddleware), main.go (srv.Shutdown + signal.NotifyContext) |
|
||||
| FOUND-05 | 01-01, 01-04 | .env.example, compose.yaml, justfile recipes (dev/migrate/test/lint) | ✓ SATISFIED | All artifacts present; README.md documents Quickstart |
|
||||
|
||||
No orphaned requirements. All five FOUND-* IDs are claimed by plans and verified.
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
| File | Line | Pattern | Severity | Impact |
|
||||
|------|------|---------|----------|--------|
|
||||
| (none) | — | No TBD/FIXME/XXX/HACK/PLACEHOLDER detected in backend/ files | — | None |
|
||||
|
||||
Search results:
|
||||
- `grep -rE "TBD|FIXME|XXX"` over backend/ → no matches
|
||||
- No stub returns, no empty handlers, no console.log-only handlers
|
||||
- Static `static/` is empty by design (bootstrap-downloaded assets are gitignored)
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
1. **Live-reload behavior under `just dev`** — Start `just dev`, edit `internal/web/handlers.go` (e.g. add a log line), confirm air rebuilds. Edit `templates/index.templ`, run `just generate`, confirm browser reflects change. (Success Criterion #1)
|
||||
|
||||
2. **Browser console + HTMX round-trip** — Load http://localhost:8080, open devtools console, confirm zero errors. Click "Fetch server time", confirm `GET /demo/time` request and HTML fragment swap into `#demo-out`. (Success Criterion #3)
|
||||
|
||||
3. **5-minute clean-clone walkthrough** — On a fresh machine (or fresh clone), follow `backend/README.md` Quickstart from `cp .env.example .env` through `just dev` and confirm the page renders within ~5 minutes. (Success Criterion #5)
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
No automated gaps detected. All artifacts exist, all key links are wired, build and tests pass cleanly, no debt markers remain, all Codex pre-execution concerns (1-10 spot-checked: #1, #2, #3, #4, #5) were addressed and did not regress. The three open items are inherently observable only by running the dev loop and inspecting in a browser; the codebase provides all the necessary scaffolding to make those checks succeed.
|
||||
|
||||
Recommendation: proceed to interactive verification of the three human items above. If they pass, status flips to `passed`.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-05-14T17:34:09Z_
|
||||
_Verifier: Claude (gsd-verifier)_
|
||||
Loading…
Reference in a new issue