Skip to content

Glossary

A reference for the terms used throughout these docs. If you're new to event sourcing, start here.

Aggregate

A cluster of domain objects that must stay consistent together. In Nagare, the aggregate is the thing that receives commands and decides whether to accept or reject them. If it accepts, it emits events.

A BookAggregate doesn't model "a book." It models the rules around borrowing — ensuring a book can't be borrowed by two people at the same time.

See: Aggregates

Aggregate ID

A string that uniquely identifies one aggregate instance. Every event in the store is tagged with the aggregate ID that produced it.

csharp
var aggregate = await repo.Load(new AggregateId("book-dune-1"));

Bounded context

A boundary around a set of domain concepts that belong together. An "Order" in the shipping context is not the same thing as an "Order" in the billing context. Each bounded context has its own aggregates, events, and projections.

See: Modular Monolith

Checkpoint

The position of the last event a subscription successfully processed. On restart, the subscription resumes from its checkpoint instead of replaying everything from the beginning.

See: Projections — Checkpoints

Command

An instruction in the imperative mood: "do this." Commands express what someone wants to happen. They can be accepted, rejected, or ignored.

csharp
public record BorrowBook(string BorrowerId) : BookCommand;

See: Commands & Events

CQRS

Command Query Responsibility Segregation. Writes go through the aggregate (commands). Reads come from projections (queries). The event store sits between the two.

Nagare implements CQRS naturally: aggregates handle the write side, projections handle the read side.

See: Core Concepts

Decider pattern

A formal way to describe an aggregate as three functions:

FunctionWhat it does
decide(state, command) → eventsBusiness rules
evolve(state, event) → stateState transitions
initialState() → stateStarting point

In Nagare, RegisterCommandHandlers is decide, RegisterEventHandlers is evolve, and State.Default is initialState.

See: Core Concepts — The Decider pattern

Domain event

See Event.

Enrichment projection

A projection that builds a read model and emits integration events for other bounded contexts to consume. It bridges the gap between internal domain events and external contracts.

See: Projections — Enrichment projection

Event

A fact in the past tense: "this happened." Events are the source of truth in an event-sourced system. Once written, they never change.

csharp
public record BookBorrowed(string BorrowerId, DateTimeOffset BorrowedAt) : BookEvent;

See: Commands & Events

Event envelope

The wrapper around an event that carries metadata: aggregate ID, position in the global stream, aggregate version, timestamp, and custom metadata (correlation ID, user ID, etc.).

csharp
envelope.AggregateId   // who
envelope.Event         // what
envelope.Position      // where in the global stream
envelope.CreatedAt     // when
envelope.Metadata      // context (correlation, causation, user)

Event sourcing

Instead of storing the current state of something, you store the sequence of events that produced it. The current state is derived by replaying those events in order.

Your bank account works this way: a ledger of transactions, not a single balance.

See: Why Event Sourcing

Event store

The append-only database where events are persisted. Events are ordered by position (global) and version (per aggregate). Nagare supports SQLite, SQL Server, and PostgreSQL as event store backends.

See: Store Adapters

Event upcaster

A function that transforms old event formats into the current format at read time. The stored events are never modified. This lets you evolve your schema without breaking existing data.

See: Event Versioning

Eventually consistent

Projections lag behind the event stream by a small delay (typically milliseconds). After an event is appended, projections process it shortly after, not instantaneously. If you need immediate read-after-write consistency, read from the aggregate directly.

Given-When-Then

The natural testing vocabulary for event-sourced systems:

  • Given these events happened in the past
  • When this command is issued
  • Then these new events should be produced (or the command should be rejected)

See: Testing

Idempotency

A command is idempotent when sending it twice produces the same result. In Nagare, use Then.Accept() for commands that are already satisfied — this acknowledges the command without duplicating events.

Integration event

An event published to a message broker (like Kafka) for other bounded contexts to consume. Integration events are coarse-grained business facts, not fine-grained state changes. They cross context boundaries and become contracts.

See: Messaging

Middleware

A handler in the command pipeline that can inspect, enrich, or short-circuit a command before it reaches the aggregate. Works like ASP.NET Core middleware.

See: Middleware

Optimistic concurrency

When two writes target the same aggregate simultaneously, one will fail with WrongExpectedVersionException. The first writer wins; the second must reload and retry. This prevents lost updates without requiring locks.

See: Concurrency

Position

A monotonically increasing number that identifies where an event sits in the global event stream (across all aggregates). Subscriptions use positions to track their progress.

Projection

A function that subscribes to the event stream and builds a read model. One event stream can feed many projections, each shaped for a different use case (dashboard, search index, report, notification).

Projections are disposable: delete the checkpoint, restart, and the read model rebuilds from scratch.

See: Projections

Read model

A denormalized data structure optimized for a specific query pattern. Built by a projection from the event stream. Also called a "view" or "query model."

See: Read Models

Snapshot

A saved copy of an aggregate's state at a particular version. Instead of replaying thousands of events from the beginning, the aggregate restores the snapshot and replays only the events after it. An optimization, not a requirement.

See: Aggregates — Snapshots

State

The current truth derived from events. State is rebuilt by folding events through handlers: state = events.Aggregate(initial, (s, e) => Apply(s, e)). State should contain only what command handlers need to make decisions.

Stream

The sequence of events belonging to one aggregate instance. Each aggregate has its own stream, identified by its aggregate ID.

Subscription

A background process that reads events from the store and delivers them to a handler (projection, notification sender, external API call). Subscriptions track their progress via checkpoints.

See: Projections — Custom subscriptions

Then DSL

The fluent API for expressing command handler decisions:

  • Then.Persist(event) — accept and record
  • Then.PersistAll(events) — accept and record multiple
  • Then.Reject("reason") — refuse with explanation
  • Then.Accept() — acknowledge without persisting (idempotent)

See: Aggregates — The Then DSL

Version

The number of events in a single aggregate's stream. Version 0 means no events (new aggregate). Version 5 means five events have been appended. Used for optimistic concurrency checks.


Next: Aggregates

流れ — flow.