Production smoke checklist
Use this checklist after a fresh production or staging deploy. It covers Postgres, Redis, API, queue worker, CRDT merge worker, and UI — not the optional www profile.
Compose: docker/compose.prod.yml
Kubernetes / Argo CD: helm/garrison/ with httpRoute or ingress enabled — use your public API hostname instead of 127.0.0.1:8080 below.
Prerequisites
Section titled “Prerequisites”- Copy
docker/stack.env.exampletodocker/stack.env. - Set secrets and URLs in
docker/stack.env:POSTGRES_PASSWORDand matchingDB_PASSWORDAPP_KEY(php artisan key:generate --showfrom a local API container or dev install)APP_URL,FRONTEND_URL,SESSION_DOMAIN,SANCTUM_STATEFUL_DOMAINS, andCORS_ALLOWED_ORIGINSfor your public hostnames
- Pull or build API and UI images; registry defaults are in
docker/compose.prod.yml.
Start the stack
Section titled “Start the stack”From the repository root:
docker compose -f docker/compose.prod.yml --env-file docker/stack.env up -d postgres redis migrate api queue uiThe one-shot migrate service runs php artisan migrate --force before api and queue start. Wait until migrate exits successfully and api is running:
docker compose -f docker/compose.prod.yml --env-file docker/stack.env psDo not run php artisan db:seed in production. Seeders are for local development only (DevSeeder sample users and studies).
1. Health — GET /up
Section titled “1. Health — GET /up”Replace the host and port with your API URL (Compose default binds API to 127.0.0.1:${GARRISON_API_PORT:-8080}):
curl -fsS "http://127.0.0.1:8080/up"Expect HTTP 200 and a JSON body indicating the application is up.
2. GraphQL auth
Section titled “2. GraphQL auth”Sanctum session cookies require CSRF for browser clients. For a quick smoke test from the shell, use the GraphQL login mutation (reCAPTCHA is optional when RECAPTCHA_SECRET_KEY is empty).
Create a user first if the database is empty — register via the UI at your FRONTEND_URL, or use GraphQL register with a strong password.
API="http://127.0.0.1:8080"COOKIE_JAR="$(mktemp)"
# CSRF cookie (Sanctum SPA flow)curl -fsS -c "$COOKIE_JAR" "$API/sanctum/csrf-cookie" >/dev/null
# Login — replace email and passwordcurl -fsS -b "$COOKIE_JAR" -c "$COOKIE_JAR" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H "X-XSRF-TOKEN: $(grep XSRF-TOKEN "$COOKIE_JAR" | awk '{print $7}' | python3 -c 'import sys, urllib.parse; print(urllib.parse.unquote(sys.stdin.read().strip()))')" \ -d '{"query":"mutation { login(input: { email: \"you@example.com\", password: \"your-password\" }) { user { id email } } }"}' \ "$API/graphql"Expect "errors": null and a data.login.user.id in the response.
Optional: confirm the session with query { me { id email } } using the same cookie jar.
3. CRDT note push
Section titled “3. CRDT note push”Requires an authenticated user who owns a note. After registering, create a study and note in the UI (or use GraphQL createStudy / note mutations), then push an empty or append change:
NOTE_ID="1" # replace with your note idCHANGES="" # base64 CRDT payload; empty string is valid for an initialized note
curl -fsS -b "$COOKIE_JAR" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H "X-XSRF-TOKEN: $(grep XSRF-TOKEN "$COOKIE_JAR" | awk '{print $7}' | python3 -c 'import sys, urllib.parse; print(urllib.parse.unquote(sys.stdin.read().strip()))')" \ -d "{\"query\":\"mutation { pushNoteUpdates(noteId: \\\"$NOTE_ID\\\", changes: \\\"$CHANGES\\\") { noteId crdtVersion } }\"}" \ "$API/graphql"Expect GraphQL success with a noteId and incremented crdtVersion. Pull sync:
curl -fsS -b "$COOKIE_JAR" \ -H 'Content-Type: application/json' \ -d "{\"query\":\"query { pullNoteUpdates(noteId: \\\"$NOTE_ID\\\") { noteId unchanged crdtVersion } }\"}" \ "$API/graphql"Automated regression
Section titled “Automated regression”For CI and local development, run the API test suite in Docker instead of against production data:
docker compose -f compose.dev.yml run --rm --no-deps api php artisan test --filter=AuthTestdocker compose -f compose.dev.yml run --rm --no-deps api php artisan test --filter=NoteCrdtTestKubernetes / Argo CD notes
Section titled “Kubernetes / Argo CD notes”When the API is behind a Gateway or ingress, set API to your public URL (for example https://api.garrisonbible.com) in the commands below. Ensure the Argo CD sync completed, API pods are ready, and the migrate init container succeeded on the current image:
kubectl get pods -n garrisonkubectl logs -n garrison deploy/garrison-api -c migrateDo not run php artisan db:seed in production on any deployment method.
See also
Section titled “See also”- Docker Compose — env files, upgrades, optional
wwwprofile - Kubernetes — Helm install and upgrades
- Argo CD — GitOps deploy and first-sync checklist
- Deployment planning — hosting models and tenancy