Skip to content
CAI
Software that uses CAICheck a score

Sairyss/domain-driven-hexagon

48.4

Weak · 21 September 2026

3k

lines of production code

TypeScript

with JavaScript

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is a NestJS-based application implementing Domain-Driven Design principles, specifically utilizing CQRS and event-driven architecture. It manages user and wallet domains, supporting data operations via HTTP, GraphQL, CLI, and message queues. The codebase enforces strict architectural boundaries and uses modern tooling like Zod for validation and Slonik for database interactions.

How it got here

2020 — User module refactoring and architecture simplification

17 changes.

This period focused on stripping away legacy abstractions, base classes, and HTTP controllers to simplify the user module's architecture. The team migrated the database layer from TypeORM to Slonik, introduced GraphQL support, and enforced stricter architectural boundaries and validation rules.

2021 — User and wallet domain modeling

11 changes.

This period focused on implementing core user and wallet functionality, including creating, deleting, and querying users via multiple interfaces (CLI, HTTP, GraphQL). It also introduced structured exception handling, TypeScript utility types, and automatic wallet provisioning upon user registration.

2022 — Domain-Driven Design and API standardization

8 changes.

This period focused on establishing the foundational architecture for the application, introducing Domain-Driven Design patterns and standardized API response structures. The work included implementing core domain models for users and wallets, setting up database migrations, and creating shared test utilities to support these new components.

Features

Add paginated user query via GraphQL and HTTP endpoints

Users can now retrieve a paginated list of users through both GraphQL and HTTP interfaces. The new FindUsersQueryHandler executes a direct database query using Slonik, supporting optional filtering by country, street, and postal code, and returns a paginated response containing user details such as email, country, street, and postal code.

src/modules/user/queries · high confidence

Added @final and @frozen class decorators

The library now provides two new decorators for class definitions. The @final decorator prevents other classes from extending a marked class by throwing an error if an attempt is made to extend it. The @frozen decorator applies Object.freeze() to a class and its prototype, ensuring that static properties and the prototype are immutable. These are exported via the decorators index.

src/libs/decorators · high confidence

Added CLI, HTTP, and message controllers for creating users

New controllers have been introduced to support creating users via the command bus across multiple interfaces: a CLI controller for command-line execution, an HTTP controller for REST API requests, and a message controller for microservice messaging. The implementation includes a CreateUserCommand, a request DTO with validation rules, and a service that handles the domain logic, ensuring users can be created through these new entry points.

src/modules/user/commands/create-user · high confidence

Added GraphQL implementation for creating users

A new GraphQL resolver and associated Data Transfer Objects (DTOs) were added to the user module, providing an alternative to the existing HTTP controller for creating users. The resolver exposes a 'create' mutation that accepts a CreateUserGqlRequestDto containing email, country, postal code, and street, and returns an IdGqlResponse with the new user's ID.

src/modules/user/commands/create-user/graphql-example · high confidence

Added GraphQL support and paginated user queries

Users can now query paginated user data via GraphQL. This change introduces new DTOs for GraphQL responses, including a base UserGraphqlResponseDto and a paginated wrapper, enabling structured GraphQL API interactions for user data.

src · high confidence

Added HTTP controller and service for deleting a user

A new HTTP controller and service have been added to handle the deletion of a user. The controller exposes a DELETE endpoint that accepts a user ID, invokes a command bus to execute the deletion logic, and maps the result to appropriate HTTP responses, including handling not-found scenarios. The underlying service uses dependency injection to access the user repository, ensuring the repository is properly injected rather than manually instantiated.

src/modules/user/commands/delete-user · medium confidence

Added new TypeScript utility types for object manipulation

The codebase now includes a new shared types library at src/libs/types, exporting several TypeScript utility types: DeepPartial and DeepMutable for recursively modifying nested object structures, NonFunctionProperties to filter out function-typed properties, ObjectLiteral for simple string-keyed objects, and RequireAtLeastOne/RequireOnlyOne to enforce constraints on optional properties. These additions provide reusable type helpers for object manipulation and validation across the application.

