Design a notification service that can deliver push notifications, SMS, and emails at scale. Notifications may be triggered by system events (payment confirmed) or marketing campaigns (10M users simultaneously). Delivery must be tracked.
[Event Sources]
Payment Service → payment.confirmed event
Marketing Tool → campaign.triggered event
│
▼
[Notification API Service]
- validates request
- checks user preferences
- resolves template
- publishes to channel-specific Kafka topic
↓
┌─────────────────────────────────────┐
│ Kafka Topics │
│ notifications.push │
│ notifications.email │
│ notifications.sms │
└─────────────────────────────────────┘
↓
[Channel Workers] (scale independently)
Push Worker → APNs / FCM
Email Worker → SendGrid
SMS Worker → Twilio
↓
[Delivery Tracker] → updates delivery_status in DB
// Trigger single notification
POST /api/v1/notifications
Body:
{
"userId": "user-123",
"template": "payment_confirmed",
"data": { "amount": "$49.99", "orderId": "ORD-789" },
"channels": ["PUSH", "EMAIL"],
"priority": "HIGH"
}
// Trigger campaign (batch)
POST /api/v1/campaigns
Body:
{
"segmentId": "premium_users",
"template": "new_feature_announcement",
"scheduledAt": "2025-09-20T09:00:00Z"
}
// Check delivery status
GET /api/v1/notifications/{notificationId}/status
Notifications (Cassandra — write-heavy delivery logs)
notification_log
notification_id UUID PK
user_id UUID
channel ENUM (PUSH, EMAIL, SMS)
template_id VARCHAR
status ENUM (PENDING, SENT, DELIVERED, FAILED, CLICKED)
created_at TIMESTAMP
delivered_at TIMESTAMP
User preferences (PostgreSQL)
notification_prefs
user_id UUID PK
channel VARCHAR
enabled BOOLEAN
updated_at TIMESTAMP
Templates (Redis cache backed by DB)
template:{templateId} → { subject, body_html, body_text }
Sending to 10M users in <60 seconds requires:
Campaign trigger → segment resolver → writes 10M user IDs to Kafka
│
100 Kafka partitions
│
100 Push Worker instances
│
10M APNs/FCM calls over 60 seconds