Implement Garmin sync cron endpoint (P2.4)

Add daily sync functionality for Garmin biometric data:
- Fetch all users with garminConnected=true
- Skip users with expired tokens
- Decrypt OAuth2 tokens and fetch HRV, Body Battery, Intensity Minutes
- Calculate cycle day, phase, phase limit, remaining minutes
- Compute training decision using decision engine
- Create DailyLog entries for each user
- Return sync summary with usersProcessed, errors, skippedExpired, timestamp

Includes 22 tests covering:
- CRON_SECRET authentication
- User iteration and filtering
- Token decryption and expiry handling
- Garmin API data fetching
- DailyLog creation with all required fields
- Error handling and graceful degradation

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-10 19:50:26 +00:00
parent 0fc25a49f1
commit fc970a2c61
3 changed files with 509 additions and 8 deletions

View File

@@ -37,7 +37,7 @@ This file is maintained by Ralph. Run `./ralph-sandbox.sh plan 3` to generate ta
| GET /api/garmin/status | **COMPLETE** | Returns connection status, expiry, warning level (11 tests) |
| GET /api/calendar/[userId]/[token].ics | 501 | Has param extraction, core logic TODO |
| POST /api/calendar/regenerate-token | 501 | Returns Not Implemented |
| POST /api/cron/garmin-sync | 501 | Has CRON_SECRET auth check, core logic TODO |
| POST /api/cron/garmin-sync | **COMPLETE** | Syncs Garmin data for all users, creates DailyLogs (22 tests) |
| POST /api/cron/notifications | 501 | Has CRON_SECRET auth check, core logic TODO |
### Pages (7 total)
@@ -84,6 +84,7 @@ This file is maintained by Ralph. Run `./ralph-sandbox.sh plan 3` to generate ta
| `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** - 22 tests (auth, user iteration, token handling, Garmin data fetching, DailyLog creation, error handling) |
| E2E tests | **NONE** |
### Critical Business Rules (from Spec)
@@ -290,15 +291,22 @@ Full feature set for production use.
- **Why:** Users need visibility into their Garmin connection
- **Depends On:** P0.1, P0.2, P2.1
### P2.4: POST /api/cron/garmin-sync Implementation
- [ ] Daily sync of all Garmin data for all users
### 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` - Iterate users, fetch data, store DailyLog
- `src/app/api/cron/garmin-sync/route.ts` - Iterates users, fetches data, stores DailyLog
- **Tests:**
- `src/app/api/cron/garmin-sync/route.test.ts` - Test auth, user iteration, data persistence
- `src/app/api/cron/garmin-sync/route.test.ts` - 22 tests covering auth, user iteration, token handling, Garmin data fetching, DailyLog creation, 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
- Returns sync summary (usersProcessed, errors, skippedExpired, timestamp)
- **Why:** Automated data sync is required for morning notifications
- **Depends On:** P2.1, P2.2
- **Note:** Route exists with CRON_SECRET auth check, needs core logic
### P2.5: POST /api/cron/notifications Implementation
- [ ] Send daily email notifications at user's preferred time
@@ -568,6 +576,7 @@ P2.14 Mini calendar
- [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, 22 tests (P2.4)
### Pages
- [x] **Login Page** - Email/password form with PocketBase auth, error handling, loading states, redirect, 14 tests (P1.6)