Files
phaseflow/IMPLEMENTATION_PLAN.md
Petru Paler 78c658822e
All checks were successful
Deploy / deploy (push) Successful in 1m57s
Add 16 new dashboard E2E tests for comprehensive UI coverage
- Decision Card tests: GENTLE/LIGHT/REDUCED status display, icon rendering
- Override behavior tests: stress forces REST, PMS forces GENTLE, persistence after refresh
- Mini Calendar tests: current month display, today highlight, phase colors, navigation
- Onboarding Banner tests: setup prompts, Garmin link, period date prompt
- Loading state tests: skeleton loaders, performance validation

Total dashboard E2E coverage now 42 tests. Overall E2E count: 129 tests across 12 files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 18:00:41 +00:00

91 KiB

PhaseFlow Implementation Plan

This file is maintained by Ralph. Run ./ralph-sandbox.sh plan 3 to generate tasks.

Current State Summary

Overall Status: 1014 unit tests passing across 51 test files + 129 E2E tests across 12 files

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

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)

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

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)
  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)
  5. ICS Feed: Generates 90 days of phase events for calendar subscription

P0: Critical Blockers ALL COMPLETE

These must be completed first - nothing else works without them.

P0.1: PocketBase Auth Helpers COMPLETE

  • Add authentication utilities to pocketbase.ts
  • Files:
    • src/lib/pocketbase.ts - Added createPocketBaseClient(), getCurrentUser(), isAuthenticated(), loadAuthFromCookies()
  • Tests:
    • src/lib/pocketbase.test.ts - 9 tests covering auth state management, cookie loading
  • Why: Every protected route and page depends on these helpers
  • Blocking: P0.2, P0.4, P1.1-P1.7, P2.2-P2.13

P0.2: Auth Middleware for API Routes COMPLETE

  • 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

P0.3: Decision Engine Override Handling COMPLETE

  • Add override priority logic before algorithmic decision
  • Files:
    • src/lib/decision-engine.ts - Added getDecisionWithOverrides(data, overrides) function
  • Tests:
    • src/lib/decision-engine.test.ts - 24 tests covering all 8 priority rules + override scenarios
  • Override Priority (enforced in this order):
    1. flare - Always forces REST
    2. stress - Forces REST
    3. sleep - Forces REST
    4. pms - Forces REST
  • Why: Overrides are core to the user experience per spec
  • Blocking: P1.4, P1.5

P0.4: GET /api/user Implementation COMPLETE

  • Return authenticated user profile
  • Files:
    • src/app/api/user/route.ts - Implemented GET handler with withAuth() wrapper
  • Tests:
    • src/app/api/user/route.test.ts - 4 tests covering auth, response shape, sensitive field exclusion
  • Response Shape:
    • id, email, garminConnected, cycleLength, lastPeriodDate, notificationTime, timezone, activeOverrides
    • Excludes sensitive fields: garminOauth1Token, garminOauth2Token, calendarToken
  • Why: Dashboard and all pages need user context
  • Depends On: P0.1, P0.2
  • Blocking: P1.7, P2.9, P2.10

P1: Core Functionality ALL COMPLETE

Minimum viable product - app can be used for daily decisions.

