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>
3.7 KiB
Calendar Specification
Job to Be Done
When I want to plan ahead, I want to view my cycle phases on a calendar, so that I can schedule training and rest days appropriately.
ICS Feed
Endpoint: GET /api/calendar/[userId]/[token].ics
Returns ICS calendar feed for subscription in external apps.
URL Format:
https://phaseflow.app/api/calendar/user123/abc123token.ics
Security:
tokenis a random 32-character secret per user- Token stored in
user.calendarToken - No authentication required (token IS authentication)
ICS Events
Generate events for the next 90 days:
Phase Events (all-day):
BEGIN:VEVENT
SUMMARY:🩸 Menstrual (Days 1-3)
DTSTART;VALUE=DATE:20240110
DTEND;VALUE=DATE:20240113
DESCRIPTION:Gentle rebounding only. Weekly limit: 30 min.
END:VEVENT
Color Coding (via categories):
- MENSTRUAL: Red
- FOLLICULAR: Green
- OVULATION: Pink
- EARLY_LUTEAL: Yellow
- LATE_LUTEAL: Orange
Token Regeneration
POST /api/calendar/regenerate-token
Generates new calendarToken, invalidating previous subscriptions.
Response:
{
"token": "newRandomToken123...",
"url": "https://phaseflow.app/api/calendar/user123/newRandomToken123.ics"
}
Period Logging Behavior
When a user logs a new period start date, the ICS feed updates as follows:
- Current cycle: Phase events are corrected retroactively to reflect actual dates
- Original predictions preserved: Previous predictions for the current cycle are kept as separate events with "(Predicted)" suffix, allowing users to compare predicted vs. actual
- Older cycles: Events from previous cycles remain unchanged
- Future cycles: Regenerated based on new period date and cycle length
Example after logging period on Day 28 of a predicted 31-day cycle:
BEGIN:VEVENT
SUMMARY:🩸 Menstrual (Days 1-3)
DTSTART;VALUE=DATE:20240128
DESCRIPTION:Actual period start
END:VEVENT
BEGIN:VEVENT
SUMMARY:🩸 Menstrual (Predicted)
DTSTART;VALUE=DATE:20240131
DESCRIPTION:Original prediction - period arrived 3 days early
END:VEVENT
This creates a built-in accuracy feedback loop for understanding cycle patterns.
In-App Calendar
Month View (/calendar)
Full-page calendar showing current month with phase visualization.
Components:
month-view.tsx- Main calendar gridday-cell.tsx- Individual day cell
Day Cell Contents:
- Date number
- Phase color background
- Period indicator (if day 1-3)
- Today highlight
- Training decision icon (for today only)
Navigation
- Previous/Next month buttons
- "Today" button to jump to current date
- Month/Year header
Phase Legend
Below calendar:
🩸 Menstrual | 🌱 Follicular | 🌸 Ovulation | 🌙 Early Luteal | 🌑 Late Luteal
ICS Utilities (src/lib/ics.ts)
Functions:
generateCalendarFeed(user, startDate, endDate)- Create ICS stringgeneratePhaseEvents(lastPeriodDate, cycleLength, range)- Create phase events
Dependencies:
icsnpm package for ICS generation
Success Criteria
- ICS feed subscribable in Google Calendar, Apple Calendar, Outlook
- Phase colors render correctly in calendar apps
- In-app calendar responsive on mobile
- Token regeneration immediately invalidates old URLs
Acceptance Tests
- ICS endpoint returns valid ICS format
- ICS contains events for next 90 days
- Invalid token returns 401
- Regenerate token creates new unique token
- Period log updates current cycle events retroactively
- Period log preserves original predictions as "(Predicted)" events
- Month view renders all days in month
- Day cells show correct phase colors
- Today is visually highlighted
- Navigation between months works
- Phase legend displays correctly