Document spec gaps: auth, phase scaling, observability, testing

Address 21 previously undefined behaviors across specs:

- Authentication: Replace email/password with OIDC (Pocket-ID)
- Cycle tracking: Add fixed-luteal phase scaling formula with examples
- Calendar: Document period logging behavior (preserve predictions)
- Garmin: Clarify connection is required (no phase-only mode)
- Dashboard: Add UI states, dark mode, onboarding, accessibility
- Notifications: Document timezone batching approach
- New specs: observability.md (health, metrics, logging)
- New specs: testing.md (unit + integration strategy)
- Main spec: Add backup/recovery, known limitations, API updates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 07:49:56 +00:00
parent 97a424e41d
commit 6a8d55c0b9
9 changed files with 596 additions and 29 deletions

View File

@@ -81,9 +81,28 @@ Protected by `CRON_SECRET` header.
### Timezone Handling
Users store preferred timezone (e.g., `America/New_York`).
Users are batched into hourly timezone windows for efficient scheduling.
Cron runs every hour. Check if current hour in user's timezone matches their `notificationTime`.
**Implementation:**
1. Cron job runs 24 times daily (once per hour, on the hour)
2. Each run queries users whose `notificationTime` hour matches the current UTC hour adjusted for their timezone
3. Users are processed in batches within their timezone window
**Example:**
- User A: timezone `America/New_York`, notificationTime `07:00`
- User B: timezone `America/Los_Angeles`, notificationTime `07:00`
- User C: timezone `Europe/London`, notificationTime `07:00`
When cron runs at 12:00 UTC:
- User A receives notification (12:00 UTC = 07:00 EST)
- User B skipped (12:00 UTC = 04:00 PST)
- User C skipped (12:00 UTC = 12:00 GMT)
**Query Logic:**
```sql
SELECT * FROM users
WHERE EXTRACT(HOUR FROM NOW() AT TIME ZONE timezone) = CAST(SUBSTRING(notificationTime, 1, 2) AS INT)
```
## Rate Limiting