Skip to content

Add the contracts of the ddd core - #6

Merged
reactivestudio merged 37 commits into
masterfrom
claude/opensource-ddd-cqrs-lib-d47eed
Oct 22, 2026
Merged

reactivestudio merged 37 commits into
masterfrom
claude/opensource-ddd-cqrs-lib-d47eed

Conversation

@reactivestudio

Copy link
Copy Markdown
Collaborator

Interfaces of the tactical building blocks in semantic-ddd: Identifier, Identifiable, Entity and AggregateRoot with self-types, Versioned, ValueObject, and an Event made of an EventHeader and the AggregateRevision it happened at. Business rules come with rule, check and checkRule in the dsl package; the errors a layer raises live in architecture.error. Base classes and adapters come later.

Identifiers, entities, an aggregate root that records events and checks invariants, domain events, business rules and domain errors.
DomainException is a closed set again, without ErrorKind. The base aggregate root and the base event are gone until the contracts settle.
Entity extends Identifiable; ValueObject moves to the vo package.
Metadata moves to the envelope an adapter stamps; the aggregate names its event type, records events and releases them. The event type is a stable name set by @eventtype.
Only the aggregate records its events, so a second type parameter for them guards nothing.
The strategic patterns will get a package of their own. DomainEvent is now Event.
An event carries eventId and occurredAt, set once when it is raised. The domain exceptions are raised by the model and the application layer alike, so they leave the tactical package.
AggregateRoot extends Entity and EventRecorder; reading the events without releasing them is no longer part of the contract.
Event is Identifiable<EventId>, a value class over UUID, instead of carrying a bare eventId.
Named like Identifiable: what an aggregate can do, not what it is.
Two changes made from the same version conflict; an adapter and an event envelope read the version from outside.
The interface is named after what its caller does with it. EventId is an Identifier a service implements with a value of its choice.
A contract can return the entity itself and a type built on it gets the identifier type from it; adding the parameter later would break every implementation.
An event is Event<A, I>, and an aggregate releases Event<A, *> only.
An aggregate root is EventReleasable<Event<A, *>>; the interface itself knows nothing of aggregates.
EventId is an interface shared by all events, so Event is typed by its aggregate only.
The event id lives in identifier, typed by the shared EventId.
@reactivestudio
reactivestudio merged commit ab5a7db into master Oct 22, 2026
1 check passed
@reactivestudio
reactivestudio deleted the claude/opensource-ddd-cqrs-lib-d47eed branch October 22, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant