CI/CD Pipelines
All projects use GitHub Actions for CI/CD with a dev → main
promotion workflow. Backend, background-tasks, frontend, and
documentation all run on GitHub-hosted ubuntu-latest runners with
OIDC against github-actions-role for AWS access. The historical
self-hosted EC2 runner has been terminated — see
Self-Hosted Runner for context.
Workflow
Never push directly to main. Always go through dev → PR → main.
Pipeline Details
Backend (aiqlick-backend)
aws-deploy.yml — runs on every push to dev or main.
- Resolve per-env variables (service name, task definition path, secret ARNs, API URL).
- Detect Prisma schema change (
git diff HEAD^ HEAD prisma/schema.prisma) — gates step 5. - Configure AWS credentials via OIDC (
github-actions-role). - Build + push Docker image to ECR (
aiqlick-backend) with BuildKit registry cache. - If schema changed, render + register
task-definition-prisma-migrate.json, thenaws ecs run-taskfor the one-shot Fargate task that runsprisma db push. Wait fortasks-stopped, fail the run if exit code ≠ 0. - Render
task-definition-{dev,prod}.jsonwith the new image SHA, thenaws-actions/amazon-ecs-deploy-task-definition@v2againstbackend-{dev,prod}(wait-for-service-stability: true, 10 min cap). - External smoke test: poll
https://api(.dev).aiqlick.com/healthuntil 200, then GraphQL introspection.
The deployment circuit breaker on the ECS service auto-rolls back on health-check failure — see ECS Fargate. Typical end-to-end: ~3-4 min (cold cache push dominates; warm deploys with no schema change land in ~2 min).
Background Tasks (background-tasks)
aws-deploy.yml — same shape as backend, minus the Prisma migrate step.
- Resolve per-env variables.
- Configure AWS credentials via OIDC.
- Build + push Docker image to ECR (
background-tasks) with BuildKit cache. - Render
task-definition-{dev,prod}.jsonwith the new image SHA. amazon-ecs-deploy-task-definition@v2againstbg-tasks-{dev,prod}(wait-for-stability).- External smoke test against the internal ALB Cloud Map name from inside the workflow's runner network is not possible — instead the workflow trusts ECS health-check + circuit breaker to assert task healthiness.
Typical end-to-end: ~3 min. Rollback is handled by the deployment
circuit breaker (no :previous tag dance — that was an EC2-era pattern
and is gone).
Frontend (aiqlick-frontend)
- Amplify auto-builds on push — this is the actual deploy path. No GitHub Actions deploy workflow.
devbranch →dev.aiqlick.commainbranch →www.aiqlick.com
- Secrets fetched from Secrets Manager at build time via the Amplify build role.
- Companion workflow
ci.yamlpolls Amplify after each push, streams build logs into the Actions tab, and fails the run if Amplify returnsFAILED/CANCELLED. - A
sync-docs.ymlworkflow mirrorsDOCS/**changes into thedocumentationrepo'sdocs/platform/frontend/guides/(legacy bridge — see the docs sync caveat).
The previous playwright.yml workflow and the matching e2e/ test
suite were removed in April 2026. There is no automated UI test
coverage; the pre-commit verify-build.sh script is the only gate.
Documentation (documentation)
deploy.yml — runs on push to dev or main.
npm ci+npm run build(Docusaurus).- S3 sync (
aiqlick-docsfor prod,aiqlick-docs-devfor dev) via OIDCgithub-actions-role. - CloudFront invalidation (auto-detects distribution by domain alias).
Jitsi Deploy (jitsi-deploy)
This is the only workload that still uses SSM in CI/CD because Jitsi runs on EC2 (not ECS).
- SSM
send-commandtoi-0620d2e23695f5bfc(the Jitsi EC2). git pullon instance.docker compose pull && docker compose up -d --force-recreate.- Health check.
Jitsi Meeting Web UI (aiqlick-meeting)
- Build Docker image.
- Push to ECR (
aiqlick-meeting). - SSM redeploy web container on the Jitsi EC2.
Jigasi (jigasi)
- Build Docker image.
- Push to ECR (
aiqlick-jigasi). - SSM deploy to the Jitsi EC2.
ECR Repositories
| Repository | Image Size | Tags | Used by |
|---|---|---|---|
aiqlick-backend | ~240MB | latest, dev-latest, <git-sha>, buildcache, dev-buildcache | ECS backend-{dev,prod} |
background-tasks | ~699MB | latest, dev-latest, <git-sha>, buildcache, dev-buildcache | ECS bg-tasks-{dev,prod} |
aiqlick-meeting | ~142MB | latest, <git-sha> | Jitsi EC2 (Docker Compose) |
aiqlick-jigasi | ~505MB | latest, <git-sha> | Jitsi EC2 (Docker Compose) |
support-backend-rust | (varies) | per support-backend-rust workflow | support-backend-alb |
The *-buildcache tags hold BuildKit mode=max cache manifests
(~1.1 GB for the backend), not runnable images. Branch-specific tags
(dev-buildcache vs buildcache) prevent dev and main from
overwriting each other's cache. The :previous tag from the BG EC2
era is gone — ECS deployment circuit breaker has replaced it.
Schema migration model (backend only)
Backend's deploy includes a one-shot Fargate task running
prisma db push between the image build and the rolling service
update. Triggered only when prisma/schema.prisma actually changed in
the diff (cheap path otherwise). The same image used by the long-lived
service runs the migrate task — same code, same env, same RDS
endpoint. Failure of the migrate task fails the deploy before the
service is touched.
Detail: Backend Deployment.
Git Workflow
git checkout dev
git add <specific files>
git commit -m "type(scope): description"
git push origin dev
# Create PR: dev → main
# Merge triggers production deploy
The /ship skill automates this end-to-end including the deploy
status poll. See /ship skill.
Related
- Backend deployment — backend-specific deploy details
- AI service deployment — bg-tasks deploy details
- Frontend deployment — Amplify mechanics
- ECS Fargate — service inventory + circuit breaker config
- Self-Hosted Runner — historical context (instance terminated)