Skip to content
CAI
Software that uses CAICheck a score

marcoturi/fastify-boilerplate

69.1

Adequate · 21 September 2026

2.5k

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 Node.js-based API service that manages user lifecycles through a CQRS architecture, supporting user creation, deletion, and paginated filtering. It exposes REST and GraphQL endpoints with strict validation, OpenTelemetry tracing, and automated client type generation. The backend relies on a PostgreSQL database with configurable TLS and connection pooling, ensuring data consistency via domain events and transactional integrity.

Features

Added automated client type generation scripts

New scripts have been added to automate the generation of REST and GraphQL client types. The shell script \scripts/generate-types.sh\ starts the local server, waits for it to become healthy, and then invokes \openapi-typescript\ for REST types and \graphql-codegen\ for GraphQL types, before cleaning up the server process. The accompanying \scripts/codegen.ts\ file provides the configuration for the GraphQL code generator, pointing to the local schema endpoint and outputting TypeScript definitions to \./client/graphql.ts\.

scripts · high confidence

CQRS buses gain OpenTelemetry tracing, ordered event processing, and stricter typing

The CQRS layer now includes OpenTelemetry tracing middleware for commands, queries, and events, wrapping each execution in a span that records action type, bus kind, and correlation ID. The event bus supports ordered per-key processing via a \keyExtractor\ option, ensuring events with the same key are handled sequentially while different keys run concurrently, and isolates async handler failures by logging them instead of rejecting. A new \queryBus\ implementation is introduced alongside the existing command and event buses, and the \EventPublisher\ port allows domain aggregates to publish events via \DomainResult.commit()\. Action types are now strictly branded with phantom symbols to prevent plain-object misuse, and the \actionCreatorFactory\ returns actions with a typed \Result\ parameter. Metadata injection no longer mutates the original action, and execution time logging is lowered to debug level to avoid PII exposure.

src/shared/cqrs · high confidence

OpenTelemetry integration and native ESM migration

The application now includes OpenTelemetry instrumentation for HTTP and Fastify requests, with correlation IDs attached to all log lines and graceful shutdown flushing of telemetry data. The codebase has migrated to native ESM, replacing the previous JSON Schema type provider with TypeBox, and updated the server startup logic to use native process signal handling for graceful shutdown instead of the external graceful-server package.

src · high confidence

Behavioural changes

API error schema expanded and validation constraints tightened

The shared API error response schema now includes a structured array of field-level validation errors (subErrors) instead of a single optional string, providing detailed paths and messages for 400 validation failures. Additionally, the minimum value for the 'limit' query parameter in paginated requests has been increased from 0 to 1, and UUID fields now explicitly specify the 'uuid' format. These changes are supported by a migration from the scoped '@sinclair/typebox' package to the unscoped 'typebox' package.

src/shared/api · high confidence

Add paginated filtered user listing and fix identifier interpolation

Users can now retrieve a paginated, filtered list of users via the new findAllPaginatedFiltered method, supporting filtering by country, street, and postal code. Additionally, the findOneByEmail query now correctly uses identifier interpolation for the table name, ensuring safer and more robust SQL generation.

src/modules/user/database · high confidence

Configurable database TLS and connection pool settings

The application now exposes environment variables to control database security and performance: POSTGRES\_SSL enables TLS for production connections, while POSTGRES\_POOL\_MAX, POSTGRES\_IDLE\_TIMEOUT, and POSTGRES\_CONNECT\_TIMEOUT allow tuning of the connection pool behavior. Additionally, the PORT environment variable now defaults to 3000 if not specified.

src/config · high confidence

Configurable database connections, transaction support, and repository updates

The database layer now supports configurable TLS and connection pool settings via environment variables, with connections created lazily to optimize resource usage. A new \withTransaction\ helper allows executing queries within a database transaction, ensuring atomicity for complex operations. The base SQL repository has been extended with an \update\ method to modify existing records, and pagination now returns an accurate total count from the database rather than the size of the returned page. Additionally, strict typing has been applied throughout the repository and connection logic, removing unsafe \any\ casts and improving error handling.

src/shared/db · high confidence

Dependency injection container updated for ESM and native Node.js paths

