The Nimbly platform implements a comprehensive notification system supporting three primary channels:
WhatsApp Business API - Via AiSensy service provider
Email - Via SendGrid
Push Notifications - Via Firebase Cloud Messaging (FCM)
The system is designed with a microservices architecture, utilizing message queues and cloud functions for scalable, asynchronous notification delivery.
sequenceDiagram
participant Service as Core Service<br/>(Issues/Reports)
participant WhatsApp as WhatsApp API<br/>Service
participant User as User Repository
participant Unsubscribe as Unsubscribe<br/>Settings
participant AiSensy as AiSensy API
Service->>WhatsApp: POST /report-notification
WhatsApp->>User: Get user details & WhatsApp number
WhatsApp->>Unsubscribe: Check unsubscribe settings
alt User unsubscribed
WhatsApp-->>Service: Return error (unsubscribed)
else User subscribed
WhatsApp->>WhatsApp: Determine campaign type<br/>(basic/advanced)
WhatsApp->>WhatsApp: Build template parameters
WhatsApp->>AiSensy: POST /api/v2
AiSensy-->>WhatsApp: Response
WhatsApp-->>Service: Success response
end
6.2. WhatsApp Campaign Types
Report Campaigns
// Basic Templates (text only with link)REPORT_GENERATED_BASICREPORT_OVERDUE_BASICREPORT_DUE_BASICREPORT_RECAP_DAILY_BASICREPORT_RECAP_WEEKLY_BASICREPORT_RECAP_MONTHLY_BASIC// Advanced Templates (with file attachments)REPORT_GENERATED_ADVREPORT_OVERDUE_ADVREPORT_RECAP_DAILY_ADVREPORT_RECAP_WEEKLY_ADVREPORT_RECAP_MONTHLY_ADV
Issue Campaigns
// All issue templates are currently basic (text only)ISSUE_AUDIT_BASICISSUE_ADHOC_BASICISSUE_CHANGE_STATUS_BASICISSUE_CHANGE_PRIORITY_BASICISSUE_CHANGE_FLAG_BASICISSUE_CHANGE_DEPARTMENT_BASICISSUE_CHANGE_USER_BASICISSUE_CHANGE_DUEDATE_BASICISSUE_ADD_MEMBER_BASICISSUE_REMOVE_MEMBER_BASICISSUE_NEW_COMMENT_BASICISSUE_NEAR_DUEDATE_BASICISSUE_OVERDUE_BASICISSUE_ESCALATED_BASICISSUE_RECAP_DAILY_BASIC/ADVISSUE_RECAP_WEEKLY_BASIC/ADVISSUE_RECAP_MONTHLY_BASIC/ADV
6.3. WhatsApp Implementation Details
// WhatsApp notification payload structureinterface WhatsAppNotificationPayload { apiKey: string; campaignName: string; destination: string; // User's WhatsApp number userName: string; source: string; // Organization ID templateParams: string[]; // Template variables media?: { // For advanced notifications url: string; filename: string; };}// Example implementationasync sendReportNotification(context: Context<UserAuth>, data: any) { // 1. Validate notification type if (!reportNotificationType.includes(data.notificationType)) { return { error: 'invalid', message: 'wrong notification type' }; } // 2. Get user details const user = await this.userRepo.findOneByID(data.userID); const destination = user.whatsappNumber; // 3. Check unsubscribe settings const unsubscribed = await this.unSubscribeNotificationsSettingsRepo .getByOrganizationIDAndPreferences(user.organizationID, undefined, true); // 4. Determine campaign type (basic/advanced) const campaignKey = user.whatsappAdvanceNotification ? `${notificationType}-adv` : `${notificationType}-basic`; // 5. Build and send request to AiSensy const response = await this.api.post('/api/v2', requestBody);}
7. Email Notifications
7.1. Architecture
sequenceDiagram
participant Service as Core Service
participant SendGrid as SendGrid Config
participant Template as Email Template
participant Queue as PubSub Queue
participant CloudFn as Cloud Function
participant API as SendGrid API
Service->>SendGrid: Initialize with API key
Service->>Template: Generate HTML template
Service->>Queue: Publish to emailNotification:sendBulkEmail
Queue->>CloudFn: Trigger function
CloudFn->>API: Send email via SendGrid
API-->>CloudFn: Response
7.2. Email Configuration
// SendGrid initializationimport sgMail from '@sendgrid/mail';sgMail.setApiKey(process.env.SENDGRID_KEY);// Standard email structureconst mail: MailDataRequired = { to: recipient.email, from: 'Nimbly <noreply@hellonimbly.com>', subject: 'Subject Line', text: 'For the best experience, please view this email in HTML', html: emailTemplate,};// Send emailawait sgMail.send(mail);
7.3. Email Templates
Issue Email Templates
issueCreationEmailTemplate.ts - New issue creation
// Mobile app background handlermessaging().setBackgroundMessageHandler(async (remoteMessage) => { // Handle notification when app is in background if (remoteMessage.data?.action === 'FORCE_LOGOUT') { await handleForceLogout(); } // Show local notification await Notifications.scheduleNotificationAsync({ content: { title: remoteMessage.notification.title, body: remoteMessage.notification.body, data: remoteMessage.data, }, trigger: null, });});
9. Notification Flows
9.1. Issue Creation Flow
sequenceDiagram
participant User as User
participant API as Issues API
participant Settings as Notification Settings
participant Recipients as Recipient Service
participant Email as Email Queue
participant WhatsApp as WhatsApp API
participant Push as Push Queue
User->>API: Create Issue
API->>Settings: Get notification config
alt Notifications enabled
API->>Recipients: Get recipients based on config
par Email Channel
API->>Email: Publish bulk email job
and WhatsApp Channel
API->>WhatsApp: Send WhatsApp notifications
and Push Channel
API->>Push: Publish push notification job
end
end
API-->>User: Issue created
9.2. Report Generation Flow
sequenceDiagram
participant Scheduler as Scheduler
participant Functions as Cloud Functions
participant Report as Report Generator
participant Storage as File Storage
participant Notif as Notification Service
participant WhatsApp as WhatsApp API
participant Email as Email Service
Scheduler->>Functions: Trigger report generation
Functions->>Report: Generate report
Report->>Storage: Save report file
Report->>Functions: Return file URL
Functions->>Notif: Determine recipients
par WhatsApp Notification
Functions->>WhatsApp: Send with file URL/attachment
and Email Notification
Functions->>Email: Send with file attachment
end
// Middleware for API authenticationconst authMiddleware = new AuthMiddleware<UserAuth>(process.env.JWT_SECRET!, jwt);// Apply to routesrouter.post('/report-notification', authMiddleware.expressHandler(), expressMiddlewareHandler(controller.sendReportNotification));
11.2. API Key Management
// Environment variablesSENDGRID_KEY=SG.xxxxxxxxxxxx // SendGrid API keyAISENSY_KEY=xxxxxxxxxxxxxxxxx // AiSensy WhatsApp API keyJWT_SECRET=xxxxxxxxxxxxxxxxxx // JWT signing secretWHATSAPP_URL=https://internal-api // Internal WhatsApp service URL
11.3. Data Encryption
User push tokens stored encrypted in Firebase
WhatsApp numbers stored with user consent
Notification payloads encrypted in transit (HTTPS)
The Nimbly notification system provides a robust, scalable solution for multi-channel notifications. By leveraging microservices architecture, message queues, and external service providers, the system ensures reliable delivery while maintaining flexibility. The implementation follows best practices for security, performance, and user experience, making it suitable for enterprise-scale deployments.