Health New Zealand | Te Whatu Ora
Radiology Tools Architecture and handover

Delivery and governance

Repository and pipelines

All code, database migrations and infrastructure configuration live in one GitHub repository. Every deploy runs in GitHub Actions. Changes reach preview automatically, and reach production only when someone runs the promote workflow for that app.

The repository

Location
twocolddogs/hnzradtools, private, on a personal GitHub account. Default branch develop.
History
About 1,400 commits since March 2026. One human contributor, plus the GitHub Copilot coding agent.
Structure
An npm workspaces monorepo. Shared code goes in packages/ and is consumed as a workspace dependency, never copied between apps.
Plan limits
On the current plan, branch protection, rulesets and required reviews are unavailable. Moving the repository into a Health NZ organisation removes this limit (R4).
PathContents
apps/site-profilesSite Profiles, and the email worker under workers/hnz-email
apps/my-radiologyMember portal
apps/service-sizingWorker API and frontend/
apps/triageworker/, frontend/, offline scripts/
workers/hnz-identityIdentity hub, migrations, tests
packages/Shared code (below)
docs/Plans, access model, cutover run sheet
scripts/Database drift check and utilities
.github/workflowsCI, deploy and promote workflows
architecture/This pack
PackagePurpose
@hnz/authToken signing and verification, password hashing, random tokens (Web Crypto)
@hnz/cryptoAES-256-GCM encryption and HMAC blind indexes, with strict key checks
@hnz/role-constantsLeadership and member role registries
@hnz/specialty-constantsRadiologist specialty keys and labels
@hnz/broadcast-rendererAnnouncement text to HTML

The hub uses @hnz/auth and @hnz/crypto. The older apps still carry their own copies of that code, and moving them onto the packages is on the roadmap (R18).

How a change reaches production

GIT GITHUB ACTIONS CLOUDFLARE develop every change lands here deploy-<app>.yml on push, only if that app changed Preview beta hostnames, preview D1 push migrate preview DB, deploy promote-to-prod.yml run by hand, choose the app release decision all of develop <app>-prod production branch per app build, migrate, deploy production migrations first Production live hostnames, production D1 1. opens and merges PR 2. then rollback: git revert on this branch and push
Preview is automatic; production is a deliberate act per app. The teal path is the only route to production. Today anyone with write access can run it, and it merges without review. In a Health NZ organisation the same workflow would sit behind a protected "production" environment with named approvers (R4).

Rollback

Revert the promote merge commit on the production branch and push; the push redeploys the previous code. Database migrations are forward-only and are not reversed by a revert. For data, D1's 30-day point-in-time restore (Time Travel) is the recovery tool; documenting it and recording a restore point before each production migration is on the roadmap (R15). Cloudflare also offers one-click rollback to an earlier deployment for Pages and Workers, which is faster than a revert.

Workflows

WorkflowRuns onDoes
deploy-site-profiles.ymlpush to develop or site-profiles-prodBuild, apply D1 migrations, deploy Pages.
deploy-my-radiology.ymlpush to develop or my-radiology-prodBuild, apply D1 migrations, deploy Pages.
deploy-service-sizing.ymlpush to develop or service-sizing-prodApply migrations, deploy the Worker, then build and deploy the frontend.
deploy-triage.ymlpush to develop or triage-prodDeploy the Worker and frontend. Migrations are applied by hand (R20).
deploy-hnz-identity.ymlpush to develop or hnz-identity-prodApply migrations, deploy the hub.
deploy-hnz-email.ymlpush to develop or site-profiles-prodDeploy the email worker.
deploy-portal.ymlpush to develop or mainDeploy the launch page. Currently publishes more than the launch page (R1).
deploy-architecture.ymlpush to develop touching architecture/Publish this pack to architecture.hnzradtools.nz.
promote-to-prod.ymlmanual, choose an appMerge all of develop into the app's production branch, apply production migrations, build and deploy that app. The default option promotes My HNZ Radiology and Site Profiles together.
ci-*.yml (five)pull requests; pushes to develop and prod branchesType check only. Runs alongside the deploy, not before it (R16).

One gap: the promote workflow merges using GitHub's built-in token, which does not trigger other workflows. Anything that deploys only from a push, such as the email worker, is therefore not redeployed by a promote, and the hub is not yet a promote option (R6).

Deploys authenticate with two repository secrets, CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID. Runtime secrets are set directly in Cloudflare and never pass through GitHub.

Database migrations

Each app's schema is a numbered sequence of SQL files in its migrations/ directory. D1 records which files have run and never runs one twice.

  • Append-only. Once a migration has run in any environment, the file is frozen. To change what it did, add a new migration, written to be safe to re-run (IF NOT EXISTS, INSERT OR IGNORE). Editing an applied file leaves environments with different schemas but identical-looking histories.
  • Preview first. A push to develop applies new migrations to the preview database; promote applies them to production before the new code is deployed.
  • Drift check. scripts/check-d1-drift.sh <app> compares applied migrations, repository files and the live schema across production and preview, and exits non-zero on any difference. It is read-only and should be run before any non-trivial schema change.

Proposed governance under Health NZ

These changes turn the existing pipeline into one that meets an organisational standard. None needs application changes.

ChangeWhy
Transfer the repository to a Health NZ GitHub organisationOwnership, access management through Health NZ accounts, and the features below.
Protect develop and every *-prod branch; require pull requests with one reviewNo change reaches preview or production without a second person.
A production environment with required reviewers, holding a production-only Cloudflare tokenPromotion needs Health NZ approval, and the preview token cannot touch production.
Make deploys wait for CI; add CI for the hub and email worker; run the existing testsA failing check stops a release.
Enable Dependabot alerts and updates, secret scanning and push protectionKnown-vulnerable dependencies and leaked credentials are caught automatically.
Add a CODEOWNERS file for migrations, auth code and workflowsThe most sensitive paths always get the right reviewer.