Event Sourcing
Instead of storing the current state of an entity, event sourcing stores the full sequence of events that led to that state. Current state is derived by replaying the event log.
Event sourcing = your bank statement. It doesn't store 'balance = $500' — it stores every deposit and withdrawal ever. Replay the list to get the balance.
The event store is append-only — events are immutable facts. The current aggregate state is reconstructed by folding events. Benefits: complete audit trail for free, ability to reconstruct state at any point in time (temporal queries), natural integration with CQRS projections, and event replay for debugging. Costs: increased storage, complex query patterns (you must build projections for any query beyond 'give me all events for aggregate X'), and schema evolution of past events is painful.
Snapshot optimization: replaying thousands of events on every load is expensive. Periodically persist an aggregate snapshot alongside the event position, and on load, start from the latest snapshot then replay only subsequent events. Schema evolution of immutable events is the hardest problem in event sourcing. Strategies: upcasters (transform old event version to new version at read time), versioned event types (OrderPlacedV1, OrderPlacedV2), or weak schema (store JSON and handle missing fields gracefully). The event store must guarantee ordering and optimistic concurrency (reject a write if the expected aggregate version does not match current version) to prevent lost updates.
Event sourcing is justified when you have compliance requirements for a full audit log, need temporal query capability ('what was the state of account X at 3pm yesterday?'), or need to rebuild multiple different read projections from the same historical fact base. I pair it with snapshot every N events to bound replay time. For schema evolution I use upcasters in the event deserialization layer so consumers always receive the current schema version regardless of when the event was written.
Using event sourcing as a general-purpose database pattern. It is a specialized tool. Exposing the raw event store directly as an API violates encapsulation — the event structure is an implementation detail of the aggregate, not a public API.