Requirements for the Notification System
Functional Requirements
Let's define what our Notification System needs to do. Each requirement is specific, testable, and maps directly to classes or methods in our design.
Core Delivery:
- R1 -- Multi-channel support: The system shall support sending notifications through Email, SMS, and Push channels. Adding a new channel (e.g., Slack, WhatsApp) must not require modifying existing channel implementations.
- R2 -- Notification creation: The system shall accept a notification request containing: recipient user, notification type (e.g., ORDER_SHIPPED, PAYMENT_FAILED), channel, priority level, and a data payload for template rendering.
- R3 -- Template rendering: Each notification type shall have a template with placeholders (e.g., "Your order {{orderId}} has shipped via {{carrier}}"). The system shall render the final message by substituting placeholders with the data payload.
- R4 -- Channel-specific formatting: Each channel produces a different payload format. Email needs subject + HTML body, SMS needs a plain-text body under 160 characters, and Push needs a title + short body + optional deep-link URL.
User Preferences:
- R5 -- Per-channel opt-in/opt-out: Each user shall have notification preferences that control which channels are enabled. The system shall suppress notifications to disabled channels.
- R6 -- Quiet hours: Users may define quiet-hours windows (e.g., 22:00-08:00). Non-critical notifications sent during quiet hours shall be held and dispatched when the window ends.
Filtering & Rate Limiting:
- R7 -- Rate limiting: The system shall enforce per-user, per-channel rate limits (e.g., max 5 SMS per hour). Notifications exceeding the limit shall be dropped or deferred.
- R8 -- Deduplication: If an identical notification (same type, same recipient, same payload hash) has been sent within a configurable time window (e.g., 5 minutes), the duplicate shall be suppressed.
- R9 -- Filter pipeline composability: Rate limiting, deduplication, quiet-hours, and preference checks shall be composable filters that can be reordered, added, or removed without changing the notification engine.
Priority & Queuing:
- R10 -- Priority levels: Notifications shall have one of four priority levels: CRITICAL, HIGH, MEDIUM, LOW. CRITICAL notifications (e.g., security alerts) are processed before all others.
- R11 -- Priority queue dispatch: The system shall use a priority queue to order pending notifications. Within the same priority, notifications are processed in FIFO order.
Event Integration:
- R12 -- Event-driven triggering: The system shall allow event sources (order service, payment service, auth service) to trigger notifications by emitting events. The notification engine maps events to notification types without the event source knowing about notification details.
- R13 -- Multi-recipient events: A single event may trigger notifications to multiple recipients (e.g., "order shipped" notifies both buyer and seller) through different channels.
- R14 -- Bulk notifications: The system shall support sending a notification to a list of recipients in a single request (e.g., system maintenance alerts to all users).
Non-Functional Requirements
Beyond functionality, the system must exhibit these qualities:
- Extensibility (Open/Closed Principle): Adding a new notification channel (Slack, WhatsApp), a new filter (geo-blocking), or a new priority level must not require modifying existing code -- only adding new classes.
- Testability: Each component -- channel sender, filter, template renderer, priority queue -- must be testable in isolation via dependency injection and interfaces.
- Single Responsibility: The notification service orchestrates the pipeline but does not implement channel-specific logic, template rendering, or rate-limit counting. Each concern lives in its own class.
- Thread Safety: The priority queue, rate-limit counters, and deduplication cache must be safe for concurrent access from multiple threads dispatching notifications simultaneously.
- Configurability: Rate-limit thresholds, quiet-hours windows, deduplication time windows, and template content should be configurable at runtime without code changes.
Scope Clarification
In Scope:
- Notification domain model (Notification, NotificationType, Channel, Priority)
- Channel sender interface and concrete implementations (Email, SMS, Push)
- Template system with placeholder substitution
- User notification preferences (opt-in/opt-out, quiet hours)
- Filter pipeline (rate limiting, deduplication, quiet hours, preference check)
- Priority queue for ordering notifications
- Event-to-notification mapping
- Service layer orchestrating the full pipeline
Out of Scope:
- Actual SMTP, SMS gateway, or APNs/FCM integration (we define interfaces, not vendor clients)
- Persistent storage of notifications or delivery status (database layer)
- Retry logic and dead-letter queues (infrastructure concern)
- REST API endpoints or message broker integration (system design)
- Delivery receipts, read tracking, or analytics
- Notification scheduling for future delivery (cron-based)
- Batching multiple notifications into digest emails
Requirements Traceability
Each requirement will drive specific classes in our design. Here's a preview of how requirements map to architecture:
| Requirement | Drives Class / Component |
|---|---|
| R1 (Multi-channel) | NotificationChannel interface, EmailSender, SmsSender, PushSender |
| R2 (Notification creation) | Notification, NotificationType, Priority enums |
| R3 (Template rendering) | NotificationTemplate, TemplateRenderer |
| R4 (Channel formatting) | Channel-specific send() methods with typed payloads |
| R5 (User preferences) | UserPreferences, NotificationPreference |
| R6 (Quiet hours) | QuietHoursFilter in the filter pipeline |
| R7 (Rate limiting) | RateLimitFilter, RateLimiter |
| R8 (Deduplication) | DeduplicationFilter |
| R9 (Composable filters) | NotificationFilter interface (Chain of Responsibility) |
| R10-R11 (Priority queue) | NotificationQueue (priority queue implementation) |
| R12-R13 (Event-driven) | NotificationEventListener, event-to-template mapping |
| R14 (Bulk) | NotificationService.sendBulk() method |
This traceability ensures no class appears "out of thin air" -- every design element is justified by a requirement.
Interview Tip
In a real interview, spend 3-5 minutes clarifying requirements before jumping into design. Here are the questions you should ask for a Notification System:
- "Which channels do we need to support?" -- Start with Email, SMS, and Push. The interviewer may add Slack or in-app. Your design should make adding channels trivial (Strategy Pattern).
- "Do we need priority ordering?" -- If yes, you'll need a priority queue. If no, a simple FIFO queue suffices. This changes the data structure choice.
- "Should we support rate limiting?" -- If yes, clarify: per-user? per-channel? per-notification-type? This determines the filter granularity.
- "Is deduplication needed?" -- Critical for preventing duplicate SMS charges or annoying repeated alerts.
- "Are notifications event-driven or API-driven?" -- Event-driven means you need Observer or a listener interface. API-driven means a simpler service method.
- "Do we need template rendering?" -- If yes, ask about template format. Placeholder substitution ({{key}}) is simpler than full template engines (Jinja, Mustache).
These questions demonstrate that you think about real-world constraints before committing to a design. Interviewers value this exploration phase as much as the final diagram.