Skip to main content

Notifications GraphQL API

Real-time notification system with queries, mutations, and WebSocket subscriptions.

Notification Targeting

Notifications support three targeting modes:

ModeConditionAudience
DirecttargetUserId is setSingle user
Role-basedtargetUserId is null, targetRoles is setAll users whose groups grant any of the specified roles
BroadcastBoth targetUserId and targetRoles are nullAll active users in the organization

targetUserId and targetRoles are mutually exclusive — setting both is a validation error. targetRoles must not be an empty list.

Read Status

Read status (isRead, readAt) is tracked per user via a UserNotification junction table. UserNotification rows are created lazily — only when a user marks a notification as read. Until then, the notification appears as unread.

When a notification includes both entityType and entityId, the web UI attempts to open the matching app route as a dialog. It builds a path in the form entityType/entityId, checks the matched route's permission, permissions, or requiredPermissions, and passes matched route parameters plus organizationId and currentUser into the dialog component. If no route exists or the user lacks permission, the UI shows an error instead of opening the item.

Queries

getNotification

Fetch a single notification for the current user.

query {
getNotification(organizationId: 1, notificationId: 42) {
notificationId
title
message
type
priority
targetUserId
targetRoles
entityType
entityId
isRead
readAt
created
}
}

Parameters:

ParameterTypeRequiredDescription
organizationIdIntYesOrganization scope
notificationIdIntYesNotification to fetch

Returns null if the notification doesn't exist or isn't visible to the current user (see Notification Targeting).

getNotifications

Paginated list of notifications for the current user. Supports filtering, searching, and sorting.

query {
getNotifications(organizationId: 1, filter: "isRead:false", orderBy: "-created", skip: 0, take: 20) {
items {
notificationId
title
message
type
priority
targetRoles
isRead
created
}
totalCount
}
}

Parameters:

ParameterTypeRequiredDescription
organizationIdIntYesOrganization scope
filterStringNoLucene filter syntax (e.g. isRead:false, type:Alert)
searchStringNoFull-text search
orderByStringNoSort field (default: -created = newest first)

getUnreadNotificationCount

Returns the count of unread notifications for the current user.

query {
getUnreadNotificationCount(organizationId: 1)
}

Mutations

createNotification

Create a new notification. Targeting is determined by targetUserId and targetRoles — see Notification Targeting.

mutation {
createNotification(organizationId: 1, values: {
title: "Order #1234 shipped"
message: "Your order has been picked up by the carrier."
type: ORDER_UPDATE
priority: NORMAL
entityType: "Order"
entityId: 1234
}) {
notificationId
title
created
}
}

Input fields (CreateNotificationCommandValues):

FieldTypeRequiredDefaultDescription
titleStringYesNotification title
messageStringNoNotification body (supports Markdown)
typeNotificationTypeYesSystem, OrderUpdate, TaskAssignment, Alert, Info
priorityNotificationPriorityNoNormalLow, Normal, High, Urgent
targetUserIdStringNoTarget a specific user (mutually exclusive with targetRoles)
targetRoles[String]NoTarget users by role names (mutually exclusive with targetUserId; must not be empty if provided)
entityTypeStringNoLinked entity type name
entityIdIntNoLinked entity ID
expiresAtDateTimeNoOptional expiration

markNotificationRead

Mark a single notification as read for the current user.

mutation {
markNotificationRead(organizationId: 1, notificationId: 42)
}

Returns true on success.

markAllNotificationsRead

Mark all notifications as read for the current user. Returns the count of notifications marked.

mutation {
markAllNotificationsRead(organizationId: 1)
}

deleteNotification

Delete a notification (removes for all users).

mutation {
deleteNotification(organizationId: 1, notificationId: 42) {
deletedCount
id
}
}

Subscriptions

onNotificationReceived

Real-time WebSocket subscription for new notifications. Uses PostgreSQL NOTIFY/LISTEN under the hood.

subscription {
onNotificationReceived(organizationId: 1, userId: "user-abc-123") {
notificationId
title
message
type
priority
entityType
entityId
isRead
created
createdBy
}
}

Topic format: {organizationId}_{userId}_notifications

The subscription fires whenever a new notification is created that targets the specified user (either directly or via broadcast).

Frontend Integration

The frontend uses the useNotifications React hook which:

  1. Fetches notifications via GetNotifications query (RTK Query)
  2. Fetches unread count via GetUnreadNotificationCount query
  3. Subscribes to onNotificationReceived via graphql-ws WebSocket client
  4. Shows toast notifications for real-time updates
  5. Provides markAsRead, markAllAsRead, and deleteNotification actions

The NotificationsDropdown component in the navbar renders the notification bell icon with unread badge and a dropdown panel with the notification list. Message content is rendered as Markdown.