The server's dependency injection setup now supports ESM modules by enabling the \esModules\ option in Awilix and switching from \\_\_dirname\ to \import.meta.dirname\ for resolving module paths. The module loading patterns have been expanded to include both \.js\ and \.ts\ extensions, and the \formatName\ utility now uses a more robust regex to split filenames. Additionally, the test suite for this module has been migrated from Vitest to Node's native test runner.

src/server/di · high confidence

Migrate to Node 24, pnpm, and Biome with native TypeScript execution

The project now requires Node.js 24 and uses pnpm instead of Yarn, enabling native TypeScript execution without a build step. ESLint and Prettier have been replaced by Biome for linting and formatting, and Vitest has been removed in favor of Node's built-in test runner. Configuration files for the previous tooling (\.eslintrc.js\, \.prettierrc.json\, \vitest.config.js\, \cucumber.setup.js\) have been deleted, and the \tsconfig.json\ has been updated to support ESM and stricter type checking.

(repo-wide) · high confidence

Migrate to TypeScript-native imports and refine error logging and API documentation

The server plugins now use native TypeScript imports (explicit .ts extensions and import type) and resolve paths via import.meta.dirname to support the production build. Error handling behavior changes so that 4xx domain errors are logged at warn level instead of error, reducing alert noise, while 5xx errors remain logged as errors. Additionally, the Swagger/OpenAPI documentation is enhanced to globally document shared 4xx and 5xx error response schemas for all routes, improving client type generation and API clarity.

src/server/plugins · high confidence

Refactor exception hierarchy and add ProviderErrorException

The exception module has been refactored to use native TypeScript import paths (adding .ts extensions) and the base ExceptionBase class now explicitly exposes cause and metadata properties. A new ProviderErrorException class has been added to handle provider-specific errors, reusing the internal server error status code and message structure. Additionally, the DatabaseErrorException class now explicitly sets its status code to 500 and properly passes the cause to the parent constructor, correcting previous inconsistencies where it might have inherited incorrect defaults.

src/shared/exceptions · high confidence

Server startup order, route loading, and health check improvements

The server now registers security middleware (Helmet and CORS) before GraphQL, ensuring that security headers and CORS policies apply globally to all endpoints, including GraphQL. Route auto-loading has been updated to use ESM-compatible path resolution (\import.meta.dirname\) and a more robust regex filter for \.route.ts\ and \.resolver.ts\ files, fixing issues with route discovery. Additionally, the UnderPressure plugin is now configured with a custom \/health\ endpoint and a silent log level, providing a dedicated health check route without cluttering logs.

src/server · high confidence

Settings creation now logs only user ID instead of full event payload

The event handler for creating default user settings has been updated to prevent logging personally identifiable information (PII). Previously, the entire user creation event (including email and address) was logged; it now logs only the user ID, reducing privacy risks while still tracking the creation action.

src/modules/settings · high confidence

Simplified user deletion logic and explicit 404 error handling

The user deletion command no longer emits a domain event, and the route now explicitly declares a 404 response in the API schema when a user is not found, providing clearer error feedback to clients instead of relying solely on implicit error propagation.

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

Switch from npm/yarn to pnpm and replace lint-staged with Biome

The project's pre-commit and commit-msg hooks have been updated to use pnpm instead of npx/npm for running scripts, and lint-staged has been removed in favor of Biome for pre-commit checks. Users will now see faster hook execution times due to pnpm's efficiency and Biome's integrated linting/formatting, while the commit message validation remains handled by commitlint.

.husky · high confidence

User creation now returns HTTP 201 and publishes domain events via commit()

The Create User API endpoint now returns a 201 Created status code instead of 200, with explicit 409 conflict handling in the route schema. Internally, the command handler uses the domain entity's commit() method to publish events only after the database write succeeds, ensuring consistency. The action creator and handler types have been updated to reflect the result type, and import paths have been standardized to use the \#src alias with .ts extensions.

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

User domain now emits domain events on creation

The user creation process in the domain layer now records a 'user/created' domain event alongside the new user entity. This change shifts the responsibility of event publishing to the command handler (which persists the user and then publishes the event), ensuring the domain layer remains decoupled from infrastructure concerns. Additionally, the UserRoles definition was refactored from a TypeScript enum to a const object pattern for better type safety.

