307 lines
7.6 KiB
Markdown
307 lines
7.6 KiB
Markdown
# 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<OrderLine> 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<OrderLineDto> 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<InventoryItemDto> Items { get; init; }
|
|
public DateTimeOffset ReservedAt { get; init; }
|
|
}
|
|
|
|
public record InventoryReleasedEvent
|
|
{
|
|
public string ReservationId { get; init; }
|
|
public List<InventoryItemDto> 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)
|