Deployment & Infrastructure
The EGAC platform runs entirely on Cloudflare’s free tier. There is no server to maintain — the Worker, D1 database, KV namespace, and cron triggers are all Cloudflare-managed.
Infrastructure overview
First-time setup
1. Create Cloudflare resources
# Create D1 database
wrangler d1 create egac
# Create KV namespace
wrangler kv:namespace create "KV"
Copy the generated IDs into wrangler.toml:
[[d1_databases]]
binding = "DB"
database_name = "egac"
database_id = "YOUR-D1-ID-HERE"
[[kv_namespaces]]
binding = "KV"
id = "YOUR-KV-ID-HERE"
2. Run database migrations
# Apply all migrations to production
wrangler d1 execute egac --remote --file=db/migrations/0001_initial_schema.sql
wrangler d1 execute egac --remote --file=db/migrations/0002_membership_forms.sql
wrangler d1 execute egac --remote --file=db/migrations/0003_update_academy_waitlist_template.sql
wrangler d1 execute egac --remote --file=db/migrations/0004_coach_app.sql
3. Set secrets
wrangler secret put RESEND_API_KEY # From resend.com dashboard
wrangler secret put ADMIN_TOKEN # Strong random string for admin access
wrangler secret put CRON_SECRET # Strong random string for cron auth
4. Deploy
npm run build
wrangler pages deploy dist --project-name=egac
Or connect to GitHub for automatic deploys on every push.
wrangler.toml reference
name = "egac"
compatibility_date = "2024-09-23"
pages_build_output_dir = "dist"
[vars]
APP_ENV = "production"
EMAIL_FROM = "no-reply@updates.eastgrinsteadac.co.uk"
[[d1_databases]]
binding = "DB"
database_name = "egac"
database_id = "6a053384-20ee-4fee-bf73-aa29c1779fe3"
[[kv_namespaces]]
binding = "KV"
id = "28ecc4df31b44e5e92cc4730c1870829"
Cron trigger configuration
Cron triggers must be configured in the Cloudflare Pages dashboard (not in wrangler.toml for Pages projects):
Workers & Pages → egac → Settings → Functions → Cron Triggers
| Expression | Handler | Description |
|---|---|---|
0 9 * * * | /api/cron/expire-invites | Daily 09:00 UTC |
0 18 * * 2 | /api/cron/send-reminders | Tuesday 18:00 UTC |
*/30 * * * * | /api/cron/retry-invites | Every 30 minutes |
0 9 1 * * | /api/cron/academy-rollover | 1st of month 09:00 UTC |
Local development
npm install
npm run dev # Astro dev server on http://localhost:4321
The dev server uses a local D1 database. Run migrations against local D1:
wrangler d1 execute egac --local --file=db/migrations/0001_initial_schema.sql
# ... repeat for other migrations
Seed with test data:
wrangler d1 execute egac --local --file=db/seed.sql
In development, use Authorization: Bearer dev for admin and cron routes.
CI/CD with GitHub
- Connect the repository to Cloudflare Pages via the dashboard
- Set build command:
npm run build - Set output directory:
dist - Add the
CLOUDFLARE_API_TOKENenvironment variable to GitHub Secrets for Wrangler CLI use in CI
Every push to main triggers a production build. Pull requests get automatic preview deployments at unique URLs.
Database migrations
Migrations are plain SQL files in db/migrations/, numbered sequentially. There is no migration runner — apply them manually via Wrangler in order:
# Check what's been applied (no built-in tracker — use naming convention)
wrangler d1 execute egac --remote --command "SELECT name FROM sqlite_master WHERE type='table'"
# Apply a new migration
wrangler d1 execute egac --remote --file=db/migrations/0005_new_feature.sql
ALTER TABLE ... DROP COLUMN — add new columns with defaults instead, and remove old columns only when confirmed safe. Always test migrations against the local D1 instance before running on production.Environment variables summary
| Variable | Where set | Description |
|---|---|---|
APP_ENV | wrangler.toml [vars] | production / staging / development |
EMAIL_FROM | wrangler.toml [vars] | Sender email address |
RESEND_API_KEY | Wrangler secret | Resend API key |
ADMIN_TOKEN | Wrangler secret | Admin dashboard access token |
CRON_SECRET | Wrangler secret | Cron route auth token |