Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Event Sourcing Admin Bundle Laravel Package

patchlevel/event-sourcing-admin-bundle

Patchlevel Event Sourcing Admin Bundle adds a Symfony admin UI for event-sourced apps: browse aggregates and events, inspect projections, replay or rebuild state, and debug your event store from one dashboard.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a reality check that shapes everything else: patchlevel/event-sourcing-admin-bundle is a Symfony bundle, not a Laravel package. It has no service provider, no config/event-sourcing-admin.php, and no artisan commands. It is built on top of patchlevel/event-sourcing, which is usable from Laravel as a plain library. So a Laravel developer's day-to-day path is:

  • Use patchlevel/event-sourcing for the event store (aggregate roots, repositories, subscriptions). That is where the real work happens.
  • Treat this bundle as a reference implementation / UI blueprint for inspecting the store. If you want the UI in a Laravel app, you port the two or three controllers and the Twig views onto Laravel routes and Blade — they are thin, read-only GET endpoints.
  • If you also run a Symfony service (common in mixed shops), install with composer require patchlevel/event-sourcing-admin-bundle:1.0.0-alpha8, register it in config/bundles.php, and import the bundle routing.

Where to look first:

  1. The bundle's routing definition — it tells you the entire surface area (events list, stream view, export). Nothing is hidden behind magic.
  2. The controllers in src/Controller — these query the event store directly and are the best documentation of what is queryable and how filters are named.
  3. Your own event store configuration (aggregate and event class registration). The admin UI can only show what is registered; a blank screen is almost always a registration problem, not a bundle problem.

First use case: point it at a development or staging event store, open the events listing, filter by a specific aggregate ID, and read the stream in order to reconstruct why a projection ended up in a bad state. Export the stream to CSV and diff it against the same stream from the previous release — that is the fastest "what changed in this bug report" workflow the bundle enables.

Implementation Patterns

Gate it hard. The UI is read-only but it renders full event payloads, which routinely contain PII and internal IDs. Mount it only in local/staging, or wrap every route in your auth middleware. In Symfony use access_control; in a Laravel port use auth plus a can:viewEventStore gate. Do not ship it to production without an explicit decision.

Point it at a read replica. The bundle queries the same connection the app uses. In staging, configure a replica or a restored snapshot so an unfiltered listing cannot hammer the primary during an incident — which is exactly when you will be tempted to use it.

Debugging loop. Reproduce the bug → grab the aggregate ID from logs → open that aggregate's stream → inspect payloads in order → compare with the projection's current row. The CSV export (see below) turns this into a diffable artifact you can attach to a ticket.

CSV export for release comparisons. Since 1.0.0-alpha8 the export explicitly sets the escape character to the empty string. If you automate this, treat the export as a stable interface: fetch it before and after a deploy and diff the two files to spot events that changed shape.

Query-string filters. Filters are plain GET parameters (?aggregate=…&event=…). 1.0.0-alpha8 changed request access to use explicit query/attribute lookups rather than $request->get(). This matters for you because it makes the filters behave consistently under sub-requests, ESI/fragments, and Twig render() includes — a real source of "filter works on one page, not another" bugs.

CI smoke test. The endpoints are unauthenticated-internals GET routes, so in a test environment you can curl them to assert an event stream actually exists after a replay or migration. Cheap, and catches "the projector silently wrote nothing" regressions.

Gotchas and Tips

  • Framework mismatch is the headline gotcha. Every hour spent trying to composer require this into Laravel expecting a dashboard is wasted. Port the controllers (they are small) or run it in a Symfony sidecar.
  • Alpha churn. 1.0.0-alpha8 follows alpha7 with two lock-file-only dependency bumps and two small fixes. That cadence — frequent, tiny releases — is normal here. Pin the exact version (:1.0.0-alpha8), and read the diff before bumping. Semver gives you no guarantees pre-1.0.
  • The Request::get() change is subtly breaking for forks. If you copied the controllers or overrode templates, parameters previously pulled via $request->get() are now read from query and attributes explicitly. A value that only ever existed in request (POST body) will no longer be picked up. Re-check any custom filter you added.
  • Empty CSV escape character. With escape = '', embedded quotes are doubled per RFC 4180 rather than backslash-escaped. Modern Excel and most BI importers are fine; older Excel versions and some ERP importers are not. Test the consumer before you make exports part of a reporting pipeline.
  • Performance. The listing is an unfiltered scan of the events table by default. On anything with real volume, always filter by aggregate ID or date range, and expect the page to be slow if you do not.
  • Payload rendering. Event payloads can be large JSON or binary blobs; the templates render them raw. If you port the views, truncate and pretty-print at the presentation layer — do not change what is stored.
  • Registration quirks. Filters and type labels are derived from registered aggregates and event classes. Newly added event classes that are not registered show up as untyped or are missing from the filter dropdown. That is a configuration bug in your app, not in the bundle.
  • Prefer extension over forking. Override Twig templates and decorate the controller services through bundle configuration. With alpha-level release cadence, a fork will be painful within two releases.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast