4.4 KiB
Deployment Runbook
This document explains how deployments work for the EDR platform using Docker, GitHub Actions, and self-hosted runners.
Overview
- Monorepo contains 6 deployable services:
freight-apifreight-portalfreight-backofficepassenger-apipassenger-portalpassenger-backoffice
- Deployments run through one workflow:
.github/workflows/deploy.yml - Each service is built/deployed independently in parallel (matrix jobs).
- Docker Compose project names are branch-aware to avoid environment collisions on the same host.
Prerequisites
- Docker Engine with Compose plugin on the self-hosted runner.
- GitHub self-hosted runner registered for this repository.
- Repository secret configured:
NPM_TOKEN(for private@tria-plc/*package install during Docker build)
- Server-side env files created for each branch/environment.
Server Environment Files
sync-env-from-server.sh reads env files from:
/home/<DEPLOY_USER>/environment/edr/<branch-slug>/<project>/
Where:
<DEPLOY_USER>defaults totria(overridable byDEPLOY_USER)<branch-slug>is derived from Git branch (lowercase, non-alphanumeric replaced with-)<project>isedr-freightoredr-passenger
Required files per project
For edr-freight:
freight-api.envfreight-portal.envfreight-backoffice.env- optional:
freight-web.build.env
For edr-passenger:
passenger-api.envpassenger-portal.envpassenger-backoffice.env- optional:
passenger-web.build.env
Required env key
Each service env file must contain:
PORT=<number>
The sync script validates this and fails if missing.
Build env files (optional)
Used for build-time variables (example: Vite API URLs), with export syntax:
export FREIGHT_VITE_API_URL=https://freight-api.example.com/api
export PASSENGER_VITE_API_URL=https://passenger-api.example.com
These are injected into GITHUB_ENV during workflow execution.
Docker Compose Port Mapping
docker-compose.yaml uses per-service env variables for host/container port mappings:
FREIGHT_API_PORTPASSENGER_API_PORTFREIGHT_PORTAL_PORTFREIGHT_BACKOFFICE_PORTPASSENGER_PORTAL_PORTPASSENGER_BACKOFFICE_PORT
scripts/deploy/sync-env-from-server.sh extracts PORT from each synced .env and exports the corresponding *_PORT variable to GITHUB_ENV.
GitHub Actions Deployment Flow
Workflow file: .github/workflows/deploy.yml
1) prepare job
- Checks out repository once.
- Creates workspace artifact (
workspace.tgz) and uploads it.
2) deploy matrix job (parallel)
For each service:
- Downloads and extracts workspace artifact.
- Syncs that service env file from server path.
- Computes branch slug and sets:
COMPOSE_PROJECT_NAME=<project>-<branch-slug>
- Creates
.npmrc/.npmrc_tempfromNPM_TOKEN. - Runs:
docker compose --project-name "$COMPOSE_PROJECT_NAME" build <service>docker compose --project-name "$COMPOSE_PROJECT_NAME" up -d <service>
- Cleans
.npmrc/.npmrc_temp.
Branch/Environment Isolation
Compose project name is generated as:
<project>-<branch-slug>
Examples:
edr-freight-mainedr-freight-stagingedr-passenger-dev
This prevents container/network/volume name collisions between branches.
Local Manual Deployment (Optional)
From repo root:
DOCKER_BUILDKIT=1 docker compose build <service>
docker compose up -d <service>
If private packages are required locally, create .npmrc:
cat <<EOF > .npmrc
@tria-plc:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=<YOUR_TOKEN>
always-auth=true
EOF
Passenger API Startup Behavior
Passenger container entrypoint runs on startup:
npm run prisma:generatenpm run prisma:migrate(deploy mode)npm run prisma:seed- starts API process
Troubleshooting
Missing env file
Error:
Missing env file: ...
Fix:
- Create the required file in the server env directory for that project/branch slug.
Missing PORT in env file
Error:
Missing required PORT in env file: ...
Fix:
- Add
PORT=<number>to that service env file.
Private package install fails
Check:
NPM_TOKENexists in repo secrets.- Workflow created
.npmrcsuccessfully.
Prisma seed/migrate failures (passenger)
Check:
DATABASE_URLinpassenger-api.env- DB reachability from runner host/container network
- migration history consistency