micro-module/event-store-dbal
A Doctrine DBAL-backed event store for micro-module applications. Persist and replay domain events in a relational database through a simple API suited to event sourcing and CQRS workflows.
Architecture fit. This is a low-level persistence adapter, not an application framework. It supplies a Doctrine DBAL-backed implementation of an event store (append streams, read streams, likely snapshot support), which slots into a hexagonal/DDD architecture where the domain depends on an event-store interface and infrastructure supplies the storage. That is a reasonable shape for a Laravel codebase that already separates domain from framework. It is not a Laravel package in the idiomatic sense: expect no service provider, no publishable config, no Eloquent models, no artisan commands, no queue integration. A TPM should treat this as a library to be wired manually, not a drop-in feature.
Integration feasibility. Composer-installable and MIT-licensed, so legal/procurement friction is nil. The real work is four pieces the package almost certainly does not do for you: (1) publishing the event-store schema as a Laravel migration, (2) choosing and implementing event serialization (payload + metadata + event type discriminator), (3) mapping your aggregate/stream identity convention onto its API, and (4) handling optimistic-concurrency exceptions in the application layer. Each is modest individually; together they represent a meaningful spike, not an afternoon integration.
Technical risk. High, and concentrated in three places:
Statement::execute(), fetchAll(), and friends in favour of executeStatement()/fetchAllAssociative(). Laravel 10/11 ship DBAL ^3. If this package pins DBAL ^2, it is uninstallable on a current Laravel baseline without patching. Verify the composer constraint first — this is the single highest-probability blocker.micro-module package, you inherit that dependency's health too, and a fork means forking the interface as well.Key questions to answer before committing:
SELECT … FOR UPDATE, or nothing?Stack fit. Works with any Laravel version whose doctrine/dbal constraint it satisfies, and can share the application's existing connection or use a dedicated one. The DBAL dependency is not exotic — Laravel itself pulls DBAL for column-modification support — but Laravel's constraint is a dev/optional one, so the package's own constraint governs and may force a downgrade you cannot accept.
Recommended migration path — wrap, don't couple. Define your own EventStore port in the application layer and make this package one adapter behind it, even if it is currently the only implementation. Given the maintenance signals, the strategic value of this package is as a reference implementation you can lift the SQL and semantics from, not as a long-term dependency. Two viable paths:
packages/ path repository), keep the MIT headers, apply the DBAL 3 fixes if needed. Realistic and cheap given the codebase is small.(stream_id, version) constraint plus a ranged read. Many teams write this in a few hundred lines tailored to their access patterns, avoiding a dependency entirely.Either path is defensible. composer require from Packagist as a permanent dependency is the option I would advise against.
Compatibility work to sequence before committing:
Sequencing (a 2–3 week discovery, then a gate):
If the team wants event sourcing as a feature with projections, reactors, and Laravel ergonomics, evaluate a maintained, Laravel-native option in parallel — this package will not supply the upper layers, and assembling them from an unmaintained base is the worst of both worlds.
Maintenance and support. Assume you own it from day one. There is no upstream support, no issue triage, no security response process, and no community to ask. Zero dependents means every bug you find is your bug. Budget forked-code maintenance explicitly in the team's capacity — probably low absolute effort for a small adapter, but non-zero and permanent. Add it to the dependency-risk register with a named owner and a review date.
Scaling characteristics. An append-only table with a unique (stream_id, version) index and a read index on (stream_id, version) scales to tens of millions of rows on Postgres/MySQL without drama, provided you never do unbounded scans. Watch four things:
Failure modes to design against:
ConcurrencyException; otherwise domain code depends on infrastructure. This is the most common defect when adopting a bare adapter.Ramp-up. The binding constraint is not the package, it is event sourcing literacy. Engineers new to the model tend to build CRUD-shaped aggregates, over-snapshot, and treat projections as authoritative. Budget for a design review of the first two aggregates and a short internal primer on streams, versions, replay, and eventual consistency. Team familiarity with Doctrine DBAL specifically is likely near zero in a Laravel shop — that is a smaller but real ramp.
Bottom line for the TPM: feasible as an internal, wrapped component with a clear fork/licence story and a defined owner; not advisable as an adopted third-party dependency on a current Laravel baseline. Gate the decision on dependency resolution and the concurrency test, and pre-commit to owning it, because no one else will.
How can I help you explore Laravel packages today?