dotnet-cqrs/docs/tutorials/ecommerce-example/02-domain-events.md

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)