Skip to content
CAI
Software that uses CAICheck a score

kgrzybek/sample-dotnet-core-cqrs-api

65.2

Adequate · 21 September 2026

4k

lines of production code

C#

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is an e-commerce platform that manages customers, products, and orders with support for multi-currency pricing and foreign exchange conversion. It enforces business rules through a domain-driven design, utilizing typed identifiers, aggregates, and a structured event notification system for eventual consistency. The architecture separates concerns across API, application, domain, and infrastructure layers, incorporating features like email notifications, in-memory caching, and an outbox pattern for reliable message processing.

How it got here

2019 — Domain model and infrastructure modernization

18 changes.

This period focused on modernizing the codebase by upgrading to .NET Core 3.1 and implementing strong typing for domain identifiers. The team introduced new domain models for payments, products, and foreign exchange, while simultaneously enhancing the infrastructure with structured logging, caching, and email services.

2020 — Application layer restructuring and domain event infrastructure

7 changes.

This period focused on consolidating business logic into the Application layer, introducing a domain event notification system, and implementing the outbox pattern for reliable event publishing. The work also included restructuring the database access and domain layers to support these new capabilities, accompanied by comprehensive integration and unit tests.

Features

Add support for strongly-typed entity IDs in Entity Framework Core

The application now supports strongly-typed ID value converters for Entity Framework Core. This change introduces a generic \TypedIdValueConverter\ and a \StronglyTypedIdValueConverterSelector\ that automatically maps custom ID types inheriting from \TypedIdValueBase\ to \Guid\ in the database. Additionally, a new \DbSetExtensions\ class provides an \IncludePaths\ method to simplify loading related entities via string-based navigation paths. These changes enable more type-safe entity identification and improved database query composition.

src/SampleProject.Infrastructure/SeedWork · high confidence

Added request correlation, structured logging, and API documentation

Requests are now tracked with a unique correlation ID header for better observability. Structured logging via Serilog is enabled, writing JSON-formatted logs to the console and rolling files. Swagger UI is added to the development environment to expose the API documentation. Additionally, the application now uses the Problem Details middleware to return standardized error responses in non-development environments.

src/SampleProject.API · high confidence

Adds outbox pattern and command processing infrastructure

The application now supports an outbox pattern for reliable event publishing and internal command processing. New files in src/SampleProject.Infrastructure/Processing introduce OutboxMessage, ProcessOutboxCommand, and ProcessInternalCommands components, enabling scheduled jobs to process domain events and internal commands via MediatR. The DomainEventsDispatcher was refactored to persist events to the outbox table instead of returning them directly, and the MediatorModule was updated to register validation behaviors and use a custom constructor finder.

src/SampleProject.Infrastructure/Processing · high confidence

Introduce Foreign Exchange domain for currency conversion

The domain now includes a new Foreign Exchange module containing a ConversionRate class that holds source/target currency pairs and a conversion factor, along with an IForeignExchange interface to retrieve a list of these rates. This provides the foundational types for converting MoneyValue amounts between currencies.

src/SampleProject.Domain/ForeignExchange · high confidence

Introduce domain event notification infrastructure

The application layer now includes a new domain event notification system, introducing a base class and interfaces for handling domain events. Specific notification handlers have been added for Customer, Order, and Payment events, enabling the application to process and react to these domain events through a structured notification mechanism.

SampleProject.Application · high confidence

Introduce email sending infrastructure

The application now includes an email sending implementation in the infrastructure layer. This adds an \EmailSender\ class that handles sending email messages, along with an Autofac \EmailModule\ to register the email sender and configuration settings. This provides the underlying mechanism for sending emails, with a mock sender available for testing purposes.

src/SampleProject.Infrastructure/Emails · medium confidence

Introduce in-memory caching infrastructure

The application now includes a new caching layer in the Infrastructure project, providing a memory-based cache store. This introduces a cache-aside pattern with a generic ICacheStore interface and a MemoryCacheStore implementation that supports time-based and absolute expiration policies. Consumers can now store and retrieve typed objects from an in-memory cache, with expiration durations configurable per item type.

src/SampleProject.Infrastructure/Caching · high confidence

Introduce payment domain model and repository interface

Added the foundational domain model for the Payments module, including the Payment aggregate root, a typed PaymentId value object, and the IPaymentRepository interface for data access. The PaymentStatus enum defines the lifecycle states (ToPay, Paid, Overdue).

src/SampleProject.Domain/Payments · medium confidence

Introduces SharedKernel domain primitives for money and time

The domain layer now includes a MoneyValue value object that enforces currency consistency for arithmetic operations, along with business rules to prevent mismatched currency calculations. A SystemClock abstraction is also added to provide a testable, mockable source of the current UTC time, allowing tests to control the system clock.

