@@ -15,7 +15,7 @@ graph TD
1515 Admin[Admin Endpoints]
1616 System[System Endpoints]
1717 end
18-
18+
1919 subgraph Handlers [Command Handlers / Aggregates]
2020 Book[Book]
2121 Author[Author]
@@ -37,10 +37,10 @@ graph TD
3737 Public --> Handlers
3838 Admin --> Handlers
3939 System --> Handlers
40-
40+
4141 Handlers -- Events --> EventStore
4242 EventStore -- Async Projections --> Projections
43-
43+
4444 EventStore -- PostgreSQL Protocol --> Postgres
4545 Projections -- PostgreSQL Protocol --> Postgres
4646```
@@ -61,6 +61,7 @@ Instead of storing current state, we store all changes as immutable events.
6161- Natural fit for distributed systems
6262
6363** Implementation** :
64+
6465``` csharp
6566// Events are immutable records
6667public record BookAdded (
@@ -89,12 +90,14 @@ See [Marten Guide](guides/marten-guide.md) for implementation details.
8990Separate models for writes (commands) and reads (queries).
9091
9192** Write Side** (Commands):
93+
9294- Commands routed through Wolverine message bus
9395- Handlers execute business logic
9496- Events are appended to streams
9597- Optimized for consistency
9698
9799** Read Side** (Queries):
100+
98101- Projections denormalize data
99102- Optimized for specific queries
100103- Eventually consistent
@@ -104,7 +107,7 @@ Separate models for writes (commands) and reads (queries).
104107Commands are routed through Wolverine's message bus to handlers that execute business logic.
105108
106109** Command Flow** :
107- ** Command Flow ** :
110+
108111``` mermaid
109112graph LR
110113 HTTP[HTTP Request] --> Endpoint
@@ -117,12 +120,14 @@ graph LR
117120```
118121
119122** Benefits** :
123+
120124- Clean separation of concerns
121125- Automatic transaction management
122126- Easy to test (pure functions)
123127- Foundation for async messaging
124128
125129** Example** :
130+
126131``` csharp
127132// Endpoint: Just routing
128133private static Task < IResult > CreateBook (request , IMessageBus bus )
@@ -143,6 +148,7 @@ public static IResult Handle(CreateBook cmd, IDocumentSession session)
143148The system implements ** Enterprise-grade Multi-tenancy** using Marten's Conjoined Tenancy model.
144149
145150** Key Components** :
151+
146152- ** Tenant Resolution** : ` TenantResolutionMiddleware ` extracts tenant ID from ` X-Tenant-ID ` header.
147153- ** Data Isolation** : All Marten documents and events are partitioned by ` tenant_id ` .
148154- ** Service Scoping** : ` IDocumentSession ` and ` IQuerySession ` are scoped to the current tenant.
@@ -171,44 +177,48 @@ The application automatically sends SSE notifications whenever projections are u
171177> For implementation details, flow diagrams, and client integration examples, see the [ Real-time Notifications Guide] ( guides/real-time-notifications.md ) .
172178
173179** Key Features** :
180+
174181- ** Automatic** : Tied to projection updates, not API calls.
175182- ** Reliable** : Notifications only fire if the data is successfully committed.
176183- ** Integrated** : Handles cache invalidation and notification in a single unit of work.
177- ```
178184
179185## Domain Model
180186
181187### Aggregates
182188
183189** Book Aggregate** :
190+
184191- Root entity for book management
185192- Enforces business rules
186193- Emits events: ` BookAdded ` , ` BookUpdated ` , ` BookSoftDeleted ` , ` BookRestored `
187194
188195** Author Aggregate** :
196+
189197- Manages author information
190198- Tracks biography and metadata
191199
192200** Category Aggregate** :
201+
193202- Supports multi-language translations
194203- Manages category hierarchy
195204
196205** Publisher Aggregate** :
206+
197207- Publisher information management
198208
199209### Events
200210
201211All events include:
212+
202213- Domain data (title, ISBN, etc.)
203214- Marten metadata (correlation ID, causation ID, timestamp)
204215
205216Example event flow:
206- ```
217+
2072181 . User creates book → BookAdded event
2082192 . Event stored in mt_events table
2092203 . Async projection updates BookSearchProjection
2102214 . Read model available for queries
211- ```
212222
213223## Event Modeling
214224
@@ -294,14 +304,13 @@ sequenceDiagram
294304
295305### Write Path (Command)
296306
297- ```
298307``` mermaid
299308sequenceDiagram
300309 participant Client
301310 participant API as API Endpoint
302311 participant Domain as Domain Model
303312 participant Marten as Marten Event Store
304-
313+
305314 Client->>API: 1. HTTP Request
306315 API->>Domain: 2. Load Aggregate
307316 Domain->>Domain: 3. Business Logic
@@ -310,28 +319,24 @@ sequenceDiagram
310319 Marten->>Marten: 6. SaveChanges
311320 API->>Client: 7. Return Response
312321```
313- ```
314322
315323### Read Path (Query)
316324
317- ```
318325``` mermaid
319326sequenceDiagram
320327 participant Client
321328 participant API as API Endpoint
322329 participant DB as Read Model DB
323-
330+
324331 Client->>API: 1. HTTP Request
325332 API->>DB: 2. Query Projection
326333 DB->>API: 3. Return Data (DTOs)
327334 API->>API: 4. Apply Filters/Pagination
328335 API->>Client: 5. Return Results
329336```
330- ```
331337
332338### Projection Update (Async)
333339
334- ```
335340``` mermaid
336341sequenceDiagram
337342 participant EventStore as Marten Event Store
@@ -345,11 +350,11 @@ sequenceDiagram
345350 Builder->>DB: 4. Update Read Model
346351 DB-->>Daemon: 5. Commit Checkpoint
347352```
348- ```
349353
350354## Technology Stack
351355
352356### Backend
357+
353358- ** ASP.NET Core 10** - Web framework
354359- ** Minimal APIs** - Endpoint definition
355360- ** Wolverine** - Command/handler pattern and message bus
@@ -359,6 +364,7 @@ sequenceDiagram
359364- ** Scalar** - API documentation
360365
361366### Features
367+
362368- ** Event Sourcing** - Marten event store
363369- ** CQRS** - Separate read/write models
364370- ** Real-time Notifications** - Server-Sent Events (SSE) for all mutations
@@ -372,6 +378,7 @@ sequenceDiagram
372378- ** Soft Deletion** - Logical deletes with restore
373379
374380### Infrastructure
381+
375382- ** Docker** - Container runtime
376383- ** PgAdmin** - Database management
377384- ** OpenTelemetry** - Distributed tracing
@@ -386,20 +393,23 @@ sequenceDiagram
386393
387394### 1. Event Sourcing with Marten
388395
389- **Why**:
396+ ** Why** :
397+
390398- Built-in event store on PostgreSQL
391399- No additional infrastructure needed
392400- Strong .NET integration
393401- Async projection support
394402
395403** Trade-offs** :
404+
396405- Learning curve for event sourcing
397406- Eventually consistent reads
398407- More complex than CRUD
399408
400409### 2. Minimal APIs
401410
402411** Why** :
412+
403413- Less boilerplate than controllers
404414- Better performance
405415- Cleaner endpoint definition
@@ -408,18 +418,21 @@ sequenceDiagram
408418### 3. Async Projections
409419
410420** Why** :
421+
411422- Decouples write and read models
412423- Optimized read models for specific queries
413424- Scalable (can run on separate processes)
414425
415426** Trade-offs** :
427+
416428- Eventually consistent
417429- Projection lag possible
418430- More complex than direct queries
419431
420432### 4. Soft Deletion
421433
422434** Why** :
435+
423436- Preserve data integrity
424437- Support undo/restore
425438- Maintain referential integrity
@@ -428,6 +441,7 @@ sequenceDiagram
428441### 5. ETags for Concurrency
429442
430443** Why** :
444+
431445- Standard HTTP mechanism
432446- Works with any client
433447- Natural fit with stream versions
@@ -437,12 +451,14 @@ sequenceDiagram
437451### 6. Identity Stored as Documents (Not Event Sourced)
438452
439453** Why** :
454+
440455- ** Standardization** : ASP.NET Core Identity provides robust, battle-tested security.
441456- ** Compliance** : GDPR "Right to be Forgotten" is easier to implement with mutable documents than immutable event streams.
442457- ** Simplicity** : Authentication state (current password hash, lock status) is more critical than the history of changes.
443458- ** Performance** : High-frequency read path (login) benefits from simple index lookups.
444459
445460** Trade-offs** :
461+
446462- ** Audit Trail** : Account changes (password reset, email change) are not automatically event-sourced (must use separate audit logs).
447463- ** Consistency** : Auth data lives outside the primary event stream (though still in Postgres/Marten).
448464
@@ -471,8 +487,6 @@ sequenceDiagram
471487
472488### Authentication & Authorization
473489
474- ### Authentication & Authorization
475-
476490The application implements a ** Token-based authentication system** :
477491
478492- ** JWT Bearer Tokens** - Primary authentication method
@@ -489,7 +503,7 @@ The application implements a **Token-based authentication system**:
489503- ** Role-Based Authorization** - Admin endpoints protected
490504 - Admin role for full access
491505 - Extensible for additional roles
492-
506+
493507See [ Authentication Guide] ( guides/authentication-guide.md ) and [ Passkey Guide] ( guides/passkey-guide.md ) for details.
494508
495509### Data Protection
0 commit comments