CI/CD Pipeline¶
Reggie uses GitHub Actions for continuous integration and deployment.
Deployment Pipeline¶
graph TD
PUSH["Push to main"] --> CI_TESTS["CI Tests (parallel)"]
CI_TESTS --> DEPLOY["sst deploy --stage staging"]
DEPLOY --> BUILD_MIG["Docker build migrator"]
BUILD_MIG --> PUSH_ECR["Push to ECR<br/>(tagged with SHA)"]
PUSH_ECR --> UPDATE_FN["Update Lambda code"]
UPDATE_FN --> INVOKE_MIG["Invoke migrator<br/>(alembic upgrade head)"]
INVOKE_MIG --> SMOKE["Smoke test"]
MANUAL["Manual dispatch"] --> PROD_DEPLOY["sst deploy --stage production"]
PROD_DEPLOY --> BUILD_MIG_P["Docker build migrator"]
BUILD_MIG_P --> PUSH_ECR_P["Push to ECR"]
PUSH_ECR_P --> UPDATE_FN_P["Update Lambda code"]
UPDATE_FN_P --> INVOKE_MIG_P["Invoke migrator"]
INVOKE_MIG_P --> SMOKE_P["Smoke test"]
style DEPLOY fill:#4CAF50,color:white
style PROD_DEPLOY fill:#FF9800,color:white
Workflows¶
1. Deploy (SST) -- sst-deploy.yml¶
| Triggers | Push to main (staging) or manual dispatch (staging/production) |
| Runner | ubuntu-latest, Node.js 22, Python 3.11 |
| Auth | AWS OIDC (no long-lived credentials) |
| Concurrency | One deploy per stage at a time (cancel-in-progress: false) |
Steps:
1. sst deploy -- deploys all infrastructure and application code
2. Discover migrator -- finds the Lambda function name via aws lambda list-functions
3. Build and push migrator image -- Docker build, push to ECR with $GITHUB_SHA tag
4. Run migrations -- invokes the migrator Lambda, checks result
5. Smoke test -- verifies health, docs, plate lookup, auth guard
Important deployment notes:
- SST's python.container wraps Dockerfiles with a multi-stage uv build that discards RUN pip install commands. The migrator image is built separately by CI.
- Migrations run AFTER code deploys. Use expand-contract pattern for breaking schema changes.
- The migrator uses Alembic's programmatic API (alembic.command.upgrade) not subprocess.
2. Backend Tests -- SQLite (ci-backend.yml)¶
| Triggers | PR to main or push to main (backend paths only) |
| Runner | ubuntu-latest, Python 3.11 |
| What it does | Installs deps, runs pytest -v against SQLite |
Fast feedback on backend logic changes. Does NOT test migrations or Postgres-specific behavior.
3. Backend Tests -- PostgreSQL (ci-backend-postgres.yml)¶
| Triggers | PR to main or push to main (backend paths only) |
| Runner | ubuntu-latest, Python 3.11, Postgres 17 service container |
| What it does | Init DB, run migrations, idempotency check, seed, test, schema check |
4. Frontend Build (ci-frontend.yml)¶
| Triggers | PR to main or push to main (apps/packages paths only) |
| Runner | ubuntu-latest, Node.js 22 |
| What it does | npm ci, lint, typecheck, build |
5. SST Refresh -- sst-refresh.yml¶
| Triggers | Manual dispatch |
| What it does | sst refresh --stage $STAGE to sync SST state with actual AWS resources |
Use when SST state drifts from reality (e.g., after manual resource changes).
Migrator Docker Build¶
The CI builds the migrator Docker image separately because SST's python.container wrapper is incompatible with our Dockerfile structure:
graph LR
subgraph "CI Step: Build and Push"
BUILD["docker build<br/>-f services/migrator/Dockerfile"]
TAG["docker tag<br/>:SHA + :latest"]
PUSH["docker push<br/>to ECR"]
UPDATE["aws lambda<br/>update-function-code"]
end
BUILD --> TAG --> PUSH --> UPDATE
The image is tagged with $GITHUB_SHA for audit trail.
Local Equivalents¶
| CI Check | Local Command |
|---|---|
| Backend tests (SQLite) | make test-backend |
| Backend tests (Postgres) | make test-backend-pg |
| Migration test | make test-migrations |
| Frontend lint + build | npm run lint && npm run build |
| Deploy staging | npx sst deploy --stage staging |
Common CI Failures¶
| Failure | Cause | Fix |
|---|---|---|
| Migration not idempotent | Missing IF NOT EXISTS guards |
Add idempotency guards |
| Migrator image fails | SST wraps Dockerfile | CI builds image directly |
| Schema check failed | Model doesn't match migration | Update migration or model |
| Type error in frontend | Backend schema changed | Run npm run types:generate |
| OIDC auth fails | Role ARN misconfigured | Check AWS_DEPLOY_ROLE_ARN |
| Smoke test: health 503 | DB not connected | Check DATABASE_URL, run migrations |
| Smoke test: plate 500 | Missing schema | Run migrator Lambda |