The tutorials
37 articles. 37 runnable samples.
Every capability, end to end.
Numbered, sequenced, and paired one-to-one with test-backed sample projects you can dotnet run today. Start at 001 or jump to the capability you need.
Mediator & CQRS
4 articles
Getting Started: Commands, Queries, and the Mediator
Relay is a framework for building .NET services around CQRS (Command Query Responsibility Segregation) and an in-process mediator.

Your First Aggregate
In article 001 the Product was a plain record and the "store" was a dictionary.

Domain Events
In article 002 the Order aggregate raised domain events, but they just sat in a list — nothing reacted to them. This article closes that loop.

Errors & HTTP
A handler's job is to express what went wrong in business terms — "this payment was not found," "the amount exceeds the limit," "the card was declined" — not to know that those map to HTTP 404, 422, and 402.
Event Sourcing
8 articles
Event Sourcing Basics
Every sample so far stored state: the current product, the current order, the current balance.

Concurrency & Snapshots
Article 005's event sourcing works beautifully for a fresh account with three events. Production breaks that idyll two ways.

Schema Evolution: Upcasters, Stable Names, Migrations
In an event-sourced system the events are the database, and unlike rows you can never UPDATE them — history is immutable.

Time-Travel & Live Aggregation: Reading the Past from the Stream
Event sourcing stores the sequence of events that produced an aggregate's state, and the write side rebuilds the current state by replaying that sequence (article 005).

Pessimistic Per-Aggregate Write Lock
Article 006 established Relay's default for concurrent writes to an event-sourced aggregate: optimistic concurrency.

Rich Event Metadata
Every event Relay appends already carries a little metadata: the CommandName that produced it and a Timestamp.

Event Archiving & Compaction
An event store is append-only: events are never updated and never deleted, which is exactly what makes it a trustworthy source of truth.

Crypto-Shredding for the Right to Erasure
An event-sourced system has a property its operators love and its compliance officers fear: the log is immutable and never deletes.
Projections & Read Models
7 articles
Projections
Event sourcing stores what happened, which is perfect for the write side and useless for the read side.

Projection Operations
Article 007's projection host works while every event is well-behaved. Production guarantees two things that break that assumption.

Caching Queries
A read model (article 007) already makes queries fast — a single indexed SELECT.

Inline & Multi-Stream Projections
Article 007 built the standard read side: a projection runs in a background host, catches up from a checkpoint after each command commits, and is eventually consistent.

Intra-Projection Sharding: Parallel Lanes for One Hot Projection
Article 008 makes a deliberate promise: a projection has exactly one active worker.

Automated Blue/Green Projection Rebuilds
Article 008 gave you the shadow (blue/green) rebuild: a projection implements IRebuildableProjection, IProjectionRebuildManager builds a fresh shadow read model from history while the live one keeps serving, and once the shadow has caught up an operator calls SwapAsync to atomically promote it.

Persistent Named Subscriptions
A projection (article 007) is a catch-up reader: it walks the global event log forward, updates a read model, and remembers how far it got so a restart resumes instead of reprocessing two years of history.
Messaging & Reliability
4 articles
The Outbox Pattern
A command often needs to do two things: change its own state (save the order) and tell other services about it (publish OrderPlaced).

Messaging & Transports
The outbox stages events; a transport carries them.

The Inbox Pattern
The outbox guarantees at-least-once delivery — which means the same message can arrive twice (a broker redelivery, an outbox re-publish after a crash).

Reliable Messaging (End to End)
The previous three articles built the pieces; this one assembles them into the complete, reliable, cross-service flow:
Sagas & Workflows
4 articles
Sagas
A command changes one aggregate; reliable messaging lets services react to each other.

State-Machine Sagas
Article 015 authored a saga imperatively — handler methods that mutate state and call RequestTimeout/Complete.

Routing Slips & Compensation
A distributed process books a flight, a hotel, and a car across three services. The flight and hotel succeed; the car fails.

Standalone Courier Activities
017 showed compensation inside a saga: forward legs record undo-commands onto a durable itinerary, and a failure replays them in reverse as reliable, scheduled commands.
Scheduling & Time
2 articles
Scheduling
Some work shouldn't happen now — it should happen later: send a reminder in 30 minutes, expire an unpaid order in an hour, retry a failed call after a backoff.

Recurring Jobs
Article 018 scheduled one-shot future work. This article covers the recurring case — "every night at 2am," "every Monday," "every 15 minutes" — and the job as the unit of recurring/background work.
Tenancy & Security
2 articlesProduction Operations
6 articles
Observability: Telemetry, Metrics, Tracing, Health
You cannot operate what you cannot see. Relay is instrumented with OpenTelemetry-native primitives out of the box — no wrappers, no proprietary format.

Resiliency: Retries, Circuit Breakers, Rate & Concurrency Limits
Distributed systems fail in partial, transient ways: a database blips, a downstream API times out, a queue backs up.

Distributed Coordination: Locks, Leader Election, Partitioning
You scale a service by running more copies of it — but now those copies can step on each other: two instances run the same nightly job, or both try to advance the same projection, or process the same key out of order.

Reference Architecture: A Production Service End-to-End
The previous twenty-four articles each isolated one capability.

Fenced Leadership & Cluster Membership
Article 023 elects a leader the simple way: a connection-bound ILeaderElector holds a PostgreSQL advisory lock for as long as its connection lives, and the database drops that lock when the process dies.

Operational Event Queries: A Forensic Scan over the Log
The event store is an append-only log, and article 005 is emphatic about the rule that follows from that: never query the event store for reads.

