-
Notifications
You must be signed in to change notification settings - Fork 11
Configuration Management
Runtime configuration for EPIC platform applications.
Frontend apps (eagle-admin, eagle-public) fetch configuration from /api/config at startup. This enables a single Docker image to work across all environments.
Config flow:
rproxy-config ConfigMap → nginx serves /api/config → frontends fetch on startup
graph LR
subgraph OpenShift["OpenShift"]
CM["rproxy-config<br/>ConfigMap"]
Nginx["eao-nginx<br/>(rproxy)"]
CM -->|mounted| Nginx
end
subgraph Frontends["Browser"]
Admin["eagle-admin"]
Public["eagle-public"]
end
Nginx -->|"/api/config"| Admin
Nginx -->|"/api/config"| Public
style CM fill:#e8f5e9
style Nginx fill:#e3f2fd
Key points:
- Config served by nginx, not eagle-api (no API dependency for config)
- Instant updates:
oc edit configmap rproxy-config→ immediate effect - Single source of truth across all frontends
| Variable | Type | Description |
|---|---|---|
ENVIRONMENT |
string |
dev, test, prod
|
BANNER_COLOUR |
string | CSS class: red, orange, yellow, green, purple, or empty |
LOG_LEVEL |
number | 0=All, 1=Debug, 2=Info, 3=Warn, 4=Error |
API_LOCATION |
string | API host URL |
API_PATH |
string | API route prefix (default: /api) |
ADMIN_PATH |
string | Admin frontend path (default: /admin/) |
KEYCLOAK_CLIENT_ID |
string | OAuth client ID |
KEYCLOAK_URL |
string | Keycloak server URL |
KEYCLOAK_REALM |
string | Keycloak realm (default: eao-epic) |
KEYCLOAK_ENABLED |
boolean | Enable authentication |
ANALYTICS_API_URL |
string | Analytics endpoint (default: /analytics) |
ANALYTICS_DEBUG |
boolean | Debug logging |
ANALYTICS_ENHANCED_TRACKING |
boolean | Browser fingerprinting (privacy) |
ANALYTICS_TRAFFIC_TRACKING |
boolean | Page navigation tracking |
SURVEY_URL |
string | External survey link |
SHOW_SURVEY_BANNER |
boolean | Display survey banner |
# Edit ConfigMap directly
oc edit configmap rproxy-config -n 6cdc9e-dev
# Verify
curl -s https://eagle-dev.apps.silver.devops.gov.bc.ca/api/config | jq .Changes take effect immediately - no pod restart needed.
Update Helm values files for the change to persist across deployments:
# Edit values file
vim eao-nginx/helm/rproxy/values-dev.yaml
# Deploy
helm upgrade rproxy ./helm/rproxy -f ./helm/rproxy/values-dev.yaml -n 6cdc9e-dev# eao-nginx/helm/rproxy/values-dev.yaml
config:
environment: "dev"
bannerColour: "red"
logLevel: 0
apiLocation: "https://eagle-dev.apps.silver.devops.gov.bc.ca"
apiPath: "/api"
adminPath: "/admin/"
keycloak:
clientId: "eagle-api-console"
url: "https://dev.loginproxy.gov.bc.ca/auth"
realm: "eao-epic"
enabled: true
analytics:
apiUrl: "/analytics"
debug: true
enhancedTracking: true
trafficTracking: true
survey:
url: null
showBanner: falseFrontends use ConfigService to load and expose config. The service runs in two phases:
Phase 1 — Synchronous (blocks nothing):
configService.init(); // reads window.__env, returns immediatelyPhase 2 — Async, non-blocking (deployed only):
// Fires in background when configEndpoint = true
// Fetches /api/config and merges into config signal
// Components using config() signal auto-update when this completesLists (filter dropdowns) are lazy-loaded on first component subscription — not during init:
// First component to subscribe triggers the HTTP fetch
configService.lists.subscribe(lists => { ... });eagle-admin note: Preserves its own KEYCLOAK_CLIENT_ID (eagle-admin-console) rather than accepting the API's value. This is set in env.js and not overwritten by /api/config.
-
eao-nginx: Add to
helm/rproxy/templates/configmap.yamlandvalues*.yaml -
eagle-admin: Add to
EnvConfiginterface inconfig.service.ts -
eagle-public: Add to
EnvConfiginterface inconfig.service.ts - Update this wiki page
For local dev, frontends use env.js values directly with no API fetch.
env.js is the only file developers need to edit for local configuration.
proxy.conf.js reads API_LOCATION from env.js at dev-server startup and
generates proxy rules automatically — no separate proxy file to maintain.
graph LR
EnvJS["src/env.js<br/>API_LOCATION = localhost:3000"] -->|read by| ProxyJS["proxy.conf.js<br/>(auto-generated rules)"]
ProxyJS -->|/api/*| API["eagle-api :3000"]
ProxyJS -->|/analytics| API
API -->|proxy| PA["penguin-analytics :3001"]
style EnvJS fill:#e8f5e9
style ProxyJS fill:#e3f2fd
// src/env.js (eagle-public)
window.__env.configEndpoint = false; // Use env.js values only
window.__env.API_LOCATION = 'http://localhost:3000'; // proxy.conf.js reads this
window.__env.API_PATH = '/api';
window.__env.ANALYTICS_API_URL = '/analytics';
// To use the dev environment instead:
// window.__env.configEndpoint = true;
// window.__env.API_LOCATION = 'https://eagle-dev.apps.silver.devops.gov.bc.ca';The Angular app uses relative paths (/api, /analytics) — never API_LOCATION directly.
The dev server proxy handles routing to the API, just like nginx does in production.
Same pattern:
// src/env.js (eagle-admin)
window.__env.configEndpoint = false;
window.__env.API_LOCATION = 'http://localhost:3000';
window.__env.API_PATH = '/api';
window.__env.KEYCLOAK_CLIENT_ID = 'eagle-admin-console'; // Preserved — not from /api/config
window.__env.ANALYTICS_API_URL = '/analytics';
// To use the dev environment instead:
// window.__env.configEndpoint = true;
// window.__env.API_LOCATION = 'https://eagle-dev.apps.silver.devops.gov.bc.ca';In production, nginx routes /analytics directly to penguin-analytics.
For local dev, proxy.conf.js routes /analytics to eagle-api (:3000),
which proxies to penguin-analytics (:3001) via its /analytics Express route.
This means only one target (API_LOCATION) needs to be configured.
// proxy.conf.js (do not edit — reads from env.js automatically)
const vm = require('vm');
const envJs = fs.readFileSync('src/env.js', 'utf-8');
const sandbox = { __env: {} };
vm.runInNewContext(envJs, sandbox);
const target = sandbox.__env.API_LOCATION || 'http://localhost:3000';
const proxyRule = { target, secure: false, changeOrigin: true };
module.exports = {
'/api': proxyRule,
'/analytics': proxyRule
};The Dockerfile changes configEndpoint to true at build time:
RUN sed -i 's/configEndpoint = false/configEndpoint = true/' src/env.jsWhen configEndpoint = true, ConfigService.init() fires a non-blocking fetch to /api/config and merges the response over env.js defaults.
Important: ConfigService.init() is synchronous — it reads window.__env and returns immediately. The /api/config fetch (deployed only) runs in the background and updates the config signal when it completes. No network I/O blocks app startup.
curl -s https://eagle-dev.apps.silver.devops.gov.bc.ca/api/config | jq .oc get configmap rproxy-config -n 6cdc9e-dev -o jsonpath='{.data.config\.json}' | jq .ConfigMap changes are instant. If not seeing changes:
- Check you're editing the correct namespace
- Hard refresh browser (Ctrl+Shift+R) to bypass cache
- Verify nginx pod has the ConfigMap mounted
Important: env.js is a runtime config file but is served by angular's nginx as a static .js file. As of v2.4.1, the Dockerfile adds a specific location = /env.js block with no-cache headers to prevent browsers from caching it.
Prior to v2.4.1, env.js was cached for 1 year (max-age=31536000, immutable) because it matched the general .js caching rule. This caused issues when env.js values changed between deployments — clients with stale cached copies would use old config values (e.g., wrong ANALYTICS_API_URL).
The fix in both eagle-public and eagle-admin Dockerfiles:
# Runtime config — must never be cached
location = /env.js {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Hashed static assets — safe to cache long-term
location ~* \.(js|css|png|...)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}The location = /env.js exact match takes priority over the regex pattern.
- Keycloak Configuration - Authentication setup
- Analytics Architecture - Tracking and privacy
- Reverse Proxy Configuration - nginx routing
Eagle Documentation
Operations
Architecture
Configuration
Help
Repositories
Environments