# Phase 1: Foundation - Context

**Gathered:** 2026-05-14
**Status:** Ready for planning

<domain>
## Phase Boundary

A fresh `backend/` Go package boots a web server, renders an HTMX-driven base layout styled with Tailwind, and connects to a local Postgres with migrations applied. A new dev can clone the repo, run `compose up -d` + `just dev`, and see the page within ~5 minutes following `backend/README.md`.

Delivers FOUND-01..05. **Not** in scope: auth, tablos, tasks, files, worker job processing (worker binary scaffold only — no real jobs yet; jobs land in Phase 6), deployment (Phase 7).

</domain>

<decisions>
## Implementation Decisions

### Directory Layout
- **D-01:** Two-binary layout with shared `internal/`. Final shape:
  ```
  backend/
    cmd/
      web/main.go
      worker/main.go
    internal/
      db/        (sqlc-generated queries + pgx pool wiring)
      web/       (chi router, handlers, middleware)
      session/   (placeholder package — populated in Phase 2)
      tablos/    (placeholder — Phase 3)
      tasks/     (placeholder — Phase 4)
      files/     (placeholder — Phase 5)
    migrations/  (goose .sql files)
    templates/   (.templ files)
    static/      (tailwind.css output, htmx.min.js)
    compose.yaml
    justfile
    .env.example
    README.md
  ```
- **D-02:** Phase 1 creates the directory skeleton for all `internal/<domain>` packages (empty `doc.go` is fine) so later phases drop files in without restructuring.
- **D-03:** `cmd/worker` in Phase 1 is a minimal binary that boots, connects to Postgres, logs "worker ready", and exits cleanly on signal. Real job runtime is Phase 6.

### Migrations
- **D-04:** Use **goose** (`pressly/goose`). Reasons: embeddable as a library (can be called from `cmd/web` startup or a small subcommand so we ship migrations inside the Docker image in Phase 7 without a second binary), supports Go-based migrations if ever needed, one `.sql` file per migration with `-- +goose Up/Down` annotations (sqlc reads the same files).
- **D-05:** `just migrate up` / `just migrate down` / `just migrate status` wired via the goose CLI for local dev. Production migration strategy (embed vs CLI) decided in Phase 7.
- **D-06:** Phase 1 includes one trivial bootstrap migration (e.g., `0001_init.sql` creating an empty `schema_migrations` baseline or a no-op) so the migration pipeline is exercised end-to-end.

### Templating + Router
- **D-07:** **templ** (`a-h/templ`) for HTML. Type-safe, compiled, plays well with HTMX partials (each fragment is a typed func returning `templ.Component`).
- **D-08:** **chi** (`go-chi/chi/v5`) as the HTTP router. Middleware stack: `RequestID → RealIP → Logger (structured) → Recoverer → GracefulShutdown wiring`.
- **D-09:** `templ generate` runs via `just generate` (alongside `sqlc generate`). Dev loop uses `templ generate --watch` or air's reload hook — pick during planning, both acceptable.
- **D-10:** Base layout template renders a Tailwind-styled page with HTMX loaded from `/static/htmx.min.js` (vendored, not CDN). Include one working `hx-get` example to satisfy success criterion 3.

