3.2 KiB
name, description
| name | description |
|---|---|
| dyolink-notifications-inbox | Header notification bell/inbox (UserNotification fan-out + Socket.IO). Use when changing inbox cards, realtime gateway, or notification deep links — distinct from sidebar tab badges. |
Notifications inbox (bell)
Permission-free feature (every dashboard user sees the bell). Cards are permission-filtered at fan-out time.
vs tab badges
Inbox (UserNotification) |
Sidebar badges (LabCaseActivity) |
|
|---|---|---|
| Entry | Header bell → dropdown + /notifications |
Sidebar Cases/Tasks/Treatment/Orgs |
| Live | Socket.IO (/realtime) |
Same socket → notifyTabBadgesChanged() → REST tab-counts |
| Read | Per-card readAt only |
Per-case / tab cursors |
Do not clear tab badges when marking an inbox card read.
Live cascade (one socket)
On notification.created, RealtimeProvider:
- Updates inbox state (bell list + unread).
- Calls
notifyTabBadgesChanged()→ Sidebar refetchesGET /notifications/tab-counts. - For connection-request types, also
notifyPendingConnectionsChanged(). - Currently mounted feature pages soft-refresh (no remount, no form wipe). Unmounted tabs do not fetch list data until opened:
- Cases — silent list + selected detail reload
- Tasks — silent task list reload
- Treatment (
TreatmentWorkspace, not thinpage.tsx) — silent patient lab-cases + unread rail - Organizations — silent connections list on
pending-connections-changedonly
Sidebar badge counts always refetch (hook lives in the always-mounted Sidebar). Treatment draft/form state is not cleared by this cascade.
Full tab-badge map: .cursor/skills/tab-badges/SKILL.md.
Backend
- Model:
UserNotification+UserNotificationTypein Prisma - Fan-out:
user-notification.service.ts - Realtime:
backend/src/realtime/—RealtimeGateway(cookie JWT),RealtimeEmitter, roomsuser:{userId}:org:{organizationId} - REST:
GET /notifications/inbox,GET /notifications/inbox/unread-count,POST /notifications/inbox/:id/read,POST /notifications/inbox/read-all
Emit sites (parallel to LabCaseActivity)
CASE_SENT, CLINIC_COMMENT, LAB_COMMENT (+ LAB_COMMENT_CLINIC), CASE_IMPORTANT, TASK_COMPLETED, TASK_ASSIGNED (assignee only), CONNECTION_REQUEST, STAFF_INVITE — see service call sites.
Inbox card context is denormalized inside UserNotificationService.notify() (enrichInboxPayload) from ids already on the payload (labCaseId, taskId, fromOrganizationId). Emit sites stay thin ({ labCaseId }, etc.). Inbox list/read does not join related tables. Older rows may lack these fields until new events are emitted.
Realtime auth: after access-token refresh (proactive, axios 401 retry, or checkAuth), frontend dispatches dyolink:access-token-refreshed so RealtimeProvider reconnects with the new cookie.
Frontend UI
NotificationBell+NotificationsPage+NotificationCard(full-width page list; same card height; extra context truncated on one line)- Deep links:
/cases?caseId=,/tasks?taskId=,/treatment?labCaseId=,/organizations,/staff