renan-taranto/cqrs-event-sourcing-example
47.8
Weak · 21 September 2026
7.7k
lines of production code
PHP
primary language
4
measurements over time
What this system is
This system is a PHP-based web application built on the Symfony framework, implementing a CQRS (Command/Query/Responsibility Separation) architecture to manage a 'List Maker' domain involving boards, lists, and items. It utilizes an event-sourced persistence model with MySQL for the event store and MongoDB for read projections, while employing RabbitMQ for asynchronous event consumption. The application exposes a RESTful API with real-time updates via Server-Sent Events (SSE) and provides comprehensive test coverage across unit, functional, and integration layers.
How it got here
2019 — Initial project scaffolding and CQRS architecture
25 changes.
The project was initialized with a complete development environment and CI infrastructure, establishing a Symfony 4.4-based application. The core architecture was built around Command/Query/Event patterns, implementing domain models for boards with event sourcing, asynchronous message handling, and Server-Sent Events for real-time updates.
2020 — List and Item domain implementation
17 changes.
This period focused on implementing the core domain models and application logic for managing lists and items, including their creation, updates, and lifecycle states. The work established the persistence layer using MongoDB and MySQL, alongside comprehensive test coverage for both features and infrastructure.
2021 — SSE publisher implementation
4 changes.
This period focused on implementing Server-Sent Events (SSE) publishing capabilities within the shared infrastructure, specifically integrating with the Symfony Mercure Hub. The work involved creating publisher classes for board and list lifecycle events, ensuring they correctly translate domain events into SSE payloads, and adding comprehensive unit tests to verify their behavior.
Features
Add JSON request validation and structured validation error responses
Two new event listeners are introduced to handle HTTP request validation. JsonRequestValidation validates that POST requests contain valid JSON, returning a 400 Bad Request for malformed payloads. ResponseOnValidationException intercepts validation failures, translating constraint violations into a structured JSON error response (400), with support for returning 404 Not Found for specific constraints.
src/Shared/Ui/Web/EventListener · high confidence
Add Swagger UI API documentation
The public API documentation is now available via Swagger UI. This includes the OpenAPI 3.0.0 specification file (api.json) and the necessary HTML, CSS, and JavaScript assets (swagger-ui-bundle.js, index.html, oauth2-redirect.html) to render the interactive documentation interface for the List Maker Web API.
public · high confidence
Add application layer for item management
The application layer for the Item feature is introduced, providing command handlers for creating, archiving, restoring, and moving items, as well as a query interface for retrieving item data. This enables users to manage individual items within lists, including updating titles, descriptions, and positions, as well as archiving and restoring items.
src/Item/Application · high confidence
Add asynchronous event consumer via RabbitMQ and Supervisor
The PHP Docker image now includes an \events\_consumer\ build stage that installs the \amqp\ extension for RabbitMQ integration and \supervisor\ for process management. This new stage is configured to run the \messenger:consume\ command asynchronously, allowing the application to handle events in the background rather than synchronously.
.docker/php · high confidence
Add list management commands and queries
The application layer now includes command handlers for creating, moving, archiving, and restoring lists, as well as a query interface for finding lists. This introduces the core application logic for list operations, including position validation and board association.
src/ItemList/Application · high confidence
Add server-sent events and persistence for items
The Item domain now includes infrastructure for persisting item state and broadcasting changes via server-sent events. A new ItemFinder and ItemProjector handle reading and projecting item data to a MongoDB 'boards' collection, while dedicated publishers (ItemAdded, ItemArchived, ItemDescriptionChanged, ItemMoved, ItemRestored, ItemTitleChanged) emit SSE updates. Additionally, validation constraints and validators (ItemDoesNotExist, ItemExists, ItemIsArchived, ItemIsNotArchived, ItemPosition) are introduced to enforce business rules on item operations.
src/Item/Infrastructure · high confidence
Added Query Bus interface and Symfony implementation
Introduced a new QueryBus abstraction and its Symfony Messenger-based implementation. The QueryBus interface defines a query method for handling messages, while the SymfonyQueryBus class implements this interface by delegating to Symfony's MessageBusInterface via the HandleTrait, enabling query execution through the Symfony Messenger component.
src/Shared/Infrastructure/MessageBus · high confidence
Added Server-Sent Events publisher via Mercure
A new SsePublisher interface and its Mercure-based implementation have been added to the shared infrastructure layer. This introduces the capability to publish Server-Sent Events (SSE) through the Symfony Mercure Hub, enabling real-time event broadcasting for the application.
src/Shared/Infrastructure/SsePublisher · high confidence
Board state changes now broadcast via Server-Sent Events
The Board infrastructure now publishes Server-Sent Events (SSE) for board lifecycle changes. New event handlers in the SsePublisher directory (BoardCreated, BoardClosed, BoardReopened, BoardTitleChanged) emit updates to the boards SSE channel, enabling real-time synchronization of board status and title changes for connected clients.
src/Board/Infrastructure · high confidence
Initial project scaffolding and CI/testing infrastructure
The repository was initialized with a complete development environment, including a Makefile for managing Docker containers, dependencies, and test suites. A Travis CI configuration was added to automate testing and code coverage reporting via Coveralls. The project now supports multiple test types (unit, integration, functional, API) using Codeception and PHPUnit, with specific configurations for MySQL, MongoDB, RabbitMQ, and Mercure. Additionally, a MIT license file was added to the project.
(repo-wide) · high confidence
Introduce AggregateRepository for event-sourced persistence
A new AggregateRepository class has been added to handle persistence for aggregate roots. It provides methods to save an aggregate's recorded events to the event store and to retrieve an aggregate by reconstructing its state from its event history.
src/Shared/Infrastructure/Persistence/Repository · high confidence
Introduce Board domain model with event-sourced lifecycle
Added the core Board domain entity, including its ID, repository interface, and event-sourced state management. The Board aggregates created, title change, close, and reopen events, ensuring title updates are skipped if the new title matches the current one. This establishes the foundational domain logic for board management.
src/Board/Domain · high confidence
Introduce CQRS controllers for handling commands and queries
Added new web controllers to support a Command/Query separation in the application's HTTP layer. The CommandController routes write operations through a command bus, while the QueryController routes read operations through a query bus. Supporting factory classes (CommandFactory and QueryFactory) handle the deserialization of HTTP requests into domain-specific command and query objects, enabling a cleaner separation of concerns for API endpoints.
src/Shared/Ui/Web/Controller · high confidence
Introduce Item domain model with lifecycle and update behaviors
The Item domain is introduced with a new \Item\ aggregate root that supports creating, archiving, restoring, and moving items, as well as changing titles and descriptions. This includes the \Item\ class, value objects (\ItemId\, \Description\), a repository interface, and a set of domain events (\ItemAdded\, \ItemArchived\, \ItemRestored\, \ItemMoved\, \ItemTitleChanged\, \ItemDescriptionChanged\) to track state changes.
src/Item/Domain · high confidence
Introduce List domain model with creation, title, position, and lifecycle management
The ItemList domain now includes a full aggregate root (ItemList) with associated value objects (ListId, Title, Position) and domain events (ListCreated, ListTitleChanged, ListArchived, ListRestored, ListMoved). Users can create lists with a title and initial position, update titles, archive/restore lists, and move them within a board, all tracked via domain events.
src/ItemList/Domain · high confidence
Introduces domain primitives and aggregate infrastructure
The domain layer now includes foundational infrastructure for the domain model: an abstract \AggregateRoot\ class that manages event recording and reconstitution, a \DomainEvent\ message type, and an \ImmutableArray\ base class to enforce immutability on collections. Additionally, value objects for \Title\ and \Position\ have been added to the shared domain namespace, and the application \Kernel\ has been reorganized into the \Shared/Infrastructure\ namespace.
src/Shared/Domain · high confidence
New validation constraints for MongoDB document existence checks
The application now includes custom validation constraints, MongoDocumentExists and MongoDocumentDoesNotExist, which verify whether a document exists or does not exist in a specified MongoDB collection. These constraints are paired with their respective validators that query the database via MongoCollectionProvider to enforce data integrity rules during command validation.
src/Shared/Infrastructure/Validation · high confidence
Persistence layer for List domain
The application now persists List entities and projections via new infrastructure classes. The ListRepository handles saving and retrieving ItemList aggregates, while the ListProjector updates the MongoDB 'boards' collection to reflect list state changes (creation, title updates, archiving, restoration, and movement). Additionally, the ListFinder provides a read-optimized view of list data from the database.
src/ItemList/Infrastructure/Persistence · high confidence
Behavioural changes
Add MySQL container configuration and initial schema
The MySQL Docker environment is now fully configured with a custom Dockerfile that copies SQL initialization scripts into the entrypoint directory. This includes a schema for an 'event\_stream' table (containing id, aggregate\_id, aggregate\_version, event\_type, payload, and created\_at columns) and a separate script to create the 'appdb-test' database with appropriate user privileges for testing.
.docker/mysql · high confidence
Add optimistic concurrency control to the MySQL event store
The MySQL event store now enforces optimistic concurrency control when committing domain events. A new ConcurrencyException is thrown if the expected aggregate version does not match the current version in the database, preventing lost updates. This is implemented in MySqlEventStore via a pre-commit version check, supported by the new EventStore interface and supporting classes (EventStoreDecorator, MessageDispatcherEventStore) that integrate the persistence layer with the message bus.
src/Shared/Infrastructure/Persistence/EventStore · medium confidence
Added server-sent event publishers for list lifecycle events
New publisher classes (ListArchivedPublisher, ListCreatedPublisher, ListMovedPublisher, ListRestoredPublisher, and ListTitleChangedPublisher) have been added to the SsePublisher infrastructure. These components translate domain events into Server-Sent Events (SSE) payloads. Specifically, the ListMoved publisher now includes additional data fields (title, items, archivedItems, position, boardId) to satisfy web client requirements, while other events like ListCreated and ListTitleChanged also broadcast relevant list metadata via SSE.
src/ItemList/Infrastructure/SsePublisher · medium confidence
Board command and query handlers moved to application layer
The Board module's application layer has been restructured: command handlers (CreateBoard, ChangeBoardTitle, CloseBoard, ReopenBoard) and query handlers (BoardById, BoardsOverview) have been moved into the \src/Board/Application\ directory. This includes the associated command and query classes, as well as the \BoardFinder\ and \BoardOverviewFinder\ interfaces and their handlers, centralizing the application logic for board management.
src/Board/Application · high confidence
Configure application services and routing for CQRS and SSE
The application is configured to support a Command/Query/Event architecture with Server-Sent Events. Service definitions in services.yaml wire up command, query, and event buses, along with projectors and SSE publishers. Routing is split into separate files for boards, lists, and items, and the entry point is explicitly mapped. Additionally, test configuration in services\_test.yaml introduces a Mercure hub stub, and bundles.php enables Doctrine, CORS, and Mercure bundles.
config · high confidence
MongoDB container setup includes index creation and fixture loading scripts
The Docker configuration for MongoDB has been updated to include a new Dockerfile that sets up the environment with specific database indexes on the 'boards' collection (including nested fields like 'lists.id' and 'archivedLists.items.id') and a script to load test fixtures into a temporary database before dumping them for testing purposes.
.docker/mongo · medium confidence
New validation constraints for list state and positioning
Added new validation constraints and their corresponding validators to enforce business rules for list management. The system now validates that a list does not already exist, that a list exists in the database, that a list is or is not archived, and that a list's position is valid (non-negative and within the current list count). These checks are implemented via new classes in the \src/ItemList/Infrastructure/Validation\ directory, utilizing the \MongoCollectionProvider\ to query the \boards\ collection for state verification.
src/ItemList/Infrastructure/Validation · high confidence
Refactored MongoDB collection access and introduced a base Projector class
The codebase now uses a new MongoCollectionProvider class to manage MongoDB collection access, replacing the previous MongoCollectionFactory. Additionally, a new abstract Projector class has been introduced to handle domain event projection, providing a standardized way to process domain events through dynamic method invocation.
src/Shared/Infrastructure/Persistence/Projection · medium confidence
Updated Kernel class import in Symfony console script
The bin/console script now imports the Kernel from the fully qualified namespace Taranto\\ListMaker\\Shared\\Infrastructure\\Kernel instead of the previous App\\Kernel. This change ensures the console application correctly instantiates the application's kernel, which is essential for the Symfony console to function properly.
bin · high confidence
Updated nginx image version and configuration
The nginx Docker image was updated from the 'mainline-alpine' tag to the specific '1.17-alpine' version. Additionally, the nginx configuration was modified to serve static files from the 'doc' directory and updated to route PHP requests to the 'web\_api' service instead of 'php'.
.docker/nginx · medium confidence
Test coverage
Add API test suite; Added API integration tests for item management; Added API tests for board management and querying; Added functional tests for Board commands and queries; Added functional tests for Item commands; Added integration tests for board, item, and list projections and event store; Added test fixtures for board, list, and item data; Added test support classes and stubs for the test suite; Added tests for list management operations; Added unit tests for Board application layer handlers; Added unit tests for EventStore and SSE Publisher; Added unit tests for Item domain and SSE publishers; Added unit tests for board event publishers; Added unit tests for list event publishers; Added unit tests for list management commands; Added unit tests for the Board domain; Added unit tests for the List domain aggregate.
Dependencies
Upgrade Symfony to 4.4 and add new dependencies
The project has been upgraded to Symfony 4.4, updating core packages such as symfony/console, symfony/dotenv, symfony/framework-bundle, symfony/http-foundation, and symfony/yaml to version 4.4.\*. Additionally, several new dependencies have been added to the project, including doctrine/doctrine-bundle, mongodb/mongodb, nelmio/cors-bundle, ramsey/uuid, symfony/mercure-bundle, symfony/messenger, symfony/serializer-pack, and symfony/validator. In the development dependencies, codeception has been upgraded to version 4.1.22, and new testing-related packages like codeception/mockery-module, codeception/module-asserts, codeception/module-db, codeception/module-mongodb, codeception/module-rest, codeception/module-symfony, codeception/verify, and dg/bypass-finals have been introduced. The composer.json file also reflects a change in the namespace from App to Taranto\\ListMaker, and the autoloading configuration has been updated accordingly.
(dependencies) · high 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 72 → 48 (-23.8)
- Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 100 → 99 (-0.9)
- Architecture 100 → 79 (-20.8)
- Maturity 76 → 76 (+0.0)
- Readiness 55 → 43 (-11.8)
- Security 87 → 87 (-0.3)
- Domain Modelling 100 → 100 (+0.0)
- Event Sourcing 100 → 100 (+0.0)
- Accessibility 28 (new)
Resolved (22)
- Coverage not included — suite not readable by the collector
- Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
- Duplicated block (11 lines × 2) (src/Item/Infrastructure/Validation/ItemPositionValidator.php)
- Duplicated block (8 lines × 2) (src/Item/Infrastructure/Validation/ItemIsNotArchivedValidator.php)
- High CVE: [GHSA redacted] (composer.lock)
- High CVE: [GHSA redacted] (composer.lock)
- High CVE: [GHSA redacted] (composer.lock)
- Low CVE: [GHSA redacted] (composer.lock)
- Low CVE: [GHSA redacted] (composer.lock)
- Low CVE: [GHSA redacted] (composer.lock)
- Low CVE: [GHSA redacted] (composer.lock)
- Low CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- No exposed public API
- …and 2 more
New (45)
- Documentation: no contributor guidance (README.md)
- Documentation: no installation or build instructions (README.md)
- Documentation: no usage examples (README.md)
- Duplicated block (12 lines × 2) (src/Item/Infrastructure/SsePublisher/ItemMovedPublisher.php)
- Duplicated block (13 lines × 2) (src/Item/Infrastructure/Validation/ItemPositionValidator.php)
- Duplicated block (18 lines × 2) (src/Item/Application/Command/ChangeItemDescription.php)
- Duplicated block (18 lines × 2) (src/Item/Application/Command/ChangeItemTitle.php)
- Duplicated block (18 lines × 2) (src/ItemList/Application/Command/ChangeListTitle.php)
- Duplicated block (18 lines × 4) (src/Board/Application/Command/ChangeBoardTitle.php)
- Duplicated block (26 lines × 2) (src/Board/Domain/Event/BoardCreated.php)
- Duplicated block (27 lines × 2) (src/Item/Application/Command/MoveItem.php)
- Duplicated block (27 lines × 2) (src/ItemList/Application/Command/MoveList.php)
- Duplicated block (5 lines × 3) (src/Board/Domain/Board.php)
- Duplicated block (6 lines × 2) (src/Shared/Ui/Web/Controller/CommandFactory.php)
- Duplicated block (7 lines × 3) (src/Board/Application/Command/ChangeBoardTitleHandler.php)
- Duplicated block (8 lines × 2) (src/Item/Infrastructure/Validation/ItemIsNotArchivedValidator.php)
- Duplicated block (9 lines × 2) (src/Item/Domain/Item.php)
- Duplicated block (9 lines × 2) (src/Item/Infrastructure/Persistence/Projection/ItemProjector.php)
- Duplicated block (9 lines × 4) (src/Item/Infrastructure/Persistence/Projection/ItemProjector.php)
- End-of-life framework: Symfony 4
- …and 25 more
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
renan-taranto/cqrs-event-sourcing-example 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 21 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 f4f5627115553975f8efd3f9ec550b95dd747be4 — 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-fa71c66cabd8.