-
Notifications
You must be signed in to change notification settings - Fork 11
Architecture Overview
Daniel Truong edited this page Jun 4, 2026
·
21 revisions
This document describes the Eagle system architecture, component interactions, and request flow.
flowchart TB
subgraph Users[" "]
direction LR
User["👤 Public User"]
Staff["👔 EAO Staff"]
end
subgraph OpenShift["OpenShift Cluster"]
Route["🌐 OpenShift Route<br/>projects.eao.gov.bc.ca"]
subgraph Proxy["Reverse Proxy"]
RProxy["eao-nginx"]
end
subgraph Apps["Application Layer"]
direction LR
Public["eagle-public<br/>Angular SPA"]
Admin["eagle-admin<br/>Angular SPA"]
API["eagle-api<br/>Node.js"]
end
subgraph Analytics["Analytics"]
direction LR
Collector["penguin-analytics<br/>Event Collector"]
Metabase["Metabase<br/>Dashboards"]
end
subgraph Data["Data Layer"]
direction LR
MongoDB[("MongoDB")]
TimescaleDB[("TimescaleDB")]
Typesense[("Typesense")]
end
subgraph Search["Search Sync"]
direction TB
ChangeStream["Change Stream<br/>(real-time)"]
Reindex["Reindex CronJob<br/>(nightly 2 AM)"]
ContentExtract["Content Extract CronJob<br/>(every 2h)"]
end
subgraph DocIntel["Document Intelligence"]
Docling["eagle-demi<br/>docling-serve CPU"]
end
end
subgraph External["External Services"]
Keycloak["🔐 BC Gov Keycloak<br/>loginproxy.gov.bc.ca"]
NRS[("NRS Object Store<br/>nrs.objectstore.gov.bc.ca")]
Engage["💬 EPIC Engage<br/>epic-engage-web-*.apps.gold.devops.gov.bc.ca"]
end
User --> Route
Staff --> Route
Route --> RProxy
RProxy -->|"/"|Public
RProxy -->|"/admin/"|Admin
RProxy -->|"/api/"|API
RProxy -->|"/analytics"|Collector
Public & Admin -.->|config|API
Public & Admin -.->|events|Collector
Staff -.->|OIDC login|Keycloak
Admin & API -.->|token validation|Keycloak
Public -.->|"engage banner"|Engage
API --> MongoDB
ChangeStream -->|watch epic collection| MongoDB
ChangeStream -->|upsert| Typesense
Reindex -->|full rebuild| Typesense
ContentExtract -->|download PDFs| NRS
ContentExtract -->|insert DocumentChunks| MongoDB
Public -.->|search| Typesense
Collector --> TimescaleDB
API -->|POST /v1/convert/file| Docling
Docling -->|extracted text| API
Metabase --> TimescaleDB
The reverse proxy (rproxy service) routes all incoming requests from projects.eao.gov.bc.ca to appropriate backend services based on URL path:
| Path | Service | Description |
|---|---|---|
/ |
eagle-public | Public-facing website |
/admin/ |
eagle-admin | Staff administration portal |
/api/ |
eagle-api | REST API endpoints |
/analytics |
penguin-analytics | Event tracking API |
/engage-api |
EPIC Engage API (proxied) | Engage banner data for eagle-public |
Repository: bcgov/eao-nginx
Key Configuration (conf.d/server.conf.tmpl):
- Environment variables for upstream service URLs
- Response caching via
proxy_cache globalcache - HTTP header passthrough for authentication tokens
- Technology: Angular 21 with nginx
- Node Version: Node.js 24.x
- Purpose: Public-facing interface for viewing environmental assessments
-
Config Pattern: Fetches runtime configuration from
/api/public/config - Features: Project search, document viewing, comment submission, Engage banner
-
Engage Integration: eagle-public integrates with EPIC Engage in two ways:
-
Engage Banner (
EngageBannerComponent): When a project has an open comment period withisMet=trueand ametURL, a banner is displayed at the top of the project page. Fetches engagement metadata from EPIC Engage via the/engage-apiproxy. -
Commenting Tab (
CommentingTabComponent): All public comment periods (both native eagle PCPs and Engage-managed PCPs) appear in a single unified list. PCPs withisMet=truerender with Engage metadata (name, status, dates fromEngageEngagement) fetched in parallel viaforkJoin. Clicking an Engage PCP card opens the engagement in a new tab. PCPs sharing the samemetURLare deduplicated to one card.
- The Engage API URL is configured per environment in the rproxy ConfigMap (
ENGAGE_API_URL). See Configuration Management for values.
-
Engage Banner (
- Technology: Angular 21 with nginx
- Node Version: Node.js 22.x
- Purpose: Staff portal for managing projects and documents
-
Config Pattern: Fetches runtime configuration from
/api/config - Features: Project management, document uploads, user administration
- Technology: Node.js with Express
- Node Version: Node.js 22.x
- Purpose: REST API backend for all data operations
- Database: MongoDB for document storage
-
Key Endpoints:
-
GET /api/public/config- Public app configuration -
GET /api/config- Admin app configuration -
GET /api/project- Project data -
GET /api/document- Document management
-
-
Search: Typesense powers full-text search for projects, documents, and PDF content. The sync service (Change Stream listener + CronJobs) lives in the standalone eagle-typesense repo. eagle-api only contains the search proxy (
typesenseProxy.js) that forwards browser queries to Typesense with server-side role filtering. -
Content Search: Document Content Search — separate CronJob in eagle-typesense extracts text from PDFs every 2h, stores as
DocumentChunkrecords in MongoDB, synced to Typesense automatically. -
Document Intelligence: On document upload, eagle-api calls eagle-demi (
POST /v1/convert/file) to extract text from PDFs and DOCX files using docling-serve. Cluster-internal only — no external exposure.
- Technology: docling-serve CPU image (no custom code)
-
Image:
ghcr.io/docling-project/docling-serve-cpu:v1.21.0 - Purpose: ML-powered PDF/DOCX text extraction for EPIC documents
-
Access: ClusterIP only — reachable as
http://eagle-demi:5001from eagle-api pods -
Auth:
X-Api-Keyheader fromeagle-demi-api-keyOpenShift Secret -
NetworkPolicy: Only
role: api-eagle-epicpods (eagle-api) may connect - Status: Deployed to dev. June 2026.
- Repository: bcgov/eagle-demi
- Technology: Node.js Express
- Purpose: Event collection and storage for usage analytics
- Database: TimescaleDB (time-series PostgreSQL)
-
Key Endpoints:
-
POST /analytics- Single event ingestion -
POST /analytics/batch- Batch event ingestion (up to 100) -
GET /health- Health check
-
- Dashboards: Metabase instance for visualization
External authentication service provided by BC Government Common Services:
| Environment | URL |
|---|---|
| Dev/Test | https://dev.loginproxy.gov.bc.ca/auth |
| Prod | https://loginproxy.gov.bc.ca/auth |
-
Realm:
eao-epic -
Client ID (Admin):
eagle-admin-console -
Client ID (API):
eagle-api-console - Protocol: OpenID Connect (OIDC)
sequenceDiagram
participant User
participant Route as OpenShift Route
participant RProxy as eao-nginx
participant Public as eagle-public
participant API as eagle-api
participant DB as MongoDB
User->>Route: GET projects.eao.gov.bc.ca/p/project-123
Route->>RProxy: Forward (TLS terminated)
RProxy->>Public: GET /p/project-123
Public->>User: Return Angular SPA
Note over User,Public: Browser loads Angular app
User->>Route: GET /api/public/config
Route->>RProxy: Forward
RProxy->>API: GET /api/public/config
API->>User: Return app configuration
User->>Route: GET /api/public/project/project-123
Route->>RProxy: Forward
RProxy->>API: GET /api/public/project/project-123
API->>DB: Query project
DB->>API: Project data
API->>User: Return project JSON
Both Angular applications use a runtime configuration pattern to avoid rebuilding containers for configuration changes:
flowchart LR
subgraph Build["Build Time"]
Code[Source Code] --> Build1[yarn build]
Build1 --> Artifact[Static Files]
Artifact --> Image[Container Image]
end
subgraph Runtime["Runtime"]
Image --> Container[Running Container]
Container --> Nginx[nginx serves SPA]
Nginx --> Browser[Browser loads app]
Browser --> Config[Fetch /api/config]
Config --> API[eagle-api]
API --> App[App configured]
end
-
Dockerfile sets
configEndpoint = trueinenv.js - Browser loads Angular application
- App fetches configuration from API endpoint
- API returns environment-specific configuration (URLs, feature flags, etc.)
- App applies configuration and renders
| Namespace | Purpose | Contains |
|---|---|---|
6cdc9e-tools |
Shared tooling | Image registry, build artifacts |
6cdc9e-dev |
Development | All services (dev tag) |
6cdc9e-test |
Testing/UAT | All services (test tag) |
6cdc9e-prod |
Production | All services (prod tag) |
| Tag | Purpose | Mutable |
|---|---|---|
dev |
Latest development build | Yes |
ci-latest |
Latest CI-verified build | Yes |
test |
Currently deployed to test | Yes |
prod |
Currently deployed to prod | Yes |
v1.2.3 |
Specific release version | No |
abc1234 |
Git commit SHA | No |
- TLS Termination: Handled at OpenShift Route level
- Authentication: Keycloak/IDIR for admin users
- API Security: JWT tokens for authenticated endpoints
- Container Scanning: Trivy scans for CRITICAL/HIGH vulnerabilities
- Network Policies: Namespace isolation (if configured)
- Deployment Pipeline - How code gets deployed
- Helm Charts - Kubernetes configuration details
- Typesense Search - Search architecture and sync
- Document Content Search - PDF content extraction and search
- Local Development - Setting up locally
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