Skip to content

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