src/modules/user/domain · high confidence

User query handling refactored with mapper integration and schema updates

The user listing endpoint now uses a dedicated user mapper to transform database entities into response objects, ensuring consistent data formatting. The underlying query handler has been simplified to rely on a repository method for paginated filtering, removing direct SQL construction. Additionally, the response schema now includes a new 'role' field (admin, moderator, guest), and request validation patterns for country and street fields have been corrected to remove unnecessary regex delimiters.

src/modules/user/queries · high confidence

Users table schema update and performance indexing

The users table now uses UUIDs for the primary key instead of variable-length strings, and constraints have been renamed to more readable identifiers. Additionally, new indexes have been added on the country, postalCode, and street columns to optimize query performance for filtered paginated searches as the dataset grows.

db · high confidence

Test coverage

Migrate user tests from Artillery to k6 and update Cucumber step definitions; Test support infrastructure modernization and isolation.

Dependencies

Updated project dependencies

This release updates the project's dependency manifests, including upgrades to the package manager (yarn to pnpm), the Node.js type definitions (@types/node), and various development tools such as ESLint, TypeScript, and semantic-release.

(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

This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.

Score

  • CAI 65 → 69 (+3.8)
  • Rubric changed (rubric-2026.08.19 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 66 → 70 (+4.4)
  • Architecture 100 → 96 (-4.3)
  • Maturity 63 → 65 (+2.3)
  • Readiness 62 → 69 (+7.2)
  • Security 63 → 75 (+11.8)

Resolved (22)

  • Coverage not included — suite not readable by the collector
  • Dependency hygiene not measured — dependency manifest found but not parsed for hygiene
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Medium CVE: [GHSA redacted] (pnpm-lock.yaml)
  • No exposed public API
  • Off-boarding risk: anonymized user #1
  • Test reliability not included
  • …and 2 more

New (31)

  • Documentation: no installation or build instructions (README.md)
  • Documentation: no usage examples (README.md)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Job token omits the contents scope its checkout needs
  • Medium CVE: [GHSA redacted] (pnpm-lock.yaml)
  • Medium IaC: WD-COMPOSE-0002 (docker-compose.yml)
  • …and 11 more

Changes since last survey

  • 104 commits — 70 feature/other, 34 fixes

By area

  • (root) — 104 commits

Notable commits

  • fix: fix(deps): update dependency @fastify/awilix to v8.2.1 (#1092)
  • fix: fix(deps): update dependency @fastify/helmet to v13.1.1 (#1107)
  • fix: fix(deps): update dependency @fastify/otel to v0.21.0 (#1134)
  • fix: fix(deps): update dependency @graphql-tools/merge to v9.2.3 (#1098)
  • fix: fix(deps): update dependency @graphql-tools/merge to v9.2.4 (#1135)
  • fix: fix(deps): update dependency fastify to v5.11.2 (#1080)
  • fix: fix(deps): update dependency fastify to v5.11.3 (#1090)
  • fix: fix(deps): update dependency fastify to v5.12.0 (#1100)
  • fix: fix(deps): update dependency fastify to v5.12.1 (#1106)
  • fix: fix(deps): update dependency fastify to v5.12.3 (#1131)
  • fix: fix(deps): update dependency fastify to v5.12.4 (#1143)
  • fix: fix(deps): update dependency fastify to v5.12.5 (#1152)
  • fix: fix(deps): update dependency typebox to v1.3.10 (#1079)
  • fix: fix(deps): update dependency typebox to v1.3.11 (#1087)
  • fix: fix(deps): update dependency typebox to v1.3.12 (#1094)
  • fix: fix(deps): update dependency typebox to v1.3.13 (#1097)
  • fix: fix(deps): update dependency typebox to v1.3.14 (#1101)
  • fix: fix(deps): update dependency typebox to v1.3.15 (#1103)
  • fix: fix(deps): update dependency typebox to v1.3.16 (#1108)
  • fix: fix(deps): update dependency typebox to v1.3.17 (#1112)
  • …and 84 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

marcoturi/fastify-boilerplate 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 fb6b37c5ca0212d878003241560d15f0d7a7f4e4 — 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.