133. Design Notification System

Asked in

Design Notification System
Implement a Notification System.

The system should support multiple notification channels such as EMAIL, SMS, PUSH etc. Users can subscribe to a specific eventType on one or more channels. When a notification is sent for an event type, the system must deliver that notification to all users currently subscribed to that event type through their subscribed channels.

For this problem, implement an in-memory and deterministic version of the notification system. Each successful delivery should be represented as a string so that outputs are easy to verify in automated tests.

Duplicate subscriptions must not create duplicate deliveries. If an operation refers to an unknown user, an unsupported channel, or a missing subscription, that operation should do nothing and should not fail.

Requirements

  • The system is initialized with a list of supported channels.
  • A user must be registered before subscribing to notifications.
  • A user may subscribe to the same eventType on multiple channels.
  • A user may unsubscribe from a previously created subscription.
  • Sending a notification must create one delivery per unique (userId, channel) subscription for the given eventType.
  • Each user should have an inbox containing all delivered notifications in delivery order.
  • Returned delivery lists must be deterministic and sorted first by userId in lexicographical order and then by channel in lexicographical order.
  • Each delivery string must use the format userId|channel|notificationId|eventType|content.
  • No String input i.e. userId, eventType, channel, content, notificationId etc will have '|' because it is being used as a separator.

Method Signatures

Constructor

NotificationSystem(List<String> supportedChannels)
  • supportedChannels contains all allowed channel names for this system.
  • Channel names are case-sensitive strings such as EMAIL, SMS, PUSH etc.
  • Duplicate channel names in the input should be treated as one logical channel.

Register User

void registerUser(String userId)
  • userId is a non-empty string.
  • If the user already exists, the operation does nothing.

Subscribe

void subscribe(String userId, String eventType, String channel)
  • userId, eventType, and channel are non-empty strings.
  • The subscription is created only if the user exists and the channel is supported.
  • If the same userId, eventType, and channel subscription already exists, the operation does nothing.

Unsubscribe

void unsubscribe(String userId, String eventType, String channel)
  • userId, eventType, and channel are non-empty strings.
  • If the subscription does not exist, the operation does nothing.

Send Notification

List<String> sendNotification(String notificationId, String eventType, String content)
  • notificationId, eventType, and content are non-empty strings.
  • The method returns all delivery strings created for the given notification.
  • If no user is subscribed to the given eventType, the method returns an empty list.
  • Returned deliveries must be sorted by userId and then by channel, both in lexicographical order.

Get User Inbox

List<String> getUserInbox(String userId)
  • userId is a non-empty string.
  • The method returns all deliveries received by that user in the exact order they were delivered.
  • If the user does not exist, the method returns an empty list.

Constraints

  • 1 ≤ supportedChannels.size() ≤ 20
  • 1 ≤ userId.length(), eventType.length(), channel.length(), notificationId.length() ≤ 100
  • 1 ≤ content.length() ≤ 500
  • At most 10^4 total method calls will be made.
  • All operations should be efficient enough for in-memory execution.
  • You must never use null as any parameter value.

Examples

Example 1

NotificationSystem(supportedChannels = ["EMAIL", "SMS", "PUSH"])
registerUser(userId = "U1")
subscribe(userId = "U1", eventType = "ORDER_PLACED", channel = "EMAIL")
subscribe(userId = "U1", eventType = "ORDER_PLACED", channel = "SMS")
sendNotification(notificationId = "N1", eventType = "ORDER_PLACED", content = "Order 101 created")
Output: ["U1|EMAIL|N1|ORDER_PLACED|Order 101 created", "U1|SMS|N1|ORDER_PLACED|Order 101 created"]
getUserInbox(userId = "U1")
Output: ["U1|EMAIL|N1|ORDER_PLACED|Order 101 created", "U1|SMS|N1|ORDER_PLACED|Order 101 created"]

Example 2

NotificationSystem(supportedChannels = ["EMAIL", "SMS"])
registerUser(userId = "U1")
registerUser(userId = "U2")
subscribe(userId = "U2", eventType = "PAYMENT_SUCCESS", channel = "SMS")
subscribe(userId = "U1", eventType = "PAYMENT_SUCCESS", channel = "EMAIL")
sendNotification(notificationId = "N2", eventType = "PAYMENT_SUCCESS", content = "Payment received")
Output: ["U1|EMAIL|N2|PAYMENT_SUCCESS|Payment received", "U2|SMS|N2|PAYMENT_SUCCESS|Payment received"]
Explanation: Both users are subscribed to PAYMENT_SUCCESS. Deliveries are returned in lexicographical order of userId, then channel.

Example 3

NotificationSystem(supportedChannels = ["EMAIL", "SMS"])
registerUser(userId = "U1")
subscribe(userId = "U1", eventType = "ORDER_CANCELLED", channel = "EMAIL")
subscribe(userId = "U1", eventType = "ORDER_CANCELLED", channel = "EMAIL")
sendNotification(notificationId = "N3", eventType = "ORDER_CANCELLED", content = "Order 202 cancelled")
Output: ["U1|EMAIL|N3|ORDER_CANCELLED|Order 202 cancelled"]
Explanation: The duplicate subscription does not create a duplicate delivery.

Example 4

NotificationSystem(supportedChannels = ["EMAIL", "SMS", "PUSH"])
registerUser(userId = "U1")
subscribe(userId = "U1", eventType = "SHIPPING_UPDATE", channel = "PUSH")
unsubscribe(userId = "U1", eventType = "SHIPPING_UPDATE", channel = "PUSH")
sendNotification(notificationId = "N4", eventType = "SHIPPING_UPDATE", content = "Package reached hub")
Output: []
getUserInbox(userId = "U1")
Output: []
Explanation: The user unsubscribed before the notification was sent, so no delivery is created.




Please use Laptop/Desktop or any other large screen to add/edit code.