Stakeholder types are CUSTOMER, SELLER, and DELIVERY_PARTNER. A stakeholder may subscribe to one or more order events and may configure separate channel preferences for each subscribed event type.
The system must support event types such as ORDER_PLACED, ORDER_SHIPPED, ORDER_DELIVERED, and more. Different stakeholders may care about different events. For example, a customer may subscribe to all three events above, a seller may subscribe only to ORDER_PLACED, and a delivery partner may subscribe only to ORDER_SHIPPED. Notifications must be generated only for stakeholders linked to the specific order for which the event is published.
The system must support multiple channels such as EMAIL, SMS, and APP_PUSH. Channel preferences are maintained separately for each (stakeholderId, stakeholderType, eventType) subscription. If a stakeholder subscribes with an empty channel list, all supported channels must be enabled by default.
A stakeholder must be able to subscribe to an event type, unsubscribe from an event type, add channels to an existing subscription, and remove channels from an existing subscription. After unsubscribing from an event type, the stakeholder must not receive notifications for that event type for any order. When an order event is published, the system must generate one notification per active channel for each linked stakeholder currently subscribed to that event type. Actual notification delivery may be asynchronous, but the method should return the generated notification log lines for that call.
The system should support replaying notifications for a given orderId, eventType, and stakeholder. Replay must use the stakeholder's latest active channel preferences for that event type, not necessarily the channel set that was active when the event was originally published.
Whenever a method returns a string representation of an object, fields must be separated using space-hyphen-space, that is - .
NOTIFICATION - orderId=<orderId> - eventType=<eventType> - stakeholderType=<stakeholderType> - stakeholderId=<stakeholderId> - channel=<channel> - message="<message>"REPLAY - orderId=<orderId> - eventType=<eventType> - stakeholderType=<stakeholderType> - stakeholderId=<stakeholderId>OrderNotificationSystem(List<String> eventTypes, List<String> notificationChannels)eventTypes must contain distinct, non-null, non-blank supported event names.notificationChannels must contain distinct, non-null, non-blank supported channel names.notificationChannels defines the channel order used in returned notification log lines.boolean subscribeUnsubscribeToEvent(String stakeholderId, String stakeholderType, String eventType, List<String> channels, boolean subscribe)subscribe=true, creates a new subscription or replaces the full active channel set for that stakeholder and event type.subscribe=true and channels is empty, all supported channels are enabled by default.subscribe=false, removes the entire subscription for that stakeholder and event type. In this case, channels is ignored.false and makes no state change.true even if the final state is unchanged.boolean addRemoveChannels(String stakeholderId, String stakeholderType, String eventType, List<String> channels, boolean add)add=true, the given channels are added to the current channel set.add=false, the given channels are removed from the current channel set.channels is null or empty, or if any input is invalid, the method returns false and makes no state change.true even if the final state is unchanged.List<String> publishOrderEvent(String orderId, String eventType, String customerId, String sellerId, String deliveryPartnerId, String message)message is used in every generated notification log line for that publish call.CUSTOMER, SELLER, DELIVERY_PARTNER. Within one stakeholder, channels must follow constructor channel order.List<String> replayNotifications(String orderId, String eventType, String stakeholderId, String stakeholderType)(orderId, eventType) for the specified stakeholder.orderId, eventType, stakeholderId, stakeholderType, and message must be non-null and non-blank wherever applicable.stakeholderType must be one of CUSTOMER, SELLER, or DELIVERY_PARTNER.eventType and channel names must belong to the sets configured in the constructor.orderId and stakeholderId are unique identifiers in the system wherever applicable.customerId and sellerId must be non-null and non-blank when publishing an order event.deliveryPartnerId may be null or empty if no delivery partner is linked to that order yet.OrderNotificationSystem system = new OrderNotificationSystem(List.of("ORDER_PLACED", "ORDER_SHIPPED", "ORDER_DELIVERED"), List.of("EMAIL", "SMS", "APP_PUSH"))
system.subscribeUnsubscribeToEvent(stakeholderId="CUSTOMER-1", stakeholderType="CUSTOMER", eventType="ORDER_PLACED", channels=List.of("SMS"), subscribe=true)
returns true
system.subscribeUnsubscribeToEvent(stakeholderId="SELLER-1", stakeholderType="SELLER", eventType="ORDER_PLACED", channels=List.of("EMAIL"), subscribe=true)
returns true
system.subscribeUnsubscribeToEvent(stakeholderId="DELIVERY-1", stakeholderType="DELIVERY_PARTNER", eventType="ORDER_SHIPPED", channels=List.of(), subscribe=true)
returns true
system.publishOrderEvent(orderId="ORDER-001", eventType="ORDER_PLACED", customerId="CUSTOMER-1", sellerId="SELLER-1", deliveryPartnerId="DELIVERY-1", message="Order ORDER-001 has been placed")
returns List.of("NOTIFICATION - orderId=ORDER-001 - eventType=ORDER_PLACED - stakeholderType=CUSTOMER - stakeholderId=CUSTOMER-1 - channel=SMS - message="Order ORDER-001 has been placed"", "NOTIFICATION - orderId=ORDER-001 - eventType=ORDER_PLACED - stakeholderType=SELLER - stakeholderId=SELLER-1 - channel=EMAIL - message="Order ORDER-001 has been placed"")
Explanation
The customer and seller are both linked to the order and subscribed to ORDER_PLACED, so they receive notifications on their active channels. The delivery partner is linked to the order but subscribed only to ORDER_SHIPPED, so no notification is generated for that stakeholder in this publish call.
OrderNotificationSystem system = new OrderNotificationSystem(List.of("ORDER_PLACED", "ORDER_SHIPPED", "ORDER_DELIVERED"), List.of("EMAIL", "SMS", "APP_PUSH"))
system.subscribeUnsubscribeToEvent(stakeholderId="CUSTOMER-1", stakeholderType="CUSTOMER", eventType="ORDER_DELIVERED", channels=List.of("EMAIL", "SMS"), subscribe=true)
returns true
system.publishOrderEvent(orderId="ORDER-002", eventType="ORDER_DELIVERED", customerId="CUSTOMER-1", sellerId="SELLER-1", deliveryPartnerId="DELIVERY-1", message="Order ORDER-002 has been delivered")
returns List.of("NOTIFICATION - orderId=ORDER-002 - eventType=ORDER_DELIVERED - stakeholderType=CUSTOMER - stakeholderId=CUSTOMER-1 - channel=EMAIL - message="Order ORDER-002 has been delivered"", "NOTIFICATION - orderId=ORDER-002 - eventType=ORDER_DELIVERED - stakeholderType=CUSTOMER - stakeholderId=CUSTOMER-1 - channel=SMS - message="Order ORDER-002 has been delivered"")
system.addRemoveChannels(stakeholderId="CUSTOMER-1", stakeholderType="CUSTOMER", eventType="ORDER_DELIVERED", channels=List.of("EMAIL"), add=false)
returns true
system.replayNotifications(orderId="ORDER-002", eventType="ORDER_DELIVERED", stakeholderId="CUSTOMER-1", stakeholderType="CUSTOMER")
returns List.of("REPLAY - orderId=ORDER-002 - eventType=ORDER_DELIVERED - stakeholderType=CUSTOMER - stakeholderId=CUSTOMER-1", "NOTIFICATION - orderId=ORDER-002 - eventType=ORDER_DELIVERED - stakeholderType=CUSTOMER - stakeholderId=CUSTOMER-1 - channel=SMS - message="Order ORDER-002 has been delivered"")
Explanation
The original publish generates one notification per active channel, so both EMAIL and SMS are used. Later, EMAIL is removed from the active subscription. Replay uses the latest active channel set, so only SMS is used during replay.