156 lines
4.5 KiB
Markdown
156 lines
4.5 KiB
Markdown
# E-Commerce Example: Domain Events
|
|
|
|
Define and implement domain events for the e-commerce order system.
|
|
|
|
## Event Design Principles
|
|
|
|
All events in this system follow these principles:
|
|
|
|
✅ **Past tense naming** - Events describe what happened
|
|
✅ **Immutable records** - Events cannot be changed once created
|
|
✅ **Complete context** - Events include all relevant data
|
|
✅ **Business language** - Events use domain terminology
|
|
|
|
## Order Lifecycle Events
|
|
|
|
### OrderPlacedEvent
|
|
|
|
Emitted when a customer places a new order.
|
|
|
|
```csharp
|
|
public record OrderPlacedEvent
|
|
{
|
|
public string OrderId { get; init; } = string.Empty;
|
|
public string CustomerId { get; init; } = string.Empty;
|
|
public string CustomerName { get; init; } = string.Empty;
|
|
public string CustomerEmail { get; init; } = string.Empty;
|
|
public List<OrderLineDto> Lines { get; init; } = new();
|
|
public decimal TotalAmount { get; init; }
|
|
public DateTimeOffset PlacedAt { get; init; }
|
|
}
|
|
|
|
public record OrderLineDto
|
|
{
|
|
public string ProductId { get; init; } = string.Empty;
|
|
public string ProductName { get; init; } = string.Empty;
|
|
public int Quantity { get; init; }
|
|
public decimal UnitPrice { get; init; }
|
|
public decimal LineTotal { get; init; }
|
|
}
|
|
```
|
|
|
|
**When to emit:** After order validation passes
|
|
**Stream:** `order-{orderId}`
|
|
**Triggers:** Inventory reservation, payment processing
|
|
|
|
### OrderPaidEvent
|
|
|
|
Emitted when payment for an order is successfully processed.
|
|
|
|
```csharp
|
|
public record OrderPaidEvent
|
|
{
|
|
public string OrderId { get; init; } = string.Empty;
|
|
public string PaymentId { get; init; } = string.Empty;
|
|
public string PaymentMethod { get; init; } = string.Empty;
|
|
public decimal Amount { get; init; }
|
|
public DateTimeOffset PaidAt { get; init; }
|
|
}
|
|
```
|
|
|
|
**When to emit:** After successful payment processing
|
|
**Stream:** `order-{orderId}`
|
|
**Triggers:** Shipment creation
|
|
|
|
### OrderShippedEvent
|
|
|
|
Emitted when an order is shipped to the customer.
|
|
|
|
```csharp
|
|
public record OrderShippedEvent
|
|
{
|
|
public string OrderId { get; init; } = string.Empty;
|
|
public string ShipmentId { get; init; } = string.Empty;
|
|
public string TrackingNumber { get; init; } = string.Empty;
|
|
public string Carrier { get; init; } = string.Empty;
|
|
public DateTimeOffset EstimatedDelivery { get; init; }
|
|
public DateTimeOffset ShippedAt { get; init; }
|
|
}
|
|
```
|
|
|
|
**When to emit:** When warehouse marks order as shipped
|
|
**Stream:** `order-{orderId}`
|
|
**Triggers:** Email notification, tracking update
|
|
|
|
### OrderDeliveredEvent
|
|
|
|
Emitted when an order is delivered to the customer.
|
|
|
|
```csharp
|
|
public record OrderDeliveredEvent
|
|
{
|
|
public string OrderId { get; init; } = string.Empty;
|
|
public string ShipmentId { get; init; } = string.Empty;
|
|
public string SignedBy { get; init; } = string.Empty;
|
|
public DateTimeOffset DeliveredAt { get; init; }
|
|
}
|
|
```
|
|
|
|
**When to emit:** When carrier confirms delivery
|
|
**Stream:** `order-{orderId}`
|
|
**Triggers:** Completion email
|
|
|
|
### OrderCancelledEvent
|
|
|
|
Emitted when an order is cancelled.
|
|
|
|
```csharp
|
|
public record OrderCancelledEvent
|
|
{
|
|
public string OrderId { get; init; } = string.Empty;
|
|
public string CancelledBy { get; init; } = string.Empty;
|
|
public string Reason { get; init; } = string.Empty;
|
|
public bool RefundIssued { get; init; }
|
|
public DateTimeOffset CancelledAt { get; init; }
|
|
}
|
|
```
|
|
|
|
**When to emit:** When customer or admin cancels order
|
|
**Stream:** `order-{orderId}`
|
|
**Triggers:** Inventory release, refund processing
|
|
|
|
## Event Stream Design
|
|
|
|
Each order has its own stream containing all lifecycle events:
|
|
|
|
```
|
|
Stream: order-12345
|
|
├── Offset 1: OrderPlacedEvent
|
|
├── Offset 2: InventoryReservedEvent
|
|
├── Offset 3: PaymentProcessedEvent
|
|
├── Offset 4: OrderPaidEvent
|
|
├── Offset 5: ShipmentCreatedEvent
|
|
└── Offset 6: OrderShippedEvent
|
|
```
|
|
|
|
## Event Registration
|
|
|
|
Register events with the event store:
|
|
|
|
```csharp
|
|
// In Program.cs
|
|
builder.Services.AddEventStreaming()
|
|
.AddPostgresEventStore(builder.Configuration.GetConnectionString("EventStore"));
|
|
|
|
// Register event handlers
|
|
builder.Services.AddEventHandler<OrderPlacedEvent, OrderPlacedEventHandler>();
|
|
builder.Services.AddEventHandler<OrderPaidEvent, OrderPaidEventHandler>();
|
|
builder.Services.AddEventHandler<OrderShippedEvent, OrderShippedEventHandler>();
|
|
```
|
|
|
|
## See Also
|
|
|
|
- [03-commands.md](03-commands.md) - Commands that produce these events
|
|
- [04-queries.md](04-queries.md) - Queries that consume these events
|
|
- [Event Design Best Practices](../../best-practices/event-design.md)
|