---
phase: 10-events
plan: 04
type: execute
wave: 4
depends_on:
  - 10-03-PLAN.md
files_modified:
  - backend/internal/web/handlers_events_test.go
  - backend/internal/web/handlers_tablos_test.go
  - backend/internal/web/handlers_tasks_test.go
  - backend/templates/events.templ
  - backend/templates/tablos.templ
autonomous: false
requirements: [EVENT-01, EVENT-02, EVENT-03, EVENT-04, EVENT-05]

must_haves:
  truths:
    - "All EVENT-01..05 requirements are covered by automated tests or the final browser checkpoint"
    - "D-01 through D-23 are represented by source behavior, tests, or the final browser checkpoint"
    - "UI-SPEC: Events tab, toolbar, month grid, inline forms, copy, colors, typography, spacing, and accessibility labels are visible"
    - "Validation Architecture: final full suite and browser UAT run before verify-work"
  artifacts:
    - path: "backend/internal/web/handlers_events_test.go"
      provides: "final regression coverage for events"
    - path: "backend/templates/events.templ"
      provides: "final UI contract adjustments"
    - path: "backend/templates/tablos.templ"
      provides: "final tab integration adjustments"
---

<objective>
Vertical slice 4: harden the completed Events feature with regression tests, full generated-code verification, and browser UAT against all event requirements, context decisions, UI contract, and security expectations.
</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-VALIDATION.md
@/Users/arthur.belleville/Documents/perso/projects/xtablo-source/.planning/phases/10-events/10-03-PLAN.md
</context>

<threat_model>
T-10-01 Cross-tablo event access remains covered by owner-only handler tests.
T-10-02 CSRF remains covered by mutation tests using real CSRF tokens.
T-10-03 XSS remains covered by templ escaped rendering and should be spot-checked with HTML-looking event content.
T-10-04 Time validation remains covered on create and update plus DB check.
T-10-07 Cross-user aggregation leak remains covered by `ListUserEventsRange` tests.
T-10-09 Regression risk: NewRouter signature changes can silently break existing tablo/task/file/auth tests if not run together.
</threat_model>

<source_audit>
SOURCE | ID | Feature/Requirement | Plan | Status | Notes
GOAL | - | Tablo-owned scheduled events with task/file-level authorization | 10-01,10-02,10-03,10-04 | COVERED | Schema, handlers, ownership tests, final UAT
REQ | EVENT-01 | Create event with title, start time, optional end time, description, location | 10-01,10-03,10-04 | COVERED | Create form, validation, submitted-value precedence
REQ | EVENT-02 | Edit and delete events | 10-02,10-04 | COVERED | Inline edit and hard delete
REQ | EVENT-03 | Tablo detail events view listing scheduled events | 10-01,10-03,10-04 | COVERED | Events tab month grid
REQ | EVENT-04 | End time empty or after start time | 10-01,10-02,10-04 | COVERED | Handler validation and DB check
REQ | EVENT-05 | Authorization follows tablo access rules | 10-01,10-02,10-03,10-04 | COVERED | Parent ownership and aggregation filtering
CONTEXT | D-01..D-05 | Local date/time storage and display assumptions | 10-01,10-02,10-04 | COVERED | date/time columns and helpers
CONTEXT | D-06..D-11 | Events tab month grid, navigation, day create, title-only cells, +N more | 10-01,10-03,10-04 | COVERED | Calendar UI tasks
CONTEXT | D-12..D-15 | Inline create/edit flow and full tab refresh | 10-01,10-02,10-04 | COVERED | `#event-form-slot`, `#events-tab`
CONTEXT | D-16..D-19 | Hard delete, past visibility, ordering, no special empty state | 10-01,10-02,10-04 | COVERED | Query/order/delete tasks
CONTEXT | D-20..D-23 | Phase 11 user-scoped date-range query with tablo metadata | 10-03,10-04 | COVERED | `ListUserEventsRange`
RESEARCH | Data model | `events` table with local date/time columns and indexes | 10-01 | COVERED | Migration task
RESEARCH | Security | Parent-scoped queries, CSRF, escaping, DB check | 10-01,10-02,10-03,10-04 | COVERED | Threat models and tests
RESEARCH | Testing | DB-backed create/list/update/delete/ownership/aggregation tests | 10-01,10-02,10-03,10-04 | COVERED | Per-plan RED tests
UI-SPEC | Contract | Events tab, calendar, forms, copy, a11y, registry safety | 10-01,10-02,10-03,10-04 | COVERED | Implemented and UAT checked
</source_audit>

<tasks>