P1.1: PATCH /api/user Implementation COMPLETE

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • Wire up dashboard with real data from /api/today
  • Integrate DecisionCard, DataPanel, NutritionPanel, OverrideToggles
  • Implement override toggle functionality with optimistic updates
  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • 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

  • Add consistent error responses across all API routes
  • Replace console.error with structured pino logger
  • 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

  • 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

  • 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)

  • 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

  • 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

  • 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

  • Skip navigation link
  • Semantic HTML landmarks (main elements)
  • Screen reader labels for calendar buttons
  • 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

  • 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

  • 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

  • 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

  • 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

  • cycle.ts - Complete with 22 tests (getCycleDay, getPhase with dynamic boundaries for variable cycle lengths, getPhaseConfig, getPhaseLimit)
  • decision-engine.ts - Complete with 24 tests (getTrainingDecision + getDecisionWithOverrides)
  • pocketbase.ts - Complete with 9 tests (createPocketBaseClient, isAuthenticated, getCurrentUser, loadAuthFromCookies)
  • nutrition.ts - Complete with 17 tests (getNutritionGuidance, getSeedSwitchAlert, phase-specific carb ranges, keto guidance) (P3.2)
  • email.ts - Complete with 30 tests (sendDailyEmail, sendPeriodConfirmationEmail, sendTokenExpirationWarning, email formatting, structured logging for sent/failed events) (P3.3, P3.9)
  • 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)
  • encryption.ts - Complete with 14 tests (AES-256-GCM encrypt/decrypt, round-trip validation, error handling) (P3.5)
  • garmin.ts - Complete with 33 tests (fetchGarminData, fetchHrvStatus, fetchBodyBattery, fetchIntensityMinutes, isTokenExpired, daysUntilExpiry, error handling) (P2.1, P3.6)
  • auth-middleware.ts - Complete with 12 tests (withAuth() wrapper, structured logging, IP address logging)
  • middleware.ts - Complete with 12 tests (Next.js page protection)
  • logger.ts - Complete with 16 tests (JSON output, log levels, error serialization, child loggers) (P2.17)
  • metrics.ts - Complete with 18 tests (metrics collection, counters, gauges, histograms, Prometheus format) (P2.16)

Components

  • DecisionCard - Displays decision status, icon, reason with color-coded backgrounds (RED/YELLOW/GREEN per status)
  • DataPanel - Shows body battery, HRV, intensity data
  • NutritionPanel - Shows seeds, carbs, keto guidance
  • OverrideToggles - Toggle buttons for flare/stress/sleep/pms
  • DayCell - Phase-colored calendar day cell with click handler
  • MonthView - Calendar grid with DayCell integration, navigation controls (prev/next month, Today button), phase legend with emojis, 31 tests
  • MiniCalendar - Compact calendar widget with phase colors, navigation, legend, 23 tests (P2.14)

API Routes (21 complete)

  • POST /api/auth/logout - Clears session cookie, logs user out, 5 tests
  • GET /api/user - Returns authenticated user profile, 4 tests (P0.4)
  • PATCH /api/user - Updates user profile (cycleLength, notificationTime, timezone), 17 tests (P1.1)
  • POST /api/cycle/period - Logs period start date, updates user, creates PeriodLog with prediction tracking, 13 tests (P1.2, P4.5)
  • GET /api/cycle/current - Returns cycle day, phase, phaseConfig, daysUntilNextPhase, cycleLength, 10 tests (P1.3)
  • GET /api/today - Returns complete daily snapshot with decision, biometrics, nutrition, 24 tests (P1.4)
  • POST /api/overrides - Adds override to user.activeOverrides array, 14 tests (P1.5)
  • DELETE /api/overrides - Removes override from user.activeOverrides array, 14 tests (P1.5)
  • POST /api/garmin/tokens - Stores encrypted Garmin OAuth tokens, 15 tests (P2.2)
  • DELETE /api/garmin/tokens - Clears tokens and disconnects Garmin, 15 tests (P2.2)
  • GET /api/garmin/status - Returns connection status, expiry, warning level, 11 tests (P2.3)
  • 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)
  • POST /api/cron/notifications - Sends daily email notifications with timezone matching, DailyLog handling, nutrition guidance, 20 tests (P2.5)
  • 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)
  • POST /api/calendar/regenerate-token - Generates new 32-char calendar token, returns URL, 9 tests (P2.7)
  • GET /api/history - Paginated historical daily logs with date filtering, validation, 19 tests (P2.8)
  • GET /api/period-history - Paginated period logs with cycle length calculation and average, 18 tests (P5.1)
  • PATCH /api/period-logs/[id] - Edit period log startDate with validation, 10 tests (P5.1)
  • DELETE /api/period-logs/[id] - Delete period log with user.lastPeriodDate update, 6 tests (P5.1)
  • GET /api/health - Health check endpoint with PocketBase connectivity check, 14 tests (P2.15)
  • GET /metrics - Prometheus metrics endpoint with counters, gauges, histograms, 33 tests (18 lib + 15 route) (P2.16)

