← Week 3: Event Sourcing & CQRS

Day 21: Challenge — CQRS Event Store with Projection

Phase 4 · Aug 11, 2026

← Week 3: Event Sourcing & CQRS

Challenge Overview

Build a CQRS/event-sourced bank account system in Rust.

Requirements:

  1. Commands: OpenAccount, Deposit, Withdraw, CloseAccount
  2. Events: AccountOpened, Deposited, Withdrawn, AccountClosed
  3. Event store: append-only table in SQLite with optimistic concurrency
  4. Two read models:
    • Account detail (balance, status, last activity)
    • Transaction history (list of events for an account)
  5. Projector: rebuilds read models from events
  6. Snapshot: every 50 events, write a snapshot for fast state reconstruction
  7. Test: 1,000 deposits, snapshot, then verify final balance matches event replay
← Week 3: Event Sourcing & CQRS

Command Handler

async fn handle_deposit(
    store: &EventStore,
    account_id: Uuid,
    amount: Decimal,
) -> Result<(), AppError> {
    // Load aggregate (with snapshot optimization)
    let (mut account, version) = store.load::<BankAccount>(account_id.to_string()).await?;

    // Validate command
    if account.is_closed() { return Err(AppError::AccountClosed); }
    if amount <= Decimal::ZERO { return Err(AppError::InvalidAmount); }

    // Produce event
    let event = AccountEvent::Deposited { amount, by: "user".to_string() };

    // Append with optimistic concurrency
    store.append(account_id.to_string(), version, &event).await?;

    Ok(())
}
← Week 3: Event Sourcing & CQRS

Projector

async fn project_event(event: &StoredEvent, db: &SqlitePool) {
    match &event.data {
        AccountEvent::Deposited { amount, .. } => {
            sqlx::query!(
                "UPDATE account_details
                 SET balance = balance + $1, last_activity = $2
                 WHERE account_id = $3",
                amount, event.created_at, event.stream_id
            ).execute(db).await.unwrap();

            sqlx::query!(
                "INSERT INTO transactions (account_id, type, amount, at)
                 VALUES ($1, 'deposit', $2, $3)",
                event.stream_id, amount, event.created_at
            ).execute(db).await.unwrap();
        }
        // ... other event types
    }
}
← Week 3: Event Sourcing & CQRS

Phase 4 Complete

Phase 4 Topic Key skills
Week 1 Reliability patterns Circuit breaker, bulkhead, timeout hierarchy, chaos
Week 2 Distributed transactions 2PC, sagas, ACID/MVCC, distributed locks, idempotency
Week 3 Event sourcing & CQRS Event store, projections, outbox, CDC, Kafka

You can now design systems that:

  • Fail gracefully under partial outages
  • Coordinate state changes across services without data loss
  • Maintain full audit history and derive multiple read models from one event log

Phase 5 starts tomorrow: AWS Distributed Primitives — managed services that implement these patterns.