domain.events.base_event¶
src.domain.events.base_event
¶
Base domain event class.
This module defines the foundational DomainEvent base class used by all domain events in the system. Domain events represent "things that happened" in the business domain and are always named in past tense (e.g., UserRegistered, PasswordChanged, ProviderConnected).
Architecture
- Frozen dataclass (immutable after creation)
- Auto-generated event_id (UUID) for event tracking
- Occurred_at timestamp (UTC) for event ordering
- All events inherit from this base class
Usage
from dataclasses import dataclass from uuid import UUID
@dataclass(frozen=True, kw_only=True, slots=True) class UserRegistered(DomainEvent): ... user_id: UUID ... email: str
event = UserRegistered(user_id=uuid7(), email="test@example.com") print(event.event_id) # Auto-generated UUID print(event.occurred_at) # Auto-generated timestamp
Reference
- docs/architecture/domain-events-architecture.md (Lines 724-811)
- ~/starter/clean-slate-reference.md Section 9.4 (Domain Events)
Classes¶
DomainEvent
dataclass
¶
Base class for all domain events.
Domain events represent "things that happened" in the business domain. They are immutable records of facts that have occurred in the system.
All domain events MUST
- Inherit from this base class
- Use past tense naming (UserRegistered, NOT RegisterUser)
- Be frozen dataclasses (immutable after creation)
- Use kw_only=True (force keyword arguments for clarity)
- Include all relevant business data for event handlers
Attributes:
| Name | Type | Description |
|---|---|---|
event_id |
UUID
|
Unique identifier for this event instance. Auto-generated UUID v4 if not provided. Used for event tracking, deduplication, and correlation across distributed systems. |
occurred_at |
datetime
|
Timestamp when the event occurred (UTC). Auto-generated if not provided. Used for event ordering, audit trails, and time-based queries. |
Example
@dataclass(frozen=True, kw_only=True, slots=True) class UserRegistered(DomainEvent): ... '''User successfully registered in the system.''' ... user_id: UUID ... email: str ... ip_address: str | None = None
Create event (event_id and occurred_at auto-generated)¶
event = UserRegistered( ... user_id=uuid7(), ... email="test@example.com", ... ip_address="192.168.1.1" ... )
Access auto-generated fields¶
assert isinstance(event.event_id, UUID) assert isinstance(event.occurred_at, datetime)
Events are immutable¶
event.email = "new@example.com" # ❌ Raises FrozenInstanceError¶
Design Decisions
- Frozen dataclass: Ensures events are immutable (facts don't change)
- kw_only=True: Forces keyword arguments (clarity, prevents mistakes)
- slots=True: Memory optimization
- Auto-generated IDs: Simplifies event creation, ensures uniqueness
- UTC timestamps: Avoids timezone confusion in distributed systems
Notes
- Events should be small and focused (single responsibility)
- Include only data relevant to event handlers (don't over-include)
- Events are published AFTER business logic succeeds (facts, not intents)
- For ATTEMPT events, publish BEFORE operation (e.g., LoginAttempted)
- Event names are past tense: UserRegistered, PasswordChanged, NOT RegisterUser or ChangePassword
Source code in src/domain/events/base_event.py
Attributes¶
event_id
class-attribute
instance-attribute
¶
Unique identifier for this event instance.
Auto-generated UUID v7 if not provided. Used for: - Event tracking across systems - Deduplication in message queues - Correlation in distributed tracing - Audit trail linking
occurred_at
class-attribute
instance-attribute
¶
Timestamp when the event occurred (UTC timezone).
Auto-generated if not provided. Used for: - Event ordering (temporal sequencing) - Audit trail timestamps - Time-based queries and analytics - Event replay ordering
Note
Always in UTC to avoid timezone confusion. Event handlers should convert to user's local timezone if needed for display.