Development Workflow
Environments
| Environment | URL | Database | Purpose |
|---|---|---|---|
| Local | http://localhost:8787 | Local D1 | Development |
| QA | https://qa.aero2.dev | aero2-qa | Staging & E2E tests |
| Production | https://aero2.dev | aero2 | Live |
Local Development
# Install dependencies
npm install
# Start local dev server
npm run dev
# Run unit tests
npm test
# Run linting
npm run lintLocal development uses a local D1 database. Changes are isolated to your machine.
Pull Request Workflow
When you push a branch and open a PR against main, CI runs automatically:
- Lint — Biome linting
- Build — Compile and bundle
- Unit Tests — Vitest against local D1
- Migration Separation — Fails if PR mixes code and migration files
No deployment happens on PRs. Code is reviewed and merged to main.
Deployment Pipeline
When a PR is merged to main:
- Build & Test — Lint, build, unit tests
- Deploy to QA — Deploys to https://qa.aero2.dev
- E2E & API Tests — Playwright tests against live QA
- Deploy to Production — Deploys to https://aero2.dev
- Health Check — Verifies production, auto-rollback on failure
Database Migrations
Migrations are manual and follow the expand-contract pattern.
Creating a Migration
touch migrations/0002_your_migration_name.sqlSafe Migration Process
- PR 1: Code that works with OLD and NEW schema — merge & deploy
- PR 2: Migration files ONLY — merge (triggers CI but no auto-apply)
- Apply migrations manually:
# Apply to QA first
npm run migrate:qa
# Verify on QA, then apply to production
npm run migrate:prodMigration Rules
Safe migrations (can apply anytime):
ALTER TABLE ... ADD COLUMNCREATE TABLECREATE INDEX
Dangerous migrations (use expand-contract):
ALTER TABLE ... DROP COLUMNALTER TABLE ... RENAME COLUMN- Changing column types
NPM Scripts Reference
| Script | Description |
|---|---|
npm run dev | Start local development server |
npm run build | Build for production |
npm run lint | Run Biome linter |
npm test | Run unit tests |
npm run test:e2e | Run Playwright E2E tests |
npm run test:api | Run API tests |
npm run deploy:qa | Deploy to QA (use CI instead) |
npm run deploy:prod | Deploy to Production (use CI instead) |
npm run migrate:qa | Apply migrations to QA database |
npm run migrate:prod | Apply migrations to Production database |
Secrets Management
Cloudflare Secrets (per environment)
# QA
wrangler secret put SECRET_NAME --env qa
# Production
wrangler secret put SECRET_NAME --env productionRequired secrets:
MASTER_KEY— Encryption keyGITHUB_CLIENT_ID— GitHub OAuth app IDGITHUB_CLIENT_SECRET— GitHub OAuth app secretBOOTSTRAP_ADMIN_EMAIL— Initial admin user email
GitHub Secrets (for CI/CD)
Set in GitHub repo → Settings → Secrets:
CF_API_TOKEN— Cloudflare API tokenCF_ACCOUNT_ID— Cloudflare account IDD1_QA_DATABASE_ID— QA database UUIDD1_PROD_DATABASE_ID— Production database UUID
Troubleshooting
CI/CD Failures
# View recent workflow runs
gh run list
# View logs for a specific run
gh run view <run-id> --log-failedCheck Environment Health
curl https://qa.aero2.dev/health
curl https://aero2.dev/healthView Live Logs
npx wrangler tail --env qa
npx wrangler tail --env productionQuick Reference
| Action | Command/Process |
|---|---|
| Start coding | npm run dev |
| Run tests locally | npm test |
| Open PR | Push branch, CI runs automatically |
| Deploy | Merge to main (automatic) |
| Apply migration | npm run migrate:qa then npm run migrate:prod |
| Rollback production | npx wrangler rollback --env production |
| Add secret | wrangler secret put NAME --env ENV |