Back to ER Diagram
InfraTraq Notifications

Notification System

Event-driven notification system spanning PostgreSQL (rules, templates, recipients) and MongoDB (delivery tracking, push logs, SMS logs). Covers email, SMS, push, in-app, and webhook channels.

5 Channels
5 RDBMS Tables
3 MongoDB Collections
Event-Driven
Multi-Tenant

Overview

The notification system uses a dual-database architecture. Rules and templates live in PostgreSQL (system.notification_rule, master_data.notification_template) for referential integrity. Delivery logs live in MongoDB (notification_delivery, push_notification_log, sms_delivery_log) for high-write throughput and TTL auto-cleanup. When an application event fires, the Notification Engine evaluates matching rules, renders templates, and dispatches to the appropriate channel — tracking delivery status in MongoDB.


App Event

Rule Engine

Template Render

Channel Router

Email

SMS

Push

In-App

Webhook
5
Channels
5
RDBMS Tables
3
Mongo Collections
90d
Log Retention
<2s
Delivery SLA

Status States

StatusDescriptionAllowed ActionsNext States
QueuedNotification created and waiting for dispatchSend, CancelSending, Cancelled
SendingBeing dispatched to delivery channelRetry on failureSent, Failed
SentSuccessfully handed to delivery providerAwait delivery confirmationDelivered, Bounced
DeliveredConfirmed delivery to recipient device/inboxTrack read statusRead
ReadRecipient opened/acknowledged the notificationArchive
FailedDelivery failed after all retry attemptsManual retry, InvestigateQueued
BouncedEmail bounced or phone number invalidUpdate contact info

Notification Channels

Email

HTML/text email via SMTP or transactional provider (SendGrid, SES). Supports templates with variables, CC/BCC, attachments. Tracks: sent, delivered, opened, bounced, clicked.

SMS

Text messages via Twilio, MSG91, or similar gateway. 160-char limit per segment. Tracks: sent, delivered, failed. Supports OTP, alerts, and reminders.

Push Notification

Mobile push via Firebase Cloud Messaging (FCM) / APNs. Supports data payloads, deep links, and rich media. Tracks: sent, delivered, dismissed.

In-App

Real-time in-app notifications via WebSocket. Displayed in notification center with read/unread status. Supports priority levels and action buttons.

Database Schema (RDBMS + MongoDB)

RDBMS: system.notification_rule

  • rule_id (PK) — Unique identifier for the notification rule
  • tenant_id (FK) — Multi-tenant isolation — rules scoped per tenant
  • event_type — The triggering event (e.g., po_approved, invoice_overdue, grn_received)
  • module — Source module (procurement, finance, hse, etc.)
  • channel — Delivery channel: email, sms, push, in_app, webhook
  • recipient_type — Who receives: role, user, group, dynamic_field
  • condition_expr — Optional JSON condition (e.g., amount > 100000)
  • template_id (FK) — Links to master_data.notification_template

RDBMS: master_data.notification_template

  • template_id (PK) — Unique identifier for the template
  • template_code — Short code for programmatic reference (e.g., PO_APPROVED_EMAIL)
  • channel — Channel this template is designed for (email, sms, push)
  • subject — Email subject or push title with {{variable}} placeholders
  • body_template — Full body content with Handlebars/Jinja2 template syntax
  • variables — JSON array of expected variables with types and defaults

RDBMS: system.module_config

  • module_code — Module identifier (e.g., procurement, finance, hse)
  • is_enabled — Whether the module is active for this tenant
  • config_json — Module-specific configuration including notification preferences

MongoDB: notification_delivery

  • notification_id — Unique delivery tracking ID
  • rule_id — Reference to RDBMS notification_rule.rule_id
  • recipient_id — Target user/group ID
  • channel — Delivery channel used
  • status — Current status: queued → sending → sent → delivered → read / failed
  • sent_at / delivered_at / read_at — Timestamps for each status transition
  • error — Error message if delivery failed — TTL: 90 days

MongoDB: push_notification_log

  • push_id — Unique push delivery ID
  • device_token — FCM/APNs device token
  • platform — ios, android, web
  • provider_response — Raw response from FCM/APNs gateway
  • status — sent, delivered, failed — TTL: 90 days

MongoDB: sms_delivery_log

  • sms_id — Unique SMS delivery ID
  • phone_number — Recipient phone number (masked for privacy)
  • gateway — SMS gateway used (Twilio, MSG91, etc.)
  • gateway_message_id — Provider-assigned message ID for tracking
  • delivery_status — submitted, sent, delivered, failed — TTL: 90 days

Notification Lifecycle

1

Event Firing

An application event occurs (e.g., PO approved, invoice overdue). The event is published to the Notification Engine with event_type, module, and context payload (entity_id, amounts, user references).

2

Rule Matching

The Notification Engine queries system.notification_rule where event_type and module match. Evaluates condition_expr against the event payload. Multiple rules may match (e.g., email to approver + push to requester).

SELECT r.*, t.subject, t.body_template
FROM system.notification_rule r
JOIN master_data.notification_template t
  ON r.template_id = t.template_id
