diff --git a/.planning/phases/03-event-write-back-pwa-install/03-UAT.md b/.planning/phases/03-event-write-back-pwa-install/03-UAT.md new file mode 100644 index 0000000..2c6437c --- /dev/null +++ b/.planning/phases/03-event-write-back-pwa-install/03-UAT.md @@ -0,0 +1,104 @@ +--- +status: complete +phase: 03-event-write-back-pwa-install +mode: mvp +source: + - 03-05-SUMMARY.md (Event Write UI) + - 03-06-SUMMARY.md (Edit/Delete + SyncStateToast) + - 03-07-SUMMARY.md (PWA Install) + - 03-08-SUMMARY.md (Gate 2 Live Verification) + - 03-12-SUMMARY.md (EventForm gap closure) + - 03-REVIEW.md / 03-REVIEW-FIX.md (code-review fix cycle, this session) +scope: regression-focused (post code-review-fix) +method: playwright-cli desktop drive (local dev-bypass stack, no real Fastmail writes) + green test suites + Gate 2 record +started: 2026-06-09T15:20:00Z +updated: 2026-06-09T15:30:00Z +--- + +## Current Test + +[testing complete] + +## Context + +Gate 2 (Plan 03-08) already operator-verified the full event write-back + iOS-install user +story **live** against real Authelia/Fastmail on desktop and the wife's iPhone (A1–A3, B1–B4, +D1–D6). This UAT pass is **regression-focused**: it re-confirms the behaviours touched by the +code-review fix cycle run this session (CR-01/CR-02 member-scoped lookups, CR-03 all-day +inclusive/exclusive, WR-01/move-path RRULE preservation, WR-04 sync-status ranking, IN-03 +payload re-validation), which landed *after* Gate 2. + +Browser drive used a local dev-bypass stack (MariaDB + API + PWA) as the credential-less dev +user, so no event ever reached a real Fastmail calendar. Seeded test data (one dev user, one +`uat.local` calendar, one recurring event) was removed after the run; DB restored to original +state (real users 2/3 and their 538 events untouched). + +## Tests + +### 1. Cold-start smoke — app boots and renders after the fixes +expected: PWA loads, calendar shell renders (nav, Calendars legend, New Event control), no real console errors. +result: pass +evidence: Loaded http://localhost:5173 in real Chromium. Title "FamilySync"; nav + "New Event" + Schedule-X month grid (June 2026) rendered; legend showed **distinct** member colours (Dev User #4A90D9, Family #F25C7A). Only console error was a benign favicon.ico 404. + +### 2. Create-event UI flow → enqueue → sync feedback +expected: New Event → fill form → Save → event enqueues (202) and SyncStateToast shows pending state. +result: pass +evidence: Opened EventForm (all UI-SPEC fields, focus on Title). Filled title, clicked "Create Event"; dialog closed, `calendar_outbox` row id=20 created (operation=create, pending), and SyncStateToast rendered `role="status"` "Syncing…". (Dispatch intentionally cannot complete — dev user has no Fastmail credential — so nothing hit a real calendar; the done/Saved transition is covered by outboxWorker tests + Gate 2 D1.) + +### 3. All-day toggle hides time inputs +expected: Toggling All day on removes the start/end time fields; off restores them. +result: pass +evidence: Toggled the all-day switch → `[checked]`; the 09:00 / 10:00 time textboxes disappeared, Start/End showed date-only. + +### 4. Edit mode pre-fill + recurrence preserved (WR-01 / WR-02 fix) +expected: Editing an event pre-populates fields; recurrence picker is disabled in edit mode with copy explaining the schedule is kept. +result: pass +evidence: Clicked a recurring occurrence → EventDetailPopover (live Edit/Delete footer) → Edit. "Edit Event" dialog pre-populated (title, dates 2026-06-10, times 10:00/11:00). Recurrence combobox rendered **`[disabled]`** with helper text **"Repeat can't be changed yet — edits keep the existing schedule."** — the exact preserve-on-edit guidance the WR-01/WR-02 fix added. Footer button correctly labelled "Save Changes". + +### 5. Member-scoped read (CR-01 GET path) +expected: A member sees only events from calendars in their writable set. +result: pass +evidence: As dev user 1 (owns only the seeded UAT calendar), GET /api/events returned only that calendar's occurrences and `writable-calendars` returned only it — never the 538 events on user 2's calendars. Confirms the member-scoped query. + +### 6. CR-01/CR-02 member-scoped edit/delete + freshest-etag (byte/SQL level) +expected: Edit/delete resolve the acting member's row (not an arbitrary shared-account duplicate); worker re-reads the writing member's etag. +result: pass +evidence: Certified by green API integration tests re-run this session (events.test.ts member-scoping + 503-join regression; outboxWorker freshest-etag WR-02 cases) — api 108 passed. Live-verified at Gate 2 D4/D5. Not UI-observable without a two-member shared-account dataset. + +### 7. CR-03 all-day inclusive/exclusive round-trip (byte level) +expected: All-day events write exclusive DTEND, pre-fill inclusive on edit; span does not grow on re-edit. +result: pass +evidence: Certified by vevent.test.ts (inclusive→exclusive write) + EventForm.test.tsx (exclusive→inclusive pre-fill) — green. The all-day off-by-one was also fixed and confirmed live at Gate 2. + +### 8. WR-01 + move-path RRULE preservation (byte level) +expected: Editing a recurring event keeps its RRULE, including edit-as-move to another calendar (worker create branch re-applies the source rule). +result: pass +evidence: Certified by the iteration-2 regression tests (events.test.ts _preservedRrule forwarding + outboxWorker create-branch RRULE re-apply) — green. UI half (disabled picker + helper) browser-verified in Test 4. Recurring round-trip live-verified at Gate 2 D3. + +### 9. WR-04 sync-status ranking + IN-03 payload re-validation +expected: sync-status ranks a failed/dead row above an older done row; worker hard-fails malformed outbox payloads before any CalDAV call. +result: pass +evidence: Certified by green API integration tests (sync-status priority CASE; outbox payload safeParse hard-fail) re-run this session. + +### 10. Coverage check (goal-backward against the phase user story) +expected: Members can create/edit/delete events written to the correct Fastmail calendar; app installable to iPhone & Android home screens with guided onboarding. +result: pass (with documented deferrals) +evidence: Create/edit/delete → correct Fastmail calendar: Gate 2 D1–D6 (live). iPhone install + standalone OIDC login + onboarding walkthrough: Gate 2 B1–B4 (live, load-bearing). Code paths present: EventForm/Edit/Delete + outbox worker, VitePWA manifest/SW + InstallPrompt walkthrough. **Deferred (not failures):** B5 Android install walkthrough (device check), C SSE smoke (Phase 4 entry gate per D-14). + +## Summary + +total: 10 +passed: 10 +issues: 0 +pending: 0 +skipped: 0 + +## Gaps + +[none — 0 UAT issues] + +## Accepted limitations (carried forward, not UAT failures) + +- **WR-01 (code-review Warning):** a missing cached etag still produces an unconditional PUT/DELETE; has a `console.warn`, but true conflict prevention needs a deeper D-08 change. v1-accepted. +- **WR-02 (code-review Warning):** edit cannot *change/remove* an RRULE — "omitted recurrence" means "keep existing"; surfaced to the user via the helper text verified in Test 4. Deferred to the recurrence-editing milestone. +- **Gate 2 deferrals:** B5 Android install walkthrough (device-only human check); C SSE 5-min smoke (Phase 4 entry gate); backlog 999.3–999.9 (session-timeout redirect, VALARM reminders, first-login app-password setup, all-day visual distinction, recurrence bound, edit-recurring-series).