Commit graph

25 commits

Author SHA1 Message Date
Arthur Belleville
4046783fd4
feat(13-05): create catalog package with route files and router wiring
- Add backend/internal/web/ui/catalog/catalog.templ: single-page layout
  with 240px sidebar nav (11 anchor links) and 11 component sections with
  section headings matching DS-XX requirement IDs
- Add backend/internal/web/ui/catalog/examples.go: Example struct + typed
  example functions for all 11 component types (badge/button/card/empty-state/
  form-field/icon-button/input/modal/select/table/textarea); modal renders
  panel-only (no backdrop wrapper, Pitfall 7)
- Add backend/internal/web/catalog_route_catalog.go (//go:build catalog):
  RegisterCatalogRoute mounts GET /ui-catalog via catalogPageHandler()
- Add backend/internal/web/catalog_route_stub.go (//go:build !catalog):
  no-op RegisterCatalogRoute for production builds
- Wire RegisterCatalogRoute(r) unconditionally in NewRouter after protected routes
- Add justfile catalog target: just generate + go run -tags catalog ./cmd/web
- go build ./... and go build -tags catalog ./... both pass; go test ./... green
2026-05-16 14:13:30 +02:00
Arthur Belleville
d15c3748e4
feat(12-03): add discussion SSE stream 2026-05-16 10:18:33 +02:00
Arthur Belleville
c5477e4ceb
feat(12-01): implement discussion tab and posting 2026-05-16 10:11:14 +02:00
Arthur Belleville
2989c0b917
feat(11-01): implement planning agenda page 2026-05-16 07:26:49 +02:00
Arthur Belleville
614003f165
feat(10-02): add event edit and delete flows 2026-05-16 00:32:55 +02:00
Arthur Belleville
0bfe8cfbb4
feat(10-01): add events calendar creation slice 2026-05-16 00:27:58 +02:00
Arthur Belleville
4af623a57b
feat(09-02): manage etapes 2026-05-15 22:44:50 +02:00
Arthur Belleville
565bb88df5
feat(09-01): add etape task slice 2026-05-15 22:40:25 +02:00
Arthur Belleville
90af9bdaef
feat(08): disable apple sign-in 2026-05-15 21:41:22 +02:00
Arthur Belleville
6e6583636f
feat(08-05): add linked providers view and provider docs 2026-05-15 21:10:45 +02:00
Arthur Belleville
59fd6b15b5
feat(08-04): show social sign-in controls on auth pages 2026-05-15 21:09:14 +02:00
Arthur Belleville
a8b6a03eac
feat(08-03): add apple social sign-in flow 2026-05-15 21:06:08 +02:00
Arthur Belleville
6779663c8a
feat(08-02): add google social sign-in flow 2026-05-15 21:03:30 +02:00
Arthur Belleville
b61f36f17e
fix(07): WR-01 NewRouter returns error instead of panicking on bad static FS
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-15 18:54:49 +02:00
Arthur Belleville
bdd3cba314
feat(07-01): wire embed.FS into NewRouter and RunMigrations into cmd/web/main.go
- backend/internal/web/router.go: staticDir string -> staticFS fs.FS; /healthz uses HealthzHandler(); /readyz registered with ReadyzHandler(pinger); embedded FS served via fs.Sub()
- backend/cmd/web/main.go: import assets "backend"; db.RunMigrations(ctx, pool, assets.Migrations) before router; web.NewRouter now receives assets.Static
- All *_test.go NewRouter call sites updated from "./static" to os.DirFS("./static"); "os" import added where missing
2026-05-15 18:14:33 +02:00
Arthur Belleville
a12c5abea6
feat(05-02): 3-tab layout + files templates + router + main.go S3 wiring
- tablos.templ: TabloDetailPage gains files+activeTab params, 3-tab nav with hx-push-url
- tablos.templ: TabloOverviewTabFragment + TasksTabFragment (wraps KanbanBoard) added
- files.templ: FilesTabFragment, FileUploadForm (hx-encoding=multipart/form-data),
  FileListRow, FileListEmpty, FileRowGone, UploadErrorFragment
- files_helpers.go: formatBytes() converts int64 bytes to human-readable string
- router.go: fileDeps FilesDeps param added; TabloTasksTabHandler + file routes wired
- handlers_tablos.go: both TabloDetailPage call sites updated (nil, 'overview')
- main.go: S3_ENDPOINT/S3_BUCKET/S3_REGION env vars read; files.NewStore constructed;
  fileDeps wired; nil filesStore allowed when S3 env unset (503 from handlers)
- All test routers updated to pass FilesDeps{} in new param position
2026-05-15 12:28:33 +02:00
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
ab6937c1aa
feat(03-03): detail/edit/delete handlers + router wiring; all 10 TABLO tests green
- loadOwnedTablo helper: uuid.Parse, GetTabloByID, ownership check (D-04: 404 not 403)
- TabloDetailHandler: GET /tablos/{id} renders detail page
- TabloEditTitleHandler/ShowTitleHandler: GET /tablos/{id}/edit-title|show-title fragments
- TabloEditDescHandler/ShowDescHandler: GET /tablos/{id}/edit-desc|show-desc fragments
- TabloUpdateHandler: POST /tablos/{id} — validates, updates DB, renders matching zone fragment
- TabloDeleteConfirmHandler/CancelHandler: GET /tablos/{id}/delete-confirm|delete-cancel
- TabloDeleteHandler: POST /tablos/{id}/delete — deletes row, HX-Redirect:/ or 303
- router.go: 9 new routes in RequireAuth group, static-before-parametric order preserved
- Fix [Rule 1 - Bug]: test title "Owner's Tablo" caused HTML entity mismatch — changed to "Owners Detail Tablo"
- go test ./internal/web/... -run TestTablo: 10/10 PASS; full suite: all PASS
2026-05-15 08:02:43 +02:00
Arthur Belleville
5db9215a73
feat(03-02): tablo handlers + router wiring — list/new/create green
- Implement TablosListHandler, TablosNewHandler, TablosCreateHandler in
  handlers_tablos.go replacing the Plan 01 stub
- TablosCreateHandler: reads via r.PostFormValue, validates title (required,
  <=255), inserts with pgtype.Text nullable params, sends HX-Retarget +
  HX-Reswap on HTMX success, 303 redirect on non-HTMX success
- router.go: replace r.Get("/", IndexHandler()) with TablosListHandler;
  add GET /tablos/new and POST /tablos (static before parametric — Pitfall 1)
- handlers.go: remove IndexHandler + unused auth/csrf imports
- index.templ: reduced to bare package declaration (dashboard moved to tablos.templ)
- index_templ.go: deleted (empty templ file generates broken import)
- TestTabloList, TestTabloList_Empty, TestTabloCreate, TestTabloCreate_Validation: PASS
- TestSignup, TestLogin, TestLogout, TestCSRF: still PASS (no regression)
2026-05-15 00:20:25 +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
8b54ff4bec
feat(02-06): implement logout, protect GET /, and update layout with auth state
- Add LogoutHandler: deletes session row (D-06), clears cookie, redirects to /login
- Protect GET / inside RequireAuth group; remove old top-level registration
- Add POST /logout inside same RequireAuth group (D-22: POST-only logout)
- Update Layout signature to accept *auth.User; render logout form + email when authed
- Update Index template to accept *auth.User and show "Signed in as {email}"
- Update SignupPage/LoginPage to pass nil to Layout (auth pages are unauthed)
- Update IndexHandler to pull user from auth.Authed(ctx) and pass to template
- Update TestIndex_RendersHxGet -> TestIndex_UnauthRedirects (GET / now protected)
- AUTH-04 (logout) and AUTH-05 (protected /) are now closed
2026-05-14 22:40:10 +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
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