Milestone v1.0: FamilySync MVP #1

Merged
luckberg merged 376 commits from gsd/v1.0-milestone into main 2026-06-10 17:39:19 -04:00
Showing only changes of commit dbf370b18c - Show all commits
@@ -721,22 +721,24 @@ Route tests in `tests/routes/` use a real MariaDB connection with `vi.mock('../.
---
## Open Questions
## Open Questions (RESOLVED)
> All three questions were resolved during planning (Phase 5 plans, 2026-06-09). Resolutions locked below.
1. **Does event-change detection require a new syncCalendar hook or a separate table diff?**
- What we know: `syncCalendar` does an `onDuplicateKeyUpdate` upsert but does not return which rows changed.
- What's unclear: To detect NOTIF-03 changes (new vs modified vs deleted event), the sync must compare old vs new state. The current sync has no "what changed" output.
- Recommendation: Add a `pushChangedEvents()` side-effect callback parameter to `syncCalendar` (or a post-sync query comparing `updatedAt` timestamps) that returns newly upserted/deleted events for push dispatch. Alternatively, use a DB trigger or a separate "last_seen_etag" comparison in the scheduler.
- **RESOLVED (Plan 05-07):** Add an `onChanges` side-effect callback parameter to `syncCalendar`, consumed by the poller (external changes) and the outbox resync (this-member writes). The syncing userId is the actor and is suppressed from its own notifications. No DB trigger.
2. **Should VAPID_PUBLIC_KEY be injected at build time (VITE_VAPID_PUBLIC_KEY) or fetched at runtime (GET /api/push/vapid-public-key)?**
- What we know: Build-time injection is simpler. Runtime fetch allows key rotation without rebuilds.
- What's unclear: How often VAPID keys will rotate in practice.
- Recommendation: Use GET /api/push/vapid-public-key endpoint (unauthenticated). Fetched once by usePushSubscription hook before subscribe. Cached in sessionStorage.
- **RESOLVED (Plan 05-04):** Runtime fetch via `GET /api/push/vapid-public-key` (unauthenticated). Fetched once by the usePushSubscription hook before subscribe. Enables key rotation without a PWA rebuild.
3. **Reminder deduplication strategy: column flag vs separate table?**
- What we know: The 1-min cron window approach risks double-firing for events at the window boundary.
- What's unclear: Whether a `sent_reminders` table is overkill for a two-person household.
- Recommendation: Add a `sentAt` timestamp column to calendarEvents for reminder tracking, or use a simple in-memory Set of `${eventUid}:${minuteBucket}` pairs per process (acceptable for single-process deployment per D-12).
- **RESOLVED (Plan 05-06):** In-memory `Set<${eventUid}:${minuteBucket}>` per process (acceptable for the single-process deployment, per D-12). No `sent_reminders` table. Tradeoff accepted: a process restart loses the dedup set, so a reminder could re-fire once after a restart that coincides with the 2-minute send window — tolerable for a two-person household.
---