Averor/event-sourcing
59.8
Adequate · 22 September 2026
1.2k
lines of production code
PHP
primary language
6
measurements over time
What this system is
This system is an event-sourcing framework that manages aggregate state by persisting and replaying domain events. It provides a repository pattern for loading and saving aggregates, along with an event store that supports both in-memory and MongoDB backends. The architecture includes optimistic locking to handle concurrency and a trait-based approach for reconstituting aggregate state from event streams.
Features
Add optimistic locking to the event store
A new OptimisticLockingEventStore implementation has been introduced to manage event streams with version-based concurrency control. This change ensures that concurrent updates to an aggregate root are detected and rejected via a ConcurrencyException when a version mismatch occurs during commit, preventing lost updates.
src/EventStore · high confidence
Added core contracts for the event-sourcing subsystem
Introduced a new set of interfaces in the \Averor\\MessageBus\\EventSourcing\\Contract\ namespace to define the event-sourcing architecture. This includes \AggregateRoot\ and \EventSourcedAggregateRoot\ for managing state and events, \DomainEvent\ for domain notifications, and \EventStore\/\EventStream\ for persistence. The \Repository\ interface now supports an optional aggregate name parameter, and new exception classes (\AggregateMethodNotFoundException\, \AggregateRootNotFoundException\, \ConcurrencyException\, \EventStoreCommitException\) are added to handle specific error conditions.
src/Contract · high confidence
Added in-memory and MongoDB event store implementations
Introduced new storage backends for the event store: a simple in-memory implementation (MemoryStorage) and a MongoDB-based implementation (MongoDbStorage) that persists events to a configurable collection. To support the MongoDB storage, a SimpleSerializer was added to handle serialization and deserialization of domain events using reflection, enabling the storage of scalar event data without external dependencies.
src/EventStore/Storage · high confidence
New event-sourcing domain classes for aggregate reconstitution and persistence
The domain layer now includes new classes and traits to support event sourcing: \AggregateRootReconstitutionTrait\ handles reconstructing aggregate state from an event stream; \DomainEventStream\ and \DomainEventsTransaction\ manage event collections and versions; \DomainEventTrait\ provides standard event metadata; \EventProducerTrait\ manages pending domain events and applies them to the aggregate; and \EventSourcedRepository\ implements the repository interface to load aggregates from an event store, save new events, and dispatch them via an event bus.
src/Domain · medium confidence
Test coverage
Added unit tests for event sourcing components
Added comprehensive unit tests for the event sourcing domain, including \AggregateRootTest\ for managing and reconstituting aggregates, \DomainEventStreamTest\ for event stream operations, \DomainEventTest\ for event metadata, \DomainEventsTransactionTest\ for transaction handling, \EventSourcedRepositoryTest\ for repository interactions, and \OptimisticLockingEventStoreTest\ for event store commit and concurrency logic.
tests · high confidence
Dependencies
Update PHP dependencies and add optional MongoDB storage support
The project's dependencies have been updated to include php-ds, ramsey/uuid, and averor/cqrs-es-bundle, while also adding a suggested dependency on mongodb/mongodb for MongoDB storage functionality.
(dependencies) · medium confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 59 → 60 (+1.2)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 100 → 100 (+0.0)
- Architecture 69 → 69 (+0.0)
- Maturity 49 → 49 (+0.0)
- Readiness 50 → 55 (+4.7)
- Security 100 → 100 (+0.0)
Resolved (7)
- Coverage not included — suite not readable by the collector
- Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
- No exposed public API
- Test reliability not included
- The README claims 'Documentation Will be surely written... someday' then only links to bare directory stubs (examples/tests) and gives no guidance on event sourcing behavior such as when events are persisted, how queries work, or the domain model structure. (README.md)
- early-stage repository — too little history to judge knowledge freshness
- single-maintainer — knowledge-concentration (bus factor) risk
New (13)
- Dependency hygiene PARTLY measured — Composer dependencies read, no committed lock to grade for currency
- Documentation: no project overview (README.md)
- Documentation: no usage examples (README.md)
- Duplicate data carriers with divergent naming and typing. EventStream and Transaction represent the same logical concept (a stream of events for a specific aggregate). However, EventStream uses Identifier for IDs in its parent context (EventStore) but returns string for ID, while Transaction also returns string. More critically, EventStream has both id() and name(), while Transaction also has both. The EventStore interface uses Identifier for IDs, but Storage and Transaction use string. This creates a type mismatch between the high-level API (Identifier) and the low-level storage API (string).
- Duplicate serialization interfaces. EventSerializer is a contract with serialize and deserialize. SimpleSerializer implements the same contract. This is standard, but the existence of EventSerializer as a contract and SimpleSerializer as a specific implementation is fine. However, DomainEventStream and DomainEventsTransaction both have toArray() methods, which suggests a lack of a unified collection interface for events.
- No assertions: test_it_commits_stream_correctly_by_pushing_to_storage (tests/EventStore/OptimisticLockingEventStoreTest.php)
- No assertions: test_it_dispatches_events_via_event_bus (tests/Domain/EventSourcedRepositoryTest.php)
- No assertions: test_it_returns_gracefully_without_doing_anything_when_no_new_events_to_be_stored (tests/EventStore/OptimisticLockingEventStoreTest.php)
- No assertions: test_it_saves_new_aggregate_in_store (tests/Domain/EventSourcedRepositoryTest.php)
- No assertions: test_it_saves_reconstituted_aggregate_in_store (tests/Domain/EventSourcedRepositoryTest.php)
- No dependency advisory monitoring
- Redundant Repository interface. Repository and EventSourcedRepository have identical signatures for get and save. EventSourcedRepository is a concrete implementation of Repository. This is acceptable if Repository is an interface, but the naming suggests EventSourcedRepository might be a separate concept rather than an implementation. If Repository is an interface, this is consistent. If Repository is a class, it is redundant.
- Redundant reconstitution logic. EventSourcedAggregateRoot has a reconstitute method, and there is a separate AggregateRootReconstitutionTrait that also provides reconstitute. It is unclear if the trait is meant to be used by the aggregate root or if it is a separate utility. If the trait is used by the aggregate root, the method on the aggregate root is redundant. If it is a separate utility, the naming is confusing as it implies it returns a new aggregate root, whereas the aggregate root method likely mutates the current instance.
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
Averor/event-sourcing was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 22 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit 692fee58117fd6736137d9bc2982cf27b0994d77 — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-821afab8930d.