# Cycle Tracking Specification ## Job to Be Done When I log my period start date, I want the app to calculate my current cycle day and phase, so that training and nutrition guidance is accurate. ## Core Concepts ### Cycle Day Day 1 = first day of menstruation. **Calculation:** ``` cycleDay = ((currentDate - lastPeriodDate) mod cycleLength) + 1 ``` Default cycle length: 31 days (configurable per user). ### Cycle Phases Phase boundaries scale based on cycle length using a **fixed luteal, variable follicular** approach. The luteal phase (14 days) is biologically consistent; the follicular phase expands or contracts with cycle length. **Phase Calculation Formula:** Given `cycleLength` (user-configurable, default 31): | Phase | Days | Weekly Limit | Training Type | |-------|------|--------------|---------------| | MENSTRUAL | 1-3 | 30 min | Gentle rebounding only | | FOLLICULAR | 4 to (cycleLength - 16) | 120 min | Strength + rebounding | | OVULATION | (cycleLength - 15) to (cycleLength - 14) | 80 min | Peak performance | | EARLY_LUTEAL | (cycleLength - 13) to (cycleLength - 7) | 100 min | Moderate training | | LATE_LUTEAL | (cycleLength - 6) to cycleLength | 50 min | Gentle rebounding ONLY | **Examples by Cycle Length:** | Phase | 28-day | 31-day | 35-day | |-------|--------|--------|--------| | MENSTRUAL | 1-3 | 1-3 | 1-3 | | FOLLICULAR | 4-12 | 4-15 | 4-19 | | OVULATION | 13-14 | 16-17 | 20-21 | | EARLY_LUTEAL | 15-21 | 18-24 | 22-28 | | LATE_LUTEAL | 22-28 | 25-31 | 29-35 | ## API Endpoints ### POST `/api/cycle/period` Log a new period start date. **Request Body:** ```json { "startDate": "2024-01-10" } ``` **Behavior:** 1. Update `user.lastPeriodDate` 2. Create `PeriodLog` record for history 3. Recalculate today's cycle day and phase ### GET `/api/cycle/current` Returns current cycle information. **Response:** ```json { "cycleDay": 12, "phase": "FOLLICULAR", "daysUntilNextPhase": 3, "phaseConfig": { "weeklyLimit": 120, "dailyAvg": 17, "trainingType": "Strength + rebounding" } } ``` ## Cycle Utilities (`src/lib/cycle.ts`) **Functions:** - `getCycleDay(lastPeriodDate, cycleLength, currentDate)` - Calculate day in cycle - `getPhase(cycleDay)` - Determine current phase - `getPhaseConfig(phase)` - Get phase configuration - `getPhaseLimit(phase)` - Get weekly intensity limit **Constants:** - `PHASE_CONFIGS` - Array of phase definitions ## Period History ### PeriodLog Schema ```typescript interface PeriodLog { id: string; user: string; startDate: Date; created: Date; } ``` ### History Display (`/history`) - List of all logged period dates - Calculated cycle lengths between periods - Average cycle length over time - Ability to edit/delete entries ## Configurable Cycle Length Users with irregular cycles can adjust: - Default: 31 days - Range: 21-45 days - Affects phase day boundaries per formula above ## Known Limitations The following scenarios are **out of scope** for MVP: - **Pregnancy** - Cycle tracking pauses; app not designed for pregnancy - **Menopause** - Irregular/absent cycles not supported - **Hormonal birth control** - May suppress or alter natural cycle phases - **Anovulatory cycles** - App assumes ovulation occurs; no detection for skipped ovulation Users in these situations should consult healthcare providers for personalized guidance. ## Success Criteria 1. Cycle day resets to 1 on period log 2. Phase transitions at correct day boundaries 3. Weekly limits adjust per phase automatically 4. History shows all logged periods ## Acceptance Tests - [ ] `getCycleDay` returns 1 on period start date - [ ] `getCycleDay` handles cycle rollover correctly - [ ] `getPhase` returns correct phase for each day range - [ ] `getPhase` scales correctly for 28-day cycle - [ ] `getPhase` scales correctly for 35-day cycle - [ ] POST `/api/cycle/period` updates user record - [ ] GET `/api/cycle/current` returns accurate phase info - [ ] Days beyond cycle length default to LATE_LUTEAL