Notifications
In-app notifications backed by Redis, with per-user mark-read state.
telark emits in-app notifications for the events that should not be silent: a rollback completed or failed, a user was assigned a new role, a group membership changed. Notifications are owned by the exporter-service and persisted in Redis; the dashboard polls the list endpoint to render the bell badge and the notifications drawer.
There is no email gateway today, and no webhook fan-out — the NATS topic that publishes change events is separate.
What gets emitted
The events telark emits today, drawn from the dispatch sites across the services:
| Event | Source | Notes |
|---|---|---|
rollback.completed | Rollback controller success path. | Carries the application name, rollback ID, target generation, status success. |
rollback.completed | Rollback controller failure path. | Same type; metadata status: failure and an error message. |
user.assigned-role | Exporter user/group handlers on role assignment. | Severity info. |
group.membership-changed | Exporter group handler on member add/remove. | Severity info. |
| Plan lifecycle events | Plan controller transitions. | Currently logged; emission to the user feed is on the ideas list. |
Each notification has a stable shape:
| Field | Notes |
|---|---|
id | Server-assigned. |
userId | Target user. |
type | Stable event identifier (e.g. rollback.completed). |
title | Short human label. |
message | One-line body. |
severity | info | success | warning | error. |
metadata | Per-type structured data (resource IDs, status, etc.). |
read | Boolean. |
createdAt | ISO timestamp. |
ValidateForEmit rejects malformed payloads; Truncate clamps
title and message to safe lengths before persistence.
Storage
Notifications live in Redis. The exporter's
redis/notifications/storage.go writes each notification as a
hash, plus per-user sorted-set indexes for the list endpoint
(scrollable via cursor) and the unread count.
There is no CRD for notifications — they are an inherently ephemeral, per-user stream. Retention is governed by the Redis keyspace TTL, not by the snapshot retention policy.
Endpoints
All exposed by the exporter service:
| Method | Path | Purpose |
|---|---|---|
POST | /notifications/emit | Emit a notification (called from other services, never from the dashboard). |
GET | /notifications?userId=<id>&limit=<n>&cursor=<c> | List for one user, paginated. |
POST | /notifications/{id}/read?userId=<id> | Mark one notification read. |
POST | /notifications/read-all?userId=<id> | Mark every notification read for the user. |
DELETE | /notifications?userId=<id> | Clear every notification for the user. |
The limit default and the cursor encoding live in the exporter's
notifications constants. The silent request header is used by
the dashboard's polling loop to suppress error toasts on transient
failures.
How discovery emits
The discovery service uses a small HTTP client
(discovery/clients/notifications) to call the exporter's emit
endpoint. The rollback controller dispatches asynchronously via
async.Dispatch so a notification failure cannot block the
rollback itself — emission is best-effort.
How the UI consumes
dashboard-ui/src/features/notifications/ is small by design:
- A
clientsdirectory wrapping the four endpoints. - A Redux slice holding the current page of notifications plus the unread count.
- A polling hook that calls
fetchNotifications({ silent: true })on an interval (configurable viauserSettings.fetchIntervalSecondsin the GlobalConfig CRD). - A bell icon in the layout header with the unread count badge.
- A slide-out drawer with the list, per-row Mark read, and a Clear all action.
What this is not
- Not a webhook fan-out. External integrations subscribe to
the NATS
telark.applications.updatetopic (and any future per-event topic), not to this surface. - Not durable for compliance. Redis keyspace TTL applies. If you need a long-term audit log, capture the NATS stream into your own store.
- Not multi-channel. No email, SMS, or push delivery today. The transport is in-app only.
Related
- Features → RBAC (most notifications today come from RBAC mutations).
- Reference → API reference
- Reference → Environment variables — Redis