Internal API for platform communication requests.
This service is the intake boundary for notifications and general platform communication. Callers submit an event/request, the service validates and enriches it, persists the request in Directus, then publishes a normalized message to Kafka for the NiFi communication flow.
- A platform service or app calls
POST /internal/notifications. - The service validates the request shape and internal bearer auth.
- If
app_idororganization_idis present, the service loads app/org context from Directus. - If
notification_keyis present, the service loads the active template from Directus and renders subject/body/data/options fromparameters. - The request and rendered message are stored in
platform_notification_requests. - A normalized event is published to
platform.notifications.requested.v1. - NiFi consumes the rendered event, performs additional validation/routing, and calls the delivery executor.
- NiFi/executors call this service to update request status and write delivery attempts.
GET /healthzGET /readyzGET /openapi.jsonPOST /internal/notificationsPOST /internal/browser-subscriptionsPOST /internal/browser-subscriptions/browsePOST /internal/browser-subscriptions/statsGET /internal/notifications/:idPOST /internal/notifications/:id/statusPOST /internal/notifications/:id/delivery-attempts
Example request:
{
"event_key": "platform.deployment.failed",
"source": "platform-deploy-service",
"severity": "error",
"priority": "high",
"app_id": "00000000-0000-0000-0000-000000000000",
"notification_key": "platform.deploy.operation-step",
"channels": ["in_app", "email"],
"recipients": [
{
"type": "role",
"id": "platform-admin"
}
],
"parameters": {
"operation_id": "00000000-0000-0000-0000-000000000000",
"operation_type": "redeploy",
"step_key": "prod-deploy",
"step_label": "Deploy production",
"status": "failed",
"message": "Deploy production failed."
},
"data": {},
"metadata": {
"correlation_source": "deployment"
}
}Browser subscription browse/stat tools are exposed through OpenAPI for GraphQL
action generation as browseBrowserSubscriptions and
getBrowserSubscriptionStats.
Example stats request:
{
"date_field": "last_seen_at",
"date_start": "2026-08-05T00:00:00.000Z",
"date_end": "2026-08-06T00:00:00.000Z",
"bucket": "hour",
"scan_limit": 5000
}Example bounded browse request:
{
"name_prefix": "c",
"status": "active",
"persistent": true,
"date_field": "last_seen_at",
"date_start": "2026-08-05T00:00:00.000Z",
"date_end": "2026-08-06T00:00:00.000Z",
"limit": 50,
"offset": 0
}Default topic:
platform.notifications.requested.v1
The published event includes:
schema_versionnotification_request_idevent_keysourceseveritypriorityorganization_idapp_idactor_user_idnotification_keytemplate_keylocalesubjectbodymessageparameterschannelsrecipientsdatametadatacontextdedupe_keyidempotency_keycorrelation_idscheduled_forexpires_atrequested_at
The service expects these managed collections to exist. The collection names are configurable through environment variables.
platform_notification_requests:
idevent_keysourceseverityprioritystatusorganization_idapp_idactor_user_idnotification_keytemplate_keylocalesubject_hintbody_hintrequested_channels_jsonrecipients_jsontemplate_parameters_jsonrendered_message_jsondata_jsonmetadata_jsoncontext_jsondedupe_keyidempotency_keycorrelation_idscheduled_forexpires_atrequested_atqueued_atstarted_atfinished_atqueue_topiclast_messageerror_messageresult_json
platform_notification_delivery_attempts:
idnotification_request_idchannelprovider_keyrecipient_jsonmessage_jsonstatusprovider_message_idrequest_payload_jsonresponse_jsonerror_messageattempted_atfinished_at
platform_notification_browser_subscriptions:
idsourcebrowser_installation_idendpointendpoint_hashexpiration_timep256dhauthuser_iduser_emailuser_phoneorganization_idapp_idpermissioncapabilities_jsonfallback_channels_jsonuser_agentmetadata_jsonstatuslast_seen_at
platform_notification_templates:
idnotification_keynamedescriptionstatuslocalechannels_jsonrequired_parameters_jsonsample_parameters_jsonsubject_templatetitle_templatebody_templatetext_templatehtml_templatedata_template_jsonoptions_template_jsonassets_jsonstylesheets_jsonmetadata_json
platform_notification_template_assets:
idtemplate_idnotification_keyasset_keyasset_typestatusmime_typeurldirectus_filecontentmetadata_jsonsort
Future collection set:
platform_notification_preferencesplatform_notification_suppression_entriesplatform_notification_rule_bindingsplatform_notification_channels
Important environment variables:
DIRECTUS_BASE_URLDIRECTUS_TOKEN_VAULT_PATHBROWSER_PUSH_TRUSTED_DIRECTUS_CLIENT_KEYSBROWSER_PUSH_TRUSTED_DIRECTUS_CLIENT_TOKEN_VAULT_PREFIXBROWSER_SUBSCRIPTION_SEARCH_TRUSTED_DIRECTUS_CLIENT_KEYSBROWSER_SUBSCRIPTION_SEARCH_TRUSTED_DIRECTUS_CLIENT_TOKEN_VAULT_PREFIXNOTIFICATION_INTAKE_TRUSTED_CLIENT_KEYSNOTIFICATION_INTAKE_TRUSTED_CLIENT_TOKEN_VAULT_PREFIXNOTIFICATION_INTAKE_TRUSTED_DIRECTUS_CLIENT_KEYSNOTIFICATION_INTAKE_TRUSTED_DIRECTUS_CLIENT_TOKEN_VAULT_PREFIXBROWSER_SUBSCRIPTION_CLEANUP_ENABLEDBROWSER_SUBSCRIPTION_CLEANUP_INTERVAL_MSBROWSER_SUBSCRIPTION_STALE_DAYSBROWSER_SUBSCRIPTION_CLEANUP_LIMITINTERNAL_TOKEN_VAULT_PATHKAFKA_BROKERSKAFKA_USERNAME_VAULT_PATHKAFKA_PASSWORD_VAULT_PATHNOTIFICATION_REQUESTED_TOPICNOTIFICATION_REQUEST_COLLECTIONNOTIFICATION_DELIVERY_COLLECTIONNOTIFICATION_BROWSER_SUBSCRIPTION_COLLECTIONNOTIFICATION_TEMPLATE_COLLECTIONNOTIFICATION_TEMPLATE_ASSET_COLLECTION
No provider tokens or credentials should be committed to this repo. Runtime credentials are resolved from Vault.
npm install
npm run build