src/libs/types · high confidence

Added user domain model with role management and address updates

Introduced the core user entity in the domain layer, implementing an aggregate root that manages user roles (admin, moderator, guest) and address updates. The implementation uses native crypto for ID generation and emits domain events for creation, deletion, and role/address changes, while enforcing business rules through private state mutation methods.

src/modules/user/domain · high confidence

Automatic wallet creation on user registration

A new event handler has been added to automatically create a wallet for a user when the user is created. This ensures that every new user account is immediately provisioned with a wallet, removing the need for manual wallet initialization or separate registration steps.

src/modules/wallet/application · high confidence

Enforced architecture rules and updated test configuration

Added a new \.dependency-cruiser.js\ configuration file that enforces architectural boundaries, preventing the domain layer from depending on the API, application, or infrastructure layers, and ensuring infrastructure does not depend on the API layer. Additionally, the Jest configuration was updated to include coverage directories, setup files, and module name mappings, while the TypeScript configuration was adjusted to support new path aliases and stricter null-checking rules.

(repo-wide) · high confidence

Introduce wallet domain model with native UUID generation

Added the core domain classes for the wallet feature: a WalletEntity that manages balance and generates a unique identifier using the native crypto.randomUUID() function, a WalletCreatedDomainEvent to track creation, and a WalletNotEnoughBalanceError for insufficient funds. This establishes the foundational structure for wallet operations within the domain layer.

src/modules/wallet/domain · medium confidence

Introduced database repository for wallet persistence

A new database repository implementation for the Wallet module has been added. This includes a type-safe schema definition using Zod to validate wallet data, and a concrete repository class that extends the base SQL repository to handle persistence operations for the Wallet entity.

src/modules/wallet/database · medium confidence

Introduces DDD foundational classes and SQL repository base

Adds new base classes for Domain-Driven Design, including \Entity\, \AggregateRoot\, \DomainEvent\, \Command\, and \ValueObject\, along with a \SqlRepositoryBase\ for database interactions. The \Command\ and \DomainEvent\ classes now store metadata (correlationId, causationId, timestamp, userId) in a dedicated \metadata\ object rather than as top-level properties. The \Entity\ class provides a \getProps()\ method that returns a frozen, deep copy of the entity's properties for safe inspection. The \SqlRepositoryBase\ implements standard repository operations (find, insert, delete) using the \slonik\ library and Zod schemas.

src/libs/ddd · high confidence

Introduces database migration, seeding, and request context infrastructure

Adds database migration and seeding scripts (SlonikMigrator) to manage schema changes and seed initial user and wallet data. Introduces a request context mechanism (AppRequestContext, ContextInterceptor) to propagate a unique request ID for logging and correlation. Adds an exception interceptor to standardize error responses with correlation IDs and handle validation errors. Includes a LoggerPort interface and a refactored Guard utility for data validation.

(repo-wide) · high confidence

Standardized API response structures and pagination support

The API layer now provides standardized base classes for HTTP and GraphQL responses. A new ApiErrorResponse class defines a consistent structure for error responses, including status code, message, error type, correlation ID, and optional sub-errors. For data responses, a new ResponseBase class standardizes the inclusion of id, createdAt, and updatedAt fields. Additionally, the codebase introduces support for paginated responses: a PaginatedResponseBase class for REST APIs and a PaginatedGraphqlResponse helper for GraphQL, both providing count, limit, and page metadata alongside the data array. A PaginatedQueryRequestDto is also added to handle pagination query parameters.

src/libs/api · high confidence

Removals

Removed HTTP controller and service for user deletion

The HTTP controller and service responsible for deleting a user have been removed from the codebase. This eliminates the direct API endpoint for user removal, meaning users can no longer be deleted via the HTTP interface.

src/modules/user/use-cases/remove-user · high confidence

