Skip to main content

CI/CD Pipeline

Last Verified: 2026-05-03
This guide documents the continuous integration and deployment pipelines for the Equa platform. Each repository has its own CI configuration with different validation jobs and runtime targets.

Pipeline Overview

GitHub Actions Workflows

RepositoryWorkflow FileTriggersJobs
equa-web.github/workflows/ci.ymlPush/PR to main (PR #516 removed stale staging trigger)lint-and-build, unit-tests, e2e-smoke, regression, visual-regression
equa-web.github/workflows/e2e-tests.ymlPush/PR to main, master, develop, feat/**E2E tests, regression tests
equa-server.github/workflows/ci.ymlPush to main, staging, prod-deploy; PRs to main/stagingbuild, test, docker-build
equabot-gateway(Vitest in CI)Push to mainlint, build, test (with coverage thresholds)
Source: GitHub Actions workflow files in each repository

equa-web CI

File: .github/workflows/ci.yml CI runs a tiered pipeline on every push/PR:

Lint & Build Job

  • Runner: ubuntu-latest
  • Node version: 18
  • Steps: Install deps -> ESLint -> webpack production build
  • Note (PR #511): @babel/core was upgraded from 7.11.6 → 7.29.0 to fix an api.assumption is not a function TypeError that broke every webpack build. The @babel/plugin-proposal-class-properties dead dep was removed and core-js entries deduped in the same PR. Webpack build failures referencing api.assumption should no longer occur.
  • Note (PR #516): The stale GH_PATTERNLIB_TOKEN: placeholder env override was removed from this job; the repo-level secret-validation step handles the token properly. The staging branch trigger was also removed because the default branch is now main.

Unit Tests Job

  • Steps: Jest 29 + React Testing Library (52 tests)

E2E Smoke Job

  • Timeout: 30 minutes
  • Steps: Start webpack dev server -> run Playwright E2E tests
  • On failure: Uploads test results and screenshots as artifacts

Regression Tests Job

  • Timeout: 20 minutes
  • Runs: Specific regression test files targeting previously fixed issues

Visual Regression Tests Job (PR #509)

  • Steps: Capture screenshots of key routes -> compare against baseline images
  • On failure: Uploads diff images as artifacts for visual review
The legacy Azure Pipelines config (azure-pipelines.yml) was removed in PR #507. CI is now fully handled by GitHub Actions. The Azure DevOps GitHub integration should also be disconnected from the equa-devops project to stop the failing EQUAStart.equa-web check from appearing on PRs.
Source: equa-web/.github/workflows/ci.yml

equa-server CI

File: .github/workflows/ci.yml Three jobs:

Build Job

  • Runner: ubuntu-latest
  • Node version: 18
  • Steps: Install deps -> compile TypeScript (yarn tsc && yarn tsa)
  • Note: Tests continue on error (continue-on-error: true)

Test Job

  • Steps: Install deps -> run tests (yarn test:api)
  • Continues on error so Docker build can proceed even if tests fail

Docker Build Job

  • Steps: Build Docker image -> verify compiled files exist
  • Does not push — only validates the image builds correctly
Source: equa-server/.github/workflows/ci.yml

Deployment Targets

Google Cloud Run (legacy equa-server deploy path)

Config: equa-server/cloudbuild.yaml Cloud Build steps:
  1. Build Docker image
  2. Push to Container Registry
  3. Deploy to Cloud Run
Cloud Run configuration:
SettingValue
Regionus-central1
Port3000
Memory1Gi
CPU1
Min instances1
Max instances10
Request timeout300s
Startup CPU boostEnabled
Source: equa-server/cloudbuild.yaml

Railway (current interim runtime targets)

Both equa-web and equa-server have Railway deployment configs. Treat these as the current committed runtime targets for the interim public stack. equa-server (railway.toml):
[build]
builder = "nixpacks"

[deploy]
startCommand = "npm run start:api"
healthcheckPath = "/health"
healthcheckTimeout = 300
restartPolicyType = "on_failure"
restartPolicyMaxRetries = 3
equa-web (railway.toml):
[build]
builder = "nixpacks"

[deploy]
startCommand = "npm run start"
healthcheckPath = "/"
Source: equa-server/railway.toml, equa-web/railway.toml

Browser API routing (same-origin)

The browser does not call a Cloud Run hostname directly in the default SPA build. equa-web defines API_URL as /api/v1, the development server proxies /api to http://localhost:3000, and the committed production nginx config proxies /api/ to https://equa-server-so-production.up.railway.app/. Treat api.equa.cc as a hostname that may exist for direct callers or future cutovers, not as the default browser proxy target documented in nginx.conf. Sources:
  • equa-web/webpack.config.js, Lines: 95-103, 262-266
  • equa-web/config/default.json, Lines: 1-4
  • equa-web/nginx.conf, Lines: 21-29

PM2 (equa-server traditional hosting)

Config: equa-server/ecosystem.config.js PM2 manages the production process with two apps:
  • api — the main API server
  • raven-addresses — the Raven address service
The production Docker image uses PM2 as its runtime (pm2-runtime start ecosystem.config.js --only api). Source: equa-server/ecosystem.config.js

Docker Configuration

File: equa-server/Dockerfile Multi-stage build using Node 18 Alpine:
StagePurpose
BuildInstall all deps, compile TypeScript
ProductionCopy compiled output, install production deps only, run via PM2
Key details:
  • Base image: node:18-alpine
  • Health check: HTTP GET to port 3000
  • Entry point: pm2-runtime start ecosystem.config.js --only api
Source: equa-server/Dockerfile

Environment Promotion

The general flow for deploying changes:
feature branch → PR → main/staging → production

equa-server

  1. Develop on feature branch
  2. PR to main or staging — GitHub Actions run build + test
  3. Keep the Railway runtime story tied to the current service wiring, not to the legacy prod-deploy branch
  4. Use prod-deploy only when intentionally exercising the legacy Cloud Build -> Cloud Run path

equa-web

  1. Develop on feature branch
  2. PR to main — CI runs lint, build, unit, smoke, regression, and visual jobs
  3. Merge to main — Railway serves the interim app.equa.cc runtime
Secrets management is handled via environment variables in the deployment platform (Railway dashboard, Cloud Run service config, or GitHub Secrets for CI). There is no centralized secrets management tool. Secrets are configured per-environment and are not documented in code.

Health Checks

ServiceEndpointConfigured In
equa-server (Railway)GET /healthrailway.toml
equa-server (Cloud Run)Port 3000 startup probecloudbuild.yaml
equa-web (Railway)GET /railway.toml

Environments

Environmentequa-web URLequa-server URLDeploy Trigger
Local devhttp://localhost:8080http://localhost:3000Manual
Stagingstaging.app.equa.ccSame-origin /api/v1 in the SPA; any direct staging API hostname must be verified separatelyMerge to staging
Productionapp.equa.cc (interim host)Same-origin /api/v1 via equa-web nginx; direct api.equa.cc usage is a separate host-level concernMerge to main for equa-web; prod-deploy remains the legacy Cloud Run path for equa-server