Notifications
The notification module gives the ability to give real time notification to clients from anywhere in the backend that uses the event queue.
NotificationEvent | notification.event.ts
The message is sent via event queue using :
export class NotificationEvent {
readonly type: string;
readonly userId: number;
readonly organisationId: number;
readonly payload: any;
readonly referenceId: number;
readonly referenceType: string;
constructor(
type: string,
userId: number,
referenceId: number,
referenceType: string,
payload: any = {},
organisationId: number = null
) {
this.type = type;
this.payload = payload;
this.organisationId = organisationId;
this.userId = userId;
this.referenceId = referenceId;
this.referenceType = referenceType;
}
}
NotificationEventsConsumer | notification-events.consumets.ts
The notification consumer receives and forwards the messages to notification service that process the messages.
RuleEngine | proccessMessages | notification.service.ts
This is the heart of the notification.It takes the decision who will receive the messages and how the messages will arrive to the target.
The decision is based on the below rule configuration example:
import { registerAs } from '@nestjs/config';
export default registerAs('notification', () => ({
rules: {
DATA_CHECKIN_JOB_COMPLETED: {
enabled: true,
template: null,
attributes: {
user: ['id', 'firstName', 'lastName', 'avatarUrl'],
organisation: ['id', 'legalName'],
},
recipients: ['USER', 'ORGANISATION_OWNER'],
},
DATA_CHECKIN_JOB_FAILED: {
enabled: true,
template: null,
attributes: {
user: ['id', 'firstName', 'lastName', 'avatarUrl'],
organisation: ['id', 'legalName'],
},
recipients: ['USER', 'ORGANISATION_OWNER'],
},
},
}));
- The recipients:[] is a list of the commands ( see below):
private commands = {
USER: async ({ userId }) => await this.userService.retrieve(userId),
ORGANISATION_ALL: async ({ organisationId }) =>
organisationId ? await this.orgService.retrieveUsers(organisationId) : [],
ORGANISATION_OWNER: async ({ organisationId }) => {
if (!organisationId) return [];
const organisation = await this.orgService.retrieve(organisationId);
return await this.userService.retrieve(organisation.createdById);
},
DEPARTMENT_ALL: async ({ departmentId }) => await this.departmentService.retrieveDepartmentUsers(departmentId),
USER_ALL: async () => await this.userService.index(),
};
- The keys from the configuration DATA_CHECKIN_JOB_COMPLETED, DATA_CHECKIN_JOB_FAILED, ... match the NotificationEvent.type
- attributes tells the messageProcessor to extend the message that arrives with specific data from user/organisation object before send it to final target.
- private async prepareAndSendMessage(event: NotificationEvent, recipientId: any) Sends the final message via SSE method
SSE Message Transportation Method | notification.controller.ts
-
sse(@CurrentUser() user: UserData, @Req() req: Request, @Res() res: Response): Observable
Sends messages only to the user that are logged in. We are using the redis cache to check if the token of SSE session is disabled or is in blacklist.
We have also some notification services to support some basic interactive functionalities ( the functions names are descriptive ):
- async create(data: CreateNotificationDTO): Promise
- async fetch(id: number): Promise<Notification[]>
- async fetchOne(id: number): Promise
- async markAsSeen(id: number): Promise
- async markAllAsSeen(userId: number): Promise<Notification[]>
- async delete(id: number): Promise
- async deleteWithReferences(id: number, type: string): Promise