Skip to content
CAI
Software that uses CAICheck a score

franzose/symfony-ddd-wishlist

54.7

Adequate · 22 September 2026

2.6k

lines of production code

PHP

with JavaScript

7

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a Symfony-based web application that manages a 'Wishlist' domain, allowing users to create, publish, and manage items with associated financial deposits and withdrawals. It employs a Domain-Driven Design architecture with distinct layers for domain logic, infrastructure, and HTTP controllers, supported by a Vue.js frontend for dynamic user interactions. The backend handles business rules for fund management and wish status, while the frontend provides a single-page application experience for interacting with the wishlist.

Features

Added CI configuration, license, and project documentation

The project now includes a Travis CI configuration (.travis.yml) to automate testing and code coverage reporting, a MIT license file (LICENSE.txt) clarifying usage rights, and updated README documentation (README.md and README\_RUS.md) that provides installation and usage instructions for the Symfony, PostgreSQL, Redis, and Vue.js stack.

(repo-wide) · high confidence

Added cache options and tag-aware adapter factory

Introduced support for tagged caching and cache invalidation by adding the CacheOptions class, which validates key, lifetime, and tags, and a new TagAwareAdapterFactory that wraps a base adapter with TagAwareAdapter to enable tag-based cache invalidation.

src/Infrastructure/Cache · high confidence

Added caching wrapper for wish repository

A new CachingWishRepository class has been introduced in the Common persistence namespace. This class implements the WishRepositoryInterface and wraps an underlying repository implementation, caching results for 5 minutes using Symfony Cache with tag-based invalidation to improve performance for wish retrieval and counting operations.

src/Infrastructure/Persistence/Common · high confidence

Added custom Doctrine DBAL types for Deposit and Wish IDs

New Doctrine DBAL type classes, DepositIdType and WishIdType, have been introduced to handle the persistence of Deposit and Wish domain IDs. These classes extend UuidType to manage the conversion between database strings and the respective domain ID objects, enabling the database layer to correctly store and retrieve these specific ID types.

src/Infrastructure/Persistence/Doctrine/Type · medium confidence

Added default currency factory

A new DefaultCurrencyFactory class was added to the Infrastructure/Currency layer, providing a static method to create default USD currency instances.

src/Infrastructure/Currency · high confidence

Added in-memory Wish repository implementation

Introduced a new in-memory implementation of the WishRepositoryInterface, allowing wishes to be stored and retrieved from a PHP array in memory. This provides a lightweight, stateful persistence layer suitable for testing or temporary storage, featuring methods for adding, retrieving, and counting wishes, as well as slicing and existence checks.

src/Infrastructure/Persistence/Memory · high confidence

Added validation error transformation utility

Introduced a new \ConstraintViolationListTransformer\ and its corresponding interface in the \src/Infrastructure/Validation\ directory. This addition provides a mechanism to convert Symfony validation violations into a structured array format, enabling consistent error handling and reporting for validation failures.

src/Infrastructure/Validation · high confidence

Added wishlist management and deposit/withdrawal capabilities

Introduced the Wishlist application service and its interface, enabling users to create new wishes, make deposits, and withdraw funds. The service now supports paginated retrieval of wishes, counting total wishes, and publishing/unpublishing wishes. The deposit method returns a DepositDto containing the deposit ID, amount, and currency, while the withdraw method returns the updated fund as a Money object. Additionally, a ListWishDtoAssembler was added to map domain objects to DTOs for API responses.

src/Application · high confidence

Introduced domain value objects and repository interface for the Wishlist app

Added new domain classes including AbstractId, DepositId, WishId, and WishName as value objects, along with an Expense class to manage price, fee, and initial fund. The WishRepositoryInterface was updated with methods for retrieving, storing, and counting wishes, as well as generating the next ID. A default controller was removed.

src/Domain · high confidence

Migrated the wishlist interface to a Vue.js single-page application

The wishlist page is now a Vue.js application, replacing the previous static or server-rendered approach. Users can now interact with the wishlist as a dynamic list where each item can be published or unpublished via AJAX. Clicking a wish opens a slide-out panel displaying its deposits, allowing users to make new deposits or withdraw funds in real-time without page reloads. The interface includes reusable components for pagination, deposit forms, and wish items, all managed by Vue Router.

app/Resources/assets/js · high confidence

