Real-World Example: Order Processing
E-commerce store purchase order workflow demonstrating event-driven architecture with Kafka and CQRS patterns.
Use Case: E-Commerce Order Flow
This workshop simulates a complete order processing system where customers browse products, add items to a cart, and submit orders asynchronously.
User Flow
1. Browse Products (REST → QueryService)
GET /api/products → List all products
2. Add to Cart (Frontend state)
Cart maintained in browser session
3. Submit Order (Kafka Producer)
POST /orders/purchase → Kafka message to 'purchase-orders' topic
4. Backend Consumes (Kafka Consumer)
@KafkaListener receives message
5. Order Processing (CommandService)
Save order to MySQL database
6. Check Status (REST → QueryService)
GET /api/orders/{id} → Get current order status
State Transitions
CREATED ─→ PENDING ─→ COMPLETED
│
├─→ SHIPPED ─→ DELIVERED
│
└─→ CANCELLED
Each state transition represents an event in the system. The order status progresses through these states as it moves through the fulfillment pipeline.
Code Walkthrough
Frontend: PurchaseOrderProducer
@Component
public class PurchaseOrderProducer {
private final KafkaTemplate<String, PurchaseOrderDTO> kafkaTemplate;
public void sendOrder(PurchaseOrderDTO order) {
kafkaTemplate.send("purchase-orders", order.getOrderId(), order);
log.info("Order sent to Kafka: {}", order.getOrderId());
}
}
Backend: PurchaseOrderConsumer
@Component
public class PurchaseOrderConsumer {
private final OrderCommandService commandService;
@KafkaListener(topics = "purchase-orders", groupId = "order-processing-group")
public void consumeOrder(PurchaseOrderDTO order) {
log.info("Received order: {}", order.getOrderId());
commandService.createOrder(order);
}
}
Backend: OrderCommandService
@Service
public class OrderCommandService {
private final OrderRepository orderRepository;
@Transactional
public void createOrder(PurchaseOrderDTO orderDTO) {
Order order = new Order();
order.setOrderId(orderDTO.getOrderId());
order.setCustomerId(orderDTO.getCustomerId());
order.setTotal(orderDTO.getTotal());
order.setStatus(PurchaseOrderStatus.CREATED);
orderRepository.save(order);
}
}
Database Schema
Order Table:
- order_id (VARCHAR, PK)
- customer_id (VARCHAR)
- total (DECIMAL)
- order_date (TIMESTAMP)
- status (VARCHAR)
OrderItem Table:
- id (BIGINT, PK, AUTO_INCREMENT)
- order_id (VARCHAR, FK → Order)
- product_id (VARCHAR)
- quantity (INT)
- price (DECIMAL)
- total (DECIMAL)
Key Takeaways
- Order submission is asynchronous via Kafka
- Order queries are synchronous via REST
- CQRS separates command and query paths
- State machine for order lifecycle management