Notifications
In-app notifications with real-time delivery via SignalR. Created by Worker after background tasks complete.
When to use this module
- After background task completes, frontend needs real-time updates.
- To show unread badge count to users.
- User reads a notification (mark as read).
Endpoints
| Method | Route | Auth | Description |
|---|---|---|---|
| GET | /api/v1/notification?page=1&pageSize=20 | Paginated list | |
| GET | /api/v1/notification/unread-count | Count for badge | |
| PUT | /api/v1/notification/{id}/read | Mark one as read | |
| PUT | /api/v1/notification/mark-all-read | Mark all as read |
Notification Delivery Flow
Worker completes task (e.g., WhatsApp message sent)
│
▼
IAppNotificationService.CreateAndPushAsync(firmId, userId, module, title, message)
│
├──→ DB: INSERT into Notifications table
│
└──→ WorkerSignalRClient → API NotificationHub → Frontend browser
│
▼
Toast/bell update
GET
/api/v1/notification
Response
JSON
{
"isSuccess": true,
"data": {
"items": [
{
"id": "guid",
"title": "Templates Synced",
"message": "12 templates synced from Meta successfully",
"module": "Template",
"status": "Unread",
"createdAt": "2026-05-26T10:00:00Z"
}
],
"totalCount": 5,
"page": 1,
"pageSize": 20
}
}GET
/api/v1/notification/unread-count
Response
JSON
{ "isSuccess": true, "data": 3, "message": "" }Notification Entity
| Property | Type | Description |
|---|---|---|
FirmId | Guid | Owning firm |
UserId | Guid? | Target user (null = firm-wide) |
Module | enum | Source module (WhatsApp, Contact, Workflow, Template, System) |
ModuleId | Guid? | Related entity ID (deep-link) |
Title | string(150) | Notification title |
Message | string(500) | Body text |
Metadata | JsonDocument? | JSONB flexible per-module data |
Status | enum | Unread / Read |
ReadAt | DateTime? | When marked read |
Client JS Example
JavaScript
const connection = new signalR.HubConnectionBuilder()
.withUrl('/notificationhub', { accessTokenFactory: () => getToken() })
.build();
connection.on('ReceiveNotification', (notification) => {
showToast(notification.title, notification.message);
updateUnreadBadge();
});
await connection.start();