Why architecture matters here
Notification architecture matters because delivering the right message at the wrong time turns users into complainers. A perfectly-worded alert at 3 AM local time is spam. A critical security notification suppressed by a rate limit is a support incident. A duplicate push for the same event is a trust erosion. Each of these failure modes has an architectural remedy.
Cost is real. SMS costs money per message; email volumes affect sender reputation; push notifications cost API quota. Deduplication and batching materially reduce spend.
Compliance is the third driver. CAN-SPAM, GDPR, CCPA all mandate opt-in/opt-out mechanisms and audit trails. Non-compliance results in fines and delivery blocklisting. The architecture enforces these; the app doesn't need to remember.
The architecture: every layer explained
Walk the diagram top to bottom.
Producers. Application services that emit events: "new comment on your post," "order confirmed," "password reset," "security alert." Producers don't know about channels; they publish events.
Ingest Queue. Kafka, SQS, or a similar durable queue. Absorbs bursts and decouples producers from notification service. Producers succeed as soon as the event is queued.
Notification Service. The central routing brain. Consumes events, looks up recipient preferences, determines channels and priority, applies deduplication and rate limits, and dispatches to channel-specific senders.
User Preference Store. Per user: which channels they want for which categories, opt-in/opt-out state, timezone, quiet hours, preferred language. Updated via the preferences UI.
Deduplication + Batching. If the same event fires twice, send once. If a user gets many notifications in a short window, batch into a digest. Reduces spam and cost.
Push (APNs/FCM). Mobile push notifications via Apple Push Notification service or Firebase Cloud Messaging. Device tokens registered at app install.
Email / SMS. AWS SES, SendGrid, Twilio, SNS. Different providers for different cost/latency profiles.
In-App / WebSocket. Real-time delivery to open sessions. Bell counter updates immediately; toast messages for high-priority events.
Delivery Tracking. Every send recorded; delivery status callbacks feed back (SES delivered/bounced, FCM success/failed, opens and clicks tracked via redirect). Powers analytics and future ranking.
Rate + Quiet Hours. Per-user limits — max N pushes per day, no messages 10 PM - 7 AM local. Enforced before dispatch.
Compliance. Unsubscribe links in every marketing email; instant honor of unsubscribe; audit log of consent state; GDPR data export/delete.
End-to-end notification flow
Trace an event. A user's teammate comments on their post. The posts service emits a "comment_added" event to the ingest queue.
Notification service consumes. It looks up the post author's preferences: category "comments" → push + in-app; category "mentions" → push + email; quiet hours 10 PM - 7 AM in America/New_York.
Local time is 3 PM; quiet hours pass. The system checks dedup: no other "comment_added" for this post in the last minute. Not batched.
Rate limit: user has received 5 pushes today; limit is 50; ok.
Push dispatch: FCM API call with device token, title, body, and deep link. FCM confirms delivery.
Simultaneously in-app dispatch: WebSocket connection has user's session; the bell icon updates; a small toast appears in the app UI. Both channels updated within 200ms of the source event.
Delivery tracking records: push sent, delivered by FCM, opened at 3:07 PM by user, clicked deep link back to the post. Analytics show 40% CTR on comment notifications.