---
phase: 10-events
plan: 03
type: execute
wave: 3
depends_on:
  - 10-02-PLAN.md
files_modified:
  - backend/internal/db/queries/events.sql
  - backend/internal/web/handlers_events_test.go
  - backend/internal/web/handlers_events.go
  - backend/templates/events.templ
  - backend/templates/events_forms.go
autonomous: true
requirements: [EVENT-01, EVENT-03, EVENT-05]

must_haves:
  truths:
    - "D-08/D-21: Events tab supports previous/next month navigation with /tablos/{id}/events?month=YYYY-MM"
    - "D-09: New event can be opened generally or from a day cell with the date prefilled"
    - "D-10/D-11: Day cells show event titles only, first few titles, and +N more"
    - "D-20/D-22/D-23: Phase 10 includes user-scoped date-range query surface returning event fields plus tablo title/color"
    - "EVENT-05: User-scoped aggregation must filter through tablos.user_id and not leak other users' events"
    - "Research pitfall: submitted form fields must win over date/month query defaults"
  artifacts:
    - path: "backend/internal/db/queries/events.sql"
      provides: "ListUserEventsRange for Phase 11 planning handoff"
    - path: "backend/internal/web/handlers_events.go"
      provides: "month navigation, day prefill, and form/query precedence helpers"
    - path: "backend/templates/events.templ"
      provides: "previous/next controls, day create controls, and +N more rendering"
---

<objective>
Vertical slice 3: the Events tab supports month navigation and day-click date prefill, while the database query layer exposes the user-scoped date-range aggregation that Phase 11 needs for individual planning.
</objective>

<context>
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-CONTEXT.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-RESEARCH.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-UI-SPEC.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-PATTERNS.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-02-PLAN.md
</context>

<threat_model>
T-10-01 Cross-tablo event access: day prefill and month links must never bypass `loadOwnedTablo`.
T-10-07 Cross-user aggregation leak: `ListUserEventsRange` must join `tablos` and filter by `tablos.user_id = $1`.
T-10-08 Query-default confusion: date query params are defaults only; POST body fields must be authoritative.
T-10-03 XSS: `+N more`, titles, and month/day labels must render as escaped text.
</threat_model>

<tasks>

<task type="auto">
  <name>Task 1: Add RED coverage for navigation, prefill, overflow, and aggregation</name>
  <files>
    - backend/internal/web/handlers_events_test.go
  </files>
  <read_first>
    - backend/internal/web/handlers_events_test.go
    - backend/internal/web/handlers_tasks_test.go
    - backend/templates/events.templ
    - .planning/phases/10-events/10-RESEARCH.md
    - .planning/phases/10-events/10-UI-SPEC.md
  </read_first>
  <action>
    Add failing tests:
    1. `TestEventsMonthNavigationPushesMonthParam` GETs `/tablos/{id}/events?month=2026-05` and expects links for `month=2026-04` and `month=2026-06` plus accessible labels naming those months.
    2. `TestEventNewFromDayPrefillsDate` GETs `/tablos/{id}/events/new?date=2026-05-20&month=2026-05` and expects the date input value `2026-05-20`.
    3. `TestEventCreateSubmittedDateOverridesQueryDefault` POSTs `/tablos/{id}/events?date=2026-05-20&month=2026-05` with form `event_date=2026-05-21` and verifies the event is stored on `2026-05-21`.
    4. `TestEventsCalendarShowsMoreIndicator` creates four events on one date and expects three titles plus `+1 more`.
    5. `TestListUserEventsRangeReturnsOnlyOwnedTablos` creates events for two users in the same date range and verifies the user-scoped query returns only the authenticated user's events with `tablo_title` and `tablo_color`.
  </action>
  <verify>
    <automated>cd backend && go test ./internal/web -run 'TestEventsMonthNavigationPushesMonthParam|TestEventNewFromDayPrefillsDate|TestEventCreateSubmittedDateOverridesQueryDefault|TestEventsCalendarShowsMoreIndicator|TestListUserEventsRangeReturnsOnlyOwnedTablos' -count=1</automated>
  </verify>
  <acceptance_criteria>
    - `handlers_events_test.go` contains all five named tests.
    - The submitted-date test fails before implementation if query defaults override form data.
    - The user-scoped query test proves foreign-user events are not returned.
  </acceptance_criteria>
</task>

<task type="auto">
  <name>Task 2: Implement navigation, day prefill, overflow display, and planning query</name>
  <files>
    - backend/internal/db/queries/events.sql
    - backend/internal/web/handlers_events.go
    - backend/templates/events.templ
    - backend/templates/events_forms.go
  </files>
  <read_first>
    - backend/internal/db/queries/events.sql
    - backend/internal/web/handlers_events.go
    - backend/templates/events.templ
    - backend/templates/events_forms.go
    - .planning/phases/10-events/10-CONTEXT.md
    - .planning/phases/10-events/10-UI-SPEC.md
  </read_first>
  <action>
    Add `ListUserEventsRange` to `events.sql`, joining `events` to `tablos`, filtering by `tablos.user_id`, `events.event_date >= $2`, and `events.event_date <= $3`, ordering by `event_date`, `start_time`, `title`, and returning event fields plus `tablo_title` and `tablo_color`.
    Extend month model generation to calculate previous and next `YYYY-MM` links, in-month day metadata, and per-day event truncation at three titles with `+N more`.
    Add day-cell create controls targeting `/tablos/{id}/events/new?date=YYYY-MM-DD&month=YYYY-MM` with `aria-label="Create event on YYYY-MM-DD"`.
    Implement `EventNewFormHandler` so query `date` pre-populates the create form date and query `month` is carried as calendar context. Ensure POST create/update reads only submitted form fields for `event_date`, `start_time`, and `end_time`; month query controls the refresh view only.
    Run `cd backend && just generate`.
  </action>
  <verify>
    <automated>cd backend && just generate && go test ./internal/web -run 'TestEventsMonthNavigationPushesMonthParam|TestEventNewFromDayPrefillsDate|TestEventCreateSubmittedDateOverridesQueryDefault|TestEventsCalendarShowsMoreIndicator|TestListUserEventsRangeReturnsOnlyOwnedTablos' -count=1</automated>
  </verify>
  <acceptance_criteria>
    - `backend/internal/db/queries/events.sql` contains `ListUserEventsRange` and `tablos.user_id`.
    - `backend/templates/events.templ` contains `+` more rendering logic and day create labels.
    - `EventNewFormHandler` pre-fills date from query only on GET.
    - POST create/update handlers use submitted `event_date`, not query `date`, for persistence.
    - Targeted tests listed in verify pass.
  </acceptance_criteria>
</task>

</tasks>

<verification>
Run:
- `cd backend && just generate`
- `cd backend && go test ./internal/web -run 'TestEventsMonthNavigationPushesMonthParam|TestEventNewFromDayPrefillsDate|TestEventCreateSubmittedDateOverridesQueryDefault|TestEventsCalendarShowsMoreIndicator|TestListUserEventsRangeReturnsOnlyOwnedTablos' -count=1`
- `git diff --check`
</verification>

<success_criteria>
- Month navigation and day-click create prefill are delivered.
- Calendar cells show titles only and handle overflow with `+N more`.
- Phase 11 can query the authenticated user's events across owned tablos by date range with tablo title/color.
</success_criteria>