src/SampleProject.Domain/SharedKernel · high confidence

Support for multiple product prices and customer registration

The system now supports multiple prices per product, introducing a new \ProductPrices\ table and \ProductPrice\ entity to store currency-specific pricing. Additionally, a new \CustomersController\ exposes a \RegisterCustomer\ endpoint, backed by a \RegisterCustomerCommand\ and Mediator, allowing users to register new customers. The database schema is updated to include an \app.OutboxMessages\ table for eventual consistency processing, and the solution structure is expanded to include separate projects for Application logic and integration tests.

src · high confidence

Behavioural changes

Customer registration and profile retrieval

The application layer now includes the full implementation for customer management: a command to register new customers (including uniqueness checks), a query to retrieve customer details (id, name, email, and welcome status), and an integration handler that marks a customer as welcomed after registration. A new CustomerDto is introduced to represent customer data, and the previous ProductDto has been repurposed and renamed to CustomerDetailsDto to support the new query.

src/SampleProject.Application/Customers · high confidence

Database access layer restructured with new context and repository registrations

The database access configuration has been reorganized into the new 'Database' namespace, introducing an 'OrdersContext' that maps Customer, Product, Payment, and Outbox entities. The previous 'InfrastructureModule' has been renamed to 'DataAccessModule' and now registers repositories for customers, products, and payments, along with a singleton 'StronglyTypedIdValueConverterSelector' for EF Core value conversions. Additionally, schema names for 'orders', 'app', and 'payments' are now explicitly defined in 'SchemaNames.cs'.

src/SampleProject.Infrastructure/Database · medium confidence

Domain model now enforces business rules via a new validation exception

The domain layer now includes a structured way to enforce business rules. A new BusinessRuleValidationException and IBusinessRule interface allow domain entities to validate conditions and throw a specific exception when a rule is broken. The abstract ValueObject and Entity base classes now include a CheckRule helper method that triggers this exception, ensuring that domain invariants are checked consistently across the model.

src/SampleProject.Domain/SeedWork · high confidence

Domain model refactoring: typed IDs, new aggregates, and event updates

The domain model has been refactored to use typed IDs (e.g., OrderId, CustomerId) instead of raw Guids, improving type safety. New aggregates for Payment and Product have been introduced, alongside updated domain events (OrderPlacedEvent, PaymentCreatedEvent) and a renamed event (CustomerRegisteredEvent). The Customer aggregate now enforces business rules via a uniqueness checker and handles order placement with eventual consistency support.

SampleProject.Domain · medium confidence

Infrastructure layer restructured with new domain services and persistence mappings

The infrastructure layer has been reorganized to separate domain concerns, introducing new entity type configurations for Customers, Payments, and Products that define database mappings and relationships. A new DomainModule registers the CustomerUniquenessChecker and ForeignExchange services, while the ForeignExchange implementation now caches conversion rates. Repository classes for Customers and Products have been moved to the Domain subdirectory and updated to use the new configuration constants, and a UnitOfWork class has been added to handle transaction commits and domain event dispatching.

src/SampleProject.Infrastructure/Domain · high confidence

Introduce multi-currency order support with automatic EUR conversion

Orders now track line items in their original currency and automatically calculate the total value in EUR using provided conversion rates. The Order entity now stores both the primary currency value and a converted EUR value, enabling consistent financial reporting across different currencies.

src/SampleProject.Domain/Customers/Orders · high confidence

Introduce typed customer identifier and uniqueness check

The Customer entity now uses a dedicated CustomerId type for its identifier, and a new ICustomerUniquenessChecker interface has been added to validate that a customer's email is unique.

src/SampleProject.Domain/Customers · high confidence

Introduce typed identifiers and repository interface for Products

The Products domain is reorganized with new files: ProductId (a typed ID value object), ProductPrice, and ProductPriceData. The IProductRepository interface is moved from the Customers/Orders folder to the Products folder and gains a new method, GetByIdsAsync, to retrieve multiple products by their IDs.

src/SampleProject.Domain/Products · high confidence

Migrate order management commands and queries to the Application layer

The application layer now owns the core order management logic, including placing, changing, removing, and retrieving customer orders. This change introduces a new command/query infrastructure (base classes, handlers, validators) and moves the specific handlers and DTOs from the API layer into the Application layer, enabling better separation of concerns and consistent handling of order-related business rules.

src/SampleProject.Application/Orders · high confidence

Orders now support currency specification

The CustomerOrderRequest model now includes a Currency field, allowing users to specify the currency for an order. This change updates the API layer to pass the currency information to the underlying application commands (PlaceCustomerOrderCommand and ChangeCustomerOrderCommand), ensuring that the currency is propagated through the system.

