| phase |
plan |
type |
wave |
depends_on |
files_modified |
autonomous |
requirements |
must_haves |
| 11-individual-planning |
01 |
execute |
1 |
|
| backend/internal/web/handlers_planning_test.go |
| backend/internal/web/handlers_planning.go |
| backend/internal/web/router.go |
| backend/cmd/web/main.go |
| backend/templates/planning.templ |
| backend/templates/planning_forms.go |
|
true |
| PLAN-01 |
| PLAN-02 |
| PLAN-03 |
| PLAN-04 |
|
| truths |
artifacts |
| D-01/D-02: /planning defaults to an upcoming 14-day agenda starting today |
| D-03/D-04: navigation uses fixed 14-day windows with Today, previous-window, and next-window controls; past events are reachable through previous-window navigation |
| D-05/D-06: planning is a single continuous agenda list, not a month/week calendar and not grouped by day or tablo |
| D-07/D-08/D-10: each row shows time, title, tablo context, and location when present; no description snippets; no-end events display start time only |
| D-09: tablo context shows title plus a color dot when tablo_color is present |
| UI-SPEC: page uses existing Layout, compact header, toolbar, semantic agenda list, empty state, and no JS framework |
| PLAN-03: every event links back to /tablos/{id}/events?month=YYYY-MM for its event date |
| Security: planning aggregation uses authenticated user ID with ListUserEventsRange; no client-supplied user/tablo ID drives results |
|
| path |
provides |
| backend/internal/web/handlers_planning.go |
protected /planning route handler and 14-day range query |
|
| path |
provides |
| backend/templates/planning.templ |
server-rendered planning agenda page |
|
| path |
provides |
| backend/templates/planning_forms.go |
planning view models and date/link helpers |
|
| path |
provides |
| backend/internal/web/handlers_planning_test.go |
DB-backed planning behavior and authorization coverage |
|
|
|
Vertical slice 1: add the protected `/planning` page that renders the authenticated user's accessible events across tablos as a fixed 14-day chronological agenda with working navigation, empty state, and source tablo links.
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/11-individual-planning/11-CONTEXT.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/11-individual-planning/11-RESEARCH.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/11-individual-planning/11-UI-SPEC.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/11-individual-planning/11-PATTERNS.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-03-SUMMARY.md
<threat_model>
T-11-01 Unauthenticated access: /planning must be mounted inside the protected auth.RequireAuth route group so unauthenticated users are redirected to /login.
T-11-02 Cross-user event leak: handler must call ListUserEventsRange with auth.UserFromContext(r.Context()).ID; no query parameter may select user or tablo scope.
T-11-03 XSS: event titles, tablo titles, locations, and color strings must render through templ escaped expressions; do not use templ.Raw.
T-11-04 Invalid date input: malformed start query values must fall back to today's local date instead of returning 500 or generating unsafe SQL.
T-11-05 Source-link drift: event deep links must derive month=YYYY-MM from each event's own event_date, not from the current planning window.
</threat_model>
Task 1: Add RED coverage for protected planning agenda behavior
- backend/internal/web/handlers_planning_test.go
- backend/internal/web/router.go
- backend/internal/web/handlers_events_test.go
- backend/internal/web/handlers_tablos_test.go
- backend/internal/web/router.go
- backend/internal/db/queries/events.sql
- .planning/phases/11-individual-planning/11-CONTEXT.md
- .planning/phases/11-individual-planning/11-UI-SPEC.md
- .planning/phases/11-individual-planning/11-RESEARCH.md
Create `backend/internal/web/handlers_planning_test.go` with DB-backed tests that initially fail:
1. `TestPlanningRequiresAuth` sends unauthenticated `GET /planning` and expects a redirect to `/login`.
2. `TestPlanningDefaultsToUpcomingFourteenDays` injects `Now` as `2026-05-16`, creates owned events on `2026-05-16`, `2026-05-29`, and `2026-05-30`, then expects the first two titles and not the third.
3. `TestPlanningListsOwnedEventsChronologically` creates owned events across two tablos in non-chronological insert order and expects response order by date, start time, then title; it also expects visible event title, time, tablo title, color value or dot marker, location, and `/tablos/{id}/events?month=YYYY-MM`.
4. `TestPlanningDoesNotLeakOtherUsersEvents` creates an event for another user in the same range and expects the foreign title to be absent.
5. `TestPlanningNavigationLinks` expects visible `Previous 14 days`, `Today`, and `Next 14 days` links with `start=2026-05-02`, `/planning` or `start=2026-05-16`, and `start=2026-05-30`.
6. `TestPlanningEmptyState` expects `No events in this range` and `Use the navigation controls to browse another 14-day window.` while the navigation controls remain visible.
7. `TestPlanningInvalidStartFallsBackToToday` requests `/planning?start=not-a-date` with injected `Now=2026-05-16` and expects the same default range label as `/planning`.
Add a local `newPlanningTestRouter(q, store, now)` helper that wires `PlanningDeps{Queries: q, Now: now}` through `NewRouter`.
cd backend && go test ./internal/web -run 'TestPlanning' -count=1
- `backend/internal/web/handlers_planning_test.go` contains all seven named `TestPlanning...` tests.
- Tests use full router requests with authenticated session cookies where needed.
- The ownership test proves another user's event title is not present in `/planning`.
- The default-window test proves `2026-05-16` and `2026-05-29` are included while `2026-05-30` is excluded.
Task 2: Implement the protected planning route, handler, view models, and agenda template
- backend/internal/web/handlers_planning.go
- backend/internal/web/router.go
- backend/cmd/web/main.go
- backend/templates/planning.templ
- backend/templates/planning_forms.go
- backend/internal/web/handlers_events.go
- backend/internal/web/router.go
- backend/cmd/web/main.go
- backend/templates/layout.templ
- backend/templates/events_forms.go
- backend/templates/events.templ
- backend/templates/tablos.templ
- backend/internal/db/queries/events.sql
- .planning/phases/11-individual-planning/11-UI-SPEC.md
- .planning/phases/11-individual-planning/11-PATTERNS.md
Add `PlanningDeps{Queries *sqlc.Queries, Now func() time.Time}` and `PlanningPageHandler(deps PlanningDeps)` in `handlers_planning.go`.
The handler must default `Now` to `time.Now`, parse `start` with layout `2006-01-02`, fall back to today's local date when blank or invalid, compute `end := start.AddDate(0, 0, 13)`, and call `ListUserEventsRange` with authenticated `user.ID`, `pgDateFromTime(start)`, and `pgDateFromTime(end)`.
Extend `NewRouter` to accept `planningDeps PlanningDeps` after `eventDeps EventsDeps` and before `fileDeps FilesDeps`; mount `r.Get("/planning", PlanningPageHandler(planningDeps))` inside the protected route group before `/tablos/new` and `/tablos/{id}` routes.
Update `backend/cmd/web/main.go` to construct `planningDeps := web.PlanningDeps{Queries: q}` and pass it to `NewRouter`; update all `NewRouter` test helper call sites with `PlanningDeps{Queries: q}` or `PlanningDeps{}` where the route is not exercised.
Add `PlanningAgenda` and `PlanningEventRow` helpers in `planning_forms.go` with exact URL helper behavior: planning navigation URLs use `start=YYYY-MM-DD`, today can use `/planning`, and event links use `/tablos/{tablo_id}/events?month=YYYY-MM` derived from each event date.
Add `PlanningPage` in `planning.templ` using existing `Layout`, `ui-button` classes, one `h1` with `Planning`, a concise date range label, previous/today/next links, a semantic continuous agenda list, compact rows, optional location, decorative tablo color dot, and the exact empty-state copy from `11-UI-SPEC.md`.
Do not add migrations, JavaScript framework code, calendar grids, description snippets, grouping headings, create/edit/delete controls, registry components, or custom SVG icons.
Run `cd backend && just generate`.
cd backend && just generate && go test ./internal/web -run 'TestPlanning' -count=1
- `backend/internal/web/router.go` contains `r.Get("/planning", PlanningPageHandler(planningDeps))` inside the protected group.
- `PlanningPageHandler` calls `ListUserEventsRange` with the authenticated user's ID.
- `planning.templ` contains `Planning`, `Previous 14 days`, `Today`, `Next 14 days`, `No events in this range`, and no description rendering.
- Event links contain `/tablos/` and `/events?month=`.
- `cd backend && just generate && go test ./internal/web -run 'TestPlanning' -count=1` exits 0.
Run:
- `cd backend && just generate`
- `cd backend && go test ./internal/web -run 'TestPlanning' -count=1`
- `git diff --check`
<success_criteria>
- PLAN-01: authenticated users can open
/planning; unauthenticated users are redirected.
- PLAN-02: planning lists owned accessible events across tablos in chronological order.
- PLAN-03: each listed event links back to its tablo Events tab with the event month.
- PLAN-04: empty state and fixed 14-day navigation work without a JS framework.
</success_criteria>