Event Sourcing: Building Auditable Systems

SOFTWARE ARCHITECTURE By TryzTech Team
Event SourcingArchitectureBackendDistributed SystemsAudit Trail

Table of Contents

Introduction

Most business applications store the current state of every transaction or change that occurs. For example, a user record holds the latest email address. An order holds the latest status. An account holds the current balance.

Event sourcing starts from a different question: what if the most important thing to store is not only the latest state, but the history of changes that created it?

Instead of storing only “order status is shipped”, an event-sourced system stores facts such as OrderCreated, PaymentCaptured, AddressChanged, and OrderShipped. The current state can be rebuilt from those events.

This pattern is a great fit for systems that require an audit trail, business history, and traceable decisions. However, this pattern is sometimes overused, especially for applications that do not demand such complexity. The most important thing is to understand both the pros and cons.

What Event Sourcing Means

Event sourcing stores a sequence of immutable business events as the source of truth.

An event is something that already happened:

  • AccountOpened
  • MoneyDeposited
  • MoneyWithdrawn
  • OrderCancelled
  • SubscriptionRenewed

Event naming is crucial. Events are facts, not commands, so use past tense verbs. For example, CancelOrder (Cancel Order) is a request, whereas OrderCancelled (Order Cancelled) is the fact that the system has received and recorded that cancellation.

State-Based vs Event-Based Thinking

In a state-based model, you usually store the latest shape:

account_idbalance
A100175

In an event-based model, you store the changes:

sequenceevent_typeamount
1AccountOpened0
2MoneyDeposited100
3MoneyDeposited75

The current balance is derived from the event stream:

0 + 100 + 75 = 175

The event stream explains how the system reached the current state.

A Simple Example

Imagine an e-wallet system. A traditional table might store:

wallet_idbalance
W01120

That value is useful, but it does not explain what happened. With event sourcing, the wallet has a stream of events:

versionevent_typeamountnote
1WalletCreated0initial wallet
2FundsAdded200top-up
3FundsSpent80purchase

The current state can be rebuilt by replaying the following event stream:

200 - 80 = 120

If a user asks why the balance is 120, the system can answer with history instead of guesswork.

Projections: Turning Events into Read Models

Applications still need fast read operations. We usually do not want to replay every event every time a user opens a dashboard.

That is why event-sourced systems use projections. A projection is a view or read model built from an event stream. Projections read events and build a model that is fast to query. This pattern pairs closely with the CQRS Pattern to separate write and read workflows in a structured way.

EventProjection update
FundsAdded(200)increase wallet balance by 200
FundsSpent(80)decrease wallet balance by 80
FundsAdded(50)increase wallet balance by 50

The projection might look like a normal table:

wallet_idcurrent_balancelast_event_version
W011704

The event store remains the source of truth. The projection is optimized for reading.

Why Use Event Sourcing?

Auditability

Event sourcing automatically provides you with a complete audit trail. You can see what happened, when it happened, and who triggered it.

Business history

Some domains care deeply about or even require transaction history: banking, billing, inventory, compliance, insurance, and approval workflows.

Debugging complex behavior

When state looks unusual, events help trace the sequence of transactions that produced it. This is far clearer than only seeing the final row.

Rebuilding read models

If you need a new report, projection, or analytics model, you can rebuild it from existing events.

Trade-Offs

Event sourcing adds power, but it also adds operational and design complexity.

BenefitCost
Strong audit trailMore complex data model
Rebuildable read modelsProjection lag and consistency concerns
Clear business historyEvent versioning over time
Better debuggingMore infrastructure and tooling

The main question is not “is event sourcing cool?” The better question is “does this domain need history enough for the complexity to be worth it?”

When Event Sourcing Fits

Event sourcing is a great fit for cases where:

  • business events are more important than current state alone
  • audit trails are required
  • decisions need to be explained later
  • workflows involve many transitions
  • reports may be rebuilt from historical facts
  • the team can handle eventual consistency

It is usually a poor fit for simple CRUD screens where the current value is enough and history has little value.

Common Mistakes

Treating events like database logs

Events should describe business facts, not low-level database operations. A good example: EmailChanged. A poor example: UserRowUpdated, because it does not explain the business fact, only that data changed.

Changing old events casually

Events are historical facts. If an event schema needs to evolve, use versioning or transformation carefully instead of rewriting old events casually, which will break your audit trail.

Ignoring projection failure

Projections can fail or fall behind. Track progress, retries, and lag. Ensure that failed projections do not corrupt read models and remain up to date.

Using event sourcing everywhere

Not every table needs an event stream. Use this pattern where history is truly valuable, and do not force it onto systems that do not need it.

Forgetting idempotency

What is Idempotency? Idempotency is the property of an operation where it can be executed multiple times without changing the result beyond the initial application.

For example: x = x + 1. If run repeatedly, the result changes each time. However, x = x (constant assignment) produces the exact same value regardless of how many times it runs.

In the context of event sourcing, projection handlers must be safe to replay. If duplicate processing occurs, it must not corrupt the read model. Idempotency is key to preventing duplicate data and ensuring data consistency. For a deeper look into handling duplicate requests at the API level, read our article on the Idempotency Key.

Checklist

  • Define events as business facts.
  • Keep events immutable.
  • Store event order per aggregate or stream.
  • Design projections for read use cases.
  • Track projection version and lag.
  • Plan event schema evolution.
  • Make handlers idempotent.
  • Decide snapshot strategy only when replay becomes expensive.
  • Use event sourcing for domains where history matters.
  • Avoid applying it to simple CRUD by default.

FAQ

Is event sourcing the same as an audit log?

No. An audit log records history beside the normal state model. In event sourcing, events are the source of truth and current state is derived.

Do I need CQRS for event sourcing?

Not always, but they are often used together. CQRS separates write models from read models, which fits naturally with event streams and projections.

Can events be changed?

Old events should be treated as immutable. If meaning changes over time, introduce new event versions or transformation logic.

Is event sourcing only for microservices?

No. Event sourcing can be used in a modular monolith too. The pattern is about persistence and history, not service count. However, in distributed architectures like Microservices Architecture or Hexagonal Architecture, event sourcing is frequently combined with the Saga Pattern to manage transactions across services.

Conclusion

Event sourcing is useful when the story behind the data matters just as much as the latest data. This pattern provides auditability, business history, and the ability to build read models from facts.

However, event sourcing is neither easy nor free. It requires significant knowledge and effort. Use it in domains that genuinely require historical truth, and stick to simpler persistence for parts of the system that only need current state.


How about the system you are currently building? Have you ever implemented event sourcing or custom audit trails in your project?

Feel free to share your experiences, questions, or thoughts in the comments section below!

Keep reading within the same topic.

Don't Miss Out

Get the latest tech articles, tips, and insights delivered to your inbox.