style(13-03): apply Prettier formatting across repo

Mechanical reformat — no logic changes. 398 files changed, 19125
insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc
(singleQuote:true, semi:true, tabWidth:2, trailingComma:all,
printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
Lucas Berger
2026-06-11 20:35:18 -04:00
parent 4bc0445173
commit 982438dc10
398 changed files with 19050 additions and 16382 deletions
@@ -14,24 +14,24 @@ requirements: [NOTIF-01]
must_haves:
truths:
- "Every minute the scheduler scans for SHARED (isShared=true) TIMED (allDay=false) events whose dtstartUtc is in [now+14min, now+16min] and dispatches a reminder to ALL members' subscriptions (NOTIF-01, D-05/D-06)"
- "All-day events get no reminder (D-07); non-shared events get no reminder (D-05)"
- "The same (eventUid, minuteBucket) never fires twice — in-memory dedup Set prevents the window-boundary double-fire (RESEARCH Pitfall 5 / Open Question 3)"
- 'All-day events get no reminder (D-07); non-shared events get no reminder (D-05)'
- 'The same (eventUid, minuteBucket) never fires twice — in-memory dedup Set prevents the window-boundary double-fire (RESEARCH Pitfall 5 / Open Question 3)'
- "Reminder copy uses the event title: title '{EventTitle}', body 'Starts in 15 min' (D-02, depends on calendar_events.title)"
- "An empty shared-calendar set (Family calendar not yet created per D-16) produces zero sends and no crash"
- 'An empty shared-calendar set (Family calendar not yet created per D-16) produces zero sends and no crash'
artifacts:
- path: "apps/api/src/broker/reminderScheduler.ts"
provides: "startReminderScheduler() + runReminderCheck() — node-cron 1-min shared-timed-event scan + dispatch"
exports: ["startReminderScheduler", "runReminderCheck"]
- path: 'apps/api/src/broker/reminderScheduler.ts'
provides: 'startReminderScheduler() + runReminderCheck() — node-cron 1-min shared-timed-event scan + dispatch'
exports: ['startReminderScheduler', 'runReminderCheck']
min_lines: 40
key_links:
- from: "apps/api/src/broker/reminderScheduler.ts"
to: "apps/api/src/lib/pushDispatcher.ts"
via: "dispatchPush per subscription for each due shared timed event"
pattern: "dispatchPush"
- from: "apps/api/src/index.ts"
to: "startReminderScheduler"
via: "isMainModule startup guard"
pattern: "startReminderScheduler"
- from: 'apps/api/src/broker/reminderScheduler.ts'
to: 'apps/api/src/lib/pushDispatcher.ts'
via: 'dispatchPush per subscription for each due shared timed event'
pattern: 'dispatchPush'
- from: 'apps/api/src/index.ts'
to: 'startReminderScheduler'
via: 'isMainModule startup guard'
pattern: 'startReminderScheduler'
---
<objective>
@@ -86,19 +86,21 @@ Output: reminderScheduler.ts (startReminderScheduler + runReminderCheck) wired i
</feature>
<threat_model>
## Trust Boundaries
| Boundary | Description |
|----------|-------------|
| Boundary | Description |
| ------------------------------ | -------------------------------------------------------------------- |
| reminder query → push audience | reminder eligibility is decided by the SQL WHERE, not by any request |
## STRIDE Threat Register
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|-----------|----------|-----------|-------------|-----------------|
| T-05-17 | Information Disclosure | reminder leaking a personal-calendar event | mitigate | D-05 enforced in the QUERY: WHERE calendars.isShared = true — personal events are never selected, not merely hidden in copy |
| T-05-18 | Denial of Service | duplicate reminder storm at window boundary | mitigate | in-memory dedup Set keyed (uid, minuteBucket); per-event try/catch isolates failures |
| T-05-19 | Denial of Service | one bad subscription aborting the cycle | mitigate | per-subscription try/catch; dispatchPush already swallows + prunes 410/404 |
| Threat ID | Category | Component | Disposition | Mitigation Plan |
| --------- | ---------------------- | ------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------- |
| T-05-17 | Information Disclosure | reminder leaking a personal-calendar event | mitigate | D-05 enforced in the QUERY: WHERE calendars.isShared = true — personal events are never selected, not merely hidden in copy |
| T-05-18 | Denial of Service | duplicate reminder storm at window boundary | mitigate | in-memory dedup Set keyed (uid, minuteBucket); per-event try/catch isolates failures |
| T-05-19 | Denial of Service | one bad subscription aborting the cycle | mitigate | per-subscription try/catch; dispatchPush already swallows + prunes 410/404 |
</threat_model>
<verification>
@@ -108,10 +110,11 @@ Output: reminderScheduler.ts (startReminderScheduler + runReminderCheck) wired i
</verification>
<success_criteria>
- Failing test committed (RED).
- runReminderCheck + startReminderScheduler implemented; test passes (GREEN).
- D-05 shared-only (query-enforced), D-07 all-day-excluded, dedup, empty-set no-op, title fallback all verified.
</success_criteria>
</success_criteria>
<output>
Create `.planning/phases/05-web-push-notifications/05-06-SUMMARY.md` with RED/GREEN commits.