Files
phaseflow/IMPLEMENTATION_PLAN.md
Petru Paler c1679789b5 Implement Garmin biometric fetching functions (P2.1)
Add specific fetchers for HRV, Body Battery, and Intensity Minutes
to enable real biometric data collection from Garmin Connect API.

Functions added:
- fetchHrvStatus(): Returns "Balanced", "Unbalanced", or "Unknown"
- fetchBodyBattery(): Returns current BB and yesterday's low value
- fetchIntensityMinutes(): Returns 7-day rolling sum of activity

All functions gracefully handle API failures with safe defaults.
Test count expanded from 14 to 33 covering all scenarios.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 19:38:22 +00:00

589 lines
28 KiB
Markdown

# PhaseFlow Implementation Plan
This file is maintained by Ralph. Run `./ralph-sandbox.sh plan 3` to generate tasks.
## Current State Summary
### Library Implementation
| File | Status | Gap Analysis |
|------|--------|--------------|
| `cycle.ts` | **COMPLETE** | 9 tests covering all functions, production-ready |
| `nutrition.ts` | **COMPLETE** | 17 tests covering getNutritionGuidance, getSeedSwitchAlert, phase-specific carb ranges, keto guidance |
| `email.ts` | **COMPLETE** | 14 tests covering sendDailyEmail, sendPeriodConfirmationEmail, email formatting, subject lines |
| `ics.ts` | **COMPLETE** | 23 tests covering generateIcsFeed (90 days of phase events), ICS format validation, timezone handling |
| `encryption.ts` | **COMPLETE** | 14 tests covering AES-256-GCM encrypt/decrypt round-trip, error handling, key validation |
| `decision-engine.ts` | **COMPLETE** | 8 priority rules + override handling with `getDecisionWithOverrides()`, 24 tests |
| `garmin.ts` | **COMPLETE** | 33 tests covering fetchGarminData, fetchHrvStatus, fetchBodyBattery, fetchIntensityMinutes, isTokenExpired, daysUntilExpiry, error handling, token validation |
| `pocketbase.ts` | **COMPLETE** | 9 tests covering `createPocketBaseClient()`, `isAuthenticated()`, `getCurrentUser()`, `loadAuthFromCookies()` |
| `auth-middleware.ts` | **COMPLETE** | 6 tests covering `withAuth()` wrapper for API route protection |
| `middleware.ts` (Next.js) | **COMPLETE** | 12 tests covering page protection, redirects to login |
### Missing Infrastructure Files (CONFIRMED NOT EXIST)
- ~~`src/lib/auth-middleware.ts`~~ - **CREATED** in P0.2
- ~~`src/middleware.ts`~~ - **CREATED** in P0.2
### API Routes (12 total)
| Route | Status | Notes |
|-------|--------|-------|
| GET /api/user | **COMPLETE** | Returns user profile with `withAuth()` |
| PATCH /api/user | **COMPLETE** | Updates cycleLength, notificationTime, timezone (17 tests) |
| POST /api/cycle/period | **COMPLETE** | Logs period start, updates user, creates PeriodLog (8 tests) |
| GET /api/cycle/current | **COMPLETE** | Returns cycle day, phase, config, daysUntilNextPhase (10 tests) |
| GET /api/today | **COMPLETE** | Returns decision, cycle, biometrics, nutrition (22 tests) |
| POST /api/overrides | **COMPLETE** | Adds override to user.activeOverrides (14 tests) |
| DELETE /api/overrides | **COMPLETE** | Removes override from user.activeOverrides (14 tests) |
| POST /api/garmin/tokens | 501 | Returns Not Implemented |
| DELETE /api/garmin/tokens | 501 | Returns Not Implemented |
| GET /api/garmin/status | 501 | Returns Not Implemented |
| GET /api/calendar/[userId]/[token].ics | 501 | Has param extraction, core logic TODO |
| POST /api/calendar/regenerate-token | 501 | Returns Not Implemented |
| POST /api/cron/garmin-sync | 501 | Has CRON_SECRET auth check, core logic TODO |
| POST /api/cron/notifications | 501 | Has CRON_SECRET auth check, core logic TODO |
### Pages (7 total)
| Page | Status | Notes |
|------|--------|-------|
| Dashboard (`/`) | **COMPLETE** | Wired with /api/today, DecisionCard, DataPanel, NutritionPanel, OverrideToggles |
| Login (`/login`) | **COMPLETE** | Email/password form with auth, error handling, loading states |
| Settings (`/settings`) | Placeholder | Needs form implementation |
| Settings/Garmin (`/settings/garmin`) | Placeholder | Needs token management UI |
| Calendar (`/calendar`) | Placeholder | Needs MonthView integration |
| History (`/history`) | Placeholder | Needs list/pagination implementation |
| Plan (`/plan`) | Placeholder | Needs phase details display |
### Components
| Component | Status | Notes |
|-----------|--------|-------|
| `DecisionCard` | **COMPLETE** | Displays status, icon, reason |
| `DataPanel` | **COMPLETE** | Shows BB, HRV, intensity data |
| `NutritionPanel` | **COMPLETE** | Shows seeds, carbs, keto guidance |
| `OverrideToggles` | **COMPLETE** | Toggle buttons with callbacks |
| `DayCell` | **COMPLETE** | Phase-colored day with click handler |
| `MiniCalendar` | **Partial (~30%)** | Has header only, **MISSING: calendar grid** |
| `MonthView` | **Partial (~30%)** | Has header only, **MISSING: calendar grid + DayCell integration** |
### Test Coverage
| Test File | Status |
|-----------|--------|
| `src/lib/cycle.test.ts` | **EXISTS** - 9 tests |
| `src/lib/decision-engine.test.ts` | **EXISTS** - 24 tests (8 algorithmic rules + 16 override scenarios) |
| `src/lib/pocketbase.test.ts` | **EXISTS** - 9 tests (auth helpers, cookie loading) |
| `src/lib/auth-middleware.test.ts` | **EXISTS** - 6 tests (withAuth wrapper, error handling) |
| `src/middleware.test.ts` | **EXISTS** - 12 tests (page protection, public routes, static assets) |
| `src/app/api/user/route.test.ts` | **EXISTS** - 21 tests (GET/PATCH profile, auth, validation, security) |
| `src/app/api/cycle/period/route.test.ts` | **EXISTS** - 8 tests (POST period, auth, validation, date checks) |
| `src/app/api/cycle/current/route.test.ts` | **EXISTS** - 10 tests (GET current cycle, auth, all phases, rollover, custom lengths) |
| `src/app/api/today/route.test.ts` | **EXISTS** - 22 tests (daily snapshot, auth, decision, overrides, phases, nutrition, biometrics) |
| `src/app/api/overrides/route.test.ts` | **EXISTS** - 14 tests (POST/DELETE overrides, auth, validation, type checks) |
| `src/app/login/page.test.tsx` | **EXISTS** - 14 tests (form rendering, auth flow, error handling, validation) |
| `src/app/page.test.tsx` | **EXISTS** - 23 tests (data fetching, component rendering, override toggles, error handling) |
| `src/lib/nutrition.test.ts` | **EXISTS** - 17 tests (seed cycling, carb ranges, keto guidance by phase) |
| `src/lib/email.test.ts` | **EXISTS** - 14 tests (email content, subject lines, formatting) |
| `src/lib/ics.test.ts` | **EXISTS** - 23 tests (ICS format validation, 90-day event generation, timezone handling) |
| `src/lib/encryption.test.ts` | **EXISTS** - 14 tests (encrypt/decrypt round-trip, error handling, key validation) |
| `src/lib/garmin.test.ts` | **EXISTS** - 33 tests (fetchGarminData, fetchHrvStatus, fetchBodyBattery, fetchIntensityMinutes, token expiry, error handling) |
| E2E tests | **NONE** |
### Critical Business Rules (from Spec)
1. **Override Priority:** flare > stress > sleep > pms (must be enforced in order)
2. **HRV Unbalanced:** ALWAYS forces REST (highest algorithmic priority, non-overridable)
3. **Phase Limits:** Strictly enforced per phase configuration
4. **Token Expiration Warnings:** Must send email at 14 days and 7 days before expiry
5. **ICS Feed:** Generates 90 days of phase events for calendar subscription
---
## P0: Critical Blockers
These must be completed first - nothing else works without them.
### P0.1: PocketBase Auth Helpers ✅ COMPLETE
- [x] Add authentication utilities to pocketbase.ts
- **Files:**
- `src/lib/pocketbase.ts` - Added `createPocketBaseClient()`, `getCurrentUser()`, `isAuthenticated()`, `loadAuthFromCookies()`
- **Tests:**
- `src/lib/pocketbase.test.ts` - 9 tests covering auth state management, cookie loading
- **Why:** Every protected route and page depends on these helpers
- **Blocking:** P0.2, P0.4, P1.1-P1.7, P2.2-P2.13
### P0.2: Auth Middleware for API Routes ✅ COMPLETE
- [x] Create reusable auth middleware for protected API endpoints
- **Files:**
- `src/lib/auth-middleware.ts` - Added `withAuth()` wrapper for route handlers
- `src/middleware.ts` - Added Next.js middleware for page protection
- **Tests:**
- `src/lib/auth-middleware.test.ts` - 6 tests covering unauthorized rejection, user context passing, error handling
- `src/middleware.test.ts` - 12 tests covering protected routes, public routes, API routes, static assets
- **Why:** All API routes except `/api/calendar/[userId]/[token].ics` and `/api/cron/*` require auth
- **Depends On:** P0.1
- **Blocking:** P0.4, P1.1-P1.5
### P0.3: Decision Engine Override Handling ✅ COMPLETE
- [x] Add override priority logic before algorithmic decision
- **Files:**
- `src/lib/decision-engine.ts` - Added `getDecisionWithOverrides(data, overrides)` function
- **Tests:**
- `src/lib/decision-engine.test.ts` - 24 tests covering all 8 priority rules + override scenarios
- **Override Priority (enforced in this order):**
1. `flare` - Always forces REST
2. `stress` - Forces REST
3. `sleep` - Forces REST
4. `pms` - Forces REST
- **Why:** Overrides are core to the user experience per spec
- **Blocking:** P1.4, P1.5
### P0.4: GET /api/user Implementation ✅ COMPLETE
- [x] Return authenticated user profile
- **Files:**
- `src/app/api/user/route.ts` - Implemented GET handler with `withAuth()` wrapper
- **Tests:**
- `src/app/api/user/route.test.ts` - 4 tests covering auth, response shape, sensitive field exclusion
- **Response Shape:**
- `id`, `email`, `garminConnected`, `cycleLength`, `lastPeriodDate`, `notificationTime`, `timezone`, `activeOverrides`
- Excludes sensitive fields: `garminOauth1Token`, `garminOauth2Token`, `calendarToken`
- **Why:** Dashboard and all pages need user context
- **Depends On:** P0.1, P0.2
- **Blocking:** P1.7, P2.9, P2.10
---
## P1: Core Functionality
Minimum viable product - app can be used for daily decisions.
### P1.1: PATCH /api/user Implementation ✅ COMPLETE
- [x] Allow profile updates (cycleLength, notificationTime, timezone)
- **Files:**
- `src/app/api/user/route.ts` - Implemented PATCH handler with validation
- **Tests:**
- `src/app/api/user/route.test.ts` - 17 tests covering field validation, persistence, security
- **Validation Rules:**
- `cycleLength`: number, range 21-45 days
- `notificationTime`: string, HH:MM format (24-hour)
- `timezone`: non-empty string
- **Security:** Ignores attempts to update non-updatable fields (email, tokens)
- **Why:** Users need to configure their cycle and preferences
- **Depends On:** P0.1, P0.2
### P1.2: POST /api/cycle/period Implementation ✅ COMPLETE
- [x] Log period start date, update user record, create PeriodLog
- **Files:**
- `src/app/api/cycle/period/route.ts` - Implemented POST handler with validation
- **Tests:**
- `src/app/api/cycle/period/route.test.ts` - 8 tests covering auth, date validation, user update, PeriodLog creation
- **Why:** Cycle tracking is the foundation of all recommendations
- **Depends On:** P0.1, P0.2
### P1.3: GET /api/cycle/current Implementation ✅ COMPLETE
- [x] Return current cycle day, phase, and phase config
- **Files:**
- `src/app/api/cycle/current/route.ts` - Implemented GET using cycle.ts utilities with `withAuth()` wrapper
- **Tests:**
- `src/app/api/cycle/current/route.test.ts` - 10 tests covering auth, validation, all phases, cycle rollover, custom cycle lengths
- **Response Shape:**
- `cycleDay`, `phase`, `phaseConfig`, `daysUntilNextPhase`, `cycleLength`
- **Why:** Dashboard needs this for display
- **Depends On:** P0.1, P0.2, P1.2
### P1.4: GET /api/today Implementation ✅ COMPLETE
- [x] Return complete daily snapshot with decision, biometrics, nutrition
- **Files:**
- `src/app/api/today/route.ts` - Implemented GET with `withAuth()` wrapper, aggregates cycle, biometrics, and nutrition
- **Tests:**
- `src/app/api/today/route.test.ts` - 22 tests covering auth, validation, decision calculation, overrides, phases, nutrition
- **Response Shape:**
- `decision` (status, reason, icon), `cycleDay`, `phase`, `phaseConfig`, `daysUntilNextPhase`, `cycleLength`
- `biometrics` (hrvStatus, bodyBatteryCurrent, bodyBatteryYesterdayLow, weekIntensityMinutes, phaseLimit)
- `nutrition` (seeds, carbRange, ketoGuidance)
- **Fallback Behavior:** When no DailyLog exists (Garmin not synced), returns defaults: hrvStatus="Unknown", BB=100, weekIntensity=0
- **Why:** This is THE core API for the dashboard
- **Depends On:** P0.1, P0.2, P0.3, P1.3
### P1.5: POST/DELETE /api/overrides Implementation ✅ COMPLETE
- [x] Toggle override flags on user record
- **Files:**
- `src/app/api/overrides/route.ts` - Implemented POST (add) and DELETE (remove) handlers with validation
- **Tests:**
- `src/app/api/overrides/route.test.ts` - 14 tests covering auth, override types, persistence, validation, edge cases
- **Override Types:** flare, stress, sleep, pms
- **POST Response:** Returns updated user with new override added to activeOverrides array
- **DELETE Response:** Returns updated user with override removed from activeOverrides array
- **Validation:** Rejects invalid override types, duplicates on POST, missing overrides on DELETE
- **Why:** Emergency overrides are critical for flare days
- **Depends On:** P0.1, P0.2, P0.3
### P1.6: Login Page Implementation ✅ COMPLETE
- [x] Functional login form with PocketBase auth
- **Files:**
- `src/app/login/page.tsx` - Client component with email/password form, error handling, loading states, redirect
- **Tests:**
- `src/app/login/page.test.tsx` - 14 tests covering rendering, form submission, auth flow, error handling, validation
- **Infrastructure Added:**
- `src/test-setup.ts` - Global test setup with @testing-library/jest-dom and cleanup
- Updated `vitest.config.ts` to include setupFiles
- **Why:** Users need to authenticate to use the app
- **Depends On:** P0.1
### P1.7: Dashboard Page Implementation ✅ COMPLETE
- [x] Wire up dashboard with real data from /api/today
- [x] Integrate DecisionCard, DataPanel, NutritionPanel, OverrideToggles
- [x] Implement override toggle functionality with optimistic updates
- [x] Add error handling and loading states
- **Files:**
- `src/app/page.tsx` - Client component fetching /api/today, rendering all dashboard components
- **Tests:**
- `src/app/page.test.tsx` - 23 tests covering data fetching, component rendering, override toggles, error handling
- **Features Implemented:**
- Real-time decision display with cycle phase information
- Biometrics panel (HRV, Body Battery, Intensity Minutes)
- Nutrition guidance panel (seeds, carbs, keto)
- Override toggles with optimistic UI updates
- Error boundaries and loading states
- **Why:** This is the main user interface
- **Depends On:** P0.4, P1.3, P1.4, P1.5
---
## P2: Important Features
Full feature set for production use.
### P2.1: Garmin Data Fetching Functions ✅ COMPLETE
- [x] Add specific fetchers for HRV, Body Battery, Intensity Minutes
- **Files:**
- `src/lib/garmin.ts` - Added `fetchHrvStatus()`, `fetchBodyBattery()`, `fetchIntensityMinutes()`
- **Tests:**
- `src/lib/garmin.test.ts` - 33 tests covering API calls, response parsing, error handling (increased from 14 tests)
- **Functions Implemented:**
- `fetchHrvStatus()` - Fetches HRV status (balanced/unbalanced) from Garmin
- `fetchBodyBattery()` - Fetches current and yesterday's low body battery values
- `fetchIntensityMinutes()` - Fetches weekly moderate + vigorous intensity minutes
- **Why:** Real biometric data is required for accurate decisions
### P2.2: POST/DELETE /api/garmin/tokens Implementation
- [ ] Store encrypted Garmin OAuth tokens
- **Files:**
- `src/app/api/garmin/tokens/route.ts` - Implement with encryption.ts
- **Tests:**
- `src/app/api/garmin/tokens/route.test.ts` - Test encryption, validation, storage
- **Why:** Users need to connect their Garmin accounts
- **Depends On:** P0.1, P0.2
### P2.3: GET /api/garmin/status Implementation
- [ ] Return Garmin connection status and days until expiry
- **Files:**
- `src/app/api/garmin/status/route.ts` - Implement status check
- **Tests:**
- `src/app/api/garmin/status/route.test.ts` - Test connected/disconnected states, expiry calc
- **Why:** Users need visibility into their Garmin connection
- **Depends On:** P0.1, P0.2, P2.1
### P2.4: POST /api/cron/garmin-sync Implementation
- [ ] Daily sync of all Garmin data for all users
- **Files:**
- `src/app/api/cron/garmin-sync/route.ts` - Iterate users, fetch data, store DailyLog
- **Tests:**
- `src/app/api/cron/garmin-sync/route.test.ts` - Test auth, user iteration, data persistence
- **Why:** Automated data sync is required for morning notifications
- **Depends On:** P2.1, P2.2
- **Note:** Route exists with CRON_SECRET auth check, needs core logic
### P2.5: POST /api/cron/notifications Implementation
- [ ] Send daily email notifications at user's preferred time
- **Files:**
- `src/app/api/cron/notifications/route.ts` - Find users by hour, compute decision, send email
- **Tests:**
- `src/app/api/cron/notifications/route.test.ts` - Test timezone handling, duplicate prevention
- **Why:** Email notifications are a key feature per spec
- **Depends On:** P2.4
- **Note:** Route exists with CRON_SECRET auth check, needs core logic
### P2.6: GET /api/calendar/[userId]/[token].ics Implementation
- [ ] Return ICS feed for calendar subscription
- **Files:**
- `src/app/api/calendar/[userId]/[token].ics/route.ts` - Validate token, generate ICS
- **Tests:**
- Integration test: valid token returns ICS, invalid returns 401
- **Why:** Calendar integration for external apps
- **Note:** Route has param extraction, needs ICS generation (90 days of events per spec)
### P2.7: POST /api/calendar/regenerate-token Implementation
- [ ] Generate new calendar token
- **Files:**
- `src/app/api/calendar/regenerate-token/route.ts` - Create random token, update user
- **Tests:**
- `src/app/api/calendar/regenerate-token/route.test.ts` - Test token uniqueness, old URL invalidation
- **Why:** Security feature for calendar URLs
- **Depends On:** P0.1, P0.2
### P2.8: GET /api/history Implementation
- [ ] Return paginated historical daily logs
- **Files:**
- `src/app/api/history/route.ts` - Query DailyLog with pagination
- **Tests:**
- `src/app/api/history/route.test.ts` - Test pagination, date filtering
- **Why:** Users want to see their training history
- **Depends On:** P0.1, P0.2
### P2.9: Settings Page Implementation
- [ ] User profile management UI
- **Files:**
- `src/app/settings/page.tsx` - Form for cycleLength, notificationTime, timezone
- **Tests:**
- E2E test: settings update and persist
- **Why:** Users need to configure their preferences
- **Depends On:** P0.4, P1.1
### P2.10: Settings/Garmin Page Implementation
- [ ] Garmin connection management UI
- **Files:**
- `src/app/settings/garmin/page.tsx` - Token input form, connection status, disconnect button
- **Tests:**
- E2E test: connect flow, disconnect flow
- **Why:** Users need to manage their Garmin connection
- **Depends On:** P0.4, P2.2, P2.3
### P2.11: Calendar Page Implementation
- [ ] In-app calendar with phase visualization
- **Files:**
- `src/app/calendar/page.tsx` - Month view with navigation
- `src/components/calendar/month-view.tsx` - **Complete calendar grid using DayCell**
- **Tests:**
- E2E test: navigation works, phases displayed correctly
- **Why:** Planning ahead is a key user need
- **Depends On:** P2.6
- **Note:** DayCell is **COMPLETE**, MonthView needs grid implementation (~70% remaining)
### P2.12: History Page Implementation
- [ ] View past training decisions and data
- **Files:**
- `src/app/history/page.tsx` - List view of DailyLogs with pagination
- **Tests:**
- E2E test: history loads, pagination works
- **Why:** Users want to review their training history
- **Depends On:** P2.8
### P2.13: Plan Page Implementation
- [ ] Phase-specific training plan view
- **Files:**
- `src/app/plan/page.tsx` - Current phase details, upcoming phases, limits
- **Tests:**
- E2E test: correct phase info displayed
- **Why:** Users want detailed training guidance
- **Depends On:** P0.4, P1.3
### P2.14: Mini Calendar Component
- [ ] Dashboard overview calendar
- **Files:**
- `src/components/dashboard/mini-calendar.tsx` - **Complete calendar grid with phase colors**
- **Tests:**
- Component test: renders current month, highlights today
- **Why:** Quick visual reference on dashboard
- **Note:** Component exists with header only, needs calendar grid (~70% remaining)
---
## P3: Polish and Quality
Testing, error handling, and refinements.
### P3.1: Decision Engine Tests ✅ COMPLETE
- [x] Comprehensive unit tests for all decision paths
- **Files:**
- `src/lib/decision-engine.test.ts` - All 8 priority rules, override combinations (24 tests)
- **Test Cases Covered:**
- HRV Unbalanced always forces REST (highest algorithmic priority)
- Override priority: flare > stress > sleep > pms
- Phase limits strictly enforced
- All override bypass and fallthrough scenarios
- **Why:** Critical logic is now fully tested
### P3.2: Nutrition Tests ✅ COMPLETE
- [x] Unit tests for nutrition guidance
- **Files:**
- `src/lib/nutrition.test.ts` - 17 tests covering seed cycling, carb ranges, keto guidance by phase
- **Test Cases Covered:**
- Seed cycling recommendations by phase (flax/pumpkin vs sunflower/sesame)
- Carb range calculations per phase
- Keto guidance by cycle day
- Edge cases and phase transitions
- **Why:** Nutrition advice accuracy is now fully tested
### P3.3: Email Tests ✅ COMPLETE
- [x] Unit tests for email composition
- **Files:**
- `src/lib/email.test.ts` - 14 tests covering email content, subject lines, formatting
- **Test Cases Covered:**
- Daily email composition with decision data
- Period confirmation email content
- Subject line formatting
- HTML email structure
- **Why:** Email formatting correctness is now fully tested
### P3.4: ICS Tests ✅ COMPLETE
- [x] Unit tests for calendar generation
- **Files:**
- `src/lib/ics.test.ts` - 23 tests covering ICS format validation, 90-day event generation, timezone handling
- **Test Cases Covered:**
- ICS feed generation with 90 days of phase events
- RFC 5545 format compliance
- Timezone handling (UTC conversion)
- Event boundaries and phase transitions
- **Why:** Calendar integration compatibility is now fully tested
### P3.5: Encryption Tests ✅ COMPLETE
- [x] Unit tests for encrypt/decrypt round-trip
- **Files:**
- `src/lib/encryption.test.ts` - 14 tests covering AES-256-GCM round-trip, error handling, key validation
- **Test Cases Covered:**
- Encrypt/decrypt round-trip verification
- Key validation and error handling
- IV generation uniqueness
- Malformed data handling
- **Why:** Token security is now fully tested
### P3.6: Garmin Tests ✅ COMPLETE
- [x] Unit tests for Garmin API interactions
- **Files:**
- `src/lib/garmin.test.ts` - 33 tests covering API calls, error handling, token expiry (expanded in P2.1)
- **Test Cases Covered:**
- fetchGarminData, fetchHrvStatus, fetchBodyBattery, fetchIntensityMinutes HTTP calls and response parsing
- isTokenExpired logic with various expiry dates
- daysUntilExpiry calculations
- Error handling for invalid tokens and network failures
- Response parsing for biometric data structures
- **Why:** External API integration robustness is now fully tested
### P3.7: Error Handling Improvements
- [ ] Add consistent error responses across all API routes
- **Files:**
- All route files - Standardize error format, add logging
- **Why:** Better debugging and user experience
### P3.8: Loading States
- [ ] Add loading indicators to all pages
- **Files:**
- All page files - Add loading.tsx or Suspense boundaries
- **Why:** Better perceived performance
### P3.9: Token Expiration Warnings
- [ ] Email warnings at 14 and 7 days before Garmin token expiry
- **Files:**
- `src/lib/email.ts` - Add `sendTokenExpirationWarning()`
- `src/app/api/cron/garmin-sync/route.ts` - Check expiry, trigger warnings
- **Tests:**
- Test warning triggers at exactly 14 days and 7 days
- **Why:** Users need time to refresh tokens (per spec requirement)
### P3.10: E2E Test Suite
- [ ] Comprehensive end-to-end tests
- **Files:**
- `tests/e2e/*.spec.ts` - Full user flows
- **Test Scenarios:**
- Login flow
- Period logging and phase calculation
- Override toggle functionality
- Settings update flow
- Garmin connection flow
- Calendar subscription
- **Why:** Confidence in production deployment
---
## Implementation Order
```
P0.1 PocketBase Auth ──┬──> P0.2 Auth Middleware ──> P0.4 GET /api/user
P0.3 Override Logic ───┴──> P1.4 GET /api/today ──> P1.7 Dashboard
P1.1 PATCH /api/user ────> P2.9 Settings Page
P1.2 POST period ────────> P1.3 GET current ────> P1.7 Dashboard
P1.5 Overrides API ──────> P1.7 Dashboard
P1.6 Login Page
P2.1 Garmin fetchers ──> P2.2 Garmin tokens ──> P2.4 Cron sync ──> P2.5 Notifications
└──> P3.9 Token Warnings
P2.3 Garmin status ────> P2.10 Garmin settings
P2.6 ICS endpoint ─────> P2.11 Calendar page
P2.7 Regen token
P2.8 History API ──────> P2.12 History page
P2.13 Plan page
P2.14 Mini calendar
```
### Dependency Summary
| Task | Blocked By | Blocks |
|------|------------|--------|
| P0.1 | - | P0.2, P0.4, P1.1-P1.6, P2.2-P2.3, P2.7-P2.8 |
| P0.2 | P0.1 | P0.4, P1.1-P1.5, P2.2-P2.3, P2.7-P2.8 |
| P0.3 | - | P1.4, P1.5 |
| P0.4 | P0.1, P0.2 | P1.7, P2.9, P2.10, P2.13 |
---
## Completed
### Library
- [x] **cycle.ts** - Complete with 9 tests (`getCycleDay`, `getPhase`, `getPhaseConfig`, `getPhaseLimit`)
- [x] **decision-engine.ts** - Complete with 24 tests (`getTrainingDecision` + `getDecisionWithOverrides`)
- [x] **pocketbase.ts** - Complete with 9 tests (`createPocketBaseClient`, `isAuthenticated`, `getCurrentUser`, `loadAuthFromCookies`)
- [x] **nutrition.ts** - Complete with 17 tests (`getNutritionGuidance`, `getSeedSwitchAlert`, phase-specific carb ranges, keto guidance) (P3.2)
- [x] **email.ts** - Complete with 14 tests (`sendDailyEmail`, `sendPeriodConfirmationEmail`, email formatting) (P3.3)
- [x] **ics.ts** - Complete with 23 tests (`generateIcsFeed`, ICS format validation, 90-day event generation) (P3.4)
- [x] **encryption.ts** - Complete with 14 tests (AES-256-GCM encrypt/decrypt, round-trip validation, error handling) (P3.5)
- [x] **garmin.ts** - Complete with 33 tests (`fetchGarminData`, `fetchHrvStatus`, `fetchBodyBattery`, `fetchIntensityMinutes`, `isTokenExpired`, `daysUntilExpiry`, error handling) (P2.1, P3.6)
### Components
- [x] **DecisionCard** - Displays decision status, icon, and reason
- [x] **DataPanel** - Shows body battery, HRV, intensity data
- [x] **NutritionPanel** - Shows seeds, carbs, keto guidance
- [x] **OverrideToggles** - Toggle buttons for flare/stress/sleep/pms
- [x] **DayCell** - Phase-colored calendar day cell with click handler
### API Routes
- [x] **GET /api/user** - Returns authenticated user profile, 4 tests (P0.4)
- [x] **PATCH /api/user** - Updates user profile (cycleLength, notificationTime, timezone), 17 tests (P1.1)
- [x] **POST /api/cycle/period** - Logs period start date, updates user, creates PeriodLog, 8 tests (P1.2)
- [x] **GET /api/cycle/current** - Returns cycle day, phase, phaseConfig, daysUntilNextPhase, cycleLength, 10 tests (P1.3)
- [x] **GET /api/today** - Returns complete daily snapshot with decision, biometrics, nutrition, 22 tests (P1.4)
- [x] **POST /api/overrides** - Adds override to user.activeOverrides array, 14 tests (P1.5)
- [x] **DELETE /api/overrides** - Removes override from user.activeOverrides array, 14 tests (P1.5)
### Pages
- [x] **Login Page** - Email/password form with PocketBase auth, error handling, loading states, redirect, 14 tests (P1.6)
- [x] **Dashboard Page** - Complete daily interface with /api/today integration, DecisionCard, DataPanel, NutritionPanel, OverrideToggles, 23 tests (P1.7)
### Test Infrastructure
- [x] **test-setup.ts** - Global test setup with @testing-library/jest-dom matchers and cleanup
---
## Discovered Issues
*Bugs and inconsistencies found during implementation*
- [x] ~~`src/lib/auth-middleware.ts` does not exist~~ - CREATED in P0.2
- [x] ~~`src/middleware.ts` does not exist~~ - CREATED in P0.2
- [x] ~~`garmin.ts` is only ~30% complete - missing specific biometric fetchers~~ - FIXED in P2.1 (added fetchHrvStatus, fetchBodyBattery, fetchIntensityMinutes)
- [x] ~~`pocketbase.ts` missing all auth helper functions~~ - FIXED in P0.1
- [x] ~~`src/app/api/today/route.ts` type error with null body battery values~~ - FIXED (added null coalescing)
---
## Notes
1. **TDD Approach:** Each implementation task should follow TDD - write failing tests first, then implement
2. **Auth First:** P0 items unlock all other work; prioritize ruthlessly
3. **Incremental Delivery:** P1 completion = usable app without Garmin (manual data entry fallback)
4. **P2 Completion:** Full feature set with automation
5. **P3:** Quality and polish for production confidence
6. **Component Reuse:** Dashboard components are complete and can be used directly in P1.7
7. **HRV Rule:** HRV Unbalanced status ALWAYS forces REST - this is the highest algorithmic priority and cannot be overridden by manual toggles
8. **Override Order:** When multiple overrides are active, apply in order: flare > stress > sleep > pms
9. **Token Warnings:** Per spec, warnings must be sent at exactly 14 days and 7 days before expiry