Example: the Angular SPA on Vercel
The generic recipe is in Onboard an app; this page shows it filled in for an off-cluster frontend — the Penvoice web SPA on Vercel — wired back to backends running on Ultron Infra.
The web app (penvoice-web, Angular 21) is the one piece of this example not
on the cluster — it deploys to Vercel. It runs two environments, and the git
branch selects the backend: main builds prod, any other branch (e.g.
staging) builds the staging config that points at the in-cluster test backends
and serves at test.penvoice.app.
Branch → env → backend
Section titled “Branch → env → backend”flowchart LR Main([branch: main]) -->|VERCEL_ENV=production| Prod[ng build --configuration production] Stg([branch: staging]) -->|VERCEL_ENV != production| Sg[ng build --configuration staging] Prod --> EP[environment.prod.ts] --> BP[api.penvoice.co.zw + auth.webbies.dev] Sg --> ES[environment.staging.ts] --> BS[test-api.penvoice.app + test-auth.webbies.dev] Local([ng serve :6006]) --> ED[environment.ts] --> BL[localhost:8080]
The vercel-build script
Section titled “The vercel-build script”Vercel runs vercel-build, which branches on VERCEL_ENV — Vercel sets this to
production only for the production branch (main), and preview for every other
branch:
"vercel-build": "if [ \"$VERCEL_ENV\" = production ]; then ng build --configuration production; else ng build --configuration staging; fi"So main → --configuration production; staging (and any preview) →
--configuration staging.
The Angular build configs
Section titled “The Angular build configs”angular.json swaps the environment file per configuration via fileReplacements.
The staging config replaces environment.ts with environment.staging.ts:
"staging": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.staging.ts" } ], "outputHashing": "all"}production does the same with environment.prod.ts and is the
defaultConfiguration.
The three environment files
Section titled “The three environment files”| Config | File | OIDC issuer | apiBaseUrl | redirectUri |
|---|---|---|---|---|
dev (ng serve) | environment.ts | test-auth.webbies.dev/realms/penvoice | http://localhost:8080 | http://localhost:6006/ |
| staging | environment.staging.ts | test-auth.webbies.dev/realms/penvoice | https://test-api.penvoice.app | https://test.penvoice.app/ |
| production | environment.prod.ts | auth.webbies.dev/realms/penvoice | https://api.penvoice.co.zw | https://app.penvoice.co.zw/ |
All three use OIDC client penvoice-web. Staging targets the in-cluster test
Keycloak and API documented in the other examples; production targets the future
prod instances.
// environment.staging.ts — used by the `staging` branch → test.penvoice.appexport const environment = { production: true, oidc: { issuer: 'https://test-auth.webbies.dev/realms/penvoice', clientId: 'penvoice-web', redirectUri: 'https://test.penvoice.app/', postLogoutRedirectUri: 'https://test.penvoice.app/', }, apiBaseUrl: 'https://test-api.penvoice.app',};Local development
Section titled “Local development”ng serve runs on port 6006 (not Angular’s default 4200) and uses the
unreplaced environment.ts: OIDC still points at the in-cluster test Keycloak
(test-auth.webbies.dev), but apiBaseUrl is http://localhost:8080 — so a local
SPA talks to a locally-run API while authenticating against the real test
Keycloak.