# E-Commerce Example: Domain Requirements Define the requirements for a complete e-commerce order management system. ## Business Requirements ### Order Management **As a customer, I want to:** - ✅ Place orders with multiple items - ✅ View my order history - ✅ Track order status (Placed, Paid, Shipped, Delivered, Cancelled) - ✅ Cancel orders before shipment - ✅ Receive email notifications for order events **As an admin, I want to:** - ✅ View all orders - ✅ Filter orders by status, customer, date range - ✅ Process payments - ✅ Mark orders as shipped - ✅ View order analytics (total revenue, order count) ### Inventory Management **As a system, I need to:** - ✅ Reserve inventory when orders are placed - ✅ Release inventory when orders are cancelled - ✅ Prevent overselling (no negative inventory) - ✅ Track inventory levels per product ### Payment Processing **As a system, I need to:** - ✅ Charge customers when orders are placed - ✅ Refund customers when orders are cancelled - ✅ Handle payment failures gracefully - ✅ Prevent double-charging ### Analytics **As an admin, I want to:** - ✅ View total revenue - ✅ View order count by status - ✅ View top-selling products - ✅ View customer purchase history ## Domain Model ### Entities **Order (Aggregate Root)** ```csharp public class Order { public string OrderId { get; set; } public string CustomerId { get; set; } public List Lines { get; set; } public decimal TotalAmount { get; set; } public OrderStatus Status { get; set; } public DateTimeOffset PlacedAt { get; set; } public DateTimeOffset? PaidAt { get; set; } public DateTimeOffset? ShippedAt { get; set; } public DateTimeOffset? DeliveredAt { get; set; } public DateTimeOffset? CancelledAt { get; set; } } public enum OrderStatus { Placed, Paid, Shipped, Delivered, Cancelled } public class OrderLine { public string ProductId { get; set; } public string ProductName { get; set; } public int Quantity { get; set; } public decimal UnitPrice { get; set; } public decimal LineTotal => Quantity * UnitPrice; } ``` **Customer** ```csharp public class Customer { public string CustomerId { get; set; } public string Name { get; set; } public string Email { get; set; } public decimal TotalSpent { get; set; } public int OrderCount { get; set; } } ``` **Product** ```csharp public class Product { public string ProductId { get; set; } public string Name { get; set; } public string Description { get; set; } public decimal Price { get; set; } public int AvailableStock { get; set; } } ``` ## Domain Events ### Order Events ```csharp public record OrderPlacedEvent { public string OrderId { get; init; } public string CustomerId { get; init; } public List Lines { get; init; } public decimal TotalAmount { get; init; } public DateTimeOffset PlacedAt { get; init; } } public record OrderPaidEvent { public string OrderId { get; init; } public string PaymentId { get; init; } public decimal Amount { get; init; } public DateTimeOffset PaidAt { get; init; } } public record OrderShippedEvent { public string OrderId { get; init; } public string ShipmentId { get; init; } public string TrackingNumber { get; init; } public DateTimeOffset ShippedAt { get; init; } } public record OrderDeliveredEvent { public string OrderId { get; init; } public DateTimeOffset DeliveredAt { get; init; } } public record OrderCancelledEvent { public string OrderId { get; init; } public string Reason { get; init; } public DateTimeOffset CancelledAt { get; init; } } ``` ### Inventory Events ```csharp public record InventoryReservedEvent { public string OrderId { get; init; } public string ReservationId { get; init; } public List Items { get; init; } public DateTimeOffset ReservedAt { get; init; } } public record InventoryReleasedEvent { public string ReservationId { get; init; } public List Items { get; init; } public DateTimeOffset ReleasedAt { get; init; } } public record InventoryDepletedEvent { public string ProductId { get; init; } public DateTimeOffset DepletedAt { get; init; } } ``` ### Payment Events ```csharp public record PaymentProcessedEvent { public string PaymentId { get; init; } public string OrderId { get; init; } public decimal Amount { get; init; } public DateTimeOffset ProcessedAt { get; init; } } public record PaymentRefundedEvent { public string PaymentId { get; init; } public string OrderId { get; init; } public decimal Amount { get; init; } public DateTimeOffset RefundedAt { get; init; } } public record PaymentFailedEvent { public string OrderId { get; init; } public string Reason { get; init; } public DateTimeOffset FailedAt { get; init; } } ``` ## User Stories ### Story 1: Place Order **Given** I am a customer **When** I place an order with 2 items **Then** The system should: 1. Create an order in "Placed" status 2. Reserve inventory for the items 3. Publish OrderPlacedEvent 4. Send order confirmation email ### Story 2: Process Payment **Given** An order has been placed **When** The payment is processed successfully **Then** The system should: 1. Update order status to "Paid" 2. Publish PaymentProcessedEvent and OrderPaidEvent 3. Send payment confirmation email ### Story 3: Ship Order **Given** An order has been paid **When** The order is shipped **Then** The system should: 1. Update order status to "Shipped" 2. Create shipment record with tracking number 3. Publish OrderShippedEvent 4. Send shipment notification email ### Story 4: Cancel Order **Given** An order has been placed but not shipped **When** The customer cancels the order **Then** The system should: 1. Update order status to "Cancelled" 2. Release reserved inventory 3. Refund payment if already paid 4. Publish OrderCancelledEvent 5. Send cancellation confirmation email ### Story 5: View Order History **Given** I am a customer **When** I view my order history **Then** I should see: - All my orders sorted by date - Order status for each order - Items in each order - Order totals ## Success Criteria ✅ **Functional:** - Orders can be placed, paid, shipped, and cancelled - Inventory is accurately tracked and reserved - Payments are processed and refunded correctly - Order history is queryable ✅ **Non-Functional:** - System handles 100 orders/second - Order history queries return in < 100ms - Events are processed in < 1 second - System is resilient to failures (retry logic) ## Architecture Decisions ### CQRS Pattern - **Commands**: PlaceOrder, ProcessPayment, ShipOrder, CancelOrder - **Queries**: GetOrder, ListOrders, GetOrderHistory, GetAnalytics - **Events**: All state changes emit domain events - **Projections**: Order summary, customer analytics, product analytics ### Event Sourcing - Order aggregate state is rebuilt from events - Enables full audit trail - Allows rebuilding projections - Supports temporal queries ### Saga Pattern - OrderFulfillmentSaga coordinates order processing: 1. Reserve inventory 2. Process payment 3. Ship order - Compensation logic for failures ## Next Steps - [02-domain-events.md](02-domain-events.md) - Define domain events in detail - [03-commands.md](03-commands.md) - Implement commands and handlers - [04-queries.md](04-queries.md) - Build queries and projections ## See Also - [Event Sourcing Tutorial](../event-sourcing/README.md) - [Sagas](../../event-streaming/sagas/README.md) - [Best Practices](../../best-practices/README.md)