Skip to content
CAI
Software that uses CAICheck a score

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

CAI band scale
CAI trend line
CAI lens gauges

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.