New wishlist controller with publish/unpublish and deposit/withdraw endpoints

A new \WishlistController\ has been added to handle wish management. It introduces RESTful endpoints for listing wishes with pagination, publishing and unpublishing wishes, and processing deposits and withdrawals. The controller validates deposit amounts to ensure they are greater than zero, and the pagination logic is configured to start from page 1.

src/Http/Controller · high confidence

Removals

Removed ExtendedCollection utility class

The ExtendedCollection class in the Util namespace has been removed from the codebase. This change eliminates the custom collection wrapper that previously delegated to a Doctrine Collection, affecting any code that relied on this specific utility class.

src/Util · high confidence

Behavioural changes

Add Doctrine-based persistence for the Wish repository

The application now uses a Doctrine ORM implementation for the Wish repository, providing database-backed storage for wish entities. This includes methods for retrieving, updating (via merge and persist), listing, and counting wishes, replacing or supplementing previous in-memory or alternative persistence mechanisms.

src/Infrastructure/Persistence/Doctrine · high confidence

Centralized handling of domain exceptions via a new listener

A new DomainExceptionListener has been introduced to standardize how domain-level exceptions are converted into HTTP responses. This listener maps specific exception interfaces (such as NotFoundExceptionInterface and InvalidOperationExceptionInterface) to corresponding HTTP status codes (404 and 422, respectively) and returns a JSON response with a 'success' flag and error message. This replaces previous, potentially scattered or interface-specific exception handling logic with a single, generic mechanism for all domain exceptions.

src/Http/EventListener · medium confidence

Configured Doctrine, caching, and service wiring for the Wishlist domain

The application's configuration has been updated to support the new Wishlist feature. The database driver is now parameterized (defaulting to PostgreSQL) and includes custom Doctrine types for Wish and Deposit IDs. Second-level cache is enabled, and YAML mappings are registered for the Money and Wishlist domains. A Redis-based TagAware cache adapter is wired into the service container, enabling cache invalidation. Service definitions have been updated to use the new Wishlist namespaces (replacing the old AppBundle), including repositories, factories, and event listeners, while the test environment is configured to use an in-memory SQLite database.

app/config · high confidence

Integrated Vue.js frontend assets and translations into the base template

The base template now loads the main JavaScript bundle (app.js) and the FOSJSRouter, enabling client-side routing and Vue.js functionality. It also injects a translations object containing keys for the wishlist table (e.g., title, publish, deposit, withdraw), supporting the rewritten wishlist interface.

app/Resources/views · high confidence

Introduced new SCSS styles for UI components

Added new styles for the user interface, including a reusable table component with hover effects and caption styling, a pagination block with link and icon styling, and specific styles for a wish list (including publish/unpublish button states) and wish deposits (with a slide-in overlay). The entry also includes styles for a new deposit form, global resets, button variants (primary/danger), and notification alerts.

app/Resources/assets/scss · medium confidence

Refactored Wish and Deposit domain models with new value objects and validation

The Wish entity now uses value objects for its ID, name, and expense (price/fee), and manages deposits via a collection rather than a single fund. Deposits now require an explicit ID and creation timestamp, and the Wish entity enforces stricter validation on deposits (e.g., minimum amount relative to fee, currency matching) and introduces a withdraw operation. Additionally, the Deposit class was updated to use DateTimeImmutable and a specific DepositId type, and the Wish entity now includes methods to predict the fulfillment date based on either the current fund or the fee rate.

franzose/symfony-ddd-wishlist · medium confidence

Refactored domain exception classes and interfaces

The domain exception layer has been restructured with new exception classes for specific business rules: DepositDoesNotExistException, DepositIsTooSmallException, WishIsFulfilledException, and WishIsUnpublishedException. Additionally, the codebase introduced dedicated interfaces (DomainExceptionInterface, InvalidOperationExceptionInterface, NotFoundExceptionInterface) to categorize exceptions, and renamed/restructured existing exceptions like InvalidIdentityException and WishNotFoundException to better reflect their specific error conditions.

src/Domain/Exception · high confidence

Removed default welcome page template

The default welcome page template (index.html.twig) has been removed from the application. This change eliminates the standard Symfony welcome page that is typically displayed on the root URL, indicating a shift away from the default application structure as the team begins implementing a new Wishlist feature.

