This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ICD/notifications.md
2026-03-15 01:33:38 +00:00

4.1 KiB
Raw Blame History

Notifications

Real-time notification infrastructure with WebSocket delivery and optional email transport.

Auth: All endpoints require authentication (JWT via sb_token cookie or Authorization: Bearer header).

CRUD

GET    /notifications                → paginated list
GET    /notifications/unread-count   → { "count": 5 }
PATCH  /notifications/:id/read       → mark one as read
POST   /notifications/mark-all-read  → mark all as read
DELETE /notifications/:id

GET /notifications — paginated list for the authenticated user.

Query parameters:

Param Type Default Description
limit int 20 1100, clamped
offset int 0 Pagination offset
unread_only bool false Filter to unread only

Response:

{
  "data": [ ... ],
  "total": 42,
  "limit": 20,
  "offset": 0
}

Notification object:

{
  "id": "uuid",
  "user_id": "uuid",
  "type": "role.fallback",
  "title": "Role Fallback Triggered",
  "body": "Primary model unavailable, using fallback",
  "resource_type": "channel",
  "resource_id": "uuid",
  "is_read": false,
  "created_at": "2025-01-15T12:00:00Z"
}

resource_type and resource_id are optional — used for click-to-navigate. The resource may be deleted (no FK constraint).

Preferences

Users control per-type delivery:

GET    /notifications/preferences           → { "data": [...] }
PUT    /notifications/preferences/:type     ← { "in_app": true, "email": false }
DELETE /notifications/preferences/:type      → reset to default

GET /notifications/preferences returns all preferences set by the user. Empty array if none are configured.

PUT /notifications/preferences/:type creates or updates a preference. Both in_app and email fields are optional (merges with existing values if set).

DELETE /notifications/preferences/:type removes the preference, falling back to the next level in the resolution chain. Idempotent — deleting a non-existent preference returns 200.

Resolution: specific type pref → user wildcard * pref → system default (in_app=true, email=false).

Returns 503 if the preference store is not available (unmanaged mode).

Admin

POST   /admin/notifications/test-email      → send test email to requesting admin

Requires admin role. Loads SMTP config from platform settings, sends a test message to the admin's registered email address.

Admin Broadcast (v0.28.6)

POST /admin/notifications/broadcast

Auth: Admin only.

Sends a system.announcement notification to all active users via NotifyMany. Also emits a system.broadcast WebSocket event for real-time visibility.

Request body:

{
  "title": "Scheduled Maintenance",
  "message": "Servers will be down from 2-4 AM EST.",
  "level": "warning"
}
Field Type Required Description
title string yes Short summary shown in bell dropdown
message string yes Detail text
level string no info (default), warning, or critical

Response:

{ "message": "broadcast sent", "count": 42 }

count is the number of active users notified.

WebSocket Events

Event Payload Description
notification.new Full notification object New notification created
notification.read {"id": "uuid"} Single notification marked read
notification.read {"action": "mark_all_read"} All notifications marked read
system.broadcast {"title", "message", "level"} Admin announcement (v0.28.6)

These are targeted via Hub.SendToUser — no room subscription required. Used for badge sync across tabs.

Notification Types

See enums.md for the canonical list. Types are free-form strings (domain.action convention) — new types don't require migration. Core types include system.announcement (admin broadcast, v0.28.6).

Retention

Background cleanup prunes notifications older than 90 days (default, configurable via WithRetention). Runs daily after a 5-minute startup delay.