Preview environments¶
Every pull request can get an ephemeral preview: a backend on Cloud Run plus the
Members and Clinicians apps on Firebase Hosting preview channels. This lets a
change be tested in isolation before it merges to develop.
The pipeline is the Preview - Backend and Apps workflow (preview-pr.yml); teardown
is Preview - Cleanup Resources (preview-cleanup.yml) plus a scheduled
Preview - Janitor (preview-janitor.yml). See GitHub workflows.
Triggers¶
- Pull request targeting
develop, typesready_for_reviewandsynchronize, path-filtered to backend, Members, Clinicians, and shared packages. - Manual dispatch with
force_deploy_allto bypass the optimization checks and force a redeploy.
How the pipeline works¶
To keep full rebuilds (15-30m+) rare, the workflow optimises in layers:
- Change detection (
detect_changes) —dorny/paths-filterdecides which components (backend, members, clinicians) changed; unchanged components skip their whole chain. - Content hashing (
check_*_changes) — for each changed component it hashes source + lock files (pnpm-lock.yaml/pubspec.lock), shared packages, and the Dockerfile, and compares to a value cached per PR. Hash match → skip; mismatch or force → deploy.
Jobs:
build_and_preview(backend) — builds the functions, Dockerises them (GHA layer cache; image tagged with the content hash), deploys to Cloud Run.resolve_backend_url— frontend apps point at the new backend preview if one was deployed, otherwise fall back to the staging backend (so frontend-only PRs test against a stable API).members_preview/clinicians_preview— install Flutter via FVM, inject the resolvedBFF_URLintoassets/environment_values/environment.json,flutter build web --release, deploy to a Firebase Hosting channelpr-{PR_NUMBER}(30-day expiry).comment_deployment_status— posts/updates one sticky PR comment with per-component status (✅ deployed, ⏭️ skipped, ⚪ no change, ❌ failed), URLs, API endpoints, and the content hash + commit SHA.
Backend Cloud Run details¶
Production runs on Firebase Cloud Functions; previews reuse the same code on Cloud Run via an adapter:
functions/src/cloudrun.ts— wraps the Firebase Functions as a plain Express app.Dockerfile/.dockerignore— multi-stage container build.
Each preview service:
- Name
backend-preview-pr-{PR_NUMBER}, regioneurope-west2, projectperci-platform-staging. - Publicly accessible (test data only).
- Limits: 2 GB memory, 1 CPU, 300s timeout, concurrency 80, min instances 0 (scale to zero), max 10.
Environment uses the staging config with preview overrides: ENV=preview,
DD_ENV=preview, DD_SERVICE=perci-platform-backend-preview, DD_TRACE_ENABLED=false,
SSO_CLEANUP_ENABLED=false, SLACK_PLATFORM_CHANNEL=platform-preview. Secrets are fetched
from Google Secret Manager at deploy time.
Endpoints¶
- API:
{SERVICE_URL}/api/v1 - Member BFF:
{SERVICE_URL}/bff/v1 - Clinical BFF:
{SERVICE_URL}/bff_clinical/v1 - Clinical Media:
{SERVICE_URL}/bff_clinical_media/v1 - Health:
{SERVICE_URL}/_health· Info:{SERVICE_URL}/
The Redoc docs for each API are at …/openapi — see API reference.
Cleanup¶
- On PR close/merge,
preview-cleanup.ymldeletes the Cloud Run service, its Artifact Registry images, and the PR's GitHub Actions caches, then comments confirmation. preview-janitor.ymlruns weekly (Sun 03:00 UTC) to sweep orphaned preview resources; a manual run supports a dry-run input.
Local testing¶
Run the Cloud Run adapter locally:
cd apps/perci-platform-backend/functions
pnpm install
pnpm run build # clean && generate && tsc -b (generate needs secrets)
cp .env.sample .env # then edit with local config
node lib/cloudrun.js # serves at http://localhost:8080
Or build the container the same way CI does:
cd apps/perci-platform-backend
docker build -t backend-preview .
docker run -p 8080:8080 --env-file functions/.env backend-preview
Troubleshooting¶
Preview not deploying — check the workflow logs; common causes are TypeScript build errors, Docker build failures, missing GCP permissions, or inaccessible secrets.
503 errors — the container failed to start or crashed on init. Read the logs:
gcloud run services logs read backend-preview-pr-{PR_NUMBER} \
--region europe-west2 --project perci-platform-staging
Environment variable issues — inspect the deployed service:
gcloud run services describe backend-preview-pr-{PR_NUMBER} \
--region europe-west2 --project perci-platform-staging --format yaml
Security¶
Previews use staging credentials and are publicly reachable, so they must only handle test data. Secrets come from Secret Manager; preview URLs are posted as PR comments (visible to repo collaborators); services are deleted when the PR closes.