Event Sourcing & Audit: Immutable State for Compliance
The Context: "The Deleted Record"
It was mid-2023. A customer complained that their "Transaction Limit" was changed without their consent from $5,000 to $500. Our "Limit Service" only stored the Current State in a single row. The record said: $500, Updated: 02/01/2024.
We had no idea who changed it, when it was changed, or what the previous value was before the change. The "Audit Log" was a separate, brittle table that had lived in another database. This is the State Loss problem. This article explores the architecture of Event Sourcing and why it's the gold standard for "Auditability" in modern fintech.
The Problem Statement
In a bank, the "Current Balance" is just a derivative.
- Goal: 100% Audit Integrity (Impossible to "Hide" a change).
- Metric: Zero data loss for system state history.
- Challenge: The "Query" Problem. How do you query 10 million "Events" to find a single "Current Balance" in less than 50ms?
Visual Architecture: Event Store & Read Projections
The Core Logic: The Event-First Mindset
1. The Event Store (Append-Only)
Instead of updating a row (UPDATE accounts SET balance = balance + 10), we append a new event: AccountCredited { amount: 10, ts: 1712050000 }.
- The "Truth": The Event Store is the only "Source of Truth". It is immutable. You never "Delete" or "Update" an event.
2. CQRS (Command Query Responsibility Segregation)
Event Sourcing leads to CQRS.
- The Command Side: Writes events (Optimized for speed/integrity).
- The Query Side: Listens to those events and builds a "Read Model" (Optimized for complex queries). This is where you keep the "Current State" of a bank account.
3. Snapshotting (The Optimization)
If an account has 10,000 events, you don't rebuild the state from events 0 to 10,000 every time.
- The Solution: Every 100 events, create a "Snapshot" of the state. To get the current balance, load the last snapshot and apply only the events that happened after the snapshot.
The "Baigan" Take: Insights from the Trenches
Look, people love "Event Sourcing" because it sounds "Architecture-first". But baigan ka logic hai wo (that's nonsense) when you have to fix a bug in any of the events produced 2 years ago.
The 'Event Evolution' Nightmare.
The biggest mistake I've seen is "Breaking" an event schema. If you change a field in your TransactionStarted event, your application must still be able to "Replay" the old versions of that event from 2021.
- Rule: Never remove a field from an event. Use JSON Schema Versioning. Your code must handle
v1,v2, andv3events simultaneously in the "Projection" layer. - Rule: Avoid "Global Events". Keep your streams "Account-specific". If you have one massive stream for the whole bank, your "Projection Workers" will never be able to keep up with the volume.
Performance & Implementation Checklist
- Event Store: Use a specialized store like EventStoreDB or Kafka with "Log Compaction".
- Projection Lag: Monitor the "Lag" between the Write Side and the Read Side. If the lag exceeds 1 second, your users will see "Stale" balances.
- Audit Trail: Link every event to a
user_id, arequest_id(Trace-ID), and aterminal_ip. This is your 100% bulletproof audit log. - Snapshot Strategy: Determine your "Snapshot Frequency" based on the volume. For high-volume accounts (like settlement accounts), snapshot every 100 events. For consumer accounts, snapshot every 1,000.
Conclusion
Event Sourcing is the ultimate architectural "Safety Net" for fintech. By shifting from "State Management" to "Fact Management," you eliminate the "Silent Error" and build a platform that is auditable by design. It's not a "One-Size-Fits-All" solution, but for core banking, it's the only way to ensure that your history is as reliable as your future. Append with intent, query with speed, and never lose an event again.
Verified for Technical Nexus v1.9.0 | Part of the System Design Vault archive.