Design a Multi-Channel Notification System
ReplitSoftware Engineer · OnsiteLast updated
Design a resilient, multi-channel notification service that routes notifications across in-app, email, SMS, and push channels while honoring user preferences, idempotency, rate limits, and provider status tracking.
Scenario
Modern developer platforms and collaborative workspaces require a unified notification infrastructure. When events occur—such as a collaborator joining a live workspace, a scheduled deployment failing, or an authentication code being requested—the system must deliver timely alerts across multiple channels (in-app, email, SMS, push) while respecting user opt-outs, quiet hours, and rate limits.
Design a multi-channel notification platform that processes incoming notification events, applies templating and routing logic, interacts with third-party delivery providers, and tracks delivery status through the entire lifecycle.
Requirements
Functional Requirements
- Multi-channel routing: Route a single logical notification request to one or more channels (in-app, email, SMS, push) based on event urgency and user preferences.
- User preferences and consent: Honor per-channel subscriptions, category opt-outs, quiet hours (time-zone aware), and global frequency capping.
- Templating and localization: Render channel-specific payloads using templates parameterized by user locale and event metadata.
- Lifecycle and status semantics: Clearly distinguish between
ACCEPTED(received by our system),DISPATCHED(handed off to provider),DELIVERED(confirmed delivered by provider webhook), and terminal failure states. - Scheduling and cancellation: Support scheduled notifications (e.g., send in 2 hours) and allow cancellation before delivery (e.g., cancel email/push if the user viewed the notification in-app).
- Idempotency and deduplication: Prevent duplicate sends caused by upstream retries or network blips.
Non-Functional Requirements
- Scale: 10M daily active users (DAU); 50 million notifications per day (~600 requests/sec average, 5,000 requests/sec peak burst).
- Latency: Critical alerts (e.g., 2FA codes, live collaboration pings) delivered to downstream providers in < 1 second; marketing/digests within minutes.
- Fault tolerance: External provider outages must not drop notifications; the system must support fallback channels and exponential backoff retries.
- Compliance: Support audit logging for transactional messages and strict unsubscribe tracking for promotional messages.
What to Cover
- API Design: Define the ingestion endpoint and the query/cancellation endpoints.
- Architecture & Data Flow: Component-level design detailing ingestion, preference resolution, queueing, worker dispatching, and vendor adapters.
- Data Model: Schema for notification state, user preferences, templates, and delivery logs.
- Edge Cases & Failure Modes: Addressing cancellation races, out-of-order vendor webhooks, provider rate limits, and cross-channel fallback strategies.
Hints
Hint 1
Separate initial ingestion and validation from downstream delivery pipelines using message queues partitioned by urgency or channel.
Hint 2
Maintain a clear state machine per delivery target, and check the target's current state immediately before invoking a downstream provider to handle last-second cancellations.
Hint 3
Use distinct external idempotency keys for both the incoming client requests and outgoing provider API calls to prevent duplicate deliveries across retries.
Follow-up questions
- How would you implement cross-channel cancellation if a user reads an in-app alert before the corresponding push or email is dispatched?
- How would you architect the rate limiter to enforce both per-user frequency caps and third-party vendor quota constraints (e.g., Twilio 100 TPS)?
- How do you handle out-of-order provider webhooks where a 'DELIVERED' webhook arrives before the dispatch worker records the 'DISPATCHED' status?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.