ntorga/clean-ddd-php-poc-contacts
54.3
Adequate · 20 September 2026
1.2k
lines of production code
PHP
primary language
4
measurements over time
What this system is
This system is a Contact Manager API built on PHP 8.3 and Slim4, designed to manage contact records through standard CRUD operations. It enforces strict data validation via domain value objects and persists contact data as individual JSON files on the local filesystem. The application exposes a RESTful interface with consistent JSON response envelopes and provides Swagger documentation for its endpoints.
How it got here
2020 — Initial project scaffolding and API foundation
10 changes.
This period established the foundational structure of the Contact Manager API, including containerization, Slim4 routing, and a filesystem-based persistence layer. It introduced core domain entities and value objects with strict validation, while implementing a standardized JSON response middleware and comprehensive unit tests for the repository layer.
2023 — Contact Manager API implementation
6 changes.
This period focused on implementing the core Contact Manager feature, including domain value objects, use cases with uniform error handling, and DTOs for contact creation and updates. The work extended to the presentation layer with API controllers, parameter validation helpers, and OpenAPI documentation, all supported by comprehensive unit tests for both domain logic and HTTP endpoints.
Features
Add Contact domain entity
A new Contact entity has been introduced to the domain layer, representing a contact with an ID, name, nickname, and phone number. This entity implements JsonSerializable and includes OpenAPI annotations to support API documentation generation.
src/Domain/Entity · high confidence
Added domain value objects for contact and personal data validation
Introduced new value objects in the domain layer to enforce strict validation rules for contact identifiers, names, nicknames, and phone numbers. ContactId now restricts values to the 1–50,000 integer range. PersonName validation was updated to support Unicode characters via the 'u' regex flag, ensuring international names are accepted. Nickname validation was refined to explicitly allow underscores and hyphens in addition to letters. PhoneNumber validation enforces specific formatting patterns, including optional parentheses and hyphens.
src/Domain/ValueObject · high confidence
Initial API setup with Slim4, CORS, and Swagger documentation
The API presentation layer is initialized using the Slim4 framework, establishing the core application entry point in App.php which loads environment variables and registers a JSON response middleware. Routes.php defines the HTTP endpoints for the /v1/contact resource (GET, POST, PUT, DELETE) and includes global CORS headers to allow cross-origin requests. Additionally, a Swagger/OpenAPI specification (swagger.json) is provided to document the API contract, exposing endpoints for listing, retrieving, adding, updating, and removing contacts.
src/Presentation/Api · high confidence
Initial implementation of Contact Manager API controllers
This change introduces the presentation-layer controllers for the Contact Manager API, providing endpoints to create, retrieve, update, and delete contacts. The new files include AddContact, GetContact, GetContacts, UpdateContact, and RemoveContact, which handle HTTP requests, validate parameters using MissingParamHelper, and delegate to domain use cases. Additionally, a Swagger controller is added to serve the API documentation, and OpenAPI annotations are included in the controllers to define the API schema.
src/Presentation/Api/Controller · high confidence
Initial project scaffolding and containerization setup
This change introduces the foundational structure for the Contact Manager API, including a Containerfile for building the PHP 8.3 Apache environment, an .htaccess file to route requests to the API entry point, and a .containerignore file to optimize container builds. It also adds standard project files such as the Apache 2.0 LICENSE, a README with deployment instructions, a phpunit.xml configuration for testing, and updates the .gitignore to properly exclude configuration and cache files.
(repo-wide) · high confidence
Introduce contact management use cases with consistent error handling
The domain layer now includes dedicated use-case classes for managing contacts: AddContact, GetContact, GetContacts, UpdateContact, and RemoveContact. Each use case delegates to the appropriate command or query repository and implements a uniform error-handling strategy: infrastructure failures are logged and re-thrown as specific RuntimeExceptions (e.g., AddContactInfraError, GetContactInfraError, UpdateContactInfraError, RemoveContactInfraError). GetContact distinguishes between a missing contact and other errors, re-throwing a RuntimeException for ContactNotFound. RemoveContact validates that the contact exists before attempting removal, throwing a DomainException if not found.
src/Domain/UseCase · high confidence
New DTOs for creating and updating contacts
Added \AddContact\ and \UpdateContact\ data transfer objects to the domain layer. \AddContact\ captures required name, nickname, and phone details for new entries, while \UpdateContact\ allows optional updates to these fields alongside a required contact ID, supporting partial updates.
src/Domain/Dto · high confidence
New JSON response middleware wraps API output in a status envelope
A new JsonResponseMiddleware has been added to the API presentation layer. This middleware intercepts HTTP responses and re-encodes the body into a standardized JSON structure containing a 'status' field (the HTTP status code) and a 'body' field (the original response content). This ensures that all API responses are consistently formatted as JSON with a predictable envelope, regardless of the underlying handler's output format.
src/Presentation/Api/Middleware · high confidence
New helper for validating required request parameters
A new MissingParamHelper class has been added to the API presentation layer to enforce parameter requirements. When invoked, it checks the parsed request body against a list of required parameters and throws a BadMethodCallException if any are missing or if the body is not an array, providing a clear error message listing the missing fields.
src/Presentation/Api/Helper · high confidence
Behavioural changes
Filesystem-based contact persistence layer
The application now stores and retrieves contacts using individual JSON files on the local filesystem via Flysystem, replacing any previous in-memory or alternative storage mechanism. The new ContactCommandRepository handles adding, updating, and removing contacts by writing or deleting .contact files, while the ContactQueryRepository reads these files to list, count, or fetch specific contacts by ID.
src/Infrastructure · high confidence
Introduction of dedicated command and query repository interfaces for contacts
The contact repository layer now explicitly separates write and read operations through two new domain interfaces: ContactCommandRepositoryInterface and ContactQueryRepositoryInterface. The command interface defines methods for adding, updating, and removing contacts using specific DTOs (AddContact, UpdateContact), while the query interface provides methods for retrieving all contacts or fetching a single contact by ID. This structural change clarifies the contract for contact persistence and retrieval operations within the domain layer.
src/Domain/Repository · high confidence
Test coverage
Added test utility traits for HTTP requests, environment loading, and validation; Added unit tests for contact API controllers; Added unit tests for contact command and query repositories; Added unit tests for domain value objects.
Dependencies
Upgrade PHP runtime and core dependencies
The project now requires PHP 8.3 (up from 7.4.4) and upgrades several key libraries: Slim to ^4.12, league/flysystem to ^3.19, and vlucas/phpdotenv to ^5.5. New dependencies added are zircote/swagger-php (^4.7) for API documentation and doctrine/annotations (^2.0). Development tools are also updated, including PHPUnit to ^10.3 and PHPStan to ^1.10, with the phpstan/extension-installer plugin explicitly allowed in the config.
(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 54 → 54 (+0.2)
- Rubric changed (rubric-2026.08.17 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 99 → 99 (+0.3)
- Architecture 69 → 66 (-3.3)
- Maturity 61 → 43 (-18.4)
- Readiness 34 → 49 (+14.7)
- Security 100 → 97 (-2.9)
Resolved (8)
- Coverage not included — suite not readable by the collector
- Dependency hygiene not measured — no supported dependency manifest was read
- Duplicated block (10–12 lines × 2) (src/Presentation/Api/Controller/GetContact.php)
- Duplicated block (11 lines × 2) (src/Presentation/Api/Controller/AddContact.php)
- Duplicated block (9 lines × 2) (src/Presentation/Api/Controller/GetContact.php)
- No exposed public API
- Test reliability not included
- dormant codebase — no living knowledge left to concentrate
New (33)
- Abandoned package: doctrine/annotations
- Documentation: no usage examples (README.md)
- Duplicated block (24 lines × 2) (src/Domain/Dto/UpdateContact.php)
- Duplicated block (8 lines × 2) (src/Presentation/Api/Controller/GetContact.php)
- Duplicated block (9 lines × 2) (src/Presentation/Api/Controller/AddContact.php)
- Duplicated block (9–11 lines × 2) (src/Presentation/Api/Controller/GetContact.php)
- High CVE: [GHSA redacted] (composer.lock)
- High IaC: DS-0002 (Containerfile)
- High IaC: DS-0029 (Containerfile)
- Low CVE: [GHSA redacted] (composer.lock)
- Medium CVE: [GHSA redacted] (composer.lock)
- Medium IaC: WD-DOCKER-0003 (Containerfile)
- Medium IaC: WD-DOCKER-0010 (Containerfile)
- No direct assertions: testAddAndRemoveContact (tests/Infrastructure/ContactCommandRepositoryTest.php)
- No direct assertions: testGetContactById (tests/Infrastructure/ContactQueryRepositoryTest.php)
- No direct assertions: testWithInvalidOptions (tests/Domain/ValueObject/ContactIdTest.php)
- No direct assertions: testWithInvalidOptions (tests/Domain/ValueObject/NicknameTest.php)
- No direct assertions: testWithInvalidOptions (tests/Domain/ValueObject/PersonNameTest.php)
- No direct assertions: testWithInvalidOptions (tests/Domain/ValueObject/PhoneNumberTest.php)
- No direct assertions: testWithValidOptions (tests/Domain/ValueObject/ContactIdTest.php)
- …and 13 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
ntorga/clean-ddd-php-poc-contacts 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 20 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 c68a8f547fdad9fed7e9af7c135d92f2a6072e7a — 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-28e75b8e3254.