Implement event sourcing pattern where state is derived from an immutable sequence of events. Outputs event store design, aggregate patterns, projection builders, and command/event handlers.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Implement event sourcing pattern where state is derived from an immutable sequence of events. Outputs event store design, aggregate patterns, projection builders, and command/event handlers.
argument-hint
["domain","aggregate types","projection requirements","event store technology"]
allowed-tools
Read, Write, Bash
Event Sourcing
Event sourcing stores every state change as an immutable event rather than overwriting current state. The current state is always derived by replaying events. This enables a complete audit log, temporal queries, and the ability to rebuild any projection from scratch.
When to Use Event Sourcing
Use when:
Complete audit log is required (finance, healthcare, compliance)
Temporal queries: "what was the state at 3pm last Tuesday?"
Multiple read models needed from the same write data
Complex domain with many state transitions
Don't use when:
Simple CRUD with no history requirements
Team unfamiliar with the pattern — learning curve is steep
High write throughput + simple queries — overhead isn't worth it
Process
Define the domain events — past-tense, immutable facts (OrderPlaced, PaymentProcessed).
Design aggregates — domain objects that enforce invariants and emit events.
Implement the event store — append-only log with optimistic concurrency.
Build projections — read models derived from event streams.
"""Load events of a specific type — for projections."""
async
with
self
as
"SELECT event_data, occurred_at FROM events WHERE event_type = $1"
if
" AND occurred_at > $2"
f" ORDER BY occurred_at ASC LIMIT {limit}"
await
return
self
"event_data"
for
in
def
_serialize
self, event
dict
"""Convert event to storable dict."""
import
return
for
in
if
not
in
"event_id"
"occurred_at"
"aggregate_id"
"aggregate_version"
def
_deserialize
self, event_type: str, data: str
object
"""Reconstruct event from stored data."""
"OrderPlaced"
"PaymentProcessed"
"PaymentFailed"
"OrderShipped"
"OrderCancelled"
if
not
raise
f"Unknown event type: {event_type}"
return
# Schema
"""
CREATE TABLE IF NOT EXISTS events (
event_id UUID PRIMARY KEY,
aggregate_id VARCHAR(255) NOT NULL,
version INTEGER NOT NULL,
event_type VARCHAR(255) NOT NULL,
event_data JSONB NOT NULL,
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(aggregate_id, version) -- Optimistic concurrency constraint
);
CREATE INDEX idx_events_aggregate ON events(aggregate_id, version);
CREATE INDEX idx_events_type ON events(event_type, occurred_at);
CREATE INDEX idx_events_occurred ON events(occurred_at);
"""
on_payment_processed
self, event: PaymentProcessed
await
self
"UPDATE order_read_model SET status='paid', payment_id=$2, updated_at=$3 WHERE order_id=$1"
async
def
on_order_cancelled
self, event: OrderCancelled
await
self
"UPDATE order_read_model SET status='cancelled', cancel_reason=$2, updated_at=$3 WHERE order_id=$1"
async
def
rebuild
self, event_store: EventStore
"""Rebuild entire read model from event history."""
await
self
"TRUNCATE order_read_model"
await
"OrderPlaced"
100000
# Then load other event types and merge by time...
# (In practice: use a single sorted stream of all events)
for
in
await
self
print
f"Rebuilt projection from {len(all_events)} events"