An event-driven Spring Boot microservice that consumes supply chain events from Kafka, transforms them per customer subscription, and delivers real-time notifications to external target systems — reliably, at scale.
Bridging Maersk's internal Supply Chain Planning systems with external customer endpoints, delivering the right information to the right people at the right time.
Customers receive instant notifications for booking confirmations, container milestones, transport events, and document releases — enabling proactive supply chain decisions.
Each customer only receives events they've subscribed to, routed to their specific endpoints. No noise, no irrelevant data — precision delivery based on authorization and customer codes.
All notifications are formatted as CloudEvents, ensuring interoperability with industry standards. Customers integrate once and receive a consistent, well-documented event schema.
Built-in retry mechanisms with exponential backoff, Azure Blob Storage for large payloads, and Caffeine caching for subscription lookups ensure reliable operation under load.
Events flow through a pipeline of validation, transformation, and delivery — each step orchestrated by the MessageProcessor.
SCP milestone events arrive via dedicated Kafka cluster with Avro serialization & Schema Registry
Validates authorization, fetches subscriptions, orchestrates the full notification pipeline
Routes to Booking, Container, or Transport transformer based on event type for format conversion
Large payloads automatically downloaded from Azure Blob Storage when flagged
Delivers CloudEvent-formatted notifications via HTTP with retry & exponential backoff
Kafka consumer for SCP milestone events. Receives SupplyChainEvents messages and delegates to the processor with metrics tracking.
Validates that the Kafka "Receiver" header matches subscription customer IDs/codes, preventing unauthorized notification delivery.
Fetches customer subscriptions from the external API with Caffeine LoadingCache for high-performance lookups.
Dynamically registers and routes events to BookingEventTransformer, ContainerEventTransformer, or TransportEventTransformer.
Downloads large event payloads from Azure Blob Storage when the event is flagged as a large file, with custom exception handling.
Tracks events received, processed, sent, authorization failures, and transformer errors via Micrometer for full observability.
The engine handles two categories of events: supply chain notifications (booking & document lifecycle) and transport milestones (container journey tracking).
A modern Java stack optimized for event-driven processing, cloud-native deployment, and full observability.
Deployed via Helm charts to Kubernetes across three isolated environments with environment-specific configuration.
Integration testing, feature validation, full observability stack
Staging environment mirroring production for final verification
Live customer-facing deployment with monitoring & alerting
Each SCP event type maps to specific target fields through a detailed transformation matrix. Below is the notification event routing overview.
| Target Event Code | SCP Message Type | SCP Event Trigger | Soft Code | Event Type |
|---|---|---|---|---|
| EARLY_CRD | ORDER_STATUS | SHIPPER_BOOKING_CONFIRMED | S12 | NOTIFICATION |
| LATE_CRD | ORDER_STATUS | SHIPPER_BOOKING_CONFIRMED | S10 | NOTIFICATION |
| LATE_BOOKING | ORDER_STATUS | SHIPPER_BOOKING_CONFIRMED | S8 | NOTIFICATION |
| LIGHT_LOAD_VENDOR | ORDER_STATUS | SHIPPER_BOOKING_CONFIRMED | S14 | NOTIFICATION |
| LIGHT_LOAD_LSP | ASN_CONTAINER | CARGO_STUFFING_STUFFED | C1 | EXCEPTION |
| IMP_DOC_VENDOR | ASN_CBL | DOCUMENT_RECEIVED | — | NOTIFICATION |
| IMP_DOC_TO_BROKER | ASN_CBL | POUCH_RELEASED | — | NOTIFICATION |
| FINAL_FCR_RELEASED | ASN_CBL | FCR_RELEASED | — | NOTIFICATION |
| Milestone | SCP Event Trigger | Location Type | Transport Mode | Leg Position |
|---|---|---|---|---|
| CONTAINER_GATE_IN | EVENT_GATE_IN_ACTUAL | PORT | VESSEL | Start |
| LOADED_ON_VESSEL | EVENT_LOADED_ON_VESSEL_ACTUAL | PORT | VESSEL | Start |
| VESSEL_DEPARTED | EVENT_VESSEL_DEPARTURE_ACTUAL | PORT | VESSEL | Start |
| VESSEL_ARRIVED | EVENT_VESSEL_ARRIVAL_ACTUAL | PORT | VESSEL | End |
| VESSEL_UNLOADED | EVENT_UNLOADED_FROM_VESSEL_ACTUAL | PORT | VESSEL | End |
| OUT_GATE | EVENT_GATE_OUT_ACTUAL | PORT | VESSEL | End |
| EMPTY_CONTAINER_RETURNED | EVENT_EMPTY_CONTAINER_RETURNED_ACTUAL | PORT | VESSEL | End |
| RAIL_DEPARTURE | EVENT_RAIL_DEPARTURE_FROM_ORIGIN… | PORT | RAIL | Start |
| RAIL_ARRIVAL | EVENT_RAIL_ARRIVAL_AT_DESTINATION… | RAMP | RAIL | End |
Every notification is wrapped in a CloudEvents envelope for standards-compliant integration.
{
"specversion": "1.0",
"type": "com.maersk.booking.milestone",
"source": "https://external-target-notification-engine",
"id": "evt_9f2c1a7c-4d2e-4f7a-9f1b-9e0a2d8e3c11",
"time": "2026-03-20T07:00:00+07:00",
"datacontenttype": "application/json",
"data": {
"event_info": {
"event_date": "2026-03-20T07:00:00+07:00",
"event_type": "NOTIFICATION",
"event_code": "LATE_BOOKING",
"event_id": "e57b01ad-c27a-4b32-8c30-01fc319772fb"
},
"header": {
"booking_id": "SBK0003011248"
},
"payload": {
"reason_code": "V1",
"reason_reference": null,
"reference_data": []
}
}
}