Implement token expiration warnings (P3.9)

Add email warnings for Garmin token expiration at 14-day and 7-day thresholds.
When the garmin-sync cron job runs, it now checks each user's token expiry and
sends a warning email at exactly 14 days and 7 days before expiration.

Changes:
- Add sendTokenExpirationWarning() to email.ts with differentiated subject
  lines and urgency levels for 14-day vs 7-day warnings
- Integrate warning logic into garmin-sync cron route using daysUntilExpiry()
- Track warnings sent in sync response with new warningsSent counter
- Add 20 new tests (10 for email function, 10 for sync integration)

Test count: 517 → 537

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-11 08:24:19 +00:00
parent 6c3dd34412
commit 2ffee63a59
5 changed files with 304 additions and 19 deletions

View File

@@ -81,3 +81,37 @@ Auto-generated by PhaseFlow`;
text: body,
});
}
export async function sendTokenExpirationWarning(
to: string,
daysUntilExpiry: number,
): Promise<void> {
const isUrgent = daysUntilExpiry <= 7;
const subject = isUrgent
? `🚨 PhaseFlow: Garmin tokens expire in ${daysUntilExpiry} days - action required`
: `⚠️ PhaseFlow: Garmin tokens expire in ${daysUntilExpiry} days`;
const urgencyMessage = isUrgent
? `⚠️ This is urgent - your Garmin data sync will stop working in ${daysUntilExpiry} days if you don't refresh your tokens.`
: `Your Garmin OAuth tokens will expire in ${daysUntilExpiry} days.`;
const body = `${urgencyMessage}
📋 HOW TO REFRESH YOUR TOKENS:
1. Go to Settings > Garmin in PhaseFlow
2. Follow the instructions to reconnect your Garmin account
3. Paste the new tokens from the bootstrap script
This will ensure your training recommendations continue to use fresh Garmin data.
---
Auto-generated by PhaseFlow`;
await resend.emails.send({
from: EMAIL_FROM,
to,
subject,
text: body,
});
}