The UserEntity class, along with the associated UpdateUserAddressProps interface and the Address/Email value objects, have been removed from the codebase. This eliminates the previous implementation of the user domain model, likely as part of a broader refactoring to simplify the domain entities or prepare for a new architecture.

src/modules/user/domain/entities · high confidence

Behavioural changes

Added domain event classes for user lifecycle and address changes

New domain event classes have been introduced to capture specific user state changes. UserCreated now includes address details (country, postal code, street) alongside the email. Additionally, new events have been added to track when a user's address is updated, when a user is deleted, and when a user's role changes.

src/modules/user/domain/events · high confidence

Introduce structured exception handling with standardized error codes

Added a new exception handling library in src/libs/exceptions that provides a base ExceptionBase class and several specific exception types (e.g., ArgumentInvalidException, NotFoundException). Each exception now includes a standardized 'code' string (e.g., 'GENERIC.ARGument\_invalid') to facilitate error identification across process boundaries, along with automatic correlation ID injection for debugging. This replaces previous ad-hoc error handling with a consistent, serializable exception hierarchy.

src/libs/exceptions · medium confidence

Refactored Address value object and removed Email value object

The Address value object was refactored to use a props-based structure with getters, and its validation logic was updated to throw specific ArgumentOutOfRangeExceptions for country, street, and postal code. The Email value object was removed entirely from the codebase.

src/modules/user/domain/value-objects · medium confidence

Refactored user module to use CQRS and DI tokens

The user module has been refactored to use a Command Query Responsibility Segregation (CQRS) pattern, separating commands (CreateUser, DeleteUser) and queries (FindUsers) into distinct handlers. Dependency injection now relies on explicit tokens (USER\_REPOSITORY) rather than direct class injection, and the module registers controllers, services, and mappers via provider arrays. This change affects how the user module is wired and how user-related operations are invoked.

src/modules/user · high confidence

Refactored user response DTOs and added paginated response support

The user response DTOs have been refactored to improve structure and documentation. The \UserResponse\ class was renamed to \UserResponseDto\ and simplified by removing the constructor logic that mapped from \UserEntity\, relying instead on the base \ResponseBase\ class. Additionally, \ApiProperty\ decorators were updated with explicit descriptions for each field. A new \UserPaginatedResponseDto\ was introduced to support paginated user lists, extending \PaginatedResponseDto\ to wrap an array of \UserResponseDto\ objects.

src/modules/user/dtos · high confidence

Removed FindUserByEmail HTTP controller

The HTTP controller for finding a user by email has been removed from the application. This endpoint previously allowed retrieving user data via a GET request, but the implementation has been deleted, meaning this specific API route is no longer available.

src/modules/user/use-cases/find-user-by-email · high confidence

Removed base response class for API serialization

The \ResponseBase\ class, which previously handled automatic serialization of \createdAt\ and \updatedAt\ timestamps from domain entities into ISO 8601 strings for API responses, has been removed. This change eliminates the automatic date formatting provided by the base class, meaning response DTOs will no longer automatically inherit these timestamp fields or their Swagger documentation decorators.

src/interface-adapters/base-classes · medium confidence

Removed core domain and application layer abstractions

The application and domain layers have been stripped of their foundational infrastructure. Specifically, the codebase no longer includes the base classes for entities and value objects, the generic repository and logger port interfaces, the event emitter port, or the specific value objects (DateVO, ID) and event enums (UserEvents, WalletEvents) that previously supported these structures.

src/application, src/domain · high confidence

Removed empty placeholder from user seeding directory

The empty .gitkeep file in the src/modules/user/database/seeding directory has been removed. This indicates that the directory is now populated with actual seeding logic rather than remaining an empty placeholder.

src/modules/user/database/seeding · medium confidence

Removed infrastructure exception and database base classes

