Commit graph

8 commits

Author SHA1 Message Date
Chris Parsons
ff08155170 Debug sync-and-simulate cron job: surface curl output and log auth failures
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 3m3s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 1m35s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
Remove -s (silent) from curl so CI logs show the HTTP response on failure.
Add logger.error in requireCronSecret so 401s from bad/missing secrets appear in Sentry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 09:45:06 -07:00
273742f02e Phase A: external HTTP cron jobs for snapshots, standings sync, and simulation (#79)
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
## 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
Chris Parsons
36db8f73ca Optimize CI pipeline: merge check jobs, remove docker install, improve layer caching
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 2m26s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 1m23s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
- Merge typecheck + lint into a single `check` job to eliminate one full
  job lifecycle and one npm ci invocation (~2-4 min savings)
- Remove `apt-get install docker.io` step — Docker CLI and buildx v0.23.0
  are now pre-installed in the custom brackt-runner:latest image
- Reorder Dockerfile build-env COPY layers so node_modules and config
  files are copied before source, improving registry cache hit granularity
- Expand .dockerignore to exclude .forgejo, .git, docs, plans, cypress,
  logs, .env files, and tsbuildinfo files from the build context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 21:37:01 -07:00
08474631c1 Optimize CI build pipeline (~15 min → ~3-5 min) (#59)
Some checks failed
🚀 Deploy / 🧪 Test (push) Failing after 1m34s
🚀 Deploy / ʦ TypeScript (push) Successful in 1m23s
🚀 Deploy / 🔍 Lint (push) Successful in 49s
🚀 Deploy / 🐳 Build (push) Has been skipped
🚀 Deploy / 🚀 Deploy (push) Has been skipped
## Summary

- **Dockerfile layer caching**: `development-dependencies-env` now copies only `package.json`/`package-lock.json` before `npm ci` (was `COPY . /app`), so the npm install layer is cached on every code-only commit instead of rebuilt from scratch
- **Skip QEMU**: `platforms: linux/amd64` added to `build-push-action`, cutting `setup-buildx-action` from ~5 min to ~30 sec
- **npm cache in CI jobs**: Manual `actions/cache@v3` blocks (copy-pasted 3×) replaced with `actions/setup-node@v4` + `cache: 'npm'`, which handles path/key/restore automatically and pins Node 20 explicitly
- **Harden `.npmrc`**: Switched from `COPY .npmrc` to `--mount=type=secret,id=npmrc` in both `npm ci` stages — the file is available during install but never written into a Docker layer, so it cannot leak through the registry build cache regardless of future contents

## Expected timing

| Step | Before | After (code change) |
|---|---|---|
| Setup buildx | ~5 min | ~30 sec |
| Build + push | ~5 min | ~1-2 min |
| Deploy (docker pull) | ~5 min | ~1-2 min |
| **Total** | **~15 min** | **~3-5 min** |

## Test plan

- [ ] Push a code-only commit to main — confirm `setup-buildx-action` logs ~30s (no QEMU), Docker build shows `CACHED` for npm install layers, build+push completes in ~1-2 min
- [ ] Check deploy job — `docker compose pull` should show most layers as `Already exists`
- [ ] Push a commit that changes `package.json` — confirm npm layer correctly re-runs (not cached)
- [ ] Confirm deployed app is functional

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

Co-authored-by: Chris Parsons <chrisparsons1127@gmail.com>
Reviewed-on: #59
2026-05-31 04:35:05 +00:00
Chris Parsons
4f9f9b5c6f Install Docker CLI in build job
All checks were successful
🚀 Deploy / 🧪 Test (push) Successful in 1m33s
🚀 Deploy / ʦ TypeScript (push) Successful in 1m23s
🚀 Deploy / 🔍 Lint (push) Successful in 49s
🚀 Deploy / 🐳 Build (push) Successful in 15m5s
🚀 Deploy / 🚀 Deploy (push) Successful in 31s
node:20-bookworm doesn't include the Docker CLI; install docker.io via
apt before the buildx and registry steps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 20:05:34 -07:00
Chris Parsons
b9a1ea2cb4 Remove setup-node from CI jobs
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 1m26s
🚀 Deploy / ʦ TypeScript (pull_request) Successful in 1m17s
🚀 Deploy / 🔍 Lint (pull_request) Successful in 48s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
Node 20 is already in the node:20-bookworm runner image; setup-node
was hanging ~5min trying to reach an unconfigured npm cache service.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 17:04:12 -07:00
Chris Parsons
0b8f7edc08 Fix postgres service for Forgejo Docker runner
Some checks failed
🚀 Deploy / 🧪 Test (pull_request) Failing after 21m9s
🚀 Deploy / ʦ TypeScript (pull_request) Failing after 11m24s
🚀 Deploy / 🔍 Lint (pull_request) Successful in 10m2s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
Remove host port binding (conflicts with local postgres on runner) and
use service name hostname instead of localhost for DATABASE_URL.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 16:14:27 -07:00
Chris Parsons
9ac7fb5b31 Migrate CI/CD from GitHub Actions to Forgejo Actions
Some checks failed
🚀 Deploy / 🧪 Test (pull_request) Failing after 2m57s
🚀 Deploy / ʦ TypeScript (pull_request) Failing after 10m55s
🚀 Deploy / 🔍 Lint (pull_request) Successful in 10m36s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
- Move workflows from .github/ to .forgejo/ so they only run on Forgejo
- Replace styfle/cancel-workflow-action with native concurrency block
- Use full GitHub URLs for all third-party actions to bypass mirror
- Switch Docker layer cache from type=gha to type=registry
- Drop label-subissues workflow (relies on GitHub-specific GraphQL API)
- Add timeout-minutes to all jobs; cancel-in-progress only for non-main branches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 15:52:00 -07:00