-
Notifications
You must be signed in to change notification settings - Fork 11
Architecture Overview
How the EPIC components fit together, and what a request touches on its way through.
flowchart TB
subgraph Users[" "]
direction LR
User["Public user"]
Staff["EAO staff"]
end
subgraph OpenShift["OpenShift 6cdc9e-*"]
Route["Route"]
RProxy["eao-nginx (rproxy)"]
Public["eagle-public<br/>Angular SPA"]
Admin["eagle-admin<br/>Angular SPA"]
API["eagle-api<br/>Express"]
Mongo[("MongoDB")]
Matview["matview CronJobs<br/>hot 30m, cold 02:00"]
end
subgraph Azure["Azure"]
AFD["Front Door<br/>eagle-public static site"]
DEMI["demi-api"]
Cosmos[("Cosmos DB for NoSQL")]
AISearch[("Azure AI Search<br/>demi-search-*")]
Notify["eagle-notify"]
end
subgraph External["External"]
Keycloak["BC Gov Keycloak<br/>realm eao-epic"]
Store[("NRS object store")]
Engage["ENGAGE met-api<br/>c72cba-*"]
end
User --> Route
Staff --> Route
Route --> RProxy
RProxy -->|"/ in test and prod"| AFD
RProxy -->|"/ in dev"| Public
RProxy -->|"/admin/"| Admin
RProxy -->|"/api, /eguide"| API
RProxy -->|"/analytics"| APIM["demi-apim-<env>"]
RProxy -->|"/demi-search/search"| DEMI
RProxy -->|"/demi-projects/{id}"| DEMI
Public & Admin -.->|"/api/config"| API
Public & Admin -.->|events| APIM
Staff -.->|OIDC login| Keycloak
Admin & API -.->|token validation| Keycloak
Engage -.->|comment period push| API
API --> Mongo
Matview --> Mongo
API -.->|"PUT /api/eagle/*"| DEMI
DEMI -.->|"POST /api/events"| Notify
DEMI --> Cosmos
DEMI --> AISearch
DEMI --> Store
APIM --> Analytics["analytics-api-fc-<env>"]
The rproxy service is the edge for every environment hostname. It routes by URL path:
| Path | Upstream |
|---|---|
/ |
Azure Front Door in test and prod, the in-cluster eagle-public Service in dev |
/admin/ |
eagle-admin |
/api, /api/config
|
eagle-api |
/eguide |
eagle-api |
/analytics |
demi-apim-<env> (eagle-analytics) |
/eagle-search/ |
none; localhost:9999 sentinel, 502 |
/demi-search/search |
demi-api |
/demi-projects/<id> |
demi-api, as /api/projects/<id>
|
Upstreams come from NGINX__EPIC__PROXY__* environment variables set per environment in
helm/rproxy/values-{dev,test,prod}.yaml. An unset variable renders a http://localhost:9999
sentinel, so dev has no search upstream and falls back to eagle-api's Mongo search.
/demi-search/search is an exact-match location and /demi-projects/<id> a regex that admits a
24-character hex id only. A prefix match would publish demi-api's whole route table anonymously on a
gov.bc.ca origin.
Repository: bcgov/eao-nginx. Config template
conf.d/server.conf.tmpl. Details in Reverse Proxy.
Angular 21 on Node.js 24. Public interface for viewing environmental assessments: project search,
document viewing, comment submission. Fetches runtime configuration from /api/config when the
Dockerfile has set configEndpoint = true.
Search for the Project, Document and DocumentChunk datasets goes to the path in
SEARCH_API_PATH; every other dataset stays on eagle-api. See Eagle Search.
In test and prod the bundle is served from Azure Storage behind Front Door. See Azure Hosting Cutover.
Angular 22 on Node.js 24. Staff portal for projects, documents and users. Fetches runtime
configuration from /api/config. Comment periods pushed by ENGAGE are read-only here.
Express on Node.js 24, backed by MongoDB. All models share one epic collection and are
discriminated by _schemaName.
Endpoints used by every frontend:
| Endpoint | Purpose |
|---|---|
GET /api/config |
Runtime configuration, unauthenticated, no secrets |
GET /api/public/project, /api/public/project/{projId}
|
Public project data |
GET /api/public/document, /api/public/document/{docId}
|
Public document metadata |
GET /api/public/search |
Mongo-backed search fallback |
Two CronJobs reuse the eagle-api image and connect straight to MongoDB to refresh materialized
views: eagle-cron-hot every 30 minutes and eagle-cron-cold at 02:00.
On every project, document and update write, eagle-api pushes the raw record to DEMI with
PUT /api/eagle/{projects,documents,updates}/{eagleId} and an X-Api-Key header. The push is
fire-and-forget: two attempts, 10-second timeout, failures logged and swallowed. It is disabled
unless both DEMI_API_BASE and DEMI_APIM_KEY are set, which is the case in test only.
demi-api on Azure App Service with Cosmos DB for NoSQL and Azure AI Search. DEMI is EPIC's
central data store for projects, documents, updates and chunks. Nothing writes back into Eagle's
MongoDB. See Eagle DEMI.
When an update (RecentActivity) it holds becomes published, demi-api pushes the event to
eagle-notify with POST /api/events and an x-functions-key header. See Eagle DEMI
for the payload shape and retry behaviour.
Azure Functions app behind demi-apim-<env> at /analytics. Receives batched events from
eagle-public, eagle-admin and eagle-api, writes them to Log Analytics, and serves the query API
behind the dashboard screens in eagle-demi-admin.
BC Gov Common Hosted Single Sign-On, realm eao-epic, OpenID Connect. Client eagle-admin-console
for eagle-admin user login, eagle-api-console for eagle-api token validation.
| Environment | URL |
|---|---|
| Dev | https://dev.loginproxy.gov.bc.ca/auth |
| Test | https://test.loginproxy.gov.bc.ca/auth |
| Prod | https://loginproxy.gov.bc.ca/auth |
ENGAGE (epic-engage, c72cba-*) pushes engagement data into eagle-api as comment periods with
isMet: true. The traffic is one-way. See ENGAGE–EAGLE Integration.
sequenceDiagram
participant User
participant RProxy as eao-nginx
participant Public as eagle-public
participant API as eagle-api
participant DB as MongoDB
User->>RProxy: GET /p/project-123
RProxy->>Public: GET /p/project-123
Public-->>User: Angular SPA
User->>RProxy: GET /api/config
RProxy->>API: GET /api/config
API-->>User: Runtime configuration
User->>RProxy: GET /api/public/project/project-123
RProxy->>API: GET /api/public/project/project-123
API->>DB: Query project
DB-->>API: Project document
API-->>User: Project JSON
Both Angular apps read their configuration at runtime, so a configuration change needs no rebuild.
- The Dockerfile sets
configEndpoint = trueinenv.js. - The browser loads the Angular app.
- The app fetches
/api/config. - eagle-api answers from the
Configdocument in MongoDB. - The app merges the response over its built-in defaults and renders.
SEARCH_API_PATH rides on this response, which is why moving search between backends is a MongoDB
field change and not a deploy. See Configuration Management.
| Namespace | Purpose |
|---|---|
6cdc9e-tools |
Image registry and build artifacts |
6cdc9e-dev |
Development |
6cdc9e-test |
Test and UAT |
6cdc9e-prod |
Production |
Image tags and promotion are covered in Deployment Pipeline.
- TLS terminates at the OpenShift Route.
- Staff authenticate against Keycloak with IDIR; eagle-api validates the JWT against the realm JWKS.
- eagle-api gates every read on a
read[]array on the document.'public'in that array is what makes a record publicly visible. - The eagle-api to DEMI push authenticates with a registry API key, sent as
X-Api-Key. - The demi-api to eagle-notify push authenticates with a function key scoped to one function, sent
as
x-functions-key. - Trivy scans container images for CRITICAL and HIGH vulnerabilities.
Eagle Documentation
Operations
- Deployment Pipeline
- Helm Charts
- Reverse Proxy
- Rollback Procedures
- Eagle Public Release Lines
- Eagle Search Archive
- Azure Migration Strategy
- Azure Hosting
- Front Door Per-App Split
- Error Logging
- Secrets Management
Architecture
- Architecture Overview
- API Architecture
- Analytics Architecture
- Angular Patterns
- Eagle Public Page Layout
- Eagle Public Adding A Page
- ENGAGE–EAGLE Integration
- BCGW Project Export
- Eagle Search
- Document Content Search
- Eagle DEMI
- Project Data Models
- Async Jobs API
- Bulk Document Download
Configuration
Help
Repositories
Environments