Deleted the entire \src/infrastructure/exceptions\ directory, removing the custom exception hierarchy (including \ExceptionBase\, \exception.types\, and specific error classes like \NotFoundException\ and \InputValidationException\). Also removed the \orm-entity.base\ and \repository.base\ classes from \src/infrastructure/database/base-classes\, which previously provided shared ORM and repository functionality. These changes indicate a shift in how domain errors and database interactions are handled within the application.

src/infrastructure · high confidence

Removed interface adapter interface definitions

The codebase has been refactored to remove several interface definitions from the interface-adapters layer. Specifically, the Id, ModelBase, CreateUser, and User interfaces have been deleted. This suggests a simplification or restructuring of the interface adapters, potentially moving towards a different architectural pattern or reducing boilerplate.

src/interface-adapters/interfaces · medium confidence

Removed obsolete create-user use-case files

The CLI controller, HTTP controller, command object, event handler, request DTO, service, and associated test file for the create-user use case have all been deleted. This removes the existing implementation for creating users via HTTP and CLI, along with the related command and event handling logic.

src/modules/user/use-cases/create-user · high confidence

User repository refactored from TypeORM to Slonik with runtime validation

The user database layer has been migrated from a TypeORM-based implementation to a raw SQL approach using Slonik. The old \UserOrmEntity\ and \UserRepositoryInterface\ have been removed and replaced with a new \UserRepositoryPort\ and \UserRepository\ that utilize a database pool. Additionally, a Zod schema (\userSchema\) has been introduced to enforce runtime validation of user data, ensuring safety against database schema changes.

src/modules/user/database · medium confidence

Test coverage

Added end-to-end and load testing for user creation; Added end-to-end test coverage for user deletion; Added shared test step for API error validation; Added test infrastructure and utilities for user scenarios; Removed outdated end-to-end test for the root route.

Dependencies

Major dependency and framework upgrades

The project has been upgraded to NestJS v9 and TypeScript v4.7, with a broad set of dependency updates including the addition of GraphQL support via @nestjs/graphql and apollo-server, the migration from TypeORM to slonik for database operations, and the introduction of new libraries such as zod, env-var, and oxide.ts. Development tooling has also been updated, including Jest 28, ESLint 8, and dependency-cruiser for architecture validation.

(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 49 → 48 (-0.4)
  • Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 94 → 96 (+1.3)
  • Architecture 59 → 71 (+11.5)
  • Maturity 58 → 58 (+0.0)
  • Readiness 26 → 24 (-1.9)
  • Security 100 → 99 (-0.9)

Resolved (7)

  • Change coupling: create-user.http.controller.ts ↔ find-users.http.controller.ts (src/modules/user/commands/create-user/create-user.http.controller.ts)
  • 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
  • Scanner failed to run — not a clean result
  • Test reliability not included
  • dormant codebase — no living knowledge left to concentrate

New (15)

  • Coverage not measured — JavaScript/TypeScript suite
  • Dependency hygiene PARTLY measured — npm pinning read, dependency currency not (no committed lockfile, so no resolved version to grade)
  • Documentation: no installation or build instructions (README.md)
  • Documentation: no licence statement (README.md)
  • Documentation: no usage examples (README.md)
  • High IaC: WD-COMPOSE-0002 (docker/docker-compose.yml)
  • Inverted test pyramid
  • Medium IaC: WD-COMPOSE-0002 (docker/docker-compose.yml)
  • No ADRs found
  • No assertions: I try to create a user with invalid data (tests/user/create-user/create-user.e2e-spec.ts)
  • Scanner failed to run — not a clean result
  • Scanner failed to run — not a clean result
  • Test reliability not measured — JavaScript/TypeScript suite install refused the lockfile
  • Test suite cannot be installed from its own lockfile: the repository root
  • TodoComment (src/libs/db/sql-repository.base.ts)

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

Survey your own repository

Sairyss/domain-driven-hexagon 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 5c2d15a7e2d69e83dfddf28468ee9f30e02c30de — 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-b84573e22831.