Files
vigilcare-records/docs/26-vigilcare-records-cicd.md
T
voltsrage c871dc4842
CI / backend (push) Failing after 2m26s
CI / frontend (push) Failing after 53s
Add deployment files
2026-08-11 20:17:53 +08:00

5.3 KiB

Guide 26: VigilCareRecords CI/CD (Gitea Actions + Docker Compose)

How VigilCareRecords is built, tested, and deployed on the same Gitea Actions + act_runner + container registry setup already used by VigilCareClinical. See docs/25-gitea-cicd-docker-deploy.md for the general pattern this guide instantiates; this doc only covers what is specific to this repo.

Related files:


1. Topology

VigilCareRecords ships two images:

Image Dockerfile Build context
vigilcare-records-api VigilCareRecordsAPI/Dockerfile repo root
vigilcare-records-dashboard vigilcare-records-web/Dockerfile vigilcare-records-web/

Unlike VigilCareClinical, there is no gateway service, and the frontend does not bake in an absolute API URL at build time — src/api/client.ts and src/api/fhirClient.ts use relative base URLs (/api/v1, /fhir). The dashboard's nginx.conf reverse-proxies those paths to the api container, so the same image works behind any hostname without a build-arg.

2. Shared production infrastructure

Per the "Integrated Database Deployment" decision documented in vigilcare-records-clinical-overview.md, VigilCareRecords does not run its own Postgres/Redis/MinIO/Seq in production. It joins the external shared-services Docker network already created by VigilCareClinical's own compose project and connects to those same containers, using:

  • Its own logical Postgres database (vigilcare_records, separate schema/tables from VigilCareClinical's patients/encounters/observations — see the promotion service for how the two connect at the application layer, not the infrastructure layer)
  • A dedicated Redis logical database (defaultDatabase=2 in .env.example) so batch-assignment locks never collide with VigilCareClinical's keys
  • A dedicated MinIO bucket (vigilcare-records-scans) separate from any clinical document buckets

Before the first deploy, confirm the VigilCareClinical infra stack (or whatever compose project owns shared-services) is already running on the deploy host — docker network ls | grep shared-services should show it. docker compose -f docker-compose.prod.yml up will fail to find the network otherwise.

3. One-time host setup

ssh deploy@YOUR_HOST "mkdir -p /opt/vigilcare-records"
scp .env deploy@YOUR_HOST:/opt/vigilcare-records/.env
ssh deploy@YOUR_HOST "chmod 600 /opt/vigilcare-records/.env"

Fill in .env from .env.example first — generate JWT_SECRET with openssl rand -base64 48, and get real credentials for the shared Postgres/Redis/MinIO/Seq services from whoever manages that stack. CD never uploads or overwrites .env; only the IMAGE_TAG line is patched automatically on each release.

4. Gitea secrets and variables

Repo → SettingsActions.

Secrets

Secret Used by
REGISTRY_USERNAME docker login
REGISTRY_TOKEN docker login (access token / PAT with package write)
PG_CONNECTION_DDL migrate job only — DDL-privileged connection to the shared Postgres, never given to the API container
DEPLOY_HOST SSH / SCP
DEPLOY_USER SSH / SCP
DEPLOY_SSH_KEY Private key PEM / OpenSSH private key body

Variables

Variable Used by
REGISTRY Optional override of the default git.vectur45.com/trent/vigilcare-records

5. Release flow

# CI green on master, then:
git tag v1.0.0
git push origin v1.0.0

This triggers .gitea/workflows/cd.yml: build & push both images → apply EF Core migrations against PG_CONNECTION_DDL → SSH deploy (scp the prod compose file, patch IMAGE_TAG, pull + up -d) → smoke test (/health/ready, dashboard /) → automatic rollback to the previous IMAGE_TAG on failure (schema changes are not reverted; see the expand/contract note in cd.yml).

Manual redeploy of an existing tag: Gitea UI → Actions → CD → Run workflow, with image_tag input.

6. Pre-production checklist (application-level, not part of this CI/CD change)

  • Demo data seeding runs unconditionally on startup. Program.cs calls DataSeeder.SeedAsync(db) whenever ASPNETCORE_ENVIRONMENT is not Testing — including Production. Unlike the VigilCareClinical example (Seeding__EnableDemoData=false), this app has no seeding toggle. Before a real clinical deploy, either add a guard around DataSeeder.SeedAsync for Production, or confirm the twelve seeded demo accounts (all password password) are acceptable/rotated before go-live.
  • Confirm Cors:AllowedOrigins / DASHBOARD_ORIGIN matches the real public dashboard origin if the dashboard is ever served from a different origin than the API (not the default same-origin nginx-proxy setup described above).
  • Rotate JWT_SECRET from any value used during testing before the first real deploy.