Arthur Belleville
38596ac41e
docs(02-03): complete session store + middleware plan
...
- Create 02-03-SUMMARY.md: SHA-256 token hashing, sliding TTL, HTMX-aware chi middleware
- STATE.md: advance to plan 03 complete, plan 04 (signup) next
- ROADMAP.md: Phase 2 progress 3/7 plans
- REQUIREMENTS.md: mark AUTH-02, AUTH-03, AUTH-05 complete
2026-05-14 22:11:58 +02:00
Arthur Belleville
1d07830954
feat(02-03): ResolveSession + RequireAuth + RedirectIfAuthed middleware
...
- ResolveSession: reads cookie, SHA-256 lookup, MaybeExtend best-effort, attaches Session+User to ctx
- RequireAuth: 303 /login for plain requests; HX-Redirect: /login for HTMX (D-23, Pattern 5)
- RedirectIfAuthed: bounces authed users to / from login/signup pages
- Authed(ctx): typed context accessor for session + user
- redirect helper centralizes 303 vs HX-Redirect logic (Pitfall 9: no 302)
- 9 tests: 3 real-DB (ResolveSession) + 6 pure ctx/routing (RequireAuth, RedirectIfAuthed)
2026-05-14 22:09:58 +02:00
Arthur Belleville
fd2301decf
feat(02-03): session store + cookie helpers (real-DB TDD)
...
- Store.Create: 32-byte crypto/rand token, SHA-256 hex as DB id (D-05)
- Store.Lookup: hashes cookie, maps pgx.ErrNoRows to ErrSessionNotFound (D-07)
- Store.Delete: hard-deletes session row (D-06)
- Store.Rotate: deletes old row before creating new one (D-10, T-2-04)
- Store.MaybeExtend: extends only when remaining < 7 days (D-09)
- SetSessionCookie: HttpOnly + Secure (env-gated) + SameSite=Lax (D-12)
- ClearSessionCookie: MaxAge=-1 not 0 (RESEARCH Pattern 3 / D-06)
- 10 tests: 7 real-DB (skip without TEST_DATABASE_URL) + 3 cookie unit tests
2026-05-14 22:08:04 +02:00
Arthur Belleville
648ce143a2
docs(02-02): complete argon2id password TDD plan
...
- Add 02-02-SUMMARY.md: argon2id Hash+Verify, DefaultParams (OWASP 2024), TestParams, init self-test
- Update STATE.md: plan 02 complete, plan count 7, decision logged
- Update ROADMAP.md: phase 2 now shows 2/7 plans complete
2026-05-14 22:02:25 +02:00
Arthur Belleville
ee36a5c78b
feat(02): GREEN — argon2id Hash + Verify + self-test
...
- Add Params struct with Memory/Iterations/Parallelism/SaltLength/KeyLength
- DefaultParams: OWASP 2024 baseline (m=64KiB, t=1, p=4, salt=16B, key=32B) — D-08
- TestParams: reduced cost (m=8KiB) so go test stays under 5s — D-26/Pitfall 4
- Hash(): crypto/rand salt per call, argon2.IDKey, PHC format $argon2id$v=19$...
- Verify(): PHC split/parse, ErrInvalidHash on malformed, ErrIncompatibleVersion on v!=19
- subtle.ConstantTimeCompare for timing-attack resistance (T-2-13)
- init() self-test: hash/verify round-trip panics on regression (D-08/T-2-15)
- Add golang.org/x/crypto v0.51.0 as direct dependency
2026-05-14 22:00:55 +02:00
Arthur Belleville
3bb3828cdc
test(02): RED — failing argon2id password tests
...
- Six tests: HashVerify, VerifyWrong, VerifyMalformed, VerifyVersion, DistinctSaltsPerCall, DefaultParamsShape
- Tests use auth.TestParams for fast wall time (Pitfall 4 guard)
- Guards ErrInvalidHash + ErrIncompatibleVersion sentinel errors
- All tests fail with undefined: auth.Hash / auth.TestParams / auth.Verify (implementation missing)
2026-05-14 21:59:38 +02:00
Arthur Belleville
fb9aac30ba
docs(02-01): complete auth-substrate plan
2026-05-14 21:58:23 +02:00
Arthur Belleville
2c84f4275b
feat(02-01): create internal/auth package skeleton, test DB harness, env docs
...
- auth/doc.go: package comment explaining consolidated layout (Open Question 3 resolved)
- auth/types.go: User + Session structs, SessionCookieName (D-12), SessionTTL (D-09),
SessionExtendThreshold (D-09), ErrSessionNotFound, ErrInvalidHash, ErrIncompatibleVersion
- auth/testdb_test.go: setupTestDB creates isolated per-test schema (test_<uuid>),
runs goose Up with unique version table, drops schema on cleanup (D-26)
TestSetupTestDB_Roundtrip smoke test verifies users table visible
- go.mod: added github.com/pressly/goose/v3 v3.27.1 as direct dependency
- .env.example: added TEST_DATABASE_URL and SESSION_SECRET with comments (D-14, D-26)
2026-05-14 21:56:45 +02:00
Arthur Belleville
799c26099e
feat(02-01): add sqlc queries + citext/uuid overrides; generate bindings
...
- sqlc.yaml: overrides citext→string and uuid→uuid.UUID (Pattern 10, Pitfall 3)
- users.sql: InsertUser :one and GetUserByEmail :one
- sessions.sql: InsertSession :exec, GetSessionWithUser :one (expires_at > now() per D-07),
DeleteSession :exec, DeleteSessionsByUser :exec, ExtendSession :exec
- sqlc generate produces Email string (not pgtype.Text) and uuid.UUID in bindings
- go build ./internal/db/... exits 0
2026-05-14 21:52:48 +02:00
Arthur Belleville
513044de58
feat(02-01): add 0002_auth.sql migration with users + sessions tables
...
- citext extension + pgcrypto for gen_random_uuid()
- users: id uuid PK, email citext UNIQUE, password_hash, created_at, updated_at (D-01)
- sessions: id text PK (SHA-256 hex), user_id FK ON DELETE CASCADE, created_at, expires_at (D-04)
- indexes on sessions(user_id) and sessions(expires_at)
- no deleted_at, email_verified_at, user_agent, ip_address columns (D-02, D-03, D-04)
- goose Up/Down round-trip verified against compose Postgres
2026-05-14 21:51:37 +02:00
Arthur Belleville
032e020fe3
docs(02): create phase plan (7 plans, 6 waves)
...
7 vertical-slice plans covering AUTH-01..07: schema+sqlc skeleton →
password (TDD) || session+middleware → signup → login+ratelimit →
logout+protect → CSRF. All 26 CONTEXT.md decisions cited; threat
model covers T-2-01..T-2-10.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 21:44:08 +02:00
Arthur Belleville
194072bd9a
docs(02-authentication): add CSRF integration plan (Plan 07) for AUTH-06
2026-05-14 21:36:06 +02:00
Arthur Belleville
284251083b
docs(02): add phase research
2026-05-14 21:20:13 +02:00
Arthur Belleville
0d62b9988d
docs(phase-2): add validation strategy
2026-05-14 21:19:41 +02:00
Arthur Belleville
d2af5d227b
docs(state): record phase 2 context session
2026-05-14 20:55:27 +02:00
Arthur Belleville
63672731f7
docs(02): capture phase context
2026-05-14 20:55:22 +02:00
Arthur Belleville
8d0f7a5a9c
docs(phase-01): evolve PROJECT.md after phase completion
2026-05-14 20:12:25 +02:00
Arthur Belleville
e1a1169e3e
test(01): user-approved human UAT items; close phase
2026-05-14 20:11:54 +02:00
Arthur Belleville
dd615a0195
fix(01): guard sqlc on empty queries and correct tailwind paths
2026-05-14 20:09:39 +02:00
Arthur Belleville
5eada7f480
test(01): persist human verification items as UAT
2026-05-14 19:35:41 +02:00
Arthur Belleville
d032162cc0
docs(phase-01): update tracking after wave 4
2026-05-14 19:32:14 +02:00
Arthur Belleville
5d17594356
chore: merge executor worktree (worktree-agent-a1c29b6bd03c33a2b) [plan 01-04]
2026-05-14 19:32:12 +02:00
Arthur Belleville
9149399578
docs(01-04): complete README quickstart plan
...
Adds 01-04-SUMMARY.md documenting the README onboarding doc that closes
FOUND-05 and completes Phase 1 foundation requirements.
2026-05-14 19:31:56 +02:00
Arthur Belleville
88f3706cd5
docs(01-04): add backend/README.md quickstart (closes FOUND-05)
...
- Five-minute clone-to-page onboarding doc covering prereqs, bootstrap,
two-terminal dev workflow, common commands, and troubleshooting.
- Documents docker compose fallback for contributors not on podman (D-11).
- Documents two-terminal workflow: just dev + just styles-watch (D-14).
- Every `just <recipe>` referenced is a real recipe in backend/justfile.
- Uses 'bootstrap-downloaded' wording (not 'vendored') for tailwindcss
and htmx.min.js per Codex review concern #4 .
- Clarifies HTMX runtime no-CDN policy; the unpkg URL in justfile is the
single authoritative version pin (D-10 / Codex concern #5 ).
- Top 3 pitfalls from RESEARCH surfaced in Troubleshooting.
- 195 lines, no emoji, no marketing voice.
2026-05-14 19:31:19 +02:00
Arthur Belleville
709aa5cff3
docs(phase-01): update tracking after wave 3
2026-05-14 19:28:44 +02:00
Arthur Belleville
cc204463ad
chore: merge executor worktree (worktree-agent-a69c8b0de96868f99) [plan 01-03]
2026-05-14 19:28:34 +02:00
Arthur Belleville
991af880b9
docs(01-03): summary for Walking Skeleton GREEN slice
2026-05-14 19:28:13 +02:00
Arthur Belleville
aa1e1fd415
feat(01-03): cmd/worker Phase 1 skeleton (D-03)
...
- Opens pgxpool from DATABASE_URL, logs 'worker ready', blocks on
SIGINT/SIGTERM, closes pool, exits 0
- Reuses web.NewSlogHandler — pure helper, no HTTP coupling
- No job queue libraries (river/asynq/pg_notify) — Phase 6 replaces this
file in full
- 48 lines (under 80-line budget signals 'we did not implement Phase 6
by accident')
2026-05-14 19:26:57 +02:00
Arthur Belleville
08a2c3cd96
feat(01-03): cmd/web entrypoint with graceful shutdown
...
- Reads DATABASE_URL (required), PORT (default 8080), ENV (default
development) from os.Getenv only — no third-party env loader (D-15:
.env exported by just dev, prod injects real env)
- slog.SetDefault wired before fatal-on-missing-DSN so even startup errors
emit structured output; sanitization per T-01-12 (never log DSN)
- pgxpool opened via db.NewPool; chi router mounted with ./static as the
asset root
- http.Server: ReadTimeout=15s, WriteTimeout=15s, IdleTimeout=60s
(T-01-10 slow-client mitigation)
- signal.NotifyContext (Go 1.21+) traps SIGINT/SIGTERM, propagates through
ctx; on signal: srv.Shutdown with 10s timeout, then explicit pool.Close
(Pitfall 4 — never via defer)
- No /readyz route (Phase 7 scope)
2026-05-14 19:26:22 +02:00
Arthur Belleville
3a12f8f47d
feat(01-03): templ layout/index/fragments + handlers + chi router
...
- templates/layout.templ: base HTML shell per UI-SPEC §Base Layout Contract
(max-w-5xl container, slate-50 header, slate-200 borders, footer copy,
/static/tailwind.css in <head>, /static/htmx.min.js deferred at body end —
D-10: HTMX never loaded from a CDN)
- templates/index.templ: root page consuming @ui.Card and @ui.Button for the
canonical HTMX demo (UI-SPEC §Component Library Contract canonical block)
- templates/fragments.templ: TimeFragment renders <span> with RFC3339 UTC
timestamp; templ auto-escapes interpolation (T-01-13)
- internal/web/handlers.go: HealthzHandler (200 ok / 503 degraded per D-20,
2s Ping timeout), IndexHandler, DemoTimeHandler with injected clock
- internal/web/router.go: Pinger interface; NewRouter wires
RequestIDMiddleware → RealIP → SlogLoggerMiddleware → Recoverer (D-08
+ Pitfall 6 — chi middleware.Logger deliberately NOT registered) and
routes /, /healthz, /demo/time, /static/* via http.FileServer (T-01-08
path traversal blocked by http.Dir)
All six handler tests + ui package tests are GREEN under default go test.
2026-05-14 19:25:43 +02:00
Arthur Belleville
36e96015f5
feat(01-03): pgxpool wrapper, RequestID/slog middleware, slog handler switch
...
- Remove //go:build red_gate tag from internal/web/handlers_test.go and
internal/db/pool_test.go now that consumer symbols are about to exist
- go mod tidy after real importers land (deferred from Plan 01-01 per
Codex concern #1 ) — chi/v5, templ, pgx/v5, google/uuid now in require list
- internal/db/pool.go: NewPool(ctx, dsn) builds a pgxpool.Pool with
MaxConns=10, MinConns=1; no eager Ping (RESEARCH Pitfall 2)
- internal/web/slog.go: NewSlogHandler returns JSON when env='production',
text otherwise; pure helper, no slog.SetDefault side effect
- internal/web/middleware.go: RequestIDMiddleware (UUIDv4 → ctx +
X-Request-ID header), LoggerFromContext helper, SlogLoggerMiddleware
factory using chi WrapResponseWriter; field allowlist per V7/T-01-09
2026-05-14 19:24:16 +02:00
Arthur Belleville
9c829f9783
docs(phase-01): update tracking after wave 2
2026-05-14 18:57:31 +02:00
Arthur Belleville
f2212676c5
1password
2026-05-14 18:55:51 +02:00
Arthur Belleville
3b2efbb8f7
chore: merge executor worktree (worktree-agent-afdaf4b9e5211a350) [plan 01-02]
2026-05-14 18:53:24 +02:00
Arthur Belleville
798271cc77
docs(01-02): summary for ui foundation + RED gate plan
2026-05-14 18:49:22 +02:00
Arthur Belleville
37d19a3314
test(01-02): add red-gated handler and pool tests
...
- handlers_test.go (//go:build red_gate): TestHealthz_OK, TestHealthz_Down,
TestIndex_RendersHxGet, TestDemoTime_Fragment, TestRequestID_HeaderSet,
TestSlog_HandlerSwitch — reference web.HealthzHandler / NewRouter /
NewSlogHandler / Pinger to be implemented in Plan 01-03
- pool_test.go (//go:build red_gate): TestPool_Connects with t.Skip
fallback when DATABASE_URL is unset
- Build tag isolates the RED state from default 'go test ./...' (Codex #3 )
2026-05-14 18:48:26 +02:00
Arthur Belleville
75cbd29d44
test(01-02): add ui package smoke tests
...
- TestButton_DefaultSolidMD: asserts root class and label
- TestButton_PassesThroughAttrs: asserts hx-* attribute spread
- TestButton_ExplicitTypeSubmit: type override
- TestCard_RendersChildren: templ.WithChildren child injection
- TestBadge_{Info,Success}Variant + zero-value normalization
- TestButtonClass_String / TestBadgeClass_String: class contract
- TestNormalizers_ZeroValueDefaults: every Normalized* returns safe default
2026-05-14 18:47:31 +02:00
Arthur Belleville
d056b33241
feat(01-02): add Button, Card, Badge templ components + CSS
...
- button.templ: Button(ButtonProps) renders <button type=...> with class
from ui.ButtonClass(); Attrs spread for hx-* pass-through
- button.css: .ui-button base + .ui-button-solid-default-md variant
with non-nested :hover and :focus-visible (Codex concern #7 )
- card.templ: Card(attrs) accepts children via templ child syntax
- card.css: slate-50 panel, slate-200 border
- badge.templ: Badge(BadgeProps) renders <span class=...>
- badge.css: info / success / danger variants (warning deferred)
2026-05-14 18:46:42 +02:00
Arthur Belleville
1ff8e681da
feat(01-02): add ui package enums, helpers, base CSS
...
- tokens.go: semantic token constants
- variants.go: Size/ButtonVariant/ButtonTone/BadgeVariant enums + Normalized*
- helpers.go: mergeAttrs for templ.Attributes
- base.css: resets, :focus-visible ring (no nesting)
2026-05-14 18:45:15 +02:00
Arthur Belleville
5b19a8815c
docs(phase-01): update tracking after wave 1
2026-05-14 17:58:25 +02:00
Arthur Belleville
a639fdf502
chore: merge executor worktree (worktree-agent-a98c01ef03e47adfc) [plan 01-01]
2026-05-14 17:57:38 +02:00
Arthur Belleville
586b683131
docs(01-01): complete backend scaffold plan summary
...
- Documents 5 task commits (aa90008 , 4de9685 , 2fe5b51 , d6085b7 , ce22472 )
- Records pinned versions actually wired
- Confirms Codex review concerns 1, 2, 3, 4, 6, 10 are addressed
- Logs auto-approved human-verify checkpoint (Task 6 — real bootstrap requires developer-side network)
- Path forward to Plans 01-02 (handler tests + ui/*.css) and 01-03 (cmd/* entrypoints + walking skeleton)
2026-05-14 17:57:09 +02:00
Arthur Belleville
ce224725e2
feat(01-01): justfile with bootstrap, db, migrate, generate, dev, test, lint, build, clean
...
- bootstrap: installs goose/templ/sqlc/air at pinned versions; downloads Tailwind v4 standalone
binary via explicit OS/arch case mapping (darwin->macos, x86_64->x64, arm64/aarch64->arm64)
resolving to one of {tailwindcss-macos-x64,tailwindcss-macos-arm64,tailwindcss-linux-x64,tailwindcss-linux-arm64}
(Codex concern #2 ); bootstrap-downloads htmx.min.js from unpkg into static/
- migrate: GOOSE_DRIVER + GOOSE_DBSTRING + GOOSE_MIGRATION_DIR wired
- generate / styles-watch / dev / test / lint / build / clean recipes complete
- 'just --list' enumerates 11 recipes; no pnpm/npm/node references (D-12)
- clean recipe removes bin/, tmp/, generated CSS, bootstrap-downloaded htmx, *_templ.go (Codex #10 )
- Tailwind watch is run separately (RESEARCH Open Q2 two-terminal workflow)
- The only CDN URLs in the entire backend are inside this justfile's bootstrap recipe;
served HTML/CSS/JS reference only /static/* (CONTEXT D-10 clarified)
2026-05-14 17:56:02 +02:00
Arthur Belleville
d6085b7dbb
feat(01-01): sqlc config, tailwind input CSS, air live-reload config
...
- sqlc.yaml: postgresql engine, schema points at migrations/ (Pitfall 7), pgx/v5 sql_package
- tailwind.input.css: @source globs for templ + internal/web Go files (Pitfall 3), @imports four ui/*.css files per UI-SPEC
- .air.toml: watches .go + .templ, excludes generated *_templ.go (Pitfall 5), runs 'templ generate' pre-build
- Tailwind watch is NOT wired into air pre_cmd (two-terminal workflow per RESEARCH Open Q2)
2026-05-14 17:54:35 +02:00
Arthur Belleville
2fe5b51f80
feat(01-01): compose file, env example, gitignore, bootstrap migration
...
- compose.yaml: postgres:16-alpine with pg_isready healthcheck (no seed mounts)
- .env.example: DATABASE_URL, PORT, ENV (D-15)
- .gitignore: bin/, tmp/, .env, generated tailwind.css, bootstrap-downloaded htmx.min.js, *_templ.go, sqlc output
- migrations/0001_init.sql: goose no-op bootstrap migration
2026-05-14 17:54:18 +02:00
Arthur Belleville
4de96854b5
feat(01-01): create directory skeleton and per-package doc.go placeholders
...
- internal/{db,session,tablos,tasks,files}/doc.go (D-02 placeholder packages)
- internal/db/{queries,sqlc}, templates/, migrations/, bin/, static/ via .gitkeep
- 'go build ./internal/...' compiles cleanly
- cmd/web, cmd/worker, internal/web are deliberately deferred to Plans 01-02 / 01-03
2026-05-14 17:53:55 +02:00
Arthur Belleville
aa90008d95
feat(01-01): initialize Go module and pin runtime dependencies
...
- module: backend (go 1.26.1)
- chi v5.2.5, templ v0.3.1020, pgx/v5 v5.9.2, goose v3.27.1, uuid v1.6.0
- pinned via 'go get'; 'go mod tidy' deferred to Plan 01-03 where consumers exist (Codex concern #1 )
2026-05-14 17:53:36 +02:00
Arthur Belleville
c95a64e78e
docs(01): replan with cross-AI review feedback (codex)
2026-05-14 17:50:48 +02:00
Arthur Belleville
a54a10a7fd
docs(01): cross-AI review for phase 1 (codex)
2026-05-14 17:23:11 +02:00
Arthur Belleville
ad3a3d42ef
docs(01): create phase plan (4 plans, MVP walking skeleton)
2026-05-14 17:19:04 +02:00