Repository navigation
ENGAGE EAGLE Integration
EPIC runs two products in separate OpenShift namespaces:
| Product | Namespaces | Purpose |
|---|---|---|
ENGAGE (epic-engage) |
c72cba-{dev,test,prod} |
Staff create and manage public engagement sessions |
EAGLE (eagle-api and frontends) |
6cdc9e-{dev,test,prod} |
Public EA platform; citizens browse projects and comment |
Engagements flow ENGAGE to DEMI to EAGLE. ENGAGE pushes each engagement to DEMI with
PUT /engage/engagements/:engagementId through APIM (subscription engage). DEMI owns those
rows. DEMI's sync-out (Storage queue sync-out, a worker, and an Eagle consumer) writes them into
EAGLE as comment periods marked isMet: true, through eagle-api's protected /api/commentperiod
endpoints. The consumer signs in with Keycloak client demi-sync-out (client credentials, realm
role staff). Nothing writes EAGLE's MongoDB directly. eagle-api mirrors every comment period
write back to DEMI, and for an ENGAGE-owned row DEMI accepts only the Eagle-owned fields. The
Eagle consumer is removed when eagle-public's Angular line retires.
Traffic from ENGAGE is one-way: EAGLE never calls ENGAGE. For the sync-out worker see the DEMI
wiki pages Sync-Architecture and ADR-014-Sync-Out.
EPIC_SYNC_TARGET in met-api and met-cron selects where ENGAGE pushes. The sections below
describe the payload and calls for the eagle path, a direct push to eagle-api.
| Value | ENGAGE pushes to |
|---|---|
eagle |
eagle-api only. Default; unknown values fall back to it |
both |
eagle-api and DEMI |
demi |
DEMI only |
Every value needs EPIC_URL, because ENGAGE asks eagle-api whether a project id is a project or a
project notification. DEMI is reached with DEMI_API_URL and DEMI_API_KEY. met-cron loads the
same EPIC config as met-api, so scheduled publish and close-out push too.
The manual job ENGAGEMENT_DEMI_BACKFILL (python3 invoke_jobs.py ENGAGEMENT_DEMI_BACKFILL in the
met-cron pod) loads existing engagements into DEMI. It refuses to run unless IS_EAO_ENVIRONMENT
is true and EPIC_SYNC_TARGET is both or demi.
The push is gated on IS_EAO_ENVIRONMENT and on the engagement's metadata carrying a
project_id. Without either, ENGAGE skips the call.
sequenceDiagram
participant Staff as EAO staff
participant Engage as ENGAGE met-api
participant KC as Keycloak
participant API as eagle-api
participant DB as MongoDB
Staff->>Engage: Create, edit, publish or delete engagement
Engage->>KC: Service account grant
KC-->>Engage: Bearer token
alt No tracking id stored
Engage->>API: POST /api/commentperiod
API->>DB: Insert CommentPeriod (isMet true)
API-->>Engage: 200 { _id }
Engage->>Engage: Store _id as project_tracking_id
else Tracking id stored
Engage->>API: PUT /api/commentperiod/{tracking_id}
API->>DB: Update CommentPeriod
else Engagement deleted
Engage->>API: DELETE /api/commentperiod/{tracking_id}
API->>DB: Remove CommentPeriod
end
project_tracking_id is stored on EngagementMetadataModel after the first successful POST, and
every later call uses it to build the PUT or DELETE URL. If it is absent, the next sync creates a
new comment period with a POST.
Every one of these calls ProjectService.update_project_info(), except the last:
| Event | ENGAGE code | eagle-api call |
|---|---|---|
| Engagement created | engagement_service.create_engagement() |
POST |
| Engagement edited, published or unpublished | engagement_service.edit_engagement() |
PUT |
| Scheduled auto-publish | engagement_service.publish_scheduled_engagements() |
PUT |
| Engagement closed when due | engagement_service.close_engagements_due() |
PUT |
| Engagement slug changed | engagement_slug_service.update_engagement_slug() |
PUT |
| Engagement metadata created or updated |
engagement_metadata_service.create_metadata(), update_metadata()
|
POST or PUT |
| Engagement deleted |
engagement_service.delete() → delete_from_epic()
|
DELETE |
Built by ProjectService._construct_epic_payload().
| Field | Type | Notes |
|---|---|---|
isMet |
bool | Always true. Marks the comment period as ENGAGE-managed |
isPublished |
bool |
false for Draft and Unpublished, true for every other status |
metURL |
string | Public ENGAGE engagement URL, shown to citizens |
metURLAdmin |
string | Staff ENGAGE admin URL, shown in eagle-admin |
metBannerImageUrl |
string | Banner image from ENGAGE object storage |
dateStarted |
ISO date | Engagement start, UTC |
dateCompleted |
ISO date | Engagement end, UTC |
instructions |
string | Engagement description |
informationLabel |
string | Engagement name |
commentTip |
string | Always empty |
milestone |
ObjectId | From the EPIC_MILESTONE setting |
openHouse |
string | Always empty |
relatedDocuments |
string | Always empty |
project |
ObjectId | eagle-api Project _id
|
ENGAGE sends openHouse; eagle-api reads openHouses. The value is always empty, so nothing is
lost, but the two names do not match.
eagle-api stores isPublished on the CommentPeriod document and derives the read array from it
on both POST and PUT:
-
isPublished: true→readis['public', 'staff', 'sysadmin'], so citizens see the comment period in eagle-public. -
isPublished: false→readis['staff', 'sysadmin'], staff only.
If a caller omits isPublished, eagle-api falls back to whether the incoming read array contains
'public'.
ENGAGE derives the flag from engagement status:
| ENGAGE status |
isPublished sent |
Publicly visible |
|---|---|---|
| Draft | false |
No |
| Scheduled | true |
Yes, as pending |
| Published | true |
Yes, as open |
| Closed | true |
Yes, as closed |
| Unpublished | false |
No |
A project notification has no separate CommentPeriod document. ENGAGE writes the commenting fields
onto the ProjectNotification document instead.
ENGAGE first probes GET /api/project/{id}; a non-200 means the id is a project notification and
GET /api/projectNotification/{id} is used instead. The update is
PUT /api/projectNotification/{id}?publish={true|false} carrying dateStarted, dateCompleted,
isMet, metURL and a pcp state derived from the current time against the engagement dates:
| Condition | pcp |
|---|---|
| Engagement not publicly visible | none |
| Before the start date | pending |
| After the end date | closed |
| Otherwise | open |
Deleting the engagement clears the same fields — pcp: 'none', isMet: false, empty metURL,
null dates, publish=false — without deleting the notification document.
ENGAGE authenticates to eagle-api with a Keycloak service account, obtaining a token by password
grant. Credentials live in the epic-keycloak-details Secret in the c72cba namespace, under
EPIC_KC_CLIENT_ID, EPIC_KEYCLOAK_SERVICE_ACCOUNT_ID, EPIC_KEYCLOAK_SERVICE_ACCOUNT_SECRET and
EPIC_JWT_OIDC_ISSUER.
EPIC_URL in the met-api ConfigMap holds the target environment's /api/commentperiod URL and is
what points a given ENGAGE namespace at the matching EAGLE namespace. The project-notification calls
derive their base URL by stripping the last path segment from it.
Clicking an isMet comment period that has a metURLAdmin — in the comment period table or in the
project banner — opens that ENGAGE admin URL in a new tab instead of navigating to the eagle-admin
detail page. That redirect is what keeps ENGAGE-managed periods out of eagle-admin's editor;
eagle-admin's own create, edit and delete calls are generic and carry no isMet check.
Publish and unpublish stay available through PUT /api/commentperiod/{id}/publish and
PUT /api/commentperiod/{id}/unpublish.
eagle-public (Angular line) reads comment period data from DEMI and makes no ENGAGE API call at
runtime. The site is read-only: it has no comment form, file upload or CAC sign-up. Comments are
taken in ENGAGE only. A comment period with isMet and an http or https metURL shows a link to
ENGAGE that opens in a new tab. Legacy comments are stored in DEMI and read through
/demi-search/search?dataset=Comment.
- Architecture Overview
-
API Architecture — eagle-api access control and the
read[]array
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
- Front Door Ban Ladder
- Error Logging
- Secrets Management
Architecture
- Architecture Overview
- API Architecture
- Analytics Architecture
- Angular Patterns
- Eagle Public Page Layout
- Eagle Public Adding A Page
- Extended Project Pages
- ENGAGE–EAGLE Integration
- BCGW Project Export
- Eagle Search
- Document Content Search
- Eagle DEMI
- Eagle DEMI Push Sweep
- Eagle DEMI Re-Push and Backfill
- Eagle Notify
- Project Data Models
- Async Jobs API
- Bulk Document Download
Configuration
Help
Repositories
Environments