Sairyss/domain-driven-hexagon
48.4
Weak · 21 September 2026
3k
lines of production code
TypeScript
with JavaScript
4
measurements over time
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
Removed UserEntity class and related value objects
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.