Commit graph

7 commits

Author SHA1 Message Date
Arthur Belleville
181ae79369
feat(04-02): TasksDeps, task handlers, router task routes
- Add handlers_tasks.go: TasksDeps, TaskNewFormHandler, TaskCancelNewHandler, TaskCreateHandler, TaskShowHandler, TaskDeleteConfirmHandler, TaskDeleteHandler, plus stub Edit/Update/Reorder handlers
- Add task routes to router.go (static before parametric per Pitfall 1)
- Add TasksDeps param to NewRouter; update main.go and all test callers
- Move TaskColumns/TaskColumnLabels to templates package to avoid import cycle
2026-05-15 09:31:59 +02:00
Arthur Belleville
c8f44b1ad2
test(03-01): add TablosDeps stub and RED integration test scaffold for TABLO-01..06
- handlers_tablos.go: TablosDeps stub type enabling test compilation
- handlers_tablos_test.go: 10 integration tests (RED baseline) for all TABLO-01..06 paths
  - TestTabloList, TestTabloList_Empty, TestTabloCreate, TestTabloCreate_Validation
  - TestTabloDetail_Owner, TestTabloDetail_NonOwner, TestTabloDetail_InvalidID
  - TestTabloUpdate, TestTabloDeleteConfirm, TestTabloDelete
- router.go: NewRouter accepts TablosDeps as second deps parameter
- handlers_auth_test.go, handlers_test.go, csrf_test.go: update NewRouter call sites
- cmd/web/main.go: construct and pass TablosDeps to NewRouter
2026-05-15 00:13:31 +02:00
Arthur Belleville
389e1bc8b4
feat(02-07): gorilla/csrf integration — mount middleware, wire all forms, env-driven key
- auth.Mount(env, key) wraps csrf.Protect with locked D-14/D-24 options
- auth.LoadKeyFromEnv() reads SESSION_SECRET, hex-decodes, validates 32 bytes; fails fast on error
- ui.CSRFField(token) templ component renders hidden _csrf input
- Layout, LoginPage/Fragment, SignupPage/Fragment, Index all embed @ui.CSRFField(csrfToken)
- Handlers thread csrf.Token(r) into every page/fragment render call
- NewRouter mounts auth.Mount after ResolveSession, before all route groups (D-24)
- main.go calls auth.LoadKeyFromEnv(); logs.Fatalf on missing/invalid SESSION_SECRET
- SESSION_SECRET documented in .env.example with openssl rand -hex 32 instruction
- go.mod: gorilla/csrf v1.7.3 (direct); prior tests updated with getCSRFToken helper
- All Plan 04/05/06 tests updated to acquire and submit valid _csrf tokens
2026-05-14 22:59:06 +02:00
Arthur Belleville
7d8c498980
feat(02-05): login vertical slice with rate limiting
- auth_login.templ: LoginPage + LoginFormFragment (mirrors signup shape)
- LoginForm + LoginErrors types added to templates/auth_forms.go
- LoginPageHandler + LoginPostHandler in handlers_auth.go
  - Rate-limit check before user lookup (D-16, T-2-14)
  - Single errInvalidCreds constant for D-20 enumeration defense
  - Session rotation via Store.Rotate on success (D-10, T-2-04)
  - HTMX-aware redirect and fragment responses (D-19, D-21)
- AuthDeps extended with Limiter *auth.LimiterStore field
- router.go: GET /login in RedirectIfAuthed group (D-23)
- main.go: LimiterStore created with janitor goroutine (D-16)
- Export NewLimiterStoreWithClock + SetLimiterClock for cross-package tests
- 12 TestLogin_* integration tests all pass with real DB
2026-05-14 22:27:54 +02:00
Arthur Belleville
efdc16babe
feat(02-04): signup handler, router wiring, and integration tests
- Add handlers_auth.go: SignupPageHandler + SignupPostHandler (validate -> hash -> insert -> session -> redirect)
- Add AuthDeps struct; wire argon2id hash, InsertUser, Store.Create, SetSessionCookie
- Update router.go: NewRouter accepts AuthDeps; mount ResolveSession (D-24); wire /signup routes behind RedirectIfAuthed
- Update cmd/web/main.go: build AuthDeps (sqlc.Queries + auth.Store + secure flag) and pass to NewRouter
- Add nil-Store guard to auth.ResolveSession for Phase 1 unit-test compatibility
- Update handlers_test.go: pass AuthDeps{} zero value to NewRouter (Phase 1 routes unaffected)
- Add testdb_test.go: isolated-schema test helper for web package integration tests
- Add handlers_auth_test.go: 8 TestSignup_* integration tests (all pass against real Postgres)
2026-05-14 22:17:50 +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