brackt/app/lib/cron-auth.ts

8 lines
304 B
TypeScript
Raw Normal View History

Phase A: external HTTP cron jobs for snapshots, standings sync, and simulation (#79) ## Summary - Removes the last in-process \`setInterval\` (\`server/snapshots.ts\` 24h loop) and replaces it with an external HTTP cron job via Forgejo Actions - Adds automated standings sync + conditional simulation: syncs every 2h, only simulates when standings actually changed (detected by comparing \`gamesPlayed\`/\`leagueRank\` before upsert) - Adds \`GET /healthz\` for Docker healthcheck (Phase B prerequisite) ## What's new | Endpoint | Triggered by | What it does | |---|---|---| | \`POST /admin/jobs/run-daily-snapshots\` | Forgejo schedule \`5 0 * * *\` | Creates daily fantasy standings snapshots for all active/draft seasons | | \`POST /admin/jobs/sync-and-simulate\` | Forgejo schedule \`0 */2 * * *\` | Syncs standings from external APIs; runs simulation only if standings changed | | \`GET /healthz\` | Docker / Traefik | Returns 200 \`{ok:true}\` when DB reachable, 503 otherwise | Both cron endpoints are protected by \`X-Cron-Secret\` header (set \`CRON_SECRET\` in Forgejo repo secrets + production env). ## Schema changes (migration 0118) Two new nullable columns on \`sports_seasons\`: - \`standings_last_changed_at\` — written by \`syncStandings()\` when data actually changes - \`last_simulated_at\` — written by the cron job after a successful simulation run ## Deployment notes 1. Add \`CRON_SECRET\` to Forgejo repo secrets (generate with \`openssl rand -hex 32\`) 2. Add same value to production environment 3. Migration runs automatically via the \`migrate\` container on deploy ## Test plan - [ ] \`curl -X POST https://brackt.com/admin/jobs/run-daily-snapshots -H "X-Cron-Secret: ..."\` → 200 \`{total, succeeded, errors}\` - [ ] \`curl -X POST https://brackt.com/admin/jobs/sync-and-simulate -H "X-Cron-Secret: ..."\` → 200 with \`synced\`/\`unchanged\`/\`simulated\` breakdown - [ ] \`curl https://brackt.com/healthz\` → 200 \`{ok:true}\` - [ ] Verify Forgejo workflow runs appear in Actions tab after merge - [ ] Kill web process mid-day; confirm external cron still fires (no in-process dependency) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Chris Parsons <chrisparsons1127@gmail.com> Reviewed-on: https://forge.brackt.com/chrisp/brackt/pulls/79
2026-06-08 07:42:14 +00:00
export function requireCronSecret(request: Request): void {
const secret = process.env.CRON_SECRET;
if (!secret) throw new Response("CRON_SECRET not configured", { status: 500 });
if (request.headers.get("x-cron-secret") !== secret) {
throw new Response("Unauthorized", { status: 401 });
}
}