Domain Events
Events are facts: things that already happened.
Basic Usage
Define a plain struct and implement DomainEvent with a stable KIND.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OrderPlaced {
pub product_id: String,
pub quantity: u32,
pub unit_price: i64,
}
impl DomainEvent for OrderPlaced {
const KIND: &'static str = "order.placed";
}
Rules of Thumb
- Use past tense names (
OrderPlaced, notPlaceOrder) - Keep
KINDstable forever once persisted - Keep payload focused on a single fact
Why First-Class Structs?
This crate keeps events as standalone structs rather than forcing enum variants:
- Reuse across aggregates
- Decoupled projections by event type
- Smaller, explicit imports
The aggregate derive still generates an internal event enum for replay and storage routing.
KIND Naming Guidance
const KIND: &'static str = "order.placed"; // Good
const KIND: &'static str = "OrderPlaced"; // Acceptable
const KIND: &'static str = "placed"; // Too generic
Event Design Guidelines
- Include values needed to replay decisions later.
- Keep aggregate IDs in the envelope, not event payload.
- Prefer multiple specific events over one broad event.
Trait Reference
pub trait DomainEvent {
const KIND: &'static str;
}
Next
Commands — Handling requests that produce events