From 0b894f494d0a57a3d0449d74fd8f645510301182 Mon Sep 17 00:00:00 2001 From: Arthur Belleville Date: Sat, 16 May 2026 00:15:20 +0200 Subject: [PATCH] docs(10): map event implementation patterns --- .planning/phases/10-events/10-PATTERNS.md | 86 +++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .planning/phases/10-events/10-PATTERNS.md diff --git a/.planning/phases/10-events/10-PATTERNS.md b/.planning/phases/10-events/10-PATTERNS.md new file mode 100644 index 0000000..5ca163d --- /dev/null +++ b/.planning/phases/10-events/10-PATTERNS.md @@ -0,0 +1,86 @@ +--- +phase: 10 +slug: events +status: complete +created: 2026-05-16 +--- + +# Phase 10 - Pattern Map + +## Purpose + +Map the Events implementation to existing codebase patterns so execution can add the feature without inventing a parallel architecture. + +## File Map + +| New / Modified File | Role | Closest Existing Analog | Pattern to Reuse | +|---------------------|------|-------------------------|------------------| +| `backend/migrations/0008_events.sql` | Tablo-owned child table | `backend/migrations/0007_etapes.sql`, `backend/migrations/0005_files.sql` | `tablo_id` FK with `ON DELETE CASCADE`, indexes by parent and display ordering | +| `backend/internal/db/queries/events.sql` | SQLC query surface | `backend/internal/db/queries/etapes.sql`, `backend/internal/db/queries/files.sql` | Parent-scoped CRUD with `id` + `tablo_id` guards; ordered list queries | +| `backend/internal/web/handlers_events.go` | Event tab and CRUD handlers | `backend/internal/web/handlers_etapes.go`, `backend/internal/web/handlers_files.go` | `loadOwnedTablo`, parent-scoped child loader, HTMX fragments, 422 validation | +| `backend/internal/web/router.go` | Protected route mounting | Existing `/tasks`, `/etapes`, `/files` blocks | Static child routes before parametric child routes | +| `backend/templates/events.templ` | Calendar tab and forms | `backend/templates/files.templ`, `backend/templates/etapes.templ`, `backend/templates/tasks.templ` | Tab fragment wrapper, `#event-form-slot`, inline forms, delete confirmation | +| `backend/templates/events_forms.go` | Form structs/helpers | `backend/templates/tasks_forms.go`, `backend/templates/etapes_forms.go`, `backend/templates/files_helpers.go` | Small value structs, explicit error structs, helper formatting | +| `backend/templates/tablos.templ` | Tab integration | Existing Overview/Tasks/Files links | Add Events nav link and active-tab branch | +| `backend/internal/web/handlers_events_test.go` | DB-backed web tests | `backend/internal/web/handlers_tasks_test.go`, `backend/internal/web/handlers_etapes_test.go` | `setupTestDB`, `preInsertUser`, session cookie, CSRF token, response body assertions | +| `backend/internal/db/sqlc/*` | Generated query/models | Existing generated files | Regenerate with `cd backend && just generate`; do not edit by hand | +| Router call sites/tests | Dependency wiring | Existing `NewRouter(... EtapesDeps, FilesDeps, ...)` updates from Phase 9 | Add `EventsDeps` to `NewRouter` signature and every test helper/cmd call | + +## Handler Patterns + +Use `loadOwnedTablo` for every `/tablos/{id}/events...` route. Add `loadOwnedEvent(w, r, deps)` that: + +1. Calls `loadOwnedTablo`. +2. Parses `{event_id}` as UUID. +3. Calls `GetEventByID(id, tablo_id)`. +4. Returns 404 on parse failure or `pgx.ErrNoRows`. +5. Logs and returns 500 on unexpected query errors. + +This mirrors `loadOwnedEtape` and `loadOwnedTabloForFile`. + +Use tab handlers like `TabloFilesTabHandler` and `TabloTasksTabHandler`: + +- HTMX request returns only `EventsTabFragment`. +- Non-HTMX request renders full `TabloDetailPage(..., activeTab="events")`. +- Mutations return a refreshed `EventsTabFragment` and target `#events-tab` or `#tab-content`. + +## Template Patterns + +Events should use local templ output and existing Tailwind utility style: + +- Outer tab wrapper: `id="events-tab"`. +- Inline form slot: `id="event-form-slot"`. +- Form panel classes should resemble etape/file forms: `rounded border border-slate-200 bg-white p-3 shadow-sm space-y-3` or `bg-slate-50 p-4`. +- Inputs reuse existing classes: `block w-full rounded border border-slate-300 px-2 py-1 text-sm ...`. +- Buttons should use `@ui.Button` or existing `ui-button` classes; no new button system. + +## Date and Time Patterns + +Add focused helpers in the web/template layer: + +- Parse month query: `YYYY-MM`, default current local month. +- Parse date field: `YYYY-MM-DD`. +- Parse time field: `HH:MM`. +- Format DB values back to input-compatible strings. + +Keep query-string defaults separate from submitted form values. Query params may prefill `GET /events/new`; `POST /events` must use submitted form fields. + +## Test Patterns + +Follow existing DB-backed tests: + +- Use `setupTestDB`. +- Insert users/tablos directly through helpers or SQLC queries. +- Use authenticated session cookies and `getCSRFToken`. +- Assert 404 for non-owner access rather than 403. +- For validation, assert 422 and visible error copy. +- For HTMX, set `HX-Request: true` and assert fragment-specific body/targets. + +## Security Patterns + +- Parent ownership is always through `loadOwnedTablo`. +- Event child queries always include `tablo_id`. +- CSRF is included in create/update/delete forms. +- User content renders through templ escaped expressions. +- Date/time validation happens before query execution and is reinforced by the database check constraint. +