Projections

A projection is a read model derived from events. Where events answer "what happened?", projections answer "what is the current state?". Projections are queryable, fast, and rebuildable from history at any moment.

How projections work

  1. You declare the shape of the projection (its state fields).
  2. You attach mutations that describe how each event changes that state.
  3. EventSourcerer replays matching events and keeps the projection up to date in real time.
  4. Clients fetch the latest state via the REST API or subscribe via sockets.

Registering a projection

  1. Go to Projections → Register New Projection.
  2. Give it a meaningful name (e.g. BasketSummary).
  3. Define the state fields and their types — same type system as events.
  4. Optionally choose a keying strategy:
    • Single — one global record (e.g. a counter).
    • Per Stream — one record per stream id.
    • Custom key — derived from event payload (e.g. userId).
  5. Add one or more mutations.
  6. Save and activate. EventSourcerer will perform an initial catch-up over historical events.

Querying a projection

Fetch the latest state via the API:

GET /api/projections/BasketSummary/basket-42
Authorization: Bearer <application token>

Or subscribe to live updates over a socket:

$client->catchup(
    WorkerId::fromString('basket-summary-worker'),
    function (array $event) {
        // event has just landed; the projection has been updated
    },
);

Rebuilding

Because projections are pure functions of the event log, you can rebuild them at any time — useful when you change a mutation, add new state fields, or fix a bug. Trigger a rebuild from the dashboard's Projection → Rebuild action.

Projection state is stored internally for maximum read performance. Clients should rely on the API or socket subscription rather than re-deriving state on the application side.