diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 5591e51..e8d301f 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -12,8 +12,8 @@ Each requirement maps to exactly one roadmap phase (see Traceability). ### Calendar — Per-event reminders & write-back latency -- [ ] **CAL-13**: User can choose a reminder lead time when creating or editing an event from a preset list (None / 5m / 10m / 15m / 30m / 1h / 2h / 1d / 2d), with **"None" as the default**; the choice is serialized as a VALARM on the event written back to Fastmail. -- [ ] **CAL-14**: Editing an event **preserves any existing reminder/VALARM** set in another client (Fastmail or native) — reminders are never silently stripped on round-trip. +- [x] **CAL-13**: User can choose a reminder lead time when creating or editing an event from a preset list (None / 5m / 10m / 15m / 30m / 1h / 2h / 1d / 2d), with **"None" as the default**; the choice is serialized as a VALARM on the event written back to Fastmail. +- [x] **CAL-14**: Editing an event **preserves any existing reminder/VALARM** set in another client (Fastmail or native) — reminders are never silently stripped on round-trip. - [x] **CAL-15**: A created, edited, or deleted event reaches Fastmail within ~2 seconds (event-driven outbox drain) instead of up to ~15s, while preserving the optimistic-202 accept and all outbox durability guarantees (create-before-delete ordering, drain concurrency guard, fresh-etag-before-PUT, per-uid exactly-once). ### Notifications — Variable-lead reminder scheduling @@ -79,8 +79,8 @@ Maps each REQ-ID to its phase. v1.1 phases continue v1.0 numbering (v1.0 ended a | ADMIN-01 | Phase 10 (Admin Role & Settings) | Complete | | ADMIN-02 | Phase 10 (Admin Role & Settings) | Complete | | ADMIN-03 | Phase 10 (Admin Role & Settings) | Complete | -| CAL-13 | Phase 11 (Per-Event Reminders) | Pending | -| CAL-14 | Phase 11 (Per-Event Reminders) | Pending | +| CAL-13 | Phase 11 (Per-Event Reminders) | Complete | +| CAL-14 | Phase 11 (Per-Event Reminders) | Complete | | NOTIF-04 | Phase 11 (Per-Event Reminders) | Pending | | NOTIF-05 | Phase 11 (Per-Event Reminders) | Pending | | NOTIF-06 | Phase 11 (Per-Event Reminders) | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 83b5a6f..9658c7c 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -29,7 +29,7 @@ Make FamilySync configurable, administrable, and maintainable for real multi-mem - [x] **Phase 8: Gitea CI** - Full regression on PR to main (lint/typecheck/unit/API-integration vs a MariaDB service container **+ the Phase 7 mobile harness as a UI-regression step against a CI-hosted dev stack**) + Docker image publish on merge (completed 2026-06-11) - [x] **Phase 9: Faster Write-Back** - Event-driven outbox drain so edits land in ~1-2s instead of ~15s, preserving every outbox durability guarantee (completed 2026-06-12) - [x] **Phase 10: Admin Role & Settings** - DB foundation (is_admin / reminder_lead / app_config) + role-gated admin UI to rotate app passwords and designate the shared calendar (completed 2026-06-13) -- [ ] **Phase 11: Per-Event Reminders** - Reminder selector on the event form (incl. "None") serialized as VALARM, with a variable-lead scheduler that honors each event's choice +- [x] **Phase 11: Per-Event Reminders** - Reminder selector on the event form (incl. "None") serialized as VALARM, with a variable-lead scheduler that honors each event's choice (completed 2026-06-14) - [ ] **Phase 12: Initial Setup Wizard** - First-run validated bootstrap of env/VAPID/DB/OIDC + first app password, reusing the admin route surface - [x] **Phase 13: Real Lint Gate (ESLint)** - Wire ESLint flat config (typescript-eslint + React) across both apps so the Phase 8 CI lint slot actually fails on violations instead of no-op'ing (completed 2026-06-12) - [x] **Phase 14: Desktop E2E Coverage** - Add a Desktop Chrome Playwright profile + make the mobile-authored specs desktop-safe so the Phase 8 regression gate validates desktop, not just mobile (completed 2026-06-12) @@ -225,7 +225,7 @@ Plans: **Wave 3** *(blocked on Wave 2 completion)* -- [ ] 11-04-PLAN.md — EventForm reminder picker (allDay swap, edit pre-population) + client types + Playwright smoke +- [x] 11-04-PLAN.md — EventForm reminder picker (allDay swap, edit pre-population) + client types + Playwright smoke **UI hint**: yes @@ -408,7 +408,7 @@ At ≤767px (`window.matchMedia('(max-width: 767px)')` in `apps/pwa/src/App.tsx` | 8. Gitea CI | v1.1 | 4/4 | Complete | 2026-06-11 | | 9. Faster Write-Back | v1.1 | 2/2 | Complete | 2026-06-12 | | 10. Admin Role & Settings | v1.1 | 4/4 | Complete | 2026-06-13 | -| 11. Per-Event Reminders | v1.1 | 3/4 | In Progress| | +| 11. Per-Event Reminders | v1.1 | 4/4 | Complete | 2026-06-14 | | 12. Initial Setup Wizard | v1.1 | 0/? | Not started | - | | 13. Real Lint Gate (ESLint) | v1.1 | 3/3 | Complete | 2026-06-12 | | 14. Desktop E2E Coverage | v1.1 | 1/1 | Complete | 2026-06-12 | @@ -422,7 +422,7 @@ At ≤767px (`window.matchMedia('(max-width: 767px)')` in `apps/pwa/src/App.tsx` **Goal:** [Captured for future planning] Abstract the calendar backend behind a provider interface so Fastmail/CalDAV is one implementation among potentially many. Shipping with a single provider is fine, but the broker, sync, and event-expansion layers should be structured so additional providers (e.g. other CalDAV hosts, Google Calendar, generic ICS feeds) can be added without rework. Captures the "provider" seam as an explicit architectural concern. **Requirements:** TBD -**Plans:** 3/4 plans executed +**Plans:** 4/4 plans complete Plans: diff --git a/.planning/STATE.md b/.planning/STATE.md index f84d57d..e689841 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,15 +3,15 @@ gsd_state_version: 1.0 milestone: v1.1 milestone_name: Operability & Polish status: executing -stopped_at: Phase 11 UI-SPEC approved -last_updated: "2026-06-14T01:55:34.129Z" +stopped_at: Completed 11-04-PLAN.md +last_updated: "2026-06-14T10:57:47.937Z" last_activity: 2026-06-14 -- Phase 11 execution started progress: total_phases: 22 - completed_phases: 8 + completed_phases: 9 total_plans: 31 - completed_plans: 27 - percent: 36 + completed_plans: 31 + percent: 41 --- # Project State @@ -26,8 +26,8 @@ See: .planning/PROJECT.md (updated 2026-06-10) ## Current Position Phase: 11 (per-event-reminders) — EXECUTING -Plan: 1 of 4 -Status: Executing Phase 11 +Plan: 2 of 4 +Status: Ready to execute Last activity: 2026-06-14 -- Phase 11 execution started ### ✅ Resolved Checkpoint — Phase 15 Plan 15-03 Task 2 (human-action) @@ -105,6 +105,7 @@ _Updated after each plan completion_ | Phase 10-admin-role-settings P02 | 700 | 3 tasks | 6 files | | Phase 10-admin-role-settings P03 | 720 | 3 tasks | 6 files | | Phase 10-admin-role-settings P04 | 1315 | 3 tasks | 8 files | +| Phase 11-per-event-reminders P11-04 | 60 | 3 tasks | 4 files | ## Accumulated Context @@ -179,6 +180,9 @@ Recent decisions affecting current work: - [Phase ?]: isAdmin drives nav visibility; real boundary is server-side - [Phase ?]: Single bottom sheet component handles all credential entry flows - [Phase ?]: No X button on SetupBanner; cleared by needsProviderSetup=false from /api/me refetch +- [Phase ?]: D-CLIENT-TYPES: reminderLeadMinutes required on CalendarOccurrence, optional on CreateEventPayload (absent=no-change D-08) +- [Phase ?]: D-PAYLOAD-ABSENT: __custom__ unchanged → field omitted from payload; server hasOwnProperty check preserves original VALARM (D-08) +- [Phase ?]: D-NULL-FALLBACK: occurrence.reminderLeadMinutes===null mapped to None; occurrence cannot distinguish absolute/multi-VALARM from no-reminder; rely on server-side preserve (absent payload) ### Roadmap Evolution @@ -247,9 +251,9 @@ Recent decisions affecting current work: ## Session Continuity -Last session: 2026-06-14T00:53:26.422Z -Stopped at: Phase 11 UI-SPEC approved -Resume file: .planning/phases/11-per-event-reminders/11-UI-SPEC.md +Last session: 2026-06-14T10:57:47.923Z +Stopped at: Completed 11-04-PLAN.md +Resume file: None ## Operator Next Steps diff --git a/.planning/phases/11-per-event-reminders/11-04-SUMMARY.md b/.planning/phases/11-per-event-reminders/11-04-SUMMARY.md new file mode 100644 index 0000000..cfa9bb8 --- /dev/null +++ b/.planning/phases/11-per-event-reminders/11-04-SUMMARY.md @@ -0,0 +1,191 @@ +--- +phase: 11-per-event-reminders +plan: "04" +subsystem: ui +tags: [reminder, picker, EventForm, allDay, VALARM, client-types, playwright, cal-13, cal-14] +dependency_graph: + requires: + - "Plan 11-03 (CalendarOccurrence.reminderLeadMinutes, GET /api/events surfaces the field, eventFieldsSchema accepts reminderLeadMinutes)" + provides: + - "Reminder ` in EventForm with edit-mode pre-population, Custom-kept preserve path, and payload mapping (null/integer/absent) wired to CreateEventPayload** + +## Performance + +- **Duration:** ~60 min (Tasks 1+2 implementation) + playwright-cli smoke (Task 3) +- **Started:** 2026-06-14 +- **Completed:** 2026-06-14 +- **Tasks:** 3 (Tasks 1+2 autonomous; Task 3 checkpoint:human-verify — APPROVED) +- **Files modified:** 4 (client.ts, EventForm.tsx, EventForm.test.tsx, EventDetailPopover.test.tsx) + 7 prettier-only (style commit) + +## Accomplishments + +- `reminderLeadMinutes: number | null` added to `CalendarOccurrence`; `reminderLeadMinutes?: number | null` added to `CreateEventPayload` — four-state contract (absent/null/0/positive) mirrors the server schema (D-08) +- Reminder `