A command flows in. The aggregate decides. Events are recorded. Projections reflect the truth.
Express intent. The aggregate decides what happens next.
commands
.On<BorrowBook>((state, cmd) =>
!state.Exists ? Then.Reject("Book does not exist")
: state.IsBorrowed ? Then.Reject("Already borrowed")
: Then.Persist(new BookBorrowed(cmd.BorrowerId)));Given events happened. When a command arrives. Then expect the outcome. No infrastructure. Just truth.
harness
.Given(new BookAdded("Dune", "Herbert", "978-044"))
.When(new BorrowBook("user-42"))
.ThenAccepted()
.ThenExpect<BookBorrowed>(
e => e.BorrowerId == "user-42");Express intent.
The aggregate decides.
What happened is truth.
Immutable, eternal.
The stream reflects.
Many views, one source.
NagareCore — aggregates, events, projections, subscriptions
→Nagare.SqlServerSQL Server persistence
→Nagare.SqliteSQLite persistence
→Nagare.PostgreSqlPostgreSQL persistence
→Nagare.TestingIn-memory Given-When-Then harness
→Nagare.MessagingPub/sub messaging abstractions
→Nagare.Messaging.KafkaApache Kafka implementation
→