CI/CD
lk-wiz uses GitLab CI for building and deploying application artifacts and Atlantis for Terraform plan/apply.
Atlantis (infrastructure)
atlantis.yaml defines one project per stack per stage (e.g. app-dev, frontend-prod,
docs-dev). Autoplan is disabled; a push triggers a plan via webhook, and a human applies
by commenting atlantis apply -p <stack>-<stage> after review. depends_on enforces the
deploy order — for the docs stack, docs-dev depends on frontend-dev, and docs-prod
depends on both docs-dev and frontend-prod.
GitLab CI (application)
The pipeline builds container images (MCP, backend) and pushes them to ECR tagged with the commit SHA. After the Tofu apply creates the buckets and distributions, manual deploy jobs publish the static sites:
deploy-frontend-<stage>builds the Next.js app and syncs it to the frontend bucket.deploy-docs-<stage>builds this docs site and syncs it to the docs bucket.
Both read their target bucket and CloudFront distribution ID from the Tofu state JSON in S3 (no Tofu binary needed) and then:
# immutable, fingerprinted assets
aws s3 sync out/_next/static/ s3://$BUCKET/_next/static/ \
--cache-control "public,max-age=31536000,immutable"
# everything else, always revalidated
aws s3 sync out/ s3://$BUCKET/ \
--cache-control "no-cache,no-store,must-revalidate" \
--delete --exclude "_next/static/*"
# bust the edge cache
aws cloudfront create-invalidation --distribution-id "$CF_ID" --paths "/*"Deploy jobs are manual because they need resources that only exist after the matching
atlantis apply — running them pre-apply would hit missing buckets / 403s.
Hybrid path
scripts/deploy_hybrid.sh [dev|prod] runs the whole flow locally: push, await the CI
build, tofu apply every stack in order (account_prep → data → app → mcp → frontend → docs), then trigger and await the manual deploy jobs (deploy-frontend-*,
deploy-docs-*). It bypasses Atlantis for the apply phase — use with care on prod.