brackt/app/lib
chrisp 273742f02e
Some checks failed
🚀 Deploy / 🧪 Test (push) Failing after 2m45s
🚀 Deploy / ʦ🔍 Typecheck & Lint (push) Successful in 1m27s
🚀 Deploy / 🐳 Build (push) Has been skipped
🚀 Deploy / 🚀 Deploy (push) Has been skipped
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: #79
2026-06-08 07:42:14 +00:00
..
__tests__ Fix draft order initialization for teams added mid-season (#449) 2026-05-19 18:22:47 -07:00
audit-log-display.ts Add Brackt as a league-private meta-sport (#200) (#377) 2026-05-04 20:31:44 -07:00
auth-client.ts Migrate authentication from Clerk to BetterAuth (#324) 2026-04-24 22:00:49 -07:00
auth.server.ts Add branded dark-themed HTML email template (#402) 2026-05-10 11:18:57 -07:00
auth.ts Migrate authentication from Clerk to BetterAuth (#324) 2026-04-24 22:00:49 -07:00
avatar-colors.ts Add Storybook stories for new components from staged changes (#321) 2026-04-23 22:09:25 -07:00
avatar-data.ts Add Cloudinary-backed avatar system (#385) 2026-05-06 14:47:37 -07:00
bracket-templates.ts Fix college hockey bracket resolution (#396) 2026-05-08 12:29:39 -07:00
brand.ts New design (#309) 2026-04-23 13:14:55 -07:00
cloudinary-url.ts Add Cloudinary-backed avatar system (#385) 2026-05-06 14:47:37 -07:00
cloudinary.server.ts Add Cloudinary sports icon uploads (#393) 2026-05-07 16:07:34 -07:00
color-hash.ts User/chris/bracket UI redesign (#95) 2026-03-09 22:44:33 -07:00
corona-states.ts Add Storybook stories for new components from staged changes (#321) 2026-04-23 22:09:25 -07:00
cron-auth.ts Phase A: external HTTP cron jobs for snapshots, standings sync, and simulation (#79) 2026-06-08 07:42:14 +00:00
date-utils.ts Consolidate F1/IndyCar simulators into shared AutoRacingSimulator class (#151) 2026-03-16 12:22:08 -07:00
draft-eligibility.ts Show why a participant is ineligible to draft (#378) 2026-05-04 21:54:14 -07:00
draft-order.ts Fix draft order initialization for teams added mid-season (#449) 2026-05-19 18:22:47 -07:00
draft-timer.ts Fix draft pause clock: use Math.ceil consistently via shared msToSeconds helper 2026-06-06 16:39:53 -07:00
email.server.ts Add branded dark-themed HTML email template (#402) 2026-05-10 11:18:57 -07:00
flag-generator.ts Add Cloudinary-backed avatar system (#385) 2026-05-06 14:47:37 -07:00
flag-types.ts Add Cloudinary-backed avatar system (#385) 2026-05-06 14:47:37 -07:00
fuzzy-match.ts Add golf qualifying points simulator (Plackett-Luce Monte Carlo) (#223) 2026-03-24 21:46:02 -07:00
landing-data.ts Add Storybook stories for new components from staged changes (#321) 2026-04-23 22:09:25 -07:00
logger.ts Replace console.* with structured logger, fix no-inferrable-types (closes #98) (#199) 2026-03-21 13:41:39 -07:00
normalize-team-name.ts Add regular season standings for NBA/NHL (fixes #89) (#192) 2026-03-21 00:12:01 -07:00
overnight-pause.ts Add overnight pause for draft timers (#335) 2026-04-26 22:31:52 -07:00
owner-map.ts Migrate authentication from Clerk to BetterAuth (#324) 2026-04-24 22:00:49 -07:00
parse-results-text.ts feat: batch qualifying results entry (#290) 2026-04-12 14:52:22 -07:00
scoring-types.ts feat: Add scoring rules editor to league settings and creation pages 2025-10-29 00:04:27 -07:00
season-helpers.server.ts Add oxlint linting setup with zero errors (#194) 2026-03-21 09:44:05 -07:00
sport-icon-cleanup.server.ts Harden sport icon cleanup (#397) 2026-05-08 21:19:09 -07:00
sport-icon-url.ts Add Cloudinary sports icon uploads (#393) 2026-05-07 16:07:34 -07:00
standings-display.ts Show tied ranks with T prefix across standings and Discord (#239) 2026-03-27 20:45:15 -07:00
tournament-identity.ts Canonical tournament layer: 2026-05-01 21:04:48 -07:00
unmatched-team-reconciliation.ts Improve unmatched team reconciliation UX (#425) 2026-05-14 16:45:02 -07:00
utils.ts feat: add theme system with dark mode support and navbar component 2025-10-10 23:30:26 -07:00
wizard-state.ts Add auto-start draft at scheduled time (#437) (#438) 2026-05-16 23:37:29 -07:00