The Order Management Service orchestrates the fulfillment order lifecycle from order receipt through shipment. It serves as the central coordinator for fulfillment operations, managing order validation, status tracking, and event-driven orchestration across the fulfillment network.
Architecture Pattern: Hexagonal Architecture (Ports & Adapters) Technology Stack: Spring Boot, Spring Data MongoDB, Spring Kafka, CloudEvents Integration Pattern: Event-Driven Choreography
The Fulfillment Order Management bounded context focuses on the orchestration and lifecycle management of orders within the fulfillment network.
Responsibilities (Whatβs IN):
External Dependencies (Whatβs OUT):
Core Domain Terms:
Strategic Importance: HIGH - Central coordination point
This is the heart of the order management service and provides significant business value through:
Subdomains:
Description: The central aggregate representing an order being fulfilled, managing its complete lifecycle from receipt to shipment.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@AggregateRoot
public class FulfillmentOrder {
private String orderId; // Aggregate ID
private String customerId;
private Address shippingAddress;
private List<OrderItem> items;
private OrderStatus status;
private Priority priority;
private ServiceLevel serviceLevel;
private SLADeadline slaDeadline;
private OrderTimestamps timestamps;
private List<OrderStatusTransition> statusHistory;
private int version; // Optimistic locking
// Business methods
public void validate(ValidationRules rules);
public void invalidate(List<ValidationFailure> failures);
public void release();
public void cancel(CancellationReason reason);
public void markPickingStarted();
public void markPickingCompleted();
public void markPackingCompleted();
public void markShipped(TrackingInfo trackingInfo);
// Invariants
private void ensureNotAlreadyShipped();
private void ensureCanBeCancelled();
private void ensureValidStatusTransition(OrderStatus newStatus);
}
Order Status State Machine:
1
2
3
NEW β RECEIVED β VALIDATED β RELEASED β IN_PROGRESS β PACKING β SHIPPED
β β
INVALIDATED CANCELLED
Invariants:
Domain Events:
FulfillmentOrderReceivedEventFulfillmentOrderValidatedEventFulfillmentOrderInvalidatedEventFulfillmentOrderReleasedEventFulfillmentOrderPickingCompletedEventFulfillmentOrderPackingCompletedEventFulfillmentOrderShippedEventFulfillmentOrderCancelledEventDescription: Represents a line item within an order.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Entity
public class OrderItem {
private String orderItemId;
private String sku;
private int quantityOrdered;
private int quantityFulfilled;
private BigDecimal unitPrice;
private ItemStatus status;
public void markPicked(int quantity);
public void markShipped();
public boolean isFullyFulfilled();
public boolean isShortPicked();
}
enum ItemStatus {
PENDING,
ALLOCATED,
PICKED,
PACKED,
SHIPPED,
CANCELLED
}
Description: Records each status transition for audit and analysis.
1
2
3
4
5
6
7
8
9
10
11
12
@Entity
public class OrderStatusTransition {
private OrderStatus fromStatus;
private OrderStatus toStatus;
private LocalDateTime transitionedAt;
private String transitionedBy; // User or System
private String reason;
public Duration getDurationInStatus() {
// Calculate time spent in previous status
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@ValueObject
public class Address {
private String recipientName;
private String addressLine1;
private String addressLine2;
private String city;
private String state;
private String postalCode;
private String country;
private AddressType type; // RESIDENTIAL, COMMERCIAL
public boolean isValid();
public boolean isInternational();
public String toFormattedString();
}
1
2
3
4
5
6
7
8
9
10
11
12
@ValueObject
public class SLADeadline {
private LocalDateTime orderReceivedAt;
private LocalDateTime expectedShipmentBy;
private LocalDateTime expectedDeliveryBy;
private Priority priority;
public boolean isBreached();
public boolean isAtRisk(double thresholdPercentage);
public Duration remainingTime();
public double percentageElapsed();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@ValueObject
public class OrderTimestamps {
private LocalDateTime createdAt;
private LocalDateTime receivedAt;
private LocalDateTime validatedAt;
private LocalDateTime releasedAt;
private LocalDateTime pickingStartedAt;
private LocalDateTime pickingCompletedAt;
private LocalDateTime packingCompletedAt;
private LocalDateTime shippedAt;
public Duration getProcessingTime();
public Duration getPickingDuration();
public Duration getPackingDuration();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ValueObject
public enum Priority {
STANDARD(3, Duration.ofDays(3)),
RUSH(2, Duration.ofDays(2)),
EXPRESS(1, Duration.ofHours(24)),
CRITICAL(0, Duration.ofHours(4));
private final int level;
private final Duration sla;
// Business methods
public boolean hasHigherPriorityThan(Priority other);
public Duration getAllocationTTL();
}
Responsibility: Orchestrate multi-step order validation process.
1
2
3
4
5
6
7
8
9
10
@DomainService
public class OrderValidationService {
public ValidationResult validate(FulfillmentOrder order);
private ValidationResult validateProducts(List<OrderItem> items);
private ValidationResult validateInventoryAvailability(List<OrderItem> items);
private ValidationResult validateAddress(Address address);
private ValidationResult validateBusinessRules(FulfillmentOrder order);
}
Responsibility: Coordinate order processing across services.
1
2
3
4
5
6
7
8
9
@DomainService
public class OrderOrchestrationService {
public void processNewOrder(FulfillmentOrder order);
public void handleValidationResult(String orderId, ValidationResult result);
public void handleInventoryAllocated(String orderId, AllocationResult result);
public void handlePickingCompleted(String orderId, PickingResult result);
public void handleShipmentCreated(String orderId, ShipmentInfo shipment);
}
Responsibility: Monitor order progress against SLAs.
1
2
3
4
5
6
7
8
@DomainService
public class SLATrackingService {
public SLAStatus calculateSLAStatus(FulfillmentOrder order);
public List<FulfillmentOrder> findAtRiskOrders(double thresholdPercentage);
public List<FulfillmentOrder> findBreachedOrders();
public SLAMetrics calculateSLAMetrics(LocalDate from, LocalDate to);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Commands
public interface CreateFulfillmentOrderCommand {
FulfillmentOrder execute(CreateOrderRequest request);
}
public interface CancelFulfillmentOrderCommand {
void execute(String orderId, CancellationReason reason);
}
public interface ReleaseOrderCommand {
void execute(String orderId);
}
// Queries
public interface GetOrderStatusQuery {
OrderStatus execute(String orderId);
}
public interface GetOrderDetailsQuery {
FulfillmentOrder execute(String orderId);
}
public interface GetOrderHistoryQuery {
List<OrderStatusTransition> execute(String orderId);
}
public interface ListOrdersQuery {
List<FulfillmentOrder> execute(OrderSearchCriteria criteria);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Repository ports
public interface FulfillmentOrderRepository {
Optional<FulfillmentOrder> findById(String orderId);
void save(FulfillmentOrder order);
List<FulfillmentOrder> findByStatus(OrderStatus status);
List<FulfillmentOrder> findByCustomerId(String customerId);
}
// External service ports
public interface ProductCatalogClient {
boolean allProductsExist(List<String> skus);
List<ProductInfo> getProducts(List<String> skus);
}
public interface InventoryClient {
ATPCheckResult checkAvailability(List<OrderItem> items);
}
public interface EventPublisher {
void publish(DomainEvent event);
}
REST Controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@RestController
@RequestMapping("/api/v1/fulfillment_orders")
public class FulfillmentOrderController {
@PostMapping
public ResponseEntity<OrderResponse> createOrder(
@RequestBody CreateOrderRequest request
);
@GetMapping("/{orderId}")
public ResponseEntity<OrderResponse> getOrder(
@PathVariable String orderId
);
@PostMapping("/{orderId}/cancel")
public ResponseEntity<Void> cancelOrder(
@PathVariable String orderId,
@RequestBody CancellationRequest request
);
@GetMapping
public ResponseEntity<List<OrderResponse>> listOrders(
@RequestParam(required = false) String customerId,
@RequestParam(required = false) OrderStatus status,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size
);
@GetMapping("/{orderId}/history")
public ResponseEntity<List<StatusTransitionResponse>> getHistory(
@PathVariable String orderId
);
}
Event Listener - Inventory Events
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class InventoryEventListener {
@KafkaListener(topics = "fulfillment.inventory.v1.events")
public void handleInventoryAllocated(InventoryAllocatedEvent event) {
// Update order status, potentially release for fulfillment
}
@KafkaListener(topics = "fulfillment.inventory.v1.events")
public void handleAllocationFailed(AllocationFailedEvent event) {
// Invalidate order due to insufficient inventory
}
}
Event Listener - Warehouse Events
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class WarehouseEventListener {
@KafkaListener(topics = "fulfillment.warehouse.v1.events")
public void handlePickingCompleted(PickingCompletedEvent event) {
// Update order status to packing
}
@KafkaListener(topics = "fulfillment.warehouse.v1.events")
public void handlePackingCompleted(PackingCompletedEvent event) {
// Update order status to ready for shipment
}
}
Event Listener - Shipment Events
1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class ShipmentEventListener {
@KafkaListener(topics = "fulfillment.shipment.v1.events")
public void handleShipmentCreated(ShipmentCreatedEvent event) {
// Update order with tracking information
}
@KafkaListener(topics = "fulfillment.shipment.v1.events")
public void handleShipmentDelivered(ShipmentDeliveredEvent event) {
// Mark order as delivered
}
}
MongoDB Adapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Repository
public class MongoFulfillmentOrderRepository implements FulfillmentOrderRepository {
private final MongoTemplate mongoTemplate;
@Override
public Optional<FulfillmentOrder> findById(String orderId) {
return Optional.ofNullable(
mongoTemplate.findById(orderId, FulfillmentOrder.class)
);
}
@Override
public void save(FulfillmentOrder order) {
mongoTemplate.save(order);
}
@Override
public List<FulfillmentOrder> findByStatus(OrderStatus status) {
Query query = new Query(Criteria.where("status").is(status));
return mongoTemplate.find(query, FulfillmentOrder.class);
}
}
Kafka Event Publisher
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class KafkaEventPublisher implements EventPublisher {
private final KafkaTemplate<String, CloudEvent> kafkaTemplate;
private static final String TOPIC = "fulfillment.order.v1.events";
@Override
public void publish(DomainEvent event) {
CloudEvent cloudEvent = CloudEventBuilder.v1()
.withId(event.getId())
.withType(event.getType())
.withSource(URI.create("order-management-service"))
.withData(event.toJson().getBytes())
.build();
kafkaTemplate.send(TOPIC, cloudEvent);
}
}
Manage the complete lifecycle of fulfillment orders from initial receipt through final shipment, coordinating with inventory, warehouse, and shipment services.
FulfillmentOrderReceivedEvent1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
"specversion": "1.0",
"type": "com.paklog.order.received",
"source": "order-management-service",
"id": "evt-order-12345",
"time": "2025-10-18T10:30:00Z",
"datacontenttype": "application/json",
"data": {
"orderId": "ORD-67890",
"customerId": "CUST-123",
"items": [
{"sku": "PROD-001", "quantity": 2, "unitPrice": 29.99},
{"sku": "PROD-002", "quantity": 1, "unitPrice": 49.99}
],
"shippingAddress": {
"recipientName": "John Doe",
"addressLine1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postalCode": "94105",
"country": "US"
},
"priority": "STANDARD",
"receivedAt": "2025-10-18T10:30:00Z"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"specversion": "1.0",
"type": "com.paklog.order.validated",
"source": "order-management-service",
"id": "evt-order-valid-123",
"time": "2025-10-18T10:30:30Z",
"datacontenttype": "application/json",
"data": {
"orderId": "ORD-67890",
"customerId": "CUST-123",
"items": [
{"sku": "PROD-001", "quantity": 2},
{"sku": "PROD-002", "quantity": 1}
],
"priority": "STANDARD",
"warehouseId": "WH01",
"validatedAt": "2025-10-18T10:30:30Z",
"slaDeadline": "2025-10-21T17:00:00Z"
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"specversion": "1.0",
"type": "com.paklog.order.cancelled",
"source": "order-management-service",
"id": "evt-order-cancel-456",
"time": "2025-10-18T11:00:00Z",
"datacontenttype": "application/json",
"data": {
"orderId": "ORD-67890",
"customerId": "CUST-123",
"cancelledBy": "CUSTOMER",
"cancellationReason": "CUSTOMER_REQUEST",
"previousStatus": "VALIDATED",
"cancelledAt": "2025-10-18T11:00:00Z"
}
}
The Order Management Service is the central orchestrator of the fulfillment network:
Business Impact: 10,000+ orders/hour, >95% SLA compliance, >99% perfect order rate, 4-6 hour average cycle time.