WHERE r.event_type = 'po_approved'
  AND r.is_active = true
  AND r.tenant_id = :tenant_id;
3

Recipient Resolution

Resolve recipient_type to actual user IDs. For role-based: query admin.user_role. For group-based: expand group membership. For dynamic_field: extract from event payload (e.g., po.created_by).

4

Template Rendering

Load the notification_template and render with event context variables. For email: render HTML subject + body. For SMS: render plain text within 160-char limit. For push: render title + body + data payload.

5

Channel Dispatch

Route the rendered notification to the appropriate delivery channel. Email → SMTP/SendGrid. SMS → Twilio/MSG91. Push → FCM/APNs. In-App → WebSocket broadcast. Webhook → HTTP POST to configured URL.

6

Delivery Tracking

Create a notification_delivery document in MongoDB with status "queued". Update status as delivery progresses: sending → sent → delivered → read. Log channel-specific details to push_notification_log or sms_delivery_log.

// Insert delivery tracking document
db.notification_delivery.insertOne({
  notification_id: ObjectId(),
  rule_id: "rule_123",
  recipient_id: "user_456",
  channel: "email",
  template: "PO_APPROVED_EMAIL",
  payload: { subject: "PO #1234 Approved", body: "..." },
  status: "queued",
  sent_at: null,
  delivered_at: null,
  read_at: null,
  error: null
});
7

Retry & Dead Letter

Failed deliveries are retried with exponential backoff (1min, 5min, 30min). After 3 failed attempts, move to dead letter queue. Alert operations team for persistent failures (e.g., invalid device tokens, bounced emails).

Implementation

Notification Engine (Python)

async def process_event(event_type, module, tenant_id, context):
    # 1. Find matching rules
    rules = await db.execute(
        """SELECT r.*, t.subject, t.body_template, t.variables
           FROM system.notification_rule r
           JOIN master_data.notification_template t ON r.template_id = t.template_id
           WHERE r.event_type = :evt AND r.module = :mod
             AND r.tenant_id = :tid AND r.is_active = true""",
        {"evt": event_type, "mod": module, "tid": tenant_id}
    )
    
    for rule in rules:
        # 2. Evaluate condition
        if rule.condition_expr and not evaluate_condition(rule.condition_expr, context):
            continue
        
        # 3. Resolve recipients
        recipients = await resolve_recipients(rule.recipient_type, rule.recipient_value, context)
        
        # 4. Render template
        rendered = render_template(rule.subject, rule.body_template, context)
        
        # 5. Dispatch to channel
        for recipient in recipients:
            await dispatch(rule.channel, recipient, rendered)

User Notification Preferences Query

// Get user's notification preferences from MongoDB
db.user_preference.findOne(
  { user_id: "user_456" },
  { projection: { notification_channels: 1, quiet_hours: 1, dnd_enabled: 1 } }
)

// Check user alert config for custom thresholds
db.user_alert_config.find({
  user_id: "user_456",
  module: "procurement",
  is_active: true
})

Validation Rules

Business Rules

  • Rate Limiting: Max 10 notifications per user per minute to prevent spam floods
  • Channel Fallback: If primary channel fails, fallback to secondary (e.g., push fails → email)
  • Quiet Hours: Respect user-configured quiet hours — queue non-urgent notifications
  • Deduplication: Prevent duplicate notifications for the same event + recipient within 5 minutes
  • Template Variables: All template variables must be present in context — fail gracefully with defaults
  • Phone Validation: Validate phone numbers (E.164 format) before SMS dispatch

Integration Points

Connected Modules

  • PostgreSQL: notification_rule, notification_template, module_config — rule definitions and templates
  • MongoDB: notification_delivery, push_notification_log, sms_delivery_log — delivery tracking
  • SendGrid/SES: Transactional email delivery with open/click tracking webhooks
  • Twilio/MSG91: SMS gateway with delivery status callbacks
  • Firebase (FCM): Push notification delivery for Android/iOS/Web
  • WebSocket: Real-time in-app notification delivery via persistent connections
  • Redis: Rate limiting counters and notification queue management
  • User Preferences (MongoDB): user_preference and user_alert_config for personalized delivery

Best Practices

Delivery Reliability

  • Use async message queue (Redis/RabbitMQ) between event firing and dispatch
  • Implement idempotent delivery — safe to retry without duplicate sends
  • Track delivery receipts via provider webhooks (SendGrid, FCM, Twilio)
  • Monitor delivery success rate per channel — alert below 95%

User Experience

  • Allow users to configure notification preferences per channel and module
  • Implement quiet hours and Do Not Disturb mode
  • Group related notifications (e.g., 5 approvals → 1 digest email)
  • Provide one-click unsubscribe for non-critical notification types

Operations

  • Log all delivery attempts in MongoDB with 90-day TTL
  • Dashboard: delivery success rate, average latency, bounce rate per channel
  • Alert on: delivery failure spike, queue depth > threshold, provider errors
  • Regular cleanup of expired device tokens and bounced email addresses