<task type="auto">
  <name>Task 1: Add final regression coverage for tab integration and escaping</name>
  <files>
    - backend/internal/web/handlers_events_test.go
    - backend/internal/web/handlers_tablos_test.go
  </files>
  <read_first>
    - backend/internal/web/handlers_events_test.go
    - backend/internal/web/handlers_tablos_test.go
    - backend/templates/events.templ
    - backend/templates/tablos.templ
    - .planning/phases/10-events/10-UI-SPEC.md
    - .planning/phases/10-events/10-VALIDATION.md
  </read_first>
  <action>
    Add final regression tests:
    1. `TestTabloDetailEventsTabFullPageFallback` verifies non-HTMX `/tablos/{id}/events?month=2026-05` renders the full detail shell with Events active and includes Overview, Tasks, Files, and Events tabs.
    2. `TestEventContentIsEscaped` creates an event with title `<script>alert(1)</script>` and verifies rendered HTML does not contain a raw script tag while still displaying escaped title text.
    3. `TestEventWithoutEndTimeDisplaysOnlyStartTime` verifies an event with blank end time displays `09:30` and does not render an inferred range.
    4. `TestEventsOrderedByStartTimeThenTitle` creates same-day events and verifies calendar title order follows start time ascending, then title.
  </action>
  <verify>
    <automated>cd backend && go test ./internal/web -run 'TestTabloDetailEventsTabFullPageFallback|TestEventContentIsEscaped|TestEventWithoutEndTimeDisplaysOnlyStartTime|TestEventsOrderedByStartTimeThenTitle' -count=1</automated>
  </verify>
  <acceptance_criteria>
    - `handlers_events_test.go` contains escaping, no-end-time display, and ordering tests.
    - `handlers_tablos_test.go` or `handlers_events_test.go` contains the full-page fallback test.
    - Targeted tests listed in verify pass.
  </acceptance_criteria>
</task>

<task type="auto">
  <name>Task 2: Run full backend verification and fix regressions</name>
  <files>
    - backend/internal/web/handlers_events.go
    - backend/internal/web/router.go
    - backend/templates/events.templ
    - backend/templates/tablos.templ
    - backend/internal/web/handlers_events_test.go
    - backend/internal/web/handlers_tasks_test.go
    - backend/internal/web/handlers_tablos_test.go
  </files>
  <read_first>
    - backend/internal/web/router.go
    - backend/internal/web/handlers_events.go
    - backend/templates/events.templ
    - backend/templates/tablos.templ
    - .planning/phases/10-events/10-RESEARCH.md
    - .planning/phases/10-events/10-UI-SPEC.md
    - .planning/phases/10-events/10-VALIDATION.md
  </read_first>
  <action>
    Run generated code and full backend tests. Fix any regressions caused by the new `EventsDeps` router signature, generated SQLC types, templ signatures, route ordering, or tab rendering.
    Keep fixes scoped to Phase 10 files and affected test helpers. Do not alter Phase 8 social sign-in behavior, Phase 9 etape behavior, or existing task/file route semantics except where router call sites require the new dependency parameter.
  </action>
  <verify>
    <automated>cd backend && just generate && go test ./... -count=1</automated>
  </verify>
  <acceptance_criteria>
    - `cd backend && just generate` exits 0.
    - `cd backend && go test ./... -count=1` exits 0.
    - `git diff --check` exits 0.
    - Existing task, etape, file, auth, and tablo tests still pass with the new router signature.
  </acceptance_criteria>
</task>

<task type="checkpoint:human-verify">
  <name>Task 3: Browser UAT checkpoint for Events tab</name>
  <files></files>
  <read_first>
    - .planning/phases/10-events/10-UI-SPEC.md
    - .planning/phases/10-events/10-VALIDATION.md
    - backend/templates/events.templ
  </read_first>
  <action>
    Start the app with `just dev` from the repository root or `cd backend && just dev`, sign in, open an existing tablo, and verify the Events tab manually:
    1. Open Events and confirm the month grid, `Previous month`, `Next month`, and `New event` controls render without overlap.
    2. Create an event from `New event` with title, date, start time, optional end time, description, and location.
    3. Create another event from a day cell and confirm the date is prefilled.
    4. Edit an event title/date/time and confirm the calendar refreshes to the correct month.
    5. Try equal start/end times and confirm the visible error copy is `End time must be after the start time.`.
    6. Delete an event and confirm it disappears after `Delete event`.
    7. Navigate to a past month with events and confirm past events remain visible.
  </action>
  <verify>
    <automated>cd backend && go test ./... -count=1</automated>
    <manual>Browser confirms all EVENT-01..05 success criteria and the 10-UI-SPEC interaction contract.</manual>
  </verify>
  <acceptance_criteria>
    - Full backend tests pass before the browser checkpoint.
    - Browser verification covers create, edit, delete, invalid end time, month navigation, day-cell prefill, and past-month visibility.
    - User approves the checkpoint before Phase 10 is marked complete.
  </acceptance_criteria>
</task>

</tasks>

<verification>
Run:
- `cd backend && just generate`
- `cd backend && go test ./... -count=1`
- `git diff --check`
- Browser UAT from Task 3
</verification>

<success_criteria>
- All EVENT-01..05 requirements are complete.
- All D-01..D-23 context decisions are implemented or verified.
- UI-SPEC is satisfied by the first functional Events tab UI.
- Security expectations are covered by parent-scoped queries, CSRF forms, escaped rendering, and owner-only tests.
</success_criteria>