### Local Dev Stack
- **D-11:** **podman compose** for local Postgres (matches the developer's machine setup; `compose.yaml` at `backend/compose.yaml`). Document `podman compose` commands in the justfile; if a contributor uses docker, the same `compose.yaml` works — call this out in the README.
- **D-12:** **Standalone Tailwind CLI binary** (no Node/pnpm in `backend/`). Binary is downloaded by a `just bootstrap` recipe into `./bin/tailwindcss` (gitignored) — version pinned in the justfile. Keeps the "no JS toolchain" thesis intact.
- **D-13:** **air** (`cosmtrek/air`) for Go live-reload (`just dev`). Watches `.go` + `.templ` files; triggers `templ generate` and rebuild.
- **D-14:** Tailwind in watch mode runs as a separate process (`just styles`) or via air's `pre_cmd`. Planner decides which is cleaner.

### Configuration & Operational Basics
- **D-15:** Env-driven config via `.env` (loaded from `.env` at dev startup; production injects real env vars). Required keys at minimum: `DATABASE_URL`, `PORT`, `ENV`. Provide `.env.example` in the repo.
- **D-16:** Postgres driver: **pgx/v5** with `pgxpool` for the connection pool. sqlc configured to emit pgx-compatible code (`sqlc.yaml` engine: postgresql, sql_package: pgx/v5).
- **D-17:** Structured logging: `log/slog` (std lib, Go 1.21+) with JSON handler in prod and text handler in dev, switched by `ENV`.
- **D-18:** Request ID middleware attaches a UUID per request and threads it into the slog logger via `context.Context`.
- **D-19:** Graceful shutdown: `cmd/web` traps SIGINT/SIGTERM, calls `http.Server.Shutdown` with a configurable timeout (default 10s), then closes the pgx pool.
- **D-20:** `/healthz` returns 200 with `{"status":"ok","db":"ok"}` only when `db.Ping` succeeds; otherwise 503 with `{"status":"degraded","db":"down"}`.

### Claude's Discretion
- Concrete chi middleware order (within the above stack) and slog handler configuration details.
- Exact `air.toml` settings, file watch globs, and whether tailwind runs as a separate `just styles` process or air `pre_cmd`.
- Whether goose runs migrations via library call from a `backend migrate` subcommand or pure CLI in Phase 1 (Phase 7 will likely require the library approach; planner can prepare for that).
- Layout/CSS specifics of the demo page — keep minimal but professional; one visible `hx-get` interaction is enough.
- Whether to include a basic `internal/web/handlers_test.go` smoke test now or defer to Phase 2.

</decisions>

<canonical_refs>
## Canonical References

**Downstream agents MUST read these before planning or implementing.**

### Project & Scope
- `.planning/PROJECT.md` — Core value, constraints, out-of-scope list, key decisions (fresh `backend/`, single VPS, no Node toolchain target).
- `.planning/REQUIREMENTS.md` §Foundation — FOUND-01..05 verbatim.
- `.planning/ROADMAP.md` §"Phase 1: Foundation" — Success criteria + user-in-loop callouts.

### Codebase Maps (legacy JS app — behavioral reference only)
- `.planning/codebase/STACK.md` — Existing stack inventory (used to identify what we are *replacing*, not copying).
- `.planning/codebase/CONVENTIONS.md` — Existing conventions (most do not apply to the new Go backend, but useful for parity decisions).
- `.planning/codebase/CONCERNS.md` — Known pain points in the JS version that motivated the rewrite.

### Existing Go scaffold (reference, not foundation)
- `go-backend/` — Scratch scaffold. **Not** the foundation per PROJECT.md. Useful as a sanity check for templ/chi/sqlc/pgx wiring patterns and for the `compose.yaml` + `justfile` shape, but the new `backend/` is built fresh.
- `go-backend/justfile` — Reference for podman compose + tailwind + templ + sqlc justfile layout.
- `go-backend/sqlc.yaml` — Reference for sqlc config shape.

### External tool docs (planner will pull versions during research)
- goose: https://github.com/pressly/goose
- templ: https://templ.guide
- chi: https://github.com/go-chi/chi
- pgx: https://github.com/jackc/pgx
- air: https://github.com/cosmtrek/air
- Tailwind standalone CLI: https://tailwindcss.com/blog/standalone-cli

</canonical_refs>

<code_context>
## Existing Code Insights

### Reusable Assets (reference, copy-with-care)
- `go-backend/justfile`: pattern for podman compose + tailwind + templ + sqlc recipes — adapt, do not copy wholesale (it uses pnpm tailwind, which we are dropping).
- `go-backend/compose.yaml` (postgres service): can be lifted to `backend/compose.yaml` essentially as-is.
- `go-backend/sqlc.yaml`: config shape is a good starting point for `backend/sqlc.yaml`.

### Established Patterns (from go-backend, validating our choices)
- templ + chi + pgx + sqlc is a known-working combination in this developer's hands (go-backend has all four wired).
- podman compose is the developer's local container runtime — confirmed working.

### Integration Points
- `backend/` is greenfield — no integration points yet. Future phases attach: Phase 2 adds session middleware to the chi stack and `users`/`sessions` tables via goose migrations.

### What we are deliberately NOT carrying over
- `go-backend/`'s pnpm + tailwindcss npm dependency (replaced by standalone binary).
- Any sqlc-generated code in `go-backend/internal/db/` (greenfield schema; will be regenerated against the new migrations).

</code_context>

<specifics>
## Specific Ideas

- Developer explicitly chose **goose over golang-migrate** after weighing embeddability, sqlc-file-layout, and the (small) chance of needing Go-side migrations.
- Developer explicitly chose **two-cmd layout (`cmd/web` + `cmd/worker`)** over single-binary-with-subcommand. Implication: deploy ships two binaries (or two entrypoints from one image — revisit in Phase 7).
- Developer explicitly chose **podman compose + standalone Tailwind binary** — no Node toolchain in `backend/`. This is a load-bearing decision for the "simpler stack" thesis.
- One visible `hx-get` example on the root page is required (success criterion 3). Keep it minimal — a button that swaps in a server-rendered timestamp or counter is enough.

</specifics>

<deferred>
## Deferred Ideas

- **Single-binary subcommand layout** (`backend web` / `backend worker`) — rejected for Phase 1; could be revisited in Phase 7 if the two-binary Docker image proves awkward.
- **Embedded goose migrations called from app startup** — Phase 1 uses CLI-only; embedded library call deferred to Phase 7 deploy decision.
- **`internal/web/handlers_test.go` smoke tests** — testing strategy is established in Phase 2 (auth requires real tests). Phase 1 may include a minimal `/healthz` test only.
- **Production logging configuration** (sampling, redaction, log shipping) — Phase 7 concern.
- **`/readyz` endpoint** — listed in Phase 7 success criteria (DEPLOY-04); Phase 1 ships `/healthz` only.

</deferred>

---

*Phase: 1-Foundation*
*Context gathered: 2026-05-14*
