Product Decisions This Supports
- Build vs. buy for event-sourcing plumbing. This package is a Symfony bundle over the
patchlevel/event-sourcing library, and it ships the parts teams almost always underestimate: aggregate persistence, an automatic snapshot system, subscription/projection lifecycle management, stream splitting, upcasting for event schema evolution, and crypto-shredding for personal data. The PM decision here is "do we spend a quarter building this, or adopt a focused library and spend the quarter on domain modelling and product features?" The package is explicitly scoped to be that answer for Symfony + Doctrine stacks.
- Whether to adopt event sourcing at all. Event sourcing is a one-way architectural door with real operational cost. A bundle that bundles snapshots (performance), upcasting (schema migration), and managed subscriptions (projection/read-model lifecycle) removes the three most common reasons teams abandon the approach mid-flight. That lowers the risk profile of the decision enough that it can be evaluated as a normal feature bet rather than an existential re-platforming.
- Auditability and compliance as a feature. Full event history plus crypto-shredding means you can support "show me every state change to this order/account/policy" and GDPR erasure-of-personal-data obligations without bolting on a separate audit store. This is a roadmap enabler for regulated-adjacent domains: ledgers, order lifecycle, entitlement and billing state, claims processing, subscription changes.
- Temporal queries and back-office tooling. Because state is a fold over events, "what did this record look like on date X" and "why did it change" become read-model problems rather than archaeology. That is a product capability, not just an engineering nicety — it feeds support tooling, dispute resolution, and customer-facing history timelines.
- Decoupling write models from read models. Subscriptions/processors let you add new projections (search index, reporting table, notification feed) without touching the write path. That changes how you sequence roadmap items: new read surfaces become additive rather than migrations, which affects prioritisation and release planning.
- Where it does not drive decisions. It is a Symfony bundle, not a Laravel package. If the product is on Laravel, this is not a drop-in — the correct comparison is a Laravel-native event-sourcing library plus your own Doctrine/DBAL-equivalent persistence, or a managed event store. Flag that early; it is the single biggest filtering criterion here.
When to Consider This Package
Adopt (or seriously prototype) when all of the following hold:
- The service is Symfony (6/7-era) and already uses Doctrine DBAL for persistence. The bundle leans on that ecosystem deliberately; fighting it is not worth it.
- You have a genuinely event-shaped domain: money movement, order/fulfilment lifecycle, entitlements, subscriptions, approvals, inventory — somewhere the history itself is valuable, not just the current row.
- The team has, or is willing to build, DDD/event-sourcing literacy. Aggregates, eventual consistency, idempotent projections, and replay discipline are team skills, not library features. Without them, the snapshot and upcasting conveniences just delay the pain.
- You need compliance-grade audit history or GDPR erasure and would otherwise build a parallel audit/redaction mechanism.
- You can accept eventual consistency in read paths and have a plan for it in the UX (optimistic updates, "processing" states, read-your-writes handling).
Look elsewhere when:
- You are on Laravel. This is a Symfony bundle; the integration surface (service container, bundle config, Doctrine wiring) does not carry over. You would be adopting the underlying library and rewriting the integration layer — a materially different cost.
- The data is fundamentally CRUD — a CMS, a settings table, a simple catalogue. Event sourcing here is cost with no product return.
- You need a vendor SLA, a large hiring pool, or an ecosystem of third-party integrations. 52 stars and zero dependents means you are an early adopter: expect to read the library source, and expect to be the one who finds the edge cases. That is acceptable for a strong team on a non-critical-path service; it is a poor fit for a platform team that needs a support contract.
- Throughput and scale-out are the dominant constraint. Doctrine DBAL-backed event storage is a reasonable default for typical business volumes; it is not Kafka. If you are planning millions of events per day, multi-region, or cross-language consumers, evaluate a dedicated event store or streaming platform instead of a PHP bundle.
- You need multi-language consumers (a Python ML pipeline, a Go service) reading the same stream. The storage schema is a PHP/Doctrine concern here; a language-neutral event log is a different product decision.
Mitigation if you do adopt: pin the version, budget for reading the library internals, write an internal "how we do event sourcing here" doc (aggregate conventions, upcasting policy, projection replay runbook) before the second service adopts it, and treat the bundle as a dependency you own the risk on — not one you can escalate.
How to Pitch It (Stakeholders)
For executives: We have a recurring need for full history, audit trail, and the ability to answer "what changed and when" across our transactional domains. Building that from scratch is typically a multi-month infrastructure project with ongoing maintenance. This package is a mature, MIT-licensed, actively released Symfony component that provides that infrastructure — snapshots for performance, schema evolution for upgrades, and GDPR-compatible personal-data erasure — so the team's time goes into product behaviour rather than plumbing. The trade-off is adoption risk: it is a small, single-maintainer-community project with limited public usage, so we would pilot it on one bounded service, keep it off the critical path initially, and validate before broadening. Recommendation: time-boxed pilot on one event-shaped domain, with a go/no-go review before any second adoption.
For engineering: This is the Symfony integration for patchlevel/event-sourcing, built on Doctrine DBAL. It gives us aggregates, an automatic snapshot system, stream splitting for oversized aggregates, versioned subscription/processor lifecycle, event upcasting for schema changes, and crypto-shredding for personal data — i.e. the operational features that usually get skipped on a first event-sourcing attempt. It is fully typed with published type-coverage, documented, and released on a regular cadence. The honest caveats: it is Symfony-only (no Laravel path), the ecosystem is thin (52 stars, no dependents), and event sourcing imposes real design constraints — eventual consistency in read models, projection replay as a first-class operational task, and upcasting discipline as events evolve. We should only proceed if we are prepared to own that operational surface with a runbook and a named owner, and only on a domain where history is genuinely a product requirement.
Ask: one sprint of spike work on a single non-critical aggregate to measure integration effort and validate the snapshot/projection workflow, followed by a decision review.