| TLDR; You evaluate your preconditions and invariants before the event is published, using the current state of the aggregate. Here's how that looks like in a DDD world: * An aggregate is responsible for encapsulating business rules and emitting events * An aggregate is responsible for maintaining the validity of its own state (ensuring invariants are valid) * When a command/request is received, the aggregate first rehydrates its current state by replaying all previous events * The aggregate then validates the command against its business rules using the current state * Only if validation passes does the aggregate emit the new event * If validation fails, the command is rejected (e.g., throws CartMaxLimitReached error) Example flow:
Command "AddItemToCart" arrives >> System loads CartAggregate by replaying all its events >> CartAggregate checks its invariants (current items count < 10) >> If valid: emits "ItemAddedToCart" event. If invalid: throws CartMaxLimitReached error |