Skip to main content
Version: v3

Notifications Plugin

The Notifications plugin gives every user a notification list at /notifications, reached from the Notifications sidebar entry, and shows a bell with the unread count in the header. Other systems address notifications to users through the backend REST API with a service credential.

Status: A default plugin, enabled in the catalog index's default plugin file (dynamic-plugins.default.yaml). No dynamic-plugins.yaml entry required.


Packages​

PackageRole
backstage-plugin-notificationsFrontend — notification list at /notifications
backstage-plugin-notifications-backendBackend — stores notifications and serves /api/notifications/notifications

Signals (backstage-plugin-signals and its backend) ships among the default plugins as well.


What it does​

  • Lists each user's notifications at /notifications
  • Shows a bell with the unread count in the header
  • Accepts new notifications from other systems at POST /api/notifications/notifications
  • Returns a user's notifications at GET /api/notifications/notifications

A notification that arrives while /notifications is open appears after you reload the page.


Allow another system to send notifications​

The backend accepts a post only with a service credential. A request with a user token fails with HTTP 403. Create a static token for the sending system under backend.auth.externalAccess. Generate a long random value and keep it in an environment variable; never write the token in a file:

export NOTIFICATIONS_STATIC_TOKEN="$(openssl rand -hex 32)"

Add the block below to a configuration fragment. The token resolves from the environment when the portal starts:

backend:
auth:
externalAccess:
- type: static
options:
token: ${NOTIFICATIONS_STATIC_TOKEN}
subject: notifications-sender

Local stack​

Save the fragment as app-config.notifications.yaml next to docker-compose.yml. Save this override as docker-compose.notifications.yaml. The Compose command replaces the base command, so repeat the local stack's chain and add the fragment last:

services:
devportal:
volumes:
- ./app-config.notifications.yaml:/opt/app-root/src/app-config.notifications.yaml:ro
environment:
NOTIFICATIONS_STATIC_TOKEN: ${NOTIFICATIONS_STATIC_TOKEN:?set NOTIFICATIONS_STATIC_TOKEN}
command:
- --config
- dynamic-plugins-root/app-config.dynamic-plugins.yaml
- --config
- app-config.veecode-auth.yaml
- --config
- app-config.veecode-branding.yaml
- --config
- app-config.extensions.yaml
- --config
- app-config.veecode-product.yaml
- --config
- app-config.notifications.yaml

Restart the stack with both files (see Add configuration to the local stack):

docker compose -f docker-compose.yml -f docker-compose.notifications.yaml down
docker compose -f docker-compose.yml -f docker-compose.notifications.yaml up -d

Kubernetes​

Add the same block under upstream.backstage.appConfig in your values, with the token read from the runtime Secret. Helm replaces the chart's externalAccess list with yours instead of merging them, so repeat the chart's own legacy entry next to the static one. Without it, the chart's legacy access with BACKEND_SECRET is no longer configured:

upstream:
backstage:
extraEnvVarsSecrets:
- veecode-runtime-secrets
appConfig:
backend:
auth:
externalAccess:
- type: legacy
options:
subject: legacy-default-config
secret: ${BACKEND_SECRET}
- type: static
options:
token: ${NOTIFICATIONS_STATIC_TOKEN}
subject: notifications-sender

Add NOTIFICATIONS_STATIC_TOKEN to the veecode-runtime-secrets Secret and upgrade the release (see Install DevPortal on Kubernetes).


Send a notification​

Post to the backend with the static token. Pass the token value as-is in the header:

curl -X POST http://localhost:7007/api/notifications/notifications \
-H "Authorization: Bearer $NOTIFICATIONS_STATIC_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"recipients":{"type":"entity","entityRef":"user:default/admin"},"payload":{"title":"Deploy finished","description":"Version 1.4.0 reached production.","link":"/notifications","severity":"high","topic":"deploys"}}'

The recipients select users by entity reference. The payload carries the title, a description, a link, a severity, and a topic. A post with a user token instead of the static token fails with HTTP 403. A successful post returns HTTP 200, and the stored notification records the token subject as its origin.


Read notifications​

Read the list back as the recipient user:

curl http://localhost:7007/api/notifications/notifications \
-H "Authorization: Bearer <user token>"

The response is a JSON object with a totalCount field and a notifications array.