diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index b98a0aa..f988e9d 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -2,1513 +2,154 @@ This file is maintained by Ralph. Run `./ralph-sandbox.sh plan 3` to generate tasks. -## Current State Summary +## Current Status: Feature Complete -### Overall Status: 1014 unit tests passing across 51 test files + 165 E2E tests across 12 files +**Test Coverage:** 1014 unit tests (51 files) + 165 E2E tests (12 files) = 1179 total tests -### Library Implementation -| File | Status | Gap Analysis | -|------|--------|--------------| -| `cycle.ts` | **COMPLETE** | 22 tests covering all functions including dynamic phase boundaries for variable cycle lengths | -| `nutrition.ts` | **COMPLETE** | 17 tests covering getNutritionGuidance, getSeedSwitchAlert, phase-specific carb ranges, keto guidance | -| `email.ts` | **COMPLETE** | 32 tests covering sendDailyEmail, sendPeriodConfirmationEmail, sendTokenExpirationWarning, email formatting, subject lines, structured logging | -| `ics.ts` | **COMPLETE** | 33 tests covering generateIcsFeed (90 days of phase events), ICS format validation, timezone handling, period prediction feedback, CATEGORIES for calendar colors | -| `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** | 12 tests covering `withAuth()` wrapper for API route protection, structured logging for auth failures, IP address logging | -| `middleware.ts` (Next.js) | **COMPLETE** | 12 tests covering page protection, redirects to login | -| `logger.ts` | **COMPLETE** | 16 tests covering JSON output, log levels, error stack traces, child loggers | -| `metrics.ts` | **COMPLETE** | 33 tests covering metrics collection, counters, gauges, histograms, Prometheus format | +All P0-P5 items are complete. The project is feature complete. -### Infrastructure Gaps (from specs/ - pending implementation) -| Gap | Spec Reference | Task | Priority | -|-----|----------------|------|----------| -| Health Check Endpoint | specs/observability.md | P2.15 | **COMPLETE** | -| Prometheus Metrics | specs/observability.md | P2.16 | **COMPLETE** | -| Structured Logging (pino) | specs/observability.md | P2.17 | **COMPLETE** | -| OIDC Authentication | specs/authentication.md | P2.18 | **COMPLETE** | -| Token Expiration Warnings | specs/email.md | P3.9 | **COMPLETE** | +--- -### API Routes (18 route files, 21 HTTP endpoints) -| Route | Status | Notes | -|-------|--------|-------| -| POST /api/auth/logout | **COMPLETE** | Clears pb_auth cookie, logs out user (5 tests) | -| 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 with prediction tracking (13 tests) | -| GET /api/cycle/current | **COMPLETE** | Returns cycle day, phase, config, daysUntilNextPhase (10 tests) | -| GET /api/today | **COMPLETE** | Returns decision, cycle, biometrics, nutrition (24 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 | **COMPLETE** | Stores encrypted Garmin OAuth tokens (15 tests) | -| DELETE /api/garmin/tokens | **COMPLETE** | Clears tokens and disconnects Garmin (15 tests) | -| GET /api/garmin/status | **COMPLETE** | Returns connection status, expiry, warning level (11 tests) | -| GET /api/calendar/[userId]/[token].ics | **COMPLETE** | Token validation, ICS generation with period prediction feedback, caching headers (11 tests) | -| POST /api/calendar/regenerate-token | **COMPLETE** | Generates 32-char token, returns URL (9 tests) | -| POST /api/cron/garmin-sync | **COMPLETE** | Syncs Garmin data for all users, creates DailyLogs, sends token expiration warnings (32 tests) | -| POST /api/cron/notifications | **COMPLETE** | Sends daily emails with timezone matching, DailyLog handling (20 tests) | -| GET /api/history | **COMPLETE** | Paginated historical daily logs with date filtering (19 tests) | -| GET /api/period-history | **COMPLETE** | Paginated period logs with cycle lengths and average (18 tests) | -| PATCH /api/period-logs/[id] | **COMPLETE** | Edit period log startDate (10 tests) | -| DELETE /api/period-logs/[id] | **COMPLETE** | Delete period log with user.lastPeriodDate update (6 tests) | -| GET /api/health | **COMPLETE** | Health check for deployment monitoring (14 tests) | -| GET /metrics | **COMPLETE** | 33 tests (18 lib + 15 route) | +## Architecture Summary -### Pages (8 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, rate limiting | -| Settings (`/settings`) | **COMPLETE** | Form with cycleLength, notificationTime, timezone | -| Settings/Garmin (`/settings/garmin`) | **COMPLETE** | Token management UI, connection status, disconnect functionality, 27 tests | -| Calendar (`/calendar`) | **COMPLETE** | MonthView with navigation, ICS subscription section, token regeneration, 23 tests | -| History (`/history`) | **COMPLETE** | Table view with date filtering, pagination, decision styling, 26 tests | -| Period History (`/period-history`) | **COMPLETE** | Period log table with edit/delete, cycle lengths, average, prediction accuracy, 27 tests | -| Plan (`/plan`) | **COMPLETE** | Phase overview, training guidelines, rebounding techniques, 16 tests | +### Tech Stack +| Layer | Choice | +|-------|--------| +| Framework | Next.js 16 (App Router) | +| Runtime | Node.js 24 | +| Database | PocketBase | +| Validation | Zod | +| Testing | Vitest + jsdom + Playwright | +| Linting | Biome | -### 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` | **COMPLETE** | Compact calendar widget with phase colors, navigation, legend (23 tests) | -| `OnboardingBanner` | **COMPLETE** | Setup prompts for new users with icons and action buttons, 16 tests | -| `MonthView` | **COMPLETE** | Calendar grid with DayCell integration, navigation controls, phase legend, keyboard navigation | -| `PeriodDateModal` | **COMPLETE** | Period date input modal with validation, error handling, accessibility (22 tests) | -| `Skeletons` | **COMPLETE** | Loading skeleton components for all dashboard sections with shimmer animation (29 tests) | - -### Test Coverage -| Test File | Status | -|-----------|--------| -| `src/lib/cycle.test.ts` | **EXISTS** - 22 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** - 12 tests (withAuth wrapper, error handling, structured logging, IP address logging) | -| `src/lib/logger.test.ts` | **EXISTS** - 16 tests (JSON format, log levels, error serialization, child loggers) | -| `src/lib/metrics.test.ts` | **EXISTS** - 18 tests (metrics collection, counters, gauges, histograms, Prometheus format) | -| `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** - 13 tests (POST period, auth, validation, date checks, prediction tracking) | -| `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** - 24 tests (daily snapshot, auth, decision, overrides, phases, nutrition, biometrics, seed switch alert) | -| `src/app/api/overrides/route.test.ts` | **EXISTS** - 14 tests (POST/DELETE overrides, auth, validation, type checks) | -| `src/app/login/page.test.tsx` | **EXISTS** - 32 tests (form rendering, auth flow, error handling, validation, accessibility, rate limiting) | -| `src/app/page.test.tsx` | **EXISTS** - 28 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** - 32 tests (email content, subject lines, formatting, token expiration warnings, structured logging) | -| `src/lib/ics.test.ts` | **EXISTS** - 33 tests (ICS format validation, 90-day event generation, timezone handling, period prediction feedback, CATEGORIES for colors) | -| `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) | -| `src/app/api/garmin/tokens/route.test.ts` | **EXISTS** - 15 tests (POST/DELETE tokens, encryption, validation, auth) | -| `src/app/api/garmin/status/route.test.ts` | **EXISTS** - 11 tests (connection status, expiry, warning levels) | -| `src/app/api/cron/garmin-sync/route.test.ts` | **EXISTS** - 32 tests (auth, user iteration, token handling, Garmin data fetching, DailyLog creation, token expiration warnings, error handling) | -| `src/app/api/cron/notifications/route.test.ts` | **EXISTS** - 20 tests (timezone matching, DailyLog handling, email sending) | -| `src/app/api/calendar/[userId]/[token].ics/route.test.ts` | **EXISTS** - 11 tests (token validation, ICS generation with period prediction feedback, caching, error handling) | -| `src/app/api/calendar/regenerate-token/route.test.ts` | **EXISTS** - 9 tests (token generation, URL formatting, auth) | -| `src/app/api/history/route.test.ts` | **EXISTS** - 19 tests (pagination, date filtering, auth, validation) | -| `src/app/api/period-history/route.test.ts` | **EXISTS** - 18 tests (pagination, cycle length calculation, average, auth) | -| `src/app/api/period-logs/[id]/route.test.ts` | **EXISTS** - 16 tests (PATCH edit, DELETE with user update, auth, validation) | -| `src/app/api/health/route.test.ts` | **EXISTS** - 14 tests (healthy/unhealthy states, PocketBase connectivity, error handling) | -| `src/app/history/page.test.tsx` | **EXISTS** - 26 tests (rendering, data loading, pagination, date filtering, styling) | -| `src/app/period-history/page.test.tsx` | **EXISTS** - 27 tests (rendering, edit/delete modals, pagination, prediction accuracy) | -| `src/app/api/metrics/route.test.ts` | **EXISTS** - 15 tests (Prometheus format validation, metric types, route handling) | -| `src/components/calendar/month-view.test.tsx` | **EXISTS** - 31 tests (calendar grid, phase colors, navigation, legend, keyboard navigation, emojis) | -| `src/app/calendar/page.test.tsx` | **EXISTS** - 23 tests (rendering, navigation, ICS subscription, token regeneration) | -| `src/app/settings/page.test.tsx` | **EXISTS** - 34 tests (form rendering, validation, submission, accessibility, logout functionality) | -| `src/app/api/auth/logout/route.test.ts` | **EXISTS** - 5 tests (cookie clearing, success response, error handling) | -| `src/app/settings/garmin/page.test.tsx` | **EXISTS** - 27 tests (connection status, token management) | -| `src/components/dashboard/decision-card.test.tsx` | **EXISTS** - 19 tests (rendering, status icons, styling, color-coded backgrounds) | -| `src/components/dashboard/data-panel.test.tsx` | **EXISTS** - 29 tests (biometrics display, null handling, styling, HRV status color-coding, intensity progress bar) | -| `src/components/dashboard/nutrition-panel.test.tsx` | **EXISTS** - 16 tests (seeds, carbs, keto guidance, seed switch alert) | -| `src/components/dashboard/override-toggles.test.tsx` | **EXISTS** - 18 tests (toggle states, callbacks, styling) | -| `src/components/dashboard/mini-calendar.test.tsx` | **EXISTS** - 23 tests (calendar grid, phase colors, navigation, legend) | -| `src/components/dashboard/onboarding-banner.test.tsx` | **EXISTS** - 16 tests (setup prompts, icons, action buttons, interactions, dismissal) | -| `src/components/calendar/day-cell.test.tsx` | **EXISTS** - 32 tests (phase coloring, today highlighting, click handling, accessibility, period indicator) | -| `src/app/plan/page.test.tsx` | **EXISTS** - 16 tests (loading states, error handling, phase display, exercise reference, rebounding techniques) | -| `src/app/layout.test.tsx` | **EXISTS** - 4 tests (skip navigation link rendering, accessibility, Toaster rendering) | -| `src/components/ui/toaster.test.tsx` | **EXISTS** - 23 tests (toast rendering, types, auto-dismiss, error persistence, accessibility) | - -### Critical Business Rules (from Spec) -1. **Override Priority:** flare > stress > sleep > pms (must be enforced in order) +### Critical Business Rules +1. **Override Priority:** flare > stress > sleep > pms (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 (IMPLEMENTED - P3.9 COMPLETE) +4. **Token Expiration Warnings:** Email at 14 days and 7 days before expiry 5. **ICS Feed:** Generates 90 days of phase events for calendar subscription --- -## P0: Critical Blockers ✅ ALL COMPLETE +## Completed Implementation -These must be completed first - nothing else works without them. +### Library Files (12 files, 250+ tests) +| File | Tests | Key Functions | +|------|-------|---------------| +| `cycle.ts` | 22 | `getCycleDay`, `getPhase`, `getPhaseConfig`, dynamic phase boundaries | +| `nutrition.ts` | 17 | `getNutritionGuidance`, `getSeedSwitchAlert`, phase-specific guidance | +| `email.ts` | 32 | `sendDailyEmail`, `sendPeriodConfirmationEmail`, `sendTokenExpirationWarning` | +| `ics.ts` | 33 | `generateIcsFeed`, 90-day events, period prediction feedback, CATEGORIES | +| `encryption.ts` | 14 | AES-256-GCM encrypt/decrypt | +| `decision-engine.ts` | 24 | `getTrainingDecision`, `getDecisionWithOverrides`, 8 priority rules | +| `garmin.ts` | 33 | `fetchHrvStatus`, `fetchBodyBattery`, `fetchIntensityMinutes`, token validation | +| `pocketbase.ts` | 10 | `createPocketBaseClient`, `isAuthenticated`, `getCurrentUser`, `loadAuthFromCookies` | +| `auth-middleware.ts` | 12 | `withAuth()` wrapper, structured logging, IP logging | +| `middleware.ts` | 12 | Next.js page protection, redirects | +| `logger.ts` | 16 | Pino JSON output, log levels, child loggers | +| `metrics.ts` | 33 | Prometheus metrics, counters, gauges, histograms | -### 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 +### API Routes (21 endpoints, 350+ tests) +| Route | Tests | Purpose | +|-------|-------|---------| +| POST /api/auth/logout | 5 | Session logout | +| GET /api/user | 4 | User profile | +| PATCH /api/user | 17 | Update preferences | +| POST /api/cycle/period | 13 | Log period start with prediction tracking | +| GET /api/cycle/current | 10 | Current cycle state | +| GET /api/today | 24 | Daily snapshot with decision | +| POST/DELETE /api/overrides | 14 | Override management | +| POST/DELETE /api/garmin/tokens | 15 | Token storage | +| GET /api/garmin/status | 11 | Connection status | +| POST /api/cron/garmin-sync | 32 | Daily data sync | +| POST /api/cron/notifications | 20 | Email notifications | +| GET /api/calendar/[userId]/[token].ics | 11 | ICS feed | +| POST /api/calendar/regenerate-token | 9 | Token regeneration | +| GET /api/history | 19 | Daily log history | +| GET /api/period-history | 18 | Period log history | +| PATCH/DELETE /api/period-logs/[id] | 16 | Period log management | +| GET /api/health | 14 | Health check | +| GET /metrics | 15 | Prometheus metrics | -### 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 with IP address logging - - `src/middleware.ts` - Added Next.js middleware for page protection -- **Tests:** - - `src/lib/auth-middleware.test.ts` - 12 tests covering unauthorized rejection, user context passing, error handling, IP address logging - - `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 +### Pages (8 pages, 230+ tests) +| Page | Tests | Features | +|------|-------|----------| +| Dashboard (`/`) | 28 | Decision card, data panel, nutrition, overrides, mini calendar | +| Login (`/login`) | 32 | OIDC + email/password, rate limiting | +| Settings (`/settings`) | 34 | Preferences, logout | +| Settings/Garmin | 27 | Token management, status | +| Calendar (`/calendar`) | 23 | Month view, ICS subscription | +| History (`/history`) | 26 | Daily log table | +| Period History | 27 | Period log table, edit/delete | +| Plan (`/plan`) | 16 | Phase overview, training reference | -### 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 +### Components (10 components, 200+ tests) +| Component | Tests | Purpose | +|-----------|-------|---------| +| DecisionCard | 19 | Status display with color coding | +| DataPanel | 29 | Biometrics display, HRV color coding, progress bar | +| NutritionPanel | 16 | Seeds, carbs, keto guidance | +| OverrideToggles | 18 | Override buttons | +| DayCell | 32 | Calendar day with phase colors, period indicator | +| MiniCalendar | 23 | Dashboard calendar widget | +| OnboardingBanner | 16 | Setup prompts | +| MonthView | 31 | Full calendar with navigation, keyboard nav | +| PeriodDateModal | 22 | Period input modal | +| Skeletons | 29 | Loading states with shimmer | -### 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 +### E2E Tests (12 files, 165 tests) +| File | Tests | Coverage | +|------|-------|----------| +| smoke.spec.ts | 3 | Basic app functionality | +| auth.spec.ts | 14 | Login, protected routes | +| dashboard.spec.ts | 24 | Dashboard display, overrides | +| settings.spec.ts | 15 | Settings form, validation | +| garmin.spec.ts | 7 | Garmin connection | +| period-logging.spec.ts | 14 | Period history, logging | +| calendar.spec.ts | 21 | Calendar view, ICS feed | +| decision-engine.spec.ts | 8 | Decision priority chain | +| cycle.spec.ts | 11 | Cycle tracking | +| history.spec.ts | 7 | History page | +| plan.spec.ts | 7 | Plan page | +| health.spec.ts | 3 | Health/observability | --- -## P1: Core Functionality ✅ ALL COMPLETE - -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 and prediction tracking -- **Tests:** - - `src/app/api/cycle/period/route.test.ts` - 13 tests covering auth, date validation, user update, PeriodLog creation, prediction tracking -- **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` - 24 tests covering auth, validation, decision calculation, overrides, phases, nutrition, seed switch alert -- **Response Shape:** - - `decision` (status, reason, icon), `cycleDay`, `phase`, `phaseConfig`, `daysUntilNextPhase`, `cycleLength` - - `biometrics` (hrvStatus, bodyBatteryCurrent, bodyBatteryYesterdayLow, weekIntensityMinutes, phaseLimit) - - `nutrition` (seeds, carbRange, ketoGuidance, seedSwitchAlert) -- **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 ✅ COMPLETE -- [x] Store encrypted Garmin OAuth tokens -- **Files:** - - `src/app/api/garmin/tokens/route.ts` - POST/DELETE handlers with encryption, validation -- **Tests:** - - `src/app/api/garmin/tokens/route.test.ts` - 15 tests covering encryption, validation, storage, auth, deletion -- **Features Implemented:** - - POST: Accepts oauth1, oauth2, expires_at; encrypts tokens; stores in user record - - DELETE: Clears tokens and sets garminConnected to false - - Validation for required fields and types - - Returns daysUntilExpiry in POST response -- **Why:** Users need to connect their Garmin accounts -- **Depends On:** P0.1, P0.2 - -### P2.3: GET /api/garmin/status Implementation ✅ COMPLETE -- [x] Return Garmin connection status and days until expiry -- **Files:** - - `src/app/api/garmin/status/route.ts` - GET handler with expiry calculation -- **Tests:** - - `src/app/api/garmin/status/route.test.ts` - 11 tests covering connected/disconnected states, expiry calc, warning levels -- **Response Shape:** - - `connected` - Boolean indicating if tokens exist - - `daysUntilExpiry` - Days until token expires (null if not connected) - - `expired` - Boolean indicating if tokens have expired - - `warningLevel` - "critical" (<=7 days), "warning" (8-14 days), or null -- **Why:** Users need visibility into their Garmin connection -- **Depends On:** P0.1, P0.2, P2.1 - -### P2.4: POST /api/cron/garmin-sync Implementation ✅ COMPLETE -- [x] Daily sync of all Garmin data for all users -- **Files:** - - `src/app/api/cron/garmin-sync/route.ts` - Iterates users, fetches data, stores DailyLog -- **Tests:** - - `src/app/api/cron/garmin-sync/route.test.ts` - 32 tests covering auth, user iteration, token handling, Garmin data fetching, DailyLog creation, token expiration warnings, error handling -- **Features Implemented:** - - Fetches all users with garminConnected=true - - Skips users with expired tokens - - Decrypts OAuth2 tokens and fetches HRV, Body Battery, Intensity Minutes - - Calculates cycle day, phase, phase limit, remaining minutes - - Computes training decision using decision engine - - Creates DailyLog entries for each user - - Sends token expiration warning emails at 14 and 7 days before expiry - - Returns sync summary (usersProcessed, errors, skippedExpired, timestamp) -- **Why:** Automated data sync is required for morning notifications -- **Depends On:** P2.1, P2.2 - -### P2.5: POST /api/cron/notifications Implementation ✅ COMPLETE -- [x] Send daily email notifications at user's preferred time -- **Files:** - - `src/app/api/cron/notifications/route.ts` - Timezone-aware user matching, DailyLog fallback, email sending -- **Tests:** - - `src/app/api/cron/notifications/route.test.ts` - 20 tests covering timezone matching, DailyLog handling, email sending -- **Features Implemented:** - - Timezone-aware notification matching (finds users whose notificationTime matches current hour in their timezone) - - DailyLog-based notifications with fallback to real-time calculation when DailyLog missing - - Duplicate prevention (only sends once per user per hour) - - Nutrition guidance integration (seeds, carbs, keto) - - CRON_SECRET authentication - - Returns summary with emailsSent count and timestamp -- **Why:** Email notifications are a key feature per spec -- **Depends On:** P2.4 - -### P2.6: GET /api/calendar/[userId]/[token].ics Implementation ✅ COMPLETE -- [x] Return ICS feed for calendar subscription -- **Files:** - - `src/app/api/calendar/[userId]/[token].ics/route.ts` - Validates token, generates ICS with 90 days of phase events and period prediction feedback -- **Tests:** - - `src/app/api/calendar/[userId]/[token].ics/route.test.ts` - 11 tests covering token validation, ICS generation with period predictions, caching headers, error handling -- **Features Implemented:** - - Token-based authentication (no session required) - - Validates calendar token against user record - - Fetches period logs and passes them to ICS generator for prediction feedback - - Generates 90 days of phase events using `generateIcsFeed()` - - Returns proper Content-Type header (`text/calendar; charset=utf-8`) - - Caching headers for calendar client optimization - - 404 for non-existent users, 401 for invalid tokens -- **Why:** Calendar integration for external apps - -### P2.7: POST /api/calendar/regenerate-token Implementation ✅ COMPLETE -- [x] Generate new calendar token -- **Files:** - - `src/app/api/calendar/regenerate-token/route.ts` - Creates random 32-char token, updates user -- **Tests:** - - `src/app/api/calendar/regenerate-token/route.test.ts` - 9 tests covering token generation, URL formatting, auth -- **Features Implemented:** - - Requires authentication via `withAuth()` middleware - - Generates cryptographically secure 32-character hex token - - Updates user's `calendarToken` field in database - - Returns new token and formatted calendar URL - - Old tokens immediately invalidated -- **Why:** Security feature for calendar URLs -- **Depends On:** P0.1, P0.2 - -### P2.8: GET /api/history Implementation ✅ COMPLETE -- [x] Return paginated historical daily logs -- **Files:** - - `src/app/api/history/route.ts` - Query DailyLog with pagination, date filtering, validation -- **Tests:** - - `src/app/api/history/route.test.ts` - 19 tests covering pagination, date filtering, auth, validation -- **Features Implemented:** - - Pagination with page/limit parameters (default: page=1, limit=20) - - Date filtering with startDate/endDate query params (YYYY-MM-DD format) - - Validation for all parameters with descriptive error messages - - Sort by date descending (most recent first) - - Returns items, total, page, limit, totalPages, hasMore -- **Why:** Users want to see their training history -- **Depends On:** P0.1, P0.2 - -### P2.9: Settings Page Implementation ✅ COMPLETE -- [x] User profile management UI -- **Files:** - - `src/app/settings/page.tsx` - Form for cycleLength, notificationTime, timezone with validation, loading states, error handling -- **Tests:** - - `src/app/settings/page.test.tsx` - 24 tests covering rendering, data loading, form submission, validation, error handling -- **Why:** Users need to configure their preferences -- **Depends On:** P0.4, P1.1 - -### P2.10: Settings/Garmin Page Implementation ✅ COMPLETE -- [x] Garmin connection management UI -- **Files:** - - `src/app/settings/garmin/page.tsx` - Token input form, connection status, expiry warnings, disconnect button -- **Tests:** - - `src/app/settings/garmin/page.test.tsx` - 27 tests covering rendering, connection states, warning levels, token submission, disconnect flow - - `src/app/settings/page.test.tsx` - 3 additional tests for Garmin link (28 total) -- **Features Implemented:** - - Connection status display with green/red/gray indicators - - Token expiry warnings (yellow for 14 days, red for 7 days) - - Token input form with JSON validation - - Instructions for running bootstrap script - - Disconnect functionality - - Loading and error states -- **Why:** Users need to manage their Garmin connection -- **Depends On:** P0.4, P2.2, P2.3 - -### P2.11: Calendar Page Implementation ✅ COMPLETE -- [x] In-app calendar with phase visualization -- **Files:** - - `src/app/calendar/page.tsx` - Month view with navigation, ICS subscription section with URL display, copy button, token regeneration - - `src/components/calendar/month-view.tsx` - Complete calendar grid with DayCell integration, navigation controls, phase legend with emojis -- **Tests:** - - `src/components/calendar/month-view.test.tsx` - 31 tests covering calendar grid, phase colors, navigation, legend, emojis - - `src/app/calendar/page.test.tsx` - 23 tests covering rendering, navigation, ICS subscription, token regeneration -- **Why:** Planning ahead is a key user need -- **Depends On:** P2.6 - -### P2.12: History Page Implementation ✅ COMPLETE -- [x] View past training decisions and data -- **Files:** - - `src/app/history/page.tsx` - Data fetching, table display, pagination, date filtering -- **Tests:** - - `src/app/history/page.test.tsx` - 26 tests covering rendering, data loading, pagination, filtering, error handling -- **Why:** Users want to review their training history -- **Depends On:** P2.8 - -### P2.13: Plan Page Implementation ✅ COMPLETE -- [x] Phase-specific training plan view -- **Files:** - - `src/app/plan/page.tsx` - Phase overview, training guidelines, exercise reference, rebounding techniques -- **Tests:** - - `src/app/plan/page.test.tsx` - 16 tests covering loading states, error handling, phase display, exercise reference, rebounding techniques -- **Features Implemented:** - - Current phase status display (day, phase name, training type, weekly limit) - - Phase overview cards for all 5 phases with weekly intensity minute limits - - Strength training exercises reference with descriptions - - Rebounding techniques organized by phase (follicular and luteal) - - Weekly guidelines for each phase with training goals -- **Why:** Users want detailed training guidance -- **Depends On:** P0.4, P1.3 - -### P2.14: Mini Calendar Component ✅ COMPLETE -- [x] Dashboard overview calendar -- **Current State:** COMPLETE - Compact calendar grid with phase colors, navigation buttons, today highlighting, phase legend -- **Files:** - - `src/components/dashboard/mini-calendar.tsx` - Complete calendar grid with DayCell integration -- **Tests:** - - `src/components/dashboard/mini-calendar.test.tsx` - 23 tests (calendar grid, phase colors, navigation, legend) -- **Features Implemented:** - - Calendar grid using DayCell component - - Current week/month view - - Phase color coding - - Today highlight - - Navigation buttons (prev/next month) - - Phase legend -- **Why:** Quick visual reference on dashboard - -### P2.15: Health Check Endpoint ✅ COMPLETE -- [x] GET /api/health for deployment monitoring -- **Current State:** Fully implemented with PocketBase connectivity checks -- **Files:** - - `src/app/api/health/route.ts` - Returns health status with PocketBase connectivity check -- **Tests:** - - `src/app/api/health/route.test.ts` - 14 tests for healthy (200) and unhealthy (503) states -- **Response Shape:** - - `status` - "ok" or "unhealthy" - - `timestamp` - ISO 8601 timestamp - - `version` - Application version -- **Checks Performed:** - - PocketBase connectivity - - Basic app startup complete -- **Why:** Required for Nomad health checks, load balancer probes, and uptime monitoring (per specs/observability.md) - -### P2.16: Prometheus Metrics Endpoint ✅ COMPLETE -- [x] GET /metrics for monitoring -- **Current State:** Fully implemented with prom-client -- **Files:** - - `src/app/api/metrics/route.ts` - Returns Prometheus-format metrics (15 tests) - - `src/lib/metrics.ts` - Metrics collection with prom-client (18 tests) -- **Tests:** - - `src/lib/metrics.test.ts` - 18 tests covering metrics collection, counters, gauges, histograms, Prometheus format - - `src/app/api/metrics/route.test.ts` - 15 tests for Prometheus format output, metric types, route handling -- **Metrics Implemented:** - - Custom counters: `phaseflow_garmin_sync_total`, `phaseflow_email_sent_total`, `phaseflow_decision_engine_calls_total` - - Custom gauge: `phaseflow_active_users` - - Custom histogram: `phaseflow_garmin_sync_duration_seconds` -- **Integrations:** - - garmin-sync route: garminSyncTotal, garminSyncDuration, activeUsersGauge - - email.ts: emailSentTotal (daily and warning types) - - decision-engine.ts: decisionEngineCallsTotal -- **Why:** Required for Prometheus scraping and production monitoring (per specs/observability.md) -### P2.17: Structured Logging with Pino ✅ COMPLETE -- [x] Create pino-based logger with JSON output -- **Files:** - - `src/lib/logger.ts` - Pino logger configuration with LOG_LEVEL env var support -- **Tests:** - - `src/lib/logger.test.ts` - 16 tests covering JSON format, log levels, error stack traces, child loggers -- **Features Implemented:** - - JSON output to stdout for log aggregators (Loki, ELK) - - Log levels: error, warn, info, debug - - LOG_LEVEL environment variable configuration (defaults to "info") - - Error objects serialized with type, message, and stack trace - - Child logger support for bound context - - ISO 8601 timestamps -- **Why:** Required for log aggregators and production debugging (per specs/observability.md) -- **Next Step:** Integrate logger into API routes (can be done incrementally) - -### P2.18: OIDC Authentication ✅ COMPLETE -- [x] Replace email/password login with OIDC (Pocket-ID) -- **Files:** - - `src/app/login/page.tsx` - OIDC button with email/password fallback -- **Tests:** - - `src/app/login/page.test.tsx` - 24 tests (10 new OIDC tests) -- **Features Implemented:** - - Auto-detection of OIDC provider via `listAuthMethods()` API - - "Sign In with Pocket-ID" button when OIDC provider is configured - - Email/password form fallback when OIDC is not available - - PocketBase `authWithOAuth2()` popup-based OAuth2 flow - - Loading states during authentication - - Error handling with user-friendly messages -- **Flow:** - 1. Page checks for available auth methods on mount - 2. If OIDC provider configured, shows "Sign In with Pocket-ID" button - 3. User clicks button, PocketBase handles OAuth2 popup flow - 4. On success, user redirected to dashboard - 5. Falls back to email/password when OIDC not available -- **Environment Variables (configured in PocketBase Admin):** - - Client ID, Client Secret, Issuer URL configured in PocketBase -- **Why:** Required per specs/authentication.md for secure identity management - ---- - -## 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` - 28 tests covering ICS format validation, 90-day event generation, timezone handling, period prediction feedback -- **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 - - Period prediction accuracy feedback ("Predicted" labels) -- **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 ✅ COMPLETE -- [x] Add consistent error responses across all API routes -- [x] Replace console.error with structured pino logger -- [x] Add logging for key events per observability spec -- **Files:** - - `src/lib/auth-middleware.ts` - Replaced console.error with structured logger, added auth failure logging with IP address - - `src/app/api/cycle/period/route.ts` - Added "Period logged" event logging, structured error logging - - `src/app/api/calendar/[userId]/[token].ics/route.ts` - Replaced console.error with structured logger - - `src/app/api/overrides/route.ts` - Added "Override toggled" event logging - - `src/app/api/today/route.ts` - Added "Decision calculated" event logging - - `src/app/api/cron/garmin-sync/route.ts` - Added "Garmin sync start", "Garmin sync complete", "Garmin sync failure" logging - - `src/app/api/auth/logout/route.ts` - Added "User logged out" logging -- **Tests:** - - `src/lib/auth-middleware.test.ts` - Added 6 tests for structured logging and IP address logging (12 total) -- **Events Logged (per observability spec):** - - Auth failure (warn): reason, ip (from x-forwarded-for or x-real-ip headers) - - Period logged (info): userId, date - - Override toggled (info): userId, override, enabled - - Decision calculated (info): userId, decision, reason - - Garmin sync start (info): userId - - Garmin sync complete (info): userId, duration_ms, metrics (bodyBattery, hrvStatus) - - Garmin sync failure (error): userId, err object - - User logged out (info) - - Error events (error): err object with stack trace -- **Why:** Better debugging and user experience with structured JSON logs - -### P3.8: Loading States ✅ COMPLETE -- [x] Add loading indicators to all pages -- **Files:** - - `src/components/dashboard/skeletons.tsx` - Skeleton components (DecisionCardSkeleton, DataPanelSkeleton, NutritionPanelSkeleton, MiniCalendarSkeleton, OverrideTogglesSkeleton, CycleInfoSkeleton, DashboardSkeleton) - - `src/components/dashboard/skeletons.test.tsx` - 29 tests - - `src/app/loading.tsx` - Dashboard route loading state - - `src/app/calendar/loading.tsx` - Calendar route loading state - - `src/app/history/loading.tsx` - History route loading state - - `src/app/plan/loading.tsx` - Plan route loading state - - `src/app/settings/loading.tsx` - Settings route loading state -- **Features:** Skeleton placeholders with shimmer animations matching spec requirements, updated dashboard page to use skeleton components -- **Why:** Better perceived performance -### P3.9: Token Expiration Warnings ✅ COMPLETE -- [x] Email warnings at 14 and 7 days before Garmin token expiry -- **Files:** - - `src/lib/email.ts` - Added `sendTokenExpirationWarning()` function - - `src/app/api/cron/garmin-sync/route.ts` - Added token expiry checking and warning logic -- **Tests:** - - `src/lib/email.test.ts` - 10 new tests for warning email function (24 total) - - `src/app/api/cron/garmin-sync/route.test.ts` - 10 new tests for warning integration (32 total) -- **Features Implemented:** - - Sends warning email at exactly 14 days before token expiry - - Sends warning email at exactly 7 days before token expiry - - Warning logic integrated into garmin-sync cron job - - Email includes days until expiry and instructions for refreshing tokens -- **Why:** Users need time to refresh tokens (per spec requirement in specs/email.md) - -### P3.10: E2E Test Suite ✅ COMPLETE (See P5.4) -- [x] Comprehensive end-to-end tests -- **Files:** - - `e2e/*.spec.ts` - Full user flows (100 tests across 12 files) -- **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 -- **Note:** Implementation details documented in P5.4 - -### P3.11: Missing Component Tests ✅ COMPLETE -- [x] Add unit tests for untested components -- **Components Tested (5 total):** - - `src/components/dashboard/decision-card.tsx` - 19 tests for rendering decision status, icon, reason, styling, color-coded backgrounds - - `src/components/dashboard/data-panel.tsx` - 18 tests for biometrics display (BB, HRV, intensity), null handling, styling - - `src/components/dashboard/nutrition-panel.tsx` - 16 tests for seeds, carbs, keto guidance display, seed switch alert - - `src/components/dashboard/override-toggles.tsx` - 18 tests for toggle states, callbacks, styling - - `src/components/calendar/day-cell.tsx` - 32 tests for phase coloring, today highlighting, click handling, period indicator -- **Test Files Created:** - - `src/components/dashboard/decision-card.test.tsx` - 19 tests - - `src/components/dashboard/data-panel.test.tsx` - 18 tests - - `src/components/dashboard/nutrition-panel.test.tsx` - 16 tests - - `src/components/dashboard/override-toggles.test.tsx` - 18 tests - - `src/components/calendar/day-cell.test.tsx` - 32 tests -- **Total Tests Added:** 103 tests across 5 files -- **Why:** Component isolation ensures UI correctness and prevents regressions - ---- - -## P4: UX Polish and Accessibility - -Enhancements from spec requirements that improve user experience. - -### P4.1: Dashboard Onboarding Banners ✅ COMPLETE -- [x] Show setup prompts for missing configuration -- **Spec Reference:** specs/dashboard.md mentions onboarding banners -- **Implementation Details:** - - `OnboardingBanner` component created at `src/components/dashboard/onboarding-banner.tsx` - - Tests at `src/components/dashboard/onboarding-banner.test.tsx` - 16 tests - - Dashboard integration at `src/app/page.tsx` - 5 new tests added to page.test.tsx (28 total) - - Features: Garmin connection banner, period date banner with callback, notification time banner - - Banners render at top of dashboard when setup incomplete -- **Files:** - - `src/app/page.tsx` - Added conditional banner rendering at top of dashboard - - `src/components/dashboard/onboarding-banner.tsx` - New component with icons, action buttons, styling - - `src/components/dashboard/onboarding-banner.test.tsx` - 16 tests covering rendering, interactions, dismissal -- **Why:** Helps new users complete setup for full functionality - -### P4.2: Accessibility Improvements ✅ COMPLETE -- [x] Skip navigation link -- [x] Semantic HTML landmarks (main elements) -- [x] Screen reader labels for calendar buttons -- [x] Keyboard navigation for calendar -- **Spec Reference:** specs/dashboard.md accessibility requirements -- **Implementation Details:** - - Skip navigation link added to layout with sr-only styling - - Semantic HTML landmarks (main element) added to login and settings pages - - Aria-labels added to DayCell calendar buttons with date and phase information - - Keyboard navigation: ArrowLeft/Right for prev/next day, ArrowUp/Down for prev/next week, Home/End for first/last day, boundary navigation triggers month change -- **Files:** - - `src/app/layout.tsx` - Added skip navigation link with sr-only styling - - `src/app/layout.test.tsx` - 3 tests for skip link rendering and accessibility - - `src/app/login/page.tsx` - Wrapped content in main element - - `src/app/login/page.test.tsx` - Added 2 accessibility tests (26 total) - - `src/app/settings/page.tsx` - Wrapped content in main element - - `src/app/settings/page.test.tsx` - Added 2 accessibility tests (29 total) - - `src/app/page.tsx` - Added id="main-content" to existing main element - - `src/components/calendar/day-cell.tsx` - Added aria-label with date/phase info, dataDay prop - - `src/components/calendar/day-cell.test.tsx` - Added 4 accessibility tests (27 total) - - `src/components/calendar/month-view.tsx` - Added role="grid", keyboard navigation handler - - `src/components/calendar/month-view.test.tsx` - Added 9 keyboard navigation tests (30 total) -- **Why:** Required for accessibility compliance - -### P4.3: Dark Mode Configuration ✅ COMPLETE -- [x] Complete dark mode support -- **Current State:** COMPLETE - Dark mode auto-detects system preference via `prefers-color-scheme` -- **Implementation Details:** - - Changed `@custom-variant dark` from class-based to `@media (prefers-color-scheme: dark)` in globals.css - - Changed `.dark` CSS selector to `@media (prefers-color-scheme: dark) { :root { ... } }` for CSS variables - - Dark mode now auto-detects system preference (no manual toggle needed per spec) - - No component changes needed - existing CSS variables handle the theming -- **Files:** - - `src/app/globals.css` - Updated dark mode detection to use media query instead of class -- **Why:** User preference for dark mode -### P4.4: Loading Performance ✅ COMPLETE -- [x] Loading states within 100ms target -- **Spec Reference:** specs/dashboard.md performance requirements -- **Implementation Details:** - - Skeleton loading states exist for all routes (P3.8 COMPLETE) - - Optimistic UI updates implemented for override toggles - - Suspense boundaries provided by Next.js App Router via loading.tsx files - - Next.js loading.tsx files render immediately during navigation (< 100ms) -- **Files:** - - `src/app/loading.tsx` - Dashboard route loading (uses DashboardSkeleton) - - `src/app/calendar/loading.tsx` - Calendar route loading - - `src/app/history/loading.tsx` - History route loading - - `src/app/plan/loading.tsx` - Plan route loading - - `src/app/settings/loading.tsx` - Settings route loading - - `src/components/dashboard/skeletons.tsx` - Skeleton components (29 tests) -- **Why:** Perceived performance improvement -- **Verification:** Build succeeds, all 889 tests pass, Next.js handles 100ms target via automatic loading.tsx rendering - -### P4.5: Period Prediction Accuracy Feedback ✅ COMPLETE -- [x] Mark predicted vs confirmed period dates -- **Spec Reference:** specs/calendar.md mentions predictions marked with "Predicted" suffix -- **Files Modified:** - - `src/types/index.ts` - Added `predictedDate` field to PeriodLog type - - `src/lib/ics.ts` - Modified `generateIcsFeed()` to accept period logs and mark events with "(Predicted)" when actual differs from predicted - - `src/app/api/cycle/period/route.ts` - POST handler calculates predicted date (lastPeriodDate + cycleLength), stores in PeriodLog, returns daysEarly/daysLate - - `src/app/api/calendar/[userId]/[token].ics/route.ts` - Fetches period logs and passes them to ICS generator -- **Tests Added:** - - `src/app/api/cycle/period/route.test.ts` - 5 new tests (13 total): predictedDate storage, daysEarly/daysLate calculations - - `src/lib/ics.test.ts` - 5 new tests (28 total): "(Predicted)" label on events when actual differs from predicted - - `src/app/api/calendar/[userId]/[token].ics/route.test.ts` - 1 new test (11 total): period logs fetching and passing to ICS generator -- **Features Implemented:** - - PeriodLog stores predictedDate calculated from previous period (lastPeriodDate + cycleLength) - - POST /api/cycle/period calculates predicted vs actual date, returns daysEarly (negative) or daysLate (positive) - - ICS feed shows "(Predicted)" suffix on menstruation events when actual date differs from predicted date - - Calendar route fetches all period logs and passes them to ICS generator for prediction feedback -- **Why:** Creates feedback loop for understanding cycle prediction accuracy per calendar.md spec - -### P4.6: Rate Limiting ✅ COMPLETE -- [x] Login attempt rate limiting -- **Spec Reference:** specs/email.md mentions 5 login attempts per minute -- **Files:** - - `src/app/login/page.tsx` - Added client-side rate limiting with 5 attempts per minute -- **Tests:** - - `src/app/login/page.test.tsx` - 6 new tests (32 total) covering rate limiting -- **Features Implemented:** - - Client-side rate limiting tracking login attempts with timestamps - - Rate limit: 5 attempts per minute (RATE_LIMIT_WINDOW_MS = 60000) - - Shows "Too many login attempts. Please try again in 1 minute." error when rate limited - - Shows remaining attempts warning after 3 failures - - Disables form/button when rate limited - - Auto-clears after cooldown period - - Works for both email/password and OIDC login -- **Why:** Security requirement from spec - ---- - -## 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.18 OIDC Auth (upgrade) - -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 - -P2.15 Health endpoint (independent - HIGH PRIORITY for deployment) -P2.16 Metrics endpoint (independent) -P2.17 Structured logging (independent, but should be done before other items for proper logging) - -P3.11 Component tests ─> Can be done in parallel with other work -P4.* UX Polish ────────> After core functionality complete -``` - -### Remaining Work Priority - -| Priority | Task | Effort | Notes | -|----------|------|--------|-------| -| Done | P4.4 Loading Performance | Complete | Next.js loading.tsx provides 100ms target | -| Done | P4.5 Period Prediction | Complete | Prediction tracking with feedback loop | -| Done | P4.6 Rate Limiting | Complete | Client-side rate limiting implemented | -| Done | P5.1 Period History UI | Complete | Page + 3 API routes with 61 tests | -| Done | P5.3 CI Pipeline | Complete | Lint, typecheck, tests in Gitea Actions | -| Done | P5.4 E2E Tests | Complete | 100 tests across 12 files | -| Done | P5.2 Toast Notifications | Complete | sonner library + 23 tests | - -**All P0-P5 items are complete. The project is feature complete.** - - - -### 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 | -| P3.9 | P2.4 | - | - ---- - -## Completed - -### Library -- [x] **cycle.ts** - Complete with 22 tests (`getCycleDay`, `getPhase` with dynamic boundaries for variable cycle lengths, `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 30 tests (`sendDailyEmail`, `sendPeriodConfirmationEmail`, `sendTokenExpirationWarning`, email formatting, structured logging for sent/failed events) (P3.3, P3.9) -- [x] **ics.ts** - Complete with 33 tests (`generateIcsFeed`, ICS format validation, 90-day event generation, period prediction feedback, CATEGORIES for calendar colors) (P3.4, P4.5) -- [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) -- [x] **auth-middleware.ts** - Complete with 12 tests (`withAuth()` wrapper, structured logging, IP address logging) -- [x] **middleware.ts** - Complete with 12 tests (Next.js page protection) -- [x] **logger.ts** - Complete with 16 tests (JSON output, log levels, error serialization, child loggers) (P2.17) -- [x] **metrics.ts** - Complete with 18 tests (metrics collection, counters, gauges, histograms, Prometheus format) (P2.16) - -### Components -- [x] **DecisionCard** - Displays decision status, icon, reason with color-coded backgrounds (RED/YELLOW/GREEN per status) -- [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 -- [x] **MonthView** - Calendar grid with DayCell integration, navigation controls (prev/next month, Today button), phase legend with emojis, 31 tests -- [x] **MiniCalendar** - Compact calendar widget with phase colors, navigation, legend, 23 tests (P2.14) - -### API Routes (21 complete) -- [x] **POST /api/auth/logout** - Clears session cookie, logs user out, 5 tests -- [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 with prediction tracking, 13 tests (P1.2, P4.5) -- [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, 24 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) -- [x] **POST /api/garmin/tokens** - Stores encrypted Garmin OAuth tokens, 15 tests (P2.2) -- [x] **DELETE /api/garmin/tokens** - Clears tokens and disconnects Garmin, 15 tests (P2.2) -- [x] **GET /api/garmin/status** - Returns connection status, expiry, warning level, 11 tests (P2.3) -- [x] **POST /api/cron/garmin-sync** - Daily sync of Garmin data for all connected users, creates DailyLogs, sends token expiration warnings, 32 tests (P2.4, P3.9) -- [x] **POST /api/cron/notifications** - Sends daily email notifications with timezone matching, DailyLog handling, nutrition guidance, 20 tests (P2.5) -- [x] **GET /api/calendar/[userId]/[token].ics** - Returns ICS feed with 90-day phase events and period prediction feedback, token validation, caching headers, 11 tests (P2.6, P4.5) -- [x] **POST /api/calendar/regenerate-token** - Generates new 32-char calendar token, returns URL, 9 tests (P2.7) -- [x] **GET /api/history** - Paginated historical daily logs with date filtering, validation, 19 tests (P2.8) -- [x] **GET /api/period-history** - Paginated period logs with cycle length calculation and average, 18 tests (P5.1) -- [x] **PATCH /api/period-logs/[id]** - Edit period log startDate with validation, 10 tests (P5.1) -- [x] **DELETE /api/period-logs/[id]** - Delete period log with user.lastPeriodDate update, 6 tests (P5.1) -- [x] **GET /api/health** - Health check endpoint with PocketBase connectivity check, 14 tests (P2.15) -- [x] **GET /metrics** - Prometheus metrics endpoint with counters, gauges, histograms, 33 tests (18 lib + 15 route) (P2.16) - -### Pages (8 complete) -- [x] **Login Page** - OIDC (Pocket-ID) with email/password fallback, error handling, loading states, redirect, rate limiting, 32 tests (P1.6, P2.18, P4.6) -- [x] **Dashboard Page** - Complete daily interface with /api/today integration, DecisionCard, DataPanel, NutritionPanel, OverrideToggles, 23 tests (P1.7) -- [x] **Settings Page** - Form for cycleLength, notificationTime, timezone with validation, loading states, error handling, logout button, 34 tests (P2.9) -- [x] **Settings/Garmin Page** - Token input form, connection status, expiry warnings, disconnect functionality, 27 tests (P2.10) -- [x] **Calendar Page** - MonthView with navigation controls, ICS subscription section with URL display, copy button, token regeneration, 23 tests (P2.11) -- [x] **History Page** - Table view of DailyLogs with date filtering, pagination, decision styling, 26 tests (P2.12) -- [x] **Period History Page** - Table view of PeriodLogs with edit/delete modals, pagination, cycle length calculation, average cycle length, prediction accuracy display, 27 tests (P5.1) -- [x] **Plan Page** - Phase overview, training guidance, exercise reference, rebounding techniques, 16 tests (P2.13) - -### Test Infrastructure -- [x] **test-setup.ts** - Global test setup with @testing-library/jest-dom matchers and cleanup - -### P3: Quality and Testing -- [x] **P3.1: Decision Engine Tests** - Complete with 24 tests covering all 8 priority rules and override combinations -- [x] **P3.2: Nutrition Tests** - Complete with 17 tests covering seed cycling, carb ranges, keto guidance by phase -- [x] **P3.3: Email Tests** - Complete with 30 tests covering daily emails, period confirmation, token expiration warnings, structured logging -- [x] **P3.4: ICS Tests** - Complete with 28 tests covering ICS format validation, 90-day event generation, timezone handling, period prediction feedback -- [x] **P3.5: Encryption Tests** - Complete with 14 tests covering AES-256-GCM round-trip, error handling, key validation -- [x] **P3.6: Garmin Tests** - Complete with 33 tests covering API interactions, token expiry, error handling -- [x] **P3.7: Error Handling Improvements** - Replaced console.error with structured pino logger across API routes, added key event logging (Period logged, Override toggled, Decision calculated, Auth failure with IP address), 6 new tests in auth-middleware.test.ts -- [x] **P3.8: Loading States** - Complete with skeleton components (DecisionCardSkeleton, DataPanelSkeleton, NutritionPanelSkeleton, MiniCalendarSkeleton, OverrideTogglesSkeleton, CycleInfoSkeleton, DashboardSkeleton), 29 tests in skeletons.test.tsx; loading.tsx files for all routes (dashboard, calendar, history, plan, settings); shimmer animations matching spec requirements -- [x] **P3.9: Token Expiration Warnings** - Complete with 10 new tests in email.test.ts, 10 new tests in garmin-sync/route.test.ts; sends warnings at 14 and 7 days before expiry -- [x] **P3.11: Missing Component Tests** - Complete with 98 tests across 5 component test files (DecisionCard: 19, DataPanel: 18, NutritionPanel: 16, OverrideToggles: 18, DayCell: 27) - -### P4: UX Polish and Accessibility -- [x] **P4.1: Dashboard Onboarding Banners** - Complete with OnboardingBanner component (16 tests), dashboard integration (5 new tests) -- [x] **P4.2: Accessibility Improvements** - Complete with skip navigation, semantic landmarks, calendar screen reader labels, keyboard navigation (9 new tests) -- [x] **P4.3: Dark Mode Configuration** - Complete with automatic dark mode via prefers-color-scheme media query -- [x] **P4.4: Loading Performance** - Complete with Next.js loading.tsx providing 100ms target, skeleton components, and optimistic UI for overrides -- [x] **P4.5: Period Prediction Accuracy Feedback** - Complete with predictedDate tracking in PeriodLog, daysEarly/daysLate calculations, "(Predicted)" labels in ICS feed (11 new tests across 3 files) -- [x] **P4.6: Rate Limiting** - Complete with client-side login rate limiting (5 attempts per minute, 6 new tests) - ---- - -## Discovered Issues - -*Bugs and inconsistencies found during implementation* - -### Spec Gaps Discovered (2025-01-11) -Analysis of all specs vs implementation revealed these gaps: - -| Gap | Spec | Status | Notes | -|-----|------|--------|-------| -| Logout functionality | authentication.md | **COMPLETE** | Added POST /api/auth/logout + settings button | -| Garmin sync structured logging | observability.md | **COMPLETE** | Added sync start/complete/failure logging | -| Email sent/failed logging | observability.md | **COMPLETE** | Email events now logged (info for success, error for failure) with structured data (userId, emailType, success) | -| Period history UI | cycle-tracking.md | **COMPLETE** | See P5.1 below | -| Dashboard color-coded backgrounds | dashboard.md | **COMPLETE** | DecisionCard shows RED/YELLOW/GREEN backgrounds per status (8 new tests) | -| Toast notifications | dashboard.md | **COMPLETE** | sonner library + Toaster component + showToast utility (23 tests) | -| CI pipeline | testing.md | **COMPLETE** | See P5.3 below | - -### Spec Gaps Fixed (2026-01-12) -Additional spec compliance improvements implemented: - -| Gap | Spec | Status | Notes | -|-----|------|--------|-------| -| Email subject line format | notifications.md | **FIXED** | Subject now uses spec format: `PhaseFlow: [STATUS] - Day [cycleDay] ([phase])` | -| Seed switch alert in email | notifications.md | **FIXED** | Daily email now includes seed switch alert on day 15 | -| HRV status color-coding | dashboard.md | **FIXED** | Data panel now shows green/red/gray based on HRV status | -| Intensity progress bar | dashboard.md | **FIXED** | Data panel now shows visual progress bar with color-coding | -| Seed switch alert on day 15 | nutrition.md | **FIXED** | NutritionPanel now displays seedSwitchAlert from API | -| Phase emojis in calendar legend | calendar.md | **FIXED** | MonthView now shows emojis per spec (🩸 Menstrual \| 🌱 Follicular \| 🌸 Ovulation \| 🌙 Early Luteal \| 🌑 Late Luteal) | -| Period indicator in day cells | calendar.md | **FIXED** | DayCell now shows 🩸 for days 1-3 | -| IP address in auth failure logs | observability.md | **FIXED** | Auth middleware now logs client IP from x-forwarded-for or x-real-ip headers | - ---- - -## P5: Final Items ✅ ALL COMPLETE - -These items were identified during gap analysis and have been completed. - -### P5.1: Period History UI ✅ COMPLETE -- [x] Create period history viewing and editing UI -- **Spec Reference:** specs/cycle-tracking.md lines 93-111 -- **Implementation Details:** - - **GET /api/period-history** - Paginated list of period logs with cycle length calculations (18 tests) - - Returns items with startDate, id, cycleLength (days since previous period) - - Calculates average cycle length across all periods - - Includes prediction accuracy metrics (totalPeriods, predictedCorrectly) - - Pagination with page/limit/totalPages/hasMore - - Sorts by startDate descending (most recent first) - - **PATCH /api/period-logs/[id]** - Edit period log startDate (10 tests) - - Validates startDate in YYYY-MM-DD format - - Prevents duplicate period dates - - Updates associated PeriodLog record - - Returns updated period log - - **DELETE /api/period-logs/[id]** - Delete period log (6 tests) - - Updates user.lastPeriodDate to most recent remaining period - - Handles deletion of last period log (sets lastPeriodDate to null) - - Requires authentication - - Returns 204 No Content on success - - **/period-history page** - Table view with edit/delete modals (27 tests) - - Table columns: Date, Cycle Length, Days Early/Late, Actions (Edit/Delete) - - Edit modal with date input and validation - - Delete confirmation modal with warning text - - Pagination controls with page numbers - - Displays average cycle length at top - - Shows prediction accuracy percentage - - Loading states and error handling -- **Files Created:** - - `src/app/api/period-history/route.ts` - API route with 18 tests - - `src/app/api/period-logs/[id]/route.ts` - API route with 16 tests (10 PATCH, 6 DELETE) - - `src/app/period-history/page.tsx` - Page component with 27 tests -- **Total Tests Added:** 61 tests (18 + 16 + 27) -- **Why:** Users need to view and correct their period log history per spec requirement - -### P5.2: Toast Notifications ✅ COMPLETE -- [x] Add toast notification system for user feedback -- **Spec Reference:** specs/dashboard.md lines 88-96 -- **Features Implemented:** - - Toast position: Bottom-right - - Auto-dismiss after 5 seconds for success/info toasts - - Error toasts persist until dismissed (per spec: "Errors persist until dismissed") - - Toast types: success, error, info - - Dark mode support with proper color theming - - Close button on all toasts -- **Library Used:** sonner (v2.0.7) -- **Files Created/Modified:** - - `src/components/ui/toaster.tsx` - Toaster component wrapping sonner with showToast utility (23 tests) - - `src/app/layout.tsx` - Added Toaster provider - - `src/app/page.tsx` - Dashboard override toggle errors now use toast - - `src/app/settings/page.tsx` - Settings save/load errors now use toast - - `src/app/settings/garmin/page.tsx` - Garmin connection success/error now use toast - - `src/app/calendar/page.tsx` - Calendar load errors now use toast - - `src/app/period-history/page.tsx` - Period history load/delete errors now use toast -- **Test Files Updated:** - - `src/components/ui/toaster.test.tsx` - 23 tests for toast component - - `src/app/layout.test.tsx` - Added Toaster mock - - `src/app/page.test.tsx` - Added showToast mock and test - - `src/app/settings/page.test.tsx` - Added showToast mock - - `src/app/settings/garmin/page.test.tsx` - Added showToast mock - - `src/app/calendar/page.test.tsx` - Added showToast mock and test - - `src/app/period-history/page.test.tsx` - Added showToast mock and tests -- **Total Tests Added:** 27 new tests (23 toaster + 4 integration tests across pages) -- **Why:** Better UX for transient feedback per spec requirements - -### P5.3: CI Pipeline ✅ COMPLETE -- [x] Add test/lint/build to CI pipeline -- **Spec Reference:** specs/testing.md mentions CI pipeline -- **Required:** "All tests (unit, integration, E2E) pass in CI before merge" -- **Files Created:** - - `.gitea/workflows/ci.yml` - CI workflow with lint, typecheck, and unit tests -- **Features Implemented:** - - Runs on pull requests to main and pushes to main - - Node.js 24 with pnpm 10 setup - - pnpm dependency caching for faster CI runs - - Linting with `pnpm lint` - - Type checking with `pnpm tsc --noEmit` - - Unit tests with `pnpm test:run` - - Required environment variables provided for CI context -- **Why:** CI enforcement prevents broken code from being merged - -### P5.4: E2E Tests ✅ COMPLETE -- [x] Complete E2E test suite for all user flows -- **Spec Reference:** specs/testing.md -- **Files Created:** - - `e2e/smoke.spec.ts` - 3 tests for basic app functionality - - `e2e/auth.spec.ts` - 14 tests for login page, protected routes, public routes - - `e2e/dashboard.spec.ts` - 24 tests for dashboard display, overrides, data panels, nutrition, and accessibility (expanded from 10 tests) - - `e2e/settings.spec.ts` - 15 tests for settings and Garmin configuration - - `e2e/period-logging.spec.ts` - 14 tests for period history, API auth, and period logging flow - - `e2e/calendar.spec.ts` - 21 tests for calendar view, ICS endpoints, and display features - - `e2e/garmin.spec.ts` - 7 tests for Garmin connection and token management - - `e2e/health.spec.ts` - 3 tests for health/observability endpoints (NEW) - - `e2e/history.spec.ts` - 7 tests for history page (6 authenticated + 1 unauthenticated) (NEW) - - `e2e/plan.spec.ts` - 7 tests for plan page (6 authenticated + 1 unauthenticated) (NEW) - - `e2e/decision-engine.spec.ts` - 8 tests for decision engine (4 display + 4 override) (NEW) - - `e2e/cycle.spec.ts` - 11 tests for cycle tracking (1 API + 4 display + 2 settings + 3 period logging + 1 calendar) (NEW) -- **Total E2E Tests:** 113 tests (36 pass without auth, 77 skip when TEST_USER_EMAIL/TEST_USER_PASSWORD not set) -- **Test Categories:** - - Unauthenticated flows: Login page UI, form validation, error handling, protected route redirects - - Authenticated flows: Dashboard display, settings form, calendar navigation (requires test credentials) - - API endpoints: Health check, auth requirements for protected endpoints -- **Why:** Comprehensive E2E coverage ensures production reliability - -### Previously Fixed Issues - -- [x] ~~**Decision Engine Override Inconsistency**~~ - FIXED. The decision engine implementation had an inconsistency with the spec for sleep and pms overrides. According to specs/decision-engine.md lines 93-94, sleep and pms overrides should return GENTLE status, but the implementation was incorrectly returning REST for all overrides (flare, stress, sleep, pms). Updated `getDecisionWithOverrides()` in `src/lib/decision-engine.ts` to return the correct status: flare → REST, stress → REST, sleep → GENTLE, pms → GENTLE. This aligns the implementation with the specification. -- [x] ~~**CRITICAL: Cycle phase boundaries hardcoded for 31-day cycle**~~ - FIXED. Phase boundaries were not scaling with cycle length. The spec (cycle-tracking.md) defines formulas: MENSTRUAL 1-3, FOLLICULAR 4-(cycleLength-16), OVULATION (cycleLength-15)-(cycleLength-14), EARLY_LUTEAL (cycleLength-13)-(cycleLength-7), LATE_LUTEAL (cycleLength-6)-cycleLength. Added `getPhaseBoundaries(cycleLength)` function and updated `getPhase()` to accept cycleLength parameter. Updated all callers (API routes, components) to pass cycleLength. Added 13 new tests. -- [x] ~~ICS emojis did not match calendar.md spec~~ - FIXED. Changed from colored circles (🔵🟢🟣🟡🔴) to thematic emojis (🩸🌱🌸🌙🌑) per spec. -- [x] ~~ICS missing CATEGORIES field for calendar app colors~~ - FIXED. Added CATEGORIES field per calendar.md spec: MENSTRUAL=Red, FOLLICULAR=Green, OVULATION=Pink, EARLY_LUTEAL=Yellow, LATE_LUTEAL=Orange. Added 5 new tests. -- [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) -- [x] Build requires RESEND_API_KEY and ENCRYPTION_KEY environment variables - works with `pnpm test:run` but `pnpm build` fails without them. This is expected behavior for production builds. - ---- - ---- - -## E2E Test Coverage Plan - -This section outlines comprehensive e2e tests to cover the functionality described in the 10 specification files. Tests are organized by feature area with clear acceptance criteria mapping. - -### 1. Authentication Tests (`e2e/auth.spec.ts`) - -#### Existing Coverage -- Login page loads -- Form validation -- Protected routes redirect -- Basic error handling - -#### Additional Tests Needed - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `OIDC flow completes successfully` | Click OIDC login, complete flow, verify dashboard redirect | auth.md - Login Flow | -| `Session persists across browser refresh` | Login, refresh page, verify still authenticated | auth.md - Session Management | -| `Session expires after inactivity` | Verify 14-day expiration (simulated) | auth.md - Session Management | -| `Logout clears session and cookie` | Click logout, verify redirect to login, verify cookie cleared | auth.md - Protected Routes | -| `Invalid token redirects to login` | Manually corrupt token, verify redirect | auth.md - Protected Routes | -| `Multiple tabs share session state` | Open two tabs, logout in one, verify other redirects | auth.md - Session Management | - ---- - -### 2. Dashboard Tests (`e2e/dashboard.spec.ts`) - -#### Existing Coverage -- Dashboard renders -- Decision display -- Override toggles - -#### Additional Tests Needed - -##### Decision Card -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Decision card shows REST status with red color` | Verify REST displays correctly | dashboard.md - Decision Card | -| `Decision card shows GENTLE status with yellow color` | Verify GENTLE displays correctly | dashboard.md - Decision Card | -| `Decision card shows TRAIN status with green color` | Verify TRAIN displays correctly | dashboard.md - Decision Card | -| `Decision card displays reason text` | Verify reason explains limiting factor | dashboard.md - Decision Card | -| `Decision card shows appropriate icon per status` | Verify icon matches status | dashboard.md - Decision Card | - -##### Data Panel (8 Metrics) -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `HRV status displays with correct color coding` | Balanced=green, Unbalanced=red, Unknown=grey | dashboard.md - Data Panel | -| `Body Battery current displays 0-100 range` | Verify value display and bounds | dashboard.md - Data Panel | -| `Body Battery yesterday low displays correctly` | Verify yesterday's low value | dashboard.md - Data Panel | -| `Cycle day displays correctly (Day X format)` | Verify "Day 12" format | dashboard.md - Data Panel | -| `Current phase displays correctly` | Verify phase name matches cycle day | dashboard.md - Data Panel | -| `Week intensity minutes displays correctly` | Verify cumulative weekly minutes | dashboard.md - Data Panel | -| `Phase limit displays correctly` | Verify limit matches phase config | dashboard.md - Data Panel | -| `Remaining minutes calculates correctly` | Verify phase limit minus week intensity | dashboard.md - Data Panel | - -##### Nutrition Panel -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Seeds display Flax+Pumpkin for days 1-14` | Verify follicular phase seeds | nutrition.md - Seed Cycling | -| `Seeds display Sesame+Sunflower for days 15+` | Verify luteal phase seeds | nutrition.md - Seed Cycling | -| `Carb range displays for current cycle day` | Verify range matches day | nutrition.md - Macro Guidance | -| `Keto guidance shows OPTIONAL during optimal window` | Days 7-14 should show optional | nutrition.md - Macro Guidance | -| `Keto guidance shows NEVER during late luteal` | Days 25-31 should show never (red) | nutrition.md - Macro Guidance | -| `Seed switch alert appears only on day 15` | Verify alert visibility | nutrition.md - Seed Switch Alert | -| `Seed switch alert is dismissible` | Click dismiss, verify gone | dashboard.md - Nutrition Panel | - -##### Override Toggles -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Flare toggle forces REST decision` | Enable flare, verify REST | decision-engine.md - Override Integration | -| `Stress toggle forces REST decision` | Enable stress, verify REST | decision-engine.md - Override Integration | -| `Sleep toggle forces GENTLE decision` | Enable poor sleep, verify GENTLE | decision-engine.md - Override Integration | -| `PMS toggle forces GENTLE decision` | Enable PMS, verify GENTLE | decision-engine.md - Override Integration | -| `Override persists after page refresh` | Toggle, refresh, verify still active | dashboard.md - Override Toggles | -| `Override can be cleared` | Toggle on, toggle off, verify cleared | dashboard.md - Override Toggles | -| `Multiple overrides respect priority (flare > stress)` | Enable both, verify flare message | decision-engine.md - Override Priority | - -##### Mini Calendar -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Mini calendar shows current month` | Verify correct month/year | dashboard.md - Mini Calendar | -| `Today is highlighted in calendar` | Verify today has distinct styling | dashboard.md - Mini Calendar | -| `Phase colors display correctly` | Verify color coding per phase | dashboard.md - Mini Calendar | -| `Period days marked distinctly` | Verify period days have special marker | dashboard.md - Mini Calendar | - -##### Onboarding & Error States -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Onboarding banner shows when Garmin not connected` | New user sees Garmin setup prompt | dashboard.md - User Flows | -| `Onboarding banner shows when last period not set` | Shows date picker for period | dashboard.md - User Flows | -| `Onboarding banner shows when notification time not set` | Prompts for notification preference | dashboard.md - User Flows | -| `Network error shows retry option` | Simulate failure, verify retry UI | dashboard.md - Edge Cases | -| `Skeleton loaders display during data fetch` | Verify loading states | dashboard.md - Features | -| `Error toast auto-dismisses after 5 seconds` | Verify toast timing | dashboard.md - Features | - -##### Accessibility -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Dashboard navigable with keyboard only` | Tab through all interactive elements | dashboard.md - Accessibility | -| `Override toggles not accidentally activated` | Verify deliberate activation required | dashboard.md - Success Criteria | -| `All critical metrics visible without scrolling on mobile` | Viewport check | dashboard.md - Responsive Design | - ---- - -### 3. Decision Engine Tests (`e2e/decision-engine.spec.ts`) ✅ COMPLETE - -**File created** - Tests the full decision priority chain through the UI (8 tests) - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `HRV Unbalanced forces REST` | User with unbalanced HRV sees REST | decision-engine.md - Priority 1 | -| `Body Battery yesterday low <30 forces REST` | Low recovery triggers REST | decision-engine.md - Priority 2 | -| `Late Luteal phase forces GENTLE` | Days 25-31 show GENTLE | decision-engine.md - Priority 3 | -| `Menstrual phase forces GENTLE` | Days 1-3 show GENTLE | decision-engine.md - Priority 4 | -| `Weekly intensity at phase limit forces REST` | At limit shows REST | decision-engine.md - Priority 5 | -| `Body Battery current <75 shows LIGHT` | Low current BB shows LIGHT | decision-engine.md - Priority 6 | -| `Body Battery current 75-84 shows REDUCED` | Medium BB shows REDUCED | decision-engine.md - Priority 7 | -| `All systems normal shows TRAIN` | Default state is TRAIN | decision-engine.md - Priority 8 | -| `Decision reason clearly explains limiting factor` | Verify reason text matches rule | decision-engine.md - Success Criteria | - ---- - -### 4. Cycle Tracking Tests (`e2e/cycle.spec.ts`) ✅ COMPLETE - -**File created** - Tests cycle calculation and phase transitions (11 tests) - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Cycle day resets to 1 on period start` | Log period, verify day 1 | cycle.md - Acceptance Criteria | -| `Phase transitions at correct day boundaries` | Verify each phase boundary | cycle.md - Phase System | -| `Menstrual phase shows days 1-3` | Verify phase assignment | cycle.md - Phase System | -| `Follicular phase shows days 4 to cycleLength-16` | Verify follicular range | cycle.md - Phase System | -| `Ovulation phase shows correct 2-day window` | Verify ovulation timing | cycle.md - Phase System | -| `Early luteal phase shows correct range` | Verify early luteal | cycle.md - Phase System | -| `Late luteal phase shows last 6 days` | Verify late luteal | cycle.md - Phase System | -| `Weekly limits adjust per phase` | Verify limit changes with phase | cycle.md - Acceptance Criteria | -| `Cycle exceeding configured length defaults to late luteal` | Day 35 of 31-day cycle | cycle.md - Edge Cases | -| `Custom cycle length (21 days) scales phases correctly` | Short cycle test | cycle.md - Features | -| `Custom cycle length (45 days) scales phases correctly` | Long cycle test | cycle.md - Features | - ---- - -### 5. Period Logging Tests (`e2e/period-logging.spec.ts`) - -#### Existing Coverage -- Basic period date logging - -#### Additional Tests Needed - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Period date updates cycle day immediately` | Log period, verify day reset | cycle.md - User Flows | -| `Period date cannot be in future` | Attempt future date, verify error | cycle.md - User Flows | -| `Period history shows all logged periods` | View history, verify all entries | cycle.md - Acceptance Criteria | -| `Prediction accuracy calculated on new period` | Log period, see days early/late | calendar.md - ICS Feed Details | -| `Dashboard updates after period logged` | Log period, dashboard reflects change | cycle.md - User Flows | - ---- - -### 6. Calendar Tests (`e2e/calendar.spec.ts`) - -#### Existing Coverage -- Calendar page loads -- ICS export basic - -#### Additional Tests Needed - -##### In-App Calendar -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Month navigation works (next/previous)` | Click arrows, verify month changes | calendar.md - User Flows | -| `Phase colors render correctly per day` | Verify color coding | calendar.md - Features | -| `Calendar responsive on mobile` | Viewport test | calendar.md - Acceptance Criteria | -| `Today highlighted in calendar view` | Verify today styling | calendar.md - Features | - -##### ICS Feed -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `ICS feed URL generates correctly` | Click generate, verify URL format | calendar.md - User Flows | -| `ICS feed contains next 90 days of events` | Download ICS, count events | calendar.md - ICS Feed Details | -| `ICS events are all-day events` | Parse ICS, verify all-day | calendar.md - ICS Feed Details | -| `Phase colors in ICS match spec` | Verify color hex values | calendar.md - ICS Feed Details | -| `Phase emojis included in event titles` | Verify emoji presence | calendar.md - ICS Feed Details | -| `Invalid token returns 401` | Use wrong token, verify 401 | calendar.md - Edge Cases | -| `Token regeneration invalidates old URL` | Regenerate, old URL fails | calendar.md - Acceptance Criteria | -| `Predicted vs actual events distinguished` | After period log, verify labels | calendar.md - ICS Feed Details | -| `Future cycles regenerated on new period` | Log period, future events update | calendar.md - Edge Cases | - ---- - -### 7. Settings Tests (`e2e/settings.spec.ts`) - -#### Existing Coverage -- Basic settings configuration - -#### Additional Tests Needed - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Cycle length editable (21-45 range)` | Change cycle length, verify saved | auth.md - Settings Page | -| `Cycle length rejects values outside range` | Try 20 or 46, verify error | auth.md - User Schema | -| `Notification time editable (HH:MM format)` | Change time, verify saved | auth.md - Settings Page | -| `Timezone editable (IANA format)` | Change timezone, verify saved | auth.md - Settings Page | -| `Changes persist after logout/login` | Edit, logout, login, verify | auth.md - Settings Page | -| `Garmin settings link navigates correctly` | Click manage, verify route | auth.md - Settings Page | - ---- - -### 8. Garmin Integration Tests (`e2e/garmin.spec.ts`) - -#### Existing Coverage -- Basic Garmin connection flows - -#### Additional Tests Needed - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Connection status shows green when connected` | Verify indicator color | garmin.md - Token Storage | -| `Connection status shows red when disconnected` | Verify indicator color | garmin.md - Features | -| `Days until expiry displays correctly` | Verify countdown | garmin.md - Token Expiration | -| `14-day warning shows yellow indicator` | Approaching expiry warning | garmin.md - Token Expiration | -| `7-day warning shows critical alert` | Critical expiry warning | garmin.md - Token Expiration | -| `Token paste and save works` | Paste tokens, verify saved | garmin.md - OAuth Flow | -| `Disconnect clears connection` | Click disconnect, verify cleared | garmin.md - API Endpoints | -| `Instructions display correctly` | Verify setup instructions visible | garmin.md - OAuth Flow | -| `Expired tokens show red alert` | Expired state displays correctly | garmin.md - Token Expiration | - ---- - -### 9. History Tests (`e2e/history.spec.ts`) ✅ COMPLETE - -**File created** - Tests historical data viewing (7 tests) - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `History page loads with paginated data` | Verify table and pagination | dashboard.md - implied | -| `Date range filter works correctly` | Apply filter, verify results | dashboard.md - implied | -| `Decision status shows correct colors` | REST=red, TRAIN=green, GENTLE=yellow | dashboard.md - Decision Card | -| `All required columns display` | Date, Day, Phase, Decision, BB, HRV, Intensity | dashboard.md - implied | -| `Pagination controls work` | Next/previous page navigation | dashboard.md - implied | -| `Empty state displays when no data` | New user with no history | dashboard.md - implied | - ---- - -### 10. Notifications Tests (`e2e/notifications.spec.ts`) - -**New file needed** - Tests notification preferences (not actual email delivery) - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Notification time preference saves` | Set time, verify persisted | notifications.md - Features | -| `Timezone affects notification scheduling` | Set timezone, verify display | notifications.md - Timezone Query | -| `Dashboard shows next notification time` | Display when email expected | notifications.md - Features | - ---- - -### 11. Health & Observability Tests (`e2e/health.spec.ts`) ✅ COMPLETE - -**File created** - Tests monitoring endpoints (3 tests) - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Health endpoint returns 200 when healthy` | GET /api/health succeeds | observability.md - Health Check | -| `Health endpoint responds in under 100ms` | Performance check | observability.md - Success Criteria | -| `Metrics endpoint is accessible` | GET /metrics returns data | observability.md - Prometheus Metrics | - ---- - -### 12. Exercise Plan Tests (`e2e/plan.spec.ts`) ✅ COMPLETE - -**File created** - Tests the plan/reference page (7 tests) - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Plan page shows current cycle status` | Day, phase, days until next | exercise-plan implied | -| `All 5 phase cards display` | Verify all phases shown | cycle.md - Phase System | -| `Phase limits display per phase` | Verify weekly limits | cycle.md - Phase System | -| `Training type displays per phase` | Strength vs rebounding | cycle.md - Phase System | - ---- - -### 13. Dark Mode Tests (`e2e/dark-mode.spec.ts`) - -**New file needed** - Tests system preference detection - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Auto-detect dark mode from system preference` | System dark → app dark | dashboard.md - Features | -| `Colors maintain contrast in dark mode` | Minimum 4.5:1 contrast | dashboard.md - Accessibility | - ---- - -### 14. Mobile Responsiveness Tests (`e2e/mobile.spec.ts`) - -**New file needed** - Tests mobile viewport behavior - -| Test Name | Description | Spec Reference | -|-----------|-------------|----------------| -| `Dashboard single column on mobile (<768px)` | Verify layout change | dashboard.md - Responsive Design | -| `Touch targets minimum 44x44px` | Verify tap target sizes | dashboard.md - Responsive Design | -| `All critical metrics visible without scrolling` | Viewport check | dashboard.md - Success Criteria | -| `Calendar responsive on mobile` | Verify calendar adapts | calendar.md - Acceptance Criteria | - ---- - -### E2E Test Summary - -#### New Test Files Created ✅ -1. ✅ `e2e/decision-engine.spec.ts` - 8 tests (COMPLETE) -2. ✅ `e2e/cycle.spec.ts` - 11 tests (COMPLETE) -3. ✅ `e2e/history.spec.ts` - 7 tests (COMPLETE) -4. ✅ `e2e/health.spec.ts` - 3 tests (COMPLETE) -5. ✅ `e2e/plan.spec.ts` - 7 tests (COMPLETE) - -#### Additional Test Files Planned -6. `e2e/notifications.spec.ts` - 3 tests (not yet needed) -7. `e2e/dark-mode.spec.ts` - 2 tests (not yet needed) -8. `e2e/mobile.spec.ts` - 4 tests (not yet needed) - -#### Existing Files to Extend -1. `e2e/auth.spec.ts` - +6 tests -2. `e2e/dashboard.spec.ts` - +35 tests (ALL COMPLETE) -3. `e2e/period-logging.spec.ts` - +5 tests -4. `e2e/calendar.spec.ts` - +13 tests -5. `e2e/settings.spec.ts` - +6 tests -6. `e2e/garmin.spec.ts` - +9 tests - -#### Total Test Count -- **Current E2E tests**: 165 tests across 12 test files (comprehensive coverage including auth, dashboard, period logging, calendar, settings, Garmin, decision engine, cycle tracking, health, history, and plan) -- **New tests needed**: ~50 tests -- **Across 15 test files** (12 existing + 3 new) - -#### Priority Order for Implementation -1. **High Priority** (Core functionality) - - Decision Engine tests - - Cycle Tracking tests - - Dashboard Data Panel tests - -2. **Medium Priority** (User workflows) - - Period Logging tests - - Calendar ICS tests - - Settings tests - -3. **Lower Priority** (Edge cases & polish) - - Mobile Responsiveness tests - - Dark Mode tests - - History tests - - Health/Observability tests +## E2E Test Enhancement Opportunities + +These are optional enhancements to improve E2E coverage. Not required for feature completeness. + +### New Test Files (Lower Priority) +| File | Tests | Description | +|------|-------|-------------| +| notifications.spec.ts | 3 | Notification preferences | +| dark-mode.spec.ts | 2 | System preference detection | +| mobile.spec.ts | 4 | Mobile viewport behavior | + +### Existing File Extensions +| File | Additional Tests | Focus Area | +|------|------------------|------------| +| auth.spec.ts | +6 | OIDC flow, session persistence | +| period-logging.spec.ts | +5 | Future dates, dashboard updates | +| calendar.spec.ts | +13 | ICS content validation, responsive | +| settings.spec.ts | +6 | Persistence, timezone changes | +| garmin.spec.ts | +9 | Expiry warnings, token refresh | --- ## 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. **P4:** UX polish and accessibility improvements from spec requirements -7. **Component Reuse:** Dashboard components are complete and can be used directly in P1.7 -8. **HRV Rule:** HRV Unbalanced status ALWAYS forces REST - this is the highest algorithmic priority and cannot be overridden by manual toggles -9. **Override Order:** When multiple overrides are active, apply in order: flare > stress > sleep > pms -10. **Token Warnings:** Per spec, warnings are sent at exactly 14 days and 7 days before expiry (P3.9 COMPLETE) -11. **Health Check Priority:** P2.15 (GET /api/health) should be implemented early - it's required for deployment monitoring and load balancer health probes -12. **Structured Logging:** P2.17 (pino logger) is COMPLETE - new code should use `import { logger } from "@/lib/logger"` for all logging -13. **OIDC Authentication:** P2.18 COMPLETE - Login page auto-detects OIDC via `listAuthMethods()` and shows "Sign In with Pocket-ID" button when configured. Falls back to email/password when OIDC not available. Configure OIDC provider in PocketBase Admin under Settings → Auth providers → OpenID Connect -15. **Dark Mode:** COMPLETE - Auto-detects system preference via prefers-color-scheme media query (P4.3) -16. **Component Tests:** P3.11 COMPLETE - All 5 dashboard and calendar components now have comprehensive unit tests (90 tests total) -17. **Gap Analysis (2026-01-12):** Verified 977 tests across 50 files + 64 E2E tests across 6 files. All API routes (21), pages (8), components, and lib files (12) have tests. P0-P5 complete. Project is feature complete. -18. **E2E Test Expansion (2026-01-13):** Added 36 new E2E tests across 5 new files (health, history, plan, decision-engine, cycle). Total E2E coverage now 100 tests across 12 files. -19. **E2E Test Expansion (2026-01-13):** Added 14 new E2E tests to dashboard.spec.ts (8 data panel tests, 4 nutrition panel tests, 4 accessibility tests). Total dashboard E2E coverage now 24 tests. -20. **E2E Test Expansion (2026-01-13):** Added 16 new dashboard E2E tests covering decision card status display, override behaviors (stress/PMS), mini calendar features, onboarding banner prompts, and loading states. Total dashboard E2E coverage now 42 tests. -21. **E2E Test Expansion (2026-01-13):** Added 14 new E2E tests for calendar and settings validation. Calendar gained 7 tests in "ICS feed content validation" section (VCALENDAR structure, VEVENT entries, phase events with emojis, CATEGORIES for color coding, 90-day span, warning events, content-type validation). Settings gained 7 tests in "settings form validation" section (notification time HH:MM format, cycle length min/max validation, timezone editing, value display, persistence after reload, save button loading state). Total E2E coverage now 165 tests across 12 files. +1. **TDD Approach:** Write failing tests first, then implement +2. **Auth First:** P0 items unlock all other work +3. **No Mock Mode:** Use real data and APIs only +4. **ABOUTME Comments:** All files start with 2-line ABOUTME +5. **Commit Format:** Descriptive message + Claude footer +6. **Never use --no-verify:** All commits go through pre-commit hooks + +--- + +## Revision History + +- 2026-01-13: Condensed plan after feature completion (reduced from 1514 to ~170 lines) +- 2026-01-12: Fixed spec gaps (email format, HRV colors, progress bar, emojis) +- 2026-01-11: Completed P5.1-P5.4 (period history, toast, CI, E2E)