Pages (8 complete)

  • Login Page - OIDC (Pocket-ID) with email/password fallback, error handling, loading states, redirect, rate limiting, 32 tests (P1.6, P2.18, P4.6)
  • Dashboard Page - Complete daily interface with /api/today integration, DecisionCard, DataPanel, NutritionPanel, OverrideToggles, 23 tests (P1.7)
  • Settings Page - Form for cycleLength, notificationTime, timezone with validation, loading states, error handling, logout button, 34 tests (P2.9)
  • Settings/Garmin Page - Token input form, connection status, expiry warnings, disconnect functionality, 27 tests (P2.10)
  • Calendar Page - MonthView with navigation controls, ICS subscription section with URL display, copy button, token regeneration, 23 tests (P2.11)
  • History Page - Table view of DailyLogs with date filtering, pagination, decision styling, 26 tests (P2.12)
  • 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)
  • Plan Page - Phase overview, training guidance, exercise reference, rebounding techniques, 16 tests (P2.13)

Test Infrastructure

  • test-setup.ts - Global test setup with @testing-library/jest-dom matchers and cleanup

P3: Quality and Testing

  • P3.1: Decision Engine Tests - Complete with 24 tests covering all 8 priority rules and override combinations
  • P3.2: Nutrition Tests - Complete with 17 tests covering seed cycling, carb ranges, keto guidance by phase
  • P3.3: Email Tests - Complete with 30 tests covering daily emails, period confirmation, token expiration warnings, structured logging
  • P3.4: ICS Tests - Complete with 28 tests covering ICS format validation, 90-day event generation, timezone handling, period prediction feedback
  • P3.5: Encryption Tests - Complete with 14 tests covering AES-256-GCM round-trip, error handling, key validation
  • P3.6: Garmin Tests - Complete with 33 tests covering API interactions, token expiry, error handling
  • 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
  • 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
  • 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
  • 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

  • P4.1: Dashboard Onboarding Banners - Complete with OnboardingBanner component (16 tests), dashboard integration (5 new tests)
  • P4.2: Accessibility Improvements - Complete with skip navigation, semantic landmarks, calendar screen reader labels, keyboard navigation (9 new tests)
  • P4.3: Dark Mode Configuration - Complete with automatic dark mode via prefers-color-scheme media query
  • P4.4: Loading Performance - Complete with Next.js loading.tsx providing 100ms target, skeleton components, and optimistic UI for overrides
  • 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)
  • 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

  • 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

  • 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

  • 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

  • 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

  • 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.
  • 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.
  • ICS emojis did not match calendar.md spec - FIXED. Changed from colored circles (🔵🟢🟣🟡🔴) to thematic emojis (🩸🌱🌸🌙🌑) per spec.
  • 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.
  • src/lib/auth-middleware.ts does not exist - CREATED in P0.2
  • src/middleware.ts does not exist - CREATED in P0.2
  • ~garmin.ts is only 30% complete - missing specific biometric fetchers - FIXED in P2.1 (added fetchHrvStatus, fetchBodyBattery, fetchIntensityMinutes)
  • pocketbase.ts missing all auth helper functions - FIXED in P0.1
  • src/app/api/today/route.ts type error with null body battery values - FIXED (added null coalescing)
  • 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

  1. e2e/notifications.spec.ts - 3 tests (not yet needed)
  2. e2e/dark-mode.spec.ts - 2 tests (not yet needed)
  3. 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: 113 tests (36 pass without auth + 77 with auth; includes period logging flow and calendar display tests)
  • New tests needed: ~102 tests
  • Across 15 test files (7 existing + 8 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

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
  14. Dark Mode: COMPLETE - Auto-detects system preference via prefers-color-scheme media query (P4.3)
  15. Component Tests: P3.11 COMPLETE - All 5 dashboard and calendar components now have comprehensive unit tests (90 tests total)
  16. 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.
  17. 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.
  18. 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.
  19. 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.