Migrations And Release
Build images, run migrations, refresh API contracts, and validate a release.
Migrations And Release
Use migrations and generated-contract checks as release gates. Do not depend on runtime AutoMigrate outside local development.
Image Build Matrix
The backend Dockerfile ships one Go build stage and exposes several runtime
targets. CI publishes each as a separate image; the default runtime target
remains a combined image for local compatibility.
| Image | Docker target | Entrypoint |
|---|---|---|
wipe-api | api-runtime | /app/api |
wipe-proof-worker | proof-worker-runtime | /app/worker-proof |
wipe-worker | worker-runtime | /app/worker |
wipe-verifier-cli | verifier-cli-runtime | /app/verifier |
wipe-migrator | migrator-runtime | /app/migrator |
Build an individual image locally from the repository root:
docker build --target api-runtime -t wipe-api:local backend
docker build --target proof-worker-runtime -t wipe-proof-worker:local backend
docker build --target worker-runtime -t wipe-worker:local backend
docker build --target verifier-cli-runtime -t wipe-verifier-cli:local backend
docker build --target migrator-runtime -t wipe-migrator:local backend
The wipe-worker image is shared by queue worker kinds. Set WORKER_KIND or
pass the kind as the first argument — anchor, notifications, reports,
retry, or maintenance. wipe-proof-worker is a dedicated binary and does
not take a kind argument.
Verifier CLI Smoke
The verifier CLI can call the public /verify endpoint:
docker run --rm wipe-verifier-cli:local \
-url http://host.docker.internal:8080/verify -code 4A7F2C90AB18DE55
It can also hash canonical JSON offline using the same RFC 8785/JCS transform as the certificate service:
docker run --rm -i wipe-verifier-cli:local \
-canonical-json - -expect-hash sha256:<expected> < certificate.json
Build Images
Reference build for the full stack:
docker compose build api proof-worker anchor-worker notification-worker report-worker retry-worker maintenance-worker
Run Migrations
The root compose file exposes a migrator profile:
docker compose --profile migration build db-migrate
docker compose --profile migration run --rm db-migrate version
For a reviewed migration run, set:
MIGRATIONS_DATABASE_URL='postgres://...'
MIGRATIONS_ACTION=up
Use the migrator up -dry-run command where supported before applying changes
to a shared environment.
Reviewed Migration Flow
The migrator image ships the Go cmd/migrator binary with
backend/db/migrations embedded. It supports up (with -dry-run),
version, and force VERSION, and keeps the schema_migrations table
compatible with the previous golang-migrate image.
Before any production migration run:
- Review the SQL diff and rollback script for every new
*.up.sql/*.down.sqlpair. - Run
make -C backend migrations-check. - Build the reviewed image with
docker build --target migrator-runtime -t wipe-migrator:<tag> backend. - Run a non-mutating version check against the target database.
- Run
uponly after the change ticket names the image digest, target database, expected migration versions, backup point, and rollback owner.
Example commands:
docker run --rm wipe-migrator:local help
docker run --rm --network <deployment-network> \
-e MIGRATIONS_DATABASE_URL="<reviewed-postgres-url>" \
wipe-migrator:local version
docker run --rm --network <deployment-network> \
-e MIGRATIONS_DATABASE_URL="<reviewed-postgres-url>" \
wipe-migrator:local up -dry-run
docker run --rm --network <deployment-network> \
-e MIGRATIONS_DATABASE_URL="<reviewed-postgres-url>" \
wipe-migrator:local up
The migrator only migrates forward; rollbacks apply the reviewed *.down.sql
scripts manually. Do not disable DATABASE_AUTOMIGRATE in an environment until
the reviewed SQL baseline is confirmed to cover the full current GORM schema.
Refresh API Contract
From backend/:
make api-contract
This refreshes Swagger and generated TypeScript clients. For route comparison only:
go run ./cmd/route-contract -write-docs
Expected outputs:
| File | Purpose |
|---|---|
backend/docs/swagger/swagger.json | Generated OpenAPI artifact. |
backend/docs/api-contract-status.md | Human-readable route backlog comparison. |
backend/docs/api-contract-status.json | Machine-readable route status. |
frontend/src/lib/api/client and dashboard/src/lib/api/client | Generated HeyAPI clients. |
The current contract status reports 54 expected backlog operations and 54 implemented in Swagger.
Validate Backend
Run:
cd backend
go test ./...
make api-contract
Docker-heavy checks:
make -C backend compose-e2e-config
docker compose -f compose.e2e.yml up --build -d
Use unique E2E ports when running in parallel:
COMPOSE_PROJECT_NAME=wipe-e2e-local \
WIPE_E2E_API_PORT=18080 \
WIPE_E2E_KEYCLOAK_PORT=18081 \
WIPE_E2E_PUBLIC_API_URL=http://127.0.0.1:18080 \
WIPE_E2E_PUBLIC_KEYCLOAK_URL=http://127.0.0.1:18081 \
docker compose -f compose.e2e.yml up --build -d
Validate Frontends
For the new frontend:
cd frontend
npm install
npm run check
npm run build
For the dashboard:
cd dashboard
pnpm check
pnpm build
Release Checklist
| Check | Expected result |
|---|---|
| Git status reviewed | Only intended source and generated files changed. |
| Migrations reviewed | Up/down SQL exists and migrator image can run version. |
| API contract refreshed | No missing cahier backlog endpoints. |
| Backend tests pass | go test ./... succeeds. |
| Frontend type/build checks pass | Selected portal builds with generated client. |
| Compose smoke passes | API, Keycloak, MinIO, workers, and portals start. |
| Observability heartbeats present | API and worker signals visible in Grafana/Prometheus. |
| Secrets reviewed | No local defaults or dev bypasses in non-local environment. |
Optional Cosign Policy
Buildx SBOM and provenance attestations are mandatory for pushed images. If the release policy adds cosign:
- Sign only immutable digest or commit-SHA tags after the Harbor push.
- Prefer keyless signing with CI OIDC when the Gitea runner and trust policy support it; otherwise use a key-backed cosign secret owned by the release environment.
- Deployment admission must verify either the expected OIDC issuer/identity or the configured public key before pulling promoted images.