Skip to content

Releases and CI

delabrcd edited this page Jun 6, 2026 · 2 revisions

Releases and CI

Image

Published to ghcr.io/delabrcd/ngrid-dashboard by GitHub Actions (.github/workflows/docker-publish.yml), built from the multi-stage app/Dockerfile on the Playwright base image.

CI gates (every PR + push)

The publish job (build-push) needs: [test, migration-safety] and won't run until both pass. PRs run only the two gate jobs (no publish — no GHCR secrets, and forks can't push):

  • test — builds the Dockerfile test stage and runs the hand-calculated vitest suite. This gates merges on numeric accuracy (Testing, Data Accuracy).
  • migration-safety — seeds a Postgres 16 service with the previous release's schema (git show <prev-tag>:app/prisma/schema.prisma), then applies the current schema and asserts no data was lost. The deploy entrypoint pushes the schema with prisma db push --accept-data-loss and no rollback, so this catches a destructive change before it ships. It skips automatically when there's no prior tag. Details: Backups and Migration-Safety.

Tags

Tag Points at
latest the newest non-prerelease release (what compose pulls by default)
X.Y.Z, X.Y, X a specific release
edge the current main branch
sha-xxxxxxx the exact commit of any build

Guarantees, enforced explicitly in the workflow:

  • :latest moves only on a published, non-prerelease release (type=raw,value=latest,enable=${{ github.event_name == 'release' && !github.event.release.prerelease }}, with flavor: latest=false).
  • main builds publish :edge + :sha-… and never touch :latest.

Cutting a release (release-driven)

Publishing a GitHub Release is the single action — it creates the tag and triggers the build. The workflow triggers on release: published (not bare tag pushes, so there's exactly one build per release).

gh release create v0.1.2 --generate-notes
# or: GitHub UI → Releases → Draft a new release → choose a new tag vX.Y.Z → Publish

CI then publishes 0.1.2/0.1/0 and moves :latest.

Versioning (no manual bump)

The version is derived from the release tag — don't edit package.json (its version is a 0.0.0 placeholder). CI resolves APP_VERSION (release → X.Y.Z; otherwise 0.0.0-edge.<sha>), passes it as a Docker build-arg, and the build:

  • writes it into package.json (npm pkg set version), and
  • inlines it as NEXT_PUBLIC_APP_VERSION — shown in the dashboard header and Settings.

Deploy-time backup

The deploy entrypoint (app/docker-entrypoint.sh) takes a fail-closed pg_dump backup before any schema-changing db push: if the live schema already matches it logs schema already in sync — no pre-migrate backup needed; if it differs it dumps to BACKUP_DIR first and refuses to migrate if the backup can't be written. Pairs with the migration-safety CI gate above — CI proves the upgrade is non-destructive, the backup is the on-host safety net. See Backups and Migration-Safety.

Deploy storage notes

The standalone docker-compose.yml uses Docker named volumes for Postgres (pgdata) and the session (session), and a host bind for PDFs (PDF_DIR). A separate server overlay (behind a reverse proxy + SSO) is not part of this repo.

Clone this wiki locally