Notification System
@nx/helpdesk ships its own notification subsystem with digest batching, quiet hours, multi-channel delivery, and full send-status tracking.
Architecture
Data Model
Notification
| Column | Type | Description |
|---|---|---|
id | bigint | Snowflake ID |
eventCode | varchar | Event type code (e.g. TICKET_ASSIGNED) |
recipientId | bigint | Recipient ID |
recipientType | enum | USER / AGENT / SYSTEM |
merchantId | bigint | Tenant scope |
contextType | varchar | Context entity type (e.g. Ticket) |
contextId | bigint | Context entity ID |
title | jsonb | Notification title (i18n) |
content | jsonb | Notification body (i18n) |
templateData | jsonb | Data used to render the template |
channels | varchar[] | Selected delivery channels |
status | enum | PENDING / PROCESSING / DELIVERED / PARTIALLY_DELIVERED / FAILED |
isRead | boolean | Whether the recipient has read it |
readAt | timestamp | Read timestamp |
batchId | bigint | FK → NotificationBatch (if digest) |
actionUrl | varchar | Action URL when recipient clicks the notification |
NotificationTemplate
Template per event type and channel:
| Column | Type | Description |
|---|---|---|
eventCode | varchar | Event code |
channel | enum | Channel this template applies to |
subject | jsonb | Email subject (i18n) |
bodyHtml | jsonb | HTML body (i18n) |
bodyText | jsonb | Plain-text body (i18n) |
isActive | boolean | Whether the template is in use |
NotificationPreference
Per-user/agent notification preferences:
| Column | Type | Description |
|---|---|---|
userId | bigint | User or Agent ID |
eventCode | varchar | Event type |
channels | varchar[] | Preferred delivery channels |
quietHoursStart | time | Start of quiet hours (no notifications) |
quietHoursEnd | time | End of quiet hours |
digestEnabled | boolean | Batch notifications into a digest |
digestIntervalMinutes | int | Interval between digest deliveries |
NotificationDeliveryLog
Delivery history per channel:
| Column | Type | Description |
|---|---|---|
notificationId | bigint | FK → Notification |
channel | varchar | Delivery channel |
status | enum | SUCCESS / FAILED |
errorMessage | text | Error detail on failure |
sentAt | timestamp | Send timestamp |
NotificationBatch
Digest batching — aggregates multiple notifications into a single delivery:
| Column | Type | Description |
|---|---|---|
id | bigint | Snowflake ID |
recipientId | bigint | Recipient |
status | enum | PENDING / PROCESSING / SENT |
scheduledAt | timestamp | When the digest will be sent |
sentAt | timestamp | Actual send timestamp |
itemCount | int | Number of notifications in the batch |
Delivery Channels
| Channel | Implementation | Description |
|---|---|---|
EMAIL | NodemailerComponent | SMTP with HTML/text templates |
WEBSOCKET | ApplicationWebSocketComponent | Real-time via Signal service |
PUSH | Push adapter | Mobile push notifications |
SMS | SMS adapter | Text message delivery |
Quiet Hours
ProcessNotificationService checks NotificationPreference.quietHoursStart/End before delivery. If the current time falls within a recipient's quiet hours, the notification is deferred until quiet hours end.
Digest Batching
NotificationBatchService aggregates notifications into a digest:
Workers
| Worker | Queue | Function |
|---|---|---|
notification.worker | helpdesk.notification | Processes each notification, calls ProcessNotificationService (jobs: notification, notification-batch, notification-digest) |
Notification Trigger Events
| Event | Recipient | Description |
|---|---|---|
TICKET_CREATED | Assigned agent | New ticket waiting |
TICKET_ASSIGNED | Agent | Ticket has been assigned |
STATUS_CHANGED | Reporter | Ticket status updated |
MESSAGE_ADDED | Agent / Reporter | New message in ticket |
SLA_WARNING | Agent | SLA deadline approaching (75%) |
SLA_BREACHED | Agent + Manager | SLA violated (100%) |
SLA_CRITICAL | Manager + Leadership | Critical SLA breach (150%) |
TICKET_RESOLVED | Reporter | Ticket has been resolved |
TICKET_CLOSED | Agent | Customer confirmed closure |
WebSocket Rooms & Topics
ApplicationWebSocketComponent (with socket-event.service.ts) emits on a single helpdesk topic, into rooms scoped per ticket + message. Built from @nx/core helpers:
| Builder | Value | Description |
|---|---|---|
HelpdeskWebSocketTopics.HELP_DESK | observation/helpdesk | Helpdesk observation topic |
HelpdeskWebSocketRooms.getHelpdeskRooms({ ticketId, messageId }) | helpdesk/:ticketId/:messageId | Per-ticket, per-message room |
Source:
src/components/websocket/topics.ts,src/components/websocket/rooms.ts.
Related Pages
- Helpdesk Service — service overview
- API Events
- Configuration — Mail / escalation