src/SampleProject.API/Orders · medium confidence

Removal of legacy EF Core mapping for Customer and Order aggregates

The Entity Framework Core configuration classes and the \OrdersContext\ implementation for the Orders module have been removed. This eliminates the previous database mapping for \Customer\ and \Order\ aggregates, indicating a shift away from this specific infrastructure implementation for these domain entities.

src/SampleProject.Infrastructure/Orders · high confidence

Removed order command handlers

The command handlers for adding and changing customer orders have been removed from the API layer. This change eliminates the direct handling of these specific order commands, likely as part of a broader refactoring of the order management workflow.

src/SampleProject.API/Orders/AddCustomerOrder · high confidence

Structured error responses for validation and business rule failures

The API layer now returns standardized ProblemDetails for two distinct failure modes: a 400 Bad Request for invalid commands and a 409 Conflict for business rule violations. This provides users with consistent, structured error responses that include specific titles, status codes, and detailed messages, replacing previous error handling mechanisms.

src/SampleProject.API/SeedWork · high confidence

Test coverage

Added integration and unit tests for customer, order, and payment workflows

Added new integration tests for customer registration, order placement, and payment creation, along with unit tests for customer registration, order placement, and the MoneyValue value object. The test suite now covers end-to-end scenarios including outbox message verification and domain event assertions, improving confidence in the reliability of core business processes.

src/Tests · high confidence

Dependencies

Upgrade to .NET Core 3.1 and update key dependencies

The project has been upgraded from .NET Core 2.2 to 3.1 across all components, including the API, Application, Domain, and Infrastructure layers. This migration includes updating the C\# language version to 7.2. Several libraries have been upgraded to newer versions to support this transition and add new capabilities: MediatR was upgraded from 6.0.0 to 8.0.0, Dapper from 1.50.5 to 2.0.30, and Microsoft.EntityFrameworkCore from 2.2.1 to 3.1.0. Additionally, new dependencies were added to support the outbox pattern and logging, including Quartz (3.0.7) for background processing, Serilog for structured logging, and FluentValidation for command validation.

(dependencies) · medium 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 64 → 65 (+1.0)
  • Rubric changed (rubric-2026.08.18 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 62 → 57 (-4.9)
  • Architecture 86 → 86 (+0.0)
  • Maturity 68 → 68 (+0.0)
  • Readiness 75 → 85 (+10.0)
  • Security 59 → 65 (+5.8)
  • Domain Modelling 76 → 88 (+11.7)
  • Event-Driven 100 → 100 (+0.0)

Resolved (12)

  • High CVE: Microsoft.NETCore.App 1.0.5
  • High CVE: Microsoft.NETCore.App 1.0.5
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Medium CVE: Microsoft.Data.SqlClient 1.0.19269.1
  • Medium CVE: System.Data.SqlClient 4.5.1
  • No exposed public API
  • Test runner surfaced no tests
  • The README describes the project but gives no instructions on how to run the application or integration tests. (README.md)
  • dormant codebase — no living knowledge left to concentrate
  • misleading comment (src/SampleProject.Application/Customers/IntegrationHandlers/CustomerRegisteredNotificationHandler.cs)
  • misleading comment (src/SampleProject.Domain/Payments/Payment.cs)

New (25)

  • Documentation: no installation or build instructions (README.md)
  • Documentation: no licence statement (README.md)
  • Documentation: no usage examples (README.md)
  • End-of-life runtime: .NET netcoreapp3.1
  • High CVE: Microsoft.NETCore.App 1.0.5
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Medium: security finding (details withheld)
  • Medium: security finding (details withheld)
  • Medium: security finding (details withheld)
  • No dependency advisory monitoring
  • The MemoryCacheStore implementation uses System.DateTime? for the expiration parameter, while the test helper CacheStore uses System.TimeSpan?. Although the parameter types differ, the semantic concept (expiration time/duration) is represented inconsistently across the production code and its test infrastructure.
  • Workflow token permissions not restricted
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Customer.cs)
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Customer.cs)
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Customer.cs)
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Orders/Order.cs)
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Orders/Order.cs)
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Orders/Order.cs)
  • WriteOnlyPrivateField (src/SampleProject.Domain/Customers/Orders/Order.cs)
  • …and 5 more

API surface

  • Unchanged — 4 HTTP endpoints

Architecture

  • Unchanged — 2 containers · 2 contexts · 1 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

kgrzybek/sample-dotnet-core-cqrs-api 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 2f00e194e72e9288dddd69af499fc97920cba86e — 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.