app/Resources/views/default · high confidence

Updated app kernel with new bundles and testing helpers

The application kernel was updated to replace the removed AppBundle with the FOS JsRoutingBundle, and added the Doctrine Fixtures and Liip Functional Test bundles for both development and test environments, enabling new wishlist functionality and improved testing capabilities.

app · high confidence

Wishlist page now uses Vue Router for client-side navigation

The wishlist page template has been updated to include a \<router-view /\> element, enabling client-side routing within the wishlist interface. This change supports a more dynamic, single-page application experience for wishlist interactions, replacing the previous static table-based layout with a Vue.js-driven interface.

app/Resources/views/wishlist · high confidence

Test coverage

Add tests for the in-memory Wish repository; Added HTTP controller tests for the wishlist feature; Added Wishes fixture for test data generation; Added comprehensive domain tests for the Wishlist application; Added tests for the Wishlist application service.

Dependencies

Updated project dependencies and build configuration

The project's \package.json\ was added to define Node.js dependencies for the frontend build, including Vue.js, Vue Router, and Webpack Encore. On the backend, \composer.json\ was updated to include new packages such as \friendsofsymfony/jsrouting-bundle\ and \ramsey/uuid-doctrine\, while the \composer.lock\ file was regenerated to reflect these dependency changes.

(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 51 → 55 (+3.9)
  • Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 67 → 70 (+2.8)
  • Architecture 100 → 86 (-14.4)
  • Maturity 58 → 58 (+0.0)
  • Readiness 31 → 40 (+9.5)
  • Security 90 → 86 (-4.0)

Resolved (13)

  • Coverage not included — suite not readable by the collector
  • Critical CVE: [GHSA redacted] (composer.lock)
  • Critical CVE: [GHSA redacted] (composer.lock)
  • Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
  • Duplicated block (12 lines × 2) (src/Infrastructure/Persistence/Doctrine/Fixture/LoadWishesData.php)
  • Duplicated block (16 lines × 2) (src/Infrastructure/Persistence/Doctrine/Fixture/LoadWishesData.php)
  • High CVE: [GHSA redacted] (composer.lock)
  • High CVE: [GHSA redacted] (composer.lock)
  • Medium CVE: [GHSA redacted] (composer.lock)
  • No exposed public API
  • Test reliability not included
  • The installation steps are correct (composer self-update, npm install, encore dev), but there is no mention of how to run the PHP dev server or access the database after Docker setup. (README.md)
  • single-maintainer — knowledge-concentration (bus factor) risk

New (27)

  • Abandoned package: sensio/distribution-bundle
  • Abandoned package: sensio/framework-extra-bundle
  • Abandoned package: symfony/swiftmailer-bundle
  • Critical CVE: [GHSA redacted] (composer.lock)
  • Critical CVE: [GHSA redacted] (composer.lock)
  • Documentation: no contributor guidance (README.md)
  • Documentation: no usage examples (README.md)
  • Duplicated block (13 lines × 2) (src/Infrastructure/Persistence/Doctrine/Fixture/LoadWishesData.php)
  • Duplicated block (14 lines × 2) (src/Infrastructure/Persistence/Doctrine/Fixture/LoadWishesData.php)
  • End-of-life framework: Symfony 3
  • End-of-life framework: Vue 2
  • High CVE: [GHSA redacted] (composer.lock)
  • High CVE: [GHSA redacted] (composer.lock)
  • Medium CVE: [GHSA redacted] (composer.lock)
  • No ADRs found
  • No assertions: testConstructorShouldAcceptWishesOnly (tests/Infrastructure/Persistence/Memory/WishRepositoryTest.php)
  • No assertions: testDepositAmountMustNotBeZero (tests/Domain/DepositTest.php)
  • No assertions: testFeeMustBeLessThanPrice (tests/Domain/ExpenseTest.php)
  • No assertions: testGetShouldThrowOnNonExistentId (tests/Infrastructure/Persistence/Memory/WishRepositoryTest.php)
  • No assertions: testInitialFundMustBeLessThanPrice (tests/Domain/ExpenseTest.php)
  • …and 7 more

Architecture

  • Unchanged — 0 containers · 1 contexts · 0 edges

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

franzose/symfony-ddd-wishlist 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 9df2449d4ee20c1fb86ee22ef3e9470d7477ab88 — 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.