Event Sourcing for Operations Dashboards: History You Can Rebuild
An operations dashboard often needs more than “what is the current status?” Teams need to know how it got there, which transitions failed and whether today’s totals can be explained. Event sourcing records domain changes as an ordered, durable history; dashboard views are projections derived from that history. This is powerful when auditability or multiple read models justify the operational cost, not a default replacement for ordinary tables.
Published September 28, 202614 min readOperational projections and audit trails
Keep the event log and dashboard model distinct
Commit facts once, then project purpose-built views for operators
1 / CommandValidate an authorized business action.
2 / EventAppend a fact with entity and sequence.
3 / ProjectConsume idempotently and update a read model.
4 / DashboardQuery task-specific status, counts and age.
5 / ReplayRebuild or version a projection from history.
Events should describe facts that happened, such as InvoiceApproved or DeviceProvisioningFailed, rather than vague notifications like “row changed.” Include an event ID, entity ID, entity sequence, occurred-at time, recorded-at time, schema version and causation/correlation IDs. Keep payloads small and avoid copying secrets or unnecessary personal data into an immutable log.
Design read models around operational questions
Operator question
Projection
Freshness signal
Which jobs need attention?
Current state plus next action and owner
Oldest unprocessed event and last update
Where are cases getting stuck?
Duration by workflow state and transition
Projection lag and time-in-state
What changed this shift?
Time-bounded event summary
Source event watermark
Can we explain a number?
Aggregate with drill-through entity IDs
Projection version and build timestamp
Do not force a dashboard to scan the complete event history on every page load. Build materialized projections for the queries people actually use, and expose their last processed position so stale numbers are visible. A read model can be rebuilt, but rebuilding may take time; show “as of” information instead of implying instant consistency.
Make projection processing recoverable
Consumers should handle duplicate delivery using event IDs or a per-entity sequence checkpoint. Decide how to handle out-of-order events, missing sequence numbers, poison payloads and schema changes. A projection update and its checkpoint should commit atomically where possible; otherwise a crash can skip or apply an event twice. Record failures in a replayable quarantine path with operator ownership.
Replay into a new projection version, compare counts and invariants, then switch readers. Do not replay side effects such as sending emails or charging payments. Those belong to separate consumers with their own deduplication and authorization rules. Snapshots can speed recovery, but retain a tested path from snapshot plus later events.
Account for eventual consistency
The write model may accept a command before all dashboard projections catch up. Make that delay explicit in the UI and API. For a critical action, return a command result or authoritative entity state instead of immediately reading a lagging projection and telling the user nothing happened. Monitor consumer lag, event age, projection errors and replay duration.
Know when not to use it
If the application only needs current state, simple audit columns or database change history may be enough. Event sourcing adds schema evolution, storage growth, replay tooling, privacy retention questions and eventual consistency. It is easiest to justify when historical reconstruction, multiple independently shaped read models or reliable business audit are first-class requirements.
In summary
Use an append-only event history as a source for explicit operational projections. Version events, process idempotently, expose projection freshness, and make replay safe and observable. The dashboard is a read model optimized for human decisions; it is not the event store. Adopt the pattern where history and reconstruction earn the added complexity.