ardalis/CleanArchitecture
71.3
Strong · 5 August 2026
1.4k
lines of production code
C#
with JavaScript
4
measurements over time
What this system is
This system is a .NET 10-based application template implementing Clean Architecture with a Vertical Slice and CQRS structure. It provides a complete, functional example of a domain-driven design, featuring aggregates for Contributors and Projects with associated to-do items. The architecture includes a web API layer using FastEndpoints, an infrastructure layer with Entity Framework Core and email services, and a comprehensive test suite covering unit, integration, and functional scenarios.
How it got here
2016–2023 — Modernization and domain expansion
51 changes.
The codebase was modernized by upgrading to .NET 10, adopting FastEndpoints, and implementing domain-driven design patterns such as value objects and domain events. This period also involved expanding the application's domain model to include a full Contributor aggregate and Project management features, supported by comprehensive unit, integration, and functional tests.
2024–2025 — Aspire orchestration and .NET 10 migration
9 changes.
The project modernized its infrastructure by migrating to .NET 10 and integrating .NET Aspire for application orchestration and service defaults. This period also involved refactoring startup logic into modular configuration classes and establishing a new Minimal Clean Architecture template with Vertical Slice Architecture.
Features
Add Contributors API endpoints with FastEndpoints
The sample application now exposes a full CRUD API for managing contributors. This includes endpoints to create, retrieve by ID, list (with pagination and Link headers), update, and delete contributors. The implementation uses the FastEndpoints framework, featuring explicit request/response models, FluentValidation validators, and a new \ResultExtensions\ helper to map internal \Ardalis.Result\ outcomes to standard HTTP status codes (e.g., 201 Created, 404 Not Found).
sample/src/NimblePros.SampleToDo.Web/Contributors · high confidence
Add DeleteContributorService domain service
A new domain service, DeleteContributorService, has been added to handle the deletion of a contributor. This service retrieves the contributor by ID, deletes it from the repository, and publishes a ContributorDeletedEvent via the mediator, demonstrating how to fire domain events from a service.
src/Clean.Architecture.Core/Services · high confidence
Add Minimal Clean Architecture template with VSA structure
The MinimalClean area now includes a complete template for a single-project Vertical Slice Architecture (VSA) following Clean Architecture principles. This includes an .editorconfig for consistent C\# and VB.NET coding conventions, a .gitignore for Visual Studio and .NET build artifacts, a .runsettings file to enable parallel test execution, a global.json pinning the .NET 10.0.100 SDK, a nuget.config for package management, and a Directory.Build.props file that sets the target framework to net10.0 with nullable and implicit usings enabled. The template also provides a README.template.md with usage instructions and a solution file (MinimalClean.Architecture.slnx) that organizes the Web project and Aspire host projects.
MinimalClean · high confidence
Add contributor listing query services
Introduced two new query services for listing contributors: a production implementation using Entity Framework Core with raw SQL for efficient data retrieval, and a fake implementation for testing or development. Both services return a paged result of contributor DTOs, including their phone numbers.
src/Clean.Architecture.Infrastructure/Data/Queries · high confidence
Added EF Core configuration for Contributor entity
New configuration files have been added to define the database mapping for the Contributor entity. This includes a ContributorConfiguration class that specifies property mappings, value generation, and ownership of the PhoneNumber component, alongside a VogenEfCoreConverters class to handle Entity Framework Core conversions for the ContributorId and ContributorName value objects.
src/Clean.Architecture.Infrastructure/Data/Config · high confidence
Added contributor update use case
Introduced the UpdateContributorCommand and its corresponding handler to support updating a contributor's name. The handler retrieves the existing contributor, updates their name, and returns the updated data as a ContributorDto, handling the case where the contributor is not found.
src/Clean.Architecture.UseCases/Contributors/Update · high confidence
Added new core services for deleting contributors and searching to-do items
The sample application now includes two new services in the core layer: DeleteContributorService, which handles the deletion of a contributor by removing the aggregate and publishing a domain event, and ToDoItemSearchService, which provides methods to retrieve incomplete to-do items for a project and fetch the next incomplete item. These services implement their respective interfaces and utilize the repository and mediator patterns to interact with the domain model.
sample/src/NimblePros.SampleToDo.Core/Services · high confidence
Added new service interfaces for contributor deletion and email sending
New interfaces have been introduced to support specific domain and infrastructure capabilities. IDeleteContributorService provides a contract for deleting a contributor, designed to fire domain events during the deletion process. IEmailSender defines the contract for sending emails asynchronously. These interfaces establish the core abstractions for these new functionalities within the application's architecture.
src/Clean.Architecture.Core/Interfaces · high confidence
Adds .editorconfig, runsettings, and solution structure for modern .NET development
The repository now includes an .editorconfig file that enforces .NET coding conventions, including C\# 10+ features like file-scoped namespaces, expression-bodied members, and nullability. A .runsettings file is added to enable parallel test execution across all test projects. The solution is now managed via a .slnx file that explicitly defines the project hierarchy, including Aspire host projects and test dependencies. Additionally, a global.json file pins the .NET SDK to version 10.0.100, and the Directory.Build.props file centralizes MSBuild properties such as central package management and target framework.
(repo-wide) · high confidence
Aspire orchestration and service defaults added
The solution now includes an Aspire host project that orchestrates the application and its dependencies, including a SQL Server container and a Papercut SMTP container for email testing. The host automatically provides the database connection string to the Web application. Additionally, a new ServiceDefaults project has been added to configure common .NET Aspire services, including service discovery, resilience, health checks, and OpenTelemetry instrumentation.
src/Clean.Architecture.AspireHost, src/Clean.Architecture.ServiceDefaults · high confidence
Contributor API endpoints implemented with FastEndpoints
The Contributors area now exposes full CRUD operations (Create, Read, Update, Delete, and List) using the FastEndpoints framework. Each endpoint is implemented as a dedicated class (e.g., Create.cs, GetById.cs, Update.cs, Delete.cs, List.cs) with associated request/response models, validators, and mappers. The List endpoint includes pagination support with link headers, and all endpoints are configured with Swagger documentation and OpenAPI metadata.
src/Clean.Architecture.Web/Contributors · high confidence
Introduce Aspire host and sample application scaffolding
The sample application now includes an Aspire host project (NimblePros.SampleToDo.AspireHost) that orchestrates the web service and a Papercut container for email testing. The web project (NimblePros.SampleToDo.Web) has been scaffolded with a new Program.cs that registers FastEndpoints, FluentValidation, Serilog, and JSON-based localization, alongside in-memory caching and Metronome for telemetry. A CachingBehavior pipeline behavior and a LoggingBehavior are added to demonstrate request handling patterns. Additionally, a SeedData class populates the database with sample contributors, projects, and to-do items, and an api.http file is provided for local API testing.
sample/src/NimblePros.SampleToDo.Web · high confidence
Introduce CQRS-based contributor use cases
The sample application now implements a CQRS (Command Query Responsibility Segregation) architecture for managing contributors. This adds new command handlers for creating, updating, and deleting contributors, as well as query handlers for retrieving a single contributor or listing all contributors with pagination. The changes include new command and query classes, their respective handlers, and a DTO for contributor data, enabling a more structured and testable approach to handling contributor operations in the sample app.
sample/src/NimblePros.SampleToDo.UseCases/Contributors · high confidence
Introduce Contributor aggregate with value objects and domain events
The Contributor aggregate is introduced, defining the core entity alongside supporting value objects for the contributor's name, ID, and phone number. The Contributor entity now exposes methods to update the name and phone number, which trigger corresponding domain events (ContributorNameUpdatedEvent, ContributorDeletedEvent) to notify subscribers of state changes. This establishes the foundational data model and event-driven behavior for managing contributors within the system.
src/Clean.Architecture.Core/ContributorAggregate · high confidence
Introduce cart and checkout domain models and API endpoints
Added domain models for Cart, CartItem, Order, OrderItem, and GuestUser, along with their respective ID types and specifications. Implemented API endpoints for adding items to a cart, retrieving a cart by ID, and checking out a cart to create an order. The implementation includes handlers for these features, mappers for DTOs, and configuration for database seeding and migrations. Additionally, added Aspire host configuration for local development with SQL Server and Papercut SMTP containers, and service defaults for health checks and OpenTelemetry.
MinimalClean/src · high confidence
Introduce domain models and validation for the Project aggregate
The Project aggregate now includes domain models for managing to-do items, including the Project, ToDoItem, and associated value objects (ProjectId, ProjectName, ToDoItemTitle, ToDoItemDescription, Priority, ProjectStatus). The change introduces a strongly-typed, localizable error message system (ProjectErrorMessages) that validates title and description lengths, and registers domain events (NewItemAdded, ToDoItemCompleted, ContributorAddedToItem) when items are created or completed.
sample/src/NimblePros.SampleToDo.Core/ProjectAggregate · high confidence
Introduce email sending infrastructure with configuration and implementations
Added new email infrastructure components including a FakeEmailSender for testing, a MailserverConfiguration class for SMTP settings, and a MimeKitEmailSender that connects asynchronously to the mail server. The implementation uses IOptions\<MailserverConfiguration\> to read hostname and port settings, and leverages MailKit's async API for sending emails.
src/Clean.Architecture.Infrastructure/Email · high confidence
Introduces Contributor domain model with value objects and domain events
The Contributor aggregate root is introduced, featuring a ContributorName value object that enforces non-empty and length constraints, and a ContributorId value object that ensures positive integers. The Contributor entity now exposes an UpdateName method that validates the new name and publishes a ContributorNameUpdatedEvent domain event. Additionally, a ContributorDeletedEvent is added to track deletion occurrences.
sample/src/NimblePros.SampleToDo.Core/ContributorAggregate · high confidence
Introduces core use-case abstractions and pagination support
The UseCases project now includes foundational types for application-layer logic: a Constants class defining default and maximum page sizes, a PagedResult record for standard pagination metadata, and an ICacheable interface to mark cacheable operations. Global usings streamline imports for Mediator, Ardalis.Result, and the shared kernel, while a README explains the role of the UseCases layer in the architecture.
sample/src/NimblePros.SampleToDo.UseCases · high confidence
New Projects API endpoints in the sample application
The sample application now exposes a complete set of RESTful endpoints for managing projects and their associated to-do items. Users can create, read, update, and delete projects, as well as create, list, and mark to-do items as complete. The API supports pagination for listing projects and includes validation for input data. This provides a functional interface for interacting with the project management features of the sample app.
sample/src/NimblePros.SampleToDo.Web/Projects · high confidence
New project management use cases in the sample app
The sample application now includes a complete set of use cases for managing projects and their to-do items. Users can create, update, and delete projects, as well as add, list, and mark to-do items as complete. The implementation follows a consistent command/query pattern, utilizing repository interfaces for data access and returning structured DTOs for project and item details.
sample/src/NimblePros.SampleToDo.UseCases/Projects · high confidence
Behavioural changes
Add Create and Get Contributor use cases with primary constructor support
Introduced new use cases for creating and retrieving contributors. The Create flow now accepts an optional phone number, which is validated and stored via a new PhoneNumber value object. The Get flow returns contributor details including the phone number. Both use cases leverage C\# 12 primary constructors for cleaner dependency injection of the repository, and the handler implementations follow the new command/query pattern without MediatR.
src/Clean.Architecture.UseCases/Contributors/Create · high confidence
Add Vogen value object converters and entity configurations
The sample application now supports Value Objects via Vogen. New configuration files define how entities (Contributor, Project, ToDoItem) map to the database, using custom EF Core converters to handle Vogen value types. A new class registers these converters for all relevant value types, ensuring consistent database schema generation for the sample app.
sample/src/NimblePros.SampleToDo.Infrastructure/Data/Config · high confidence
Added Bootstrap 5.1.0 grid CSS and site styles
The sample application now includes the Bootstrap 5.1.0 grid CSS (bootstrap-grid.css) and its source map, along with a new site.css for base HTML/body styling and a placeholder site.js. These static assets provide the underlying grid and layout classes for the web interface.
sample/src/NimblePros.SampleToDo.Web/wwwroot · high confidence
Added CQRS query services for listing contributors, incomplete items, and projects
The sample application now includes concrete implementations of the CQRS query pattern for three read operations: listing contributors, listing incomplete to-do items, and listing projects. Each query has a real implementation that queries the database via Entity Framework Core, alongside a corresponding fake implementation that returns mock data. These services implement the interfaces defined in the UseCases layer, enabling the application to retrieve data for these specific features.
sample/src/NimblePros.SampleToDo.Infrastructure/Data/Queries · high confidence
Added email notification handlers for contributor lifecycle events
New handlers have been introduced to send email notifications when a contributor is deleted or when their name is updated. These handlers, located in the ContributorAggregate/Handlers directory, implement the INotificationHandler interface for ContributorDeletedEvent and ContributorNameUpdatedEvent respectively, utilizing the IEmailSender interface to dispatch emails upon these specific domain events.
src/Clean.Architecture.Core/ContributorAggregate/Handlers · high confidence
Added event handlers for contributor deletion and name updates
The sample application now includes new domain event handlers in the ContributorAggregate. The ContributorDeletedHandler automatically removes a deleted contributor from all associated projects to maintain data consistency, while the ContributorNameUpdatedEventLoggingHandler logs updates to a contributor's name. These changes ensure that related project items are cleaned up and that name changes are audited via logging.
sample/src/NimblePros.SampleToDo.Core/ContributorAggregate/Handlers · medium confidence
Added logging and email notification handlers for project events
New handlers have been introduced in the ProjectAggregate to automatically log and notify on domain events. Specifically, ContributorAddedToItemLoggingHandler and NewItemAddedLoggingHandler now log information about new items and contributor assignments, while ItemCompletedEmailNotificationHandler sends an email notification when a to-do item is completed.
sample/src/NimblePros.SampleToDo.Core/ProjectAggregate/Handlers · high confidence
Added placeholder for wwwroot directory
A .gitkeep file was added to the wwwroot directory to ensure the folder is tracked by the version control system, allowing the directory structure to be preserved even when it is empty.
src/Clean.Architecture.Web/wwwroot · low confidence
Centralized application configuration into dedicated setup classes
The application startup logic in Program.cs has been refactored into five new configuration classes in the Configurations folder: LoggerConfigs for Serilog integration, MediatorConfig for MediatR source generation, MiddlewareConfig for HTTP middleware and database seeding, OptionConfigs for cookie and service diagnostics, and ServiceConfigs for infrastructure and email sender registration. This change organizes the web layer's setup into distinct, testable components, making the startup process more modular and easier to maintain.
src/Clean.Architecture.Web/Configurations · high confidence
Centralized configuration and service registration for the sample app
The sample application's startup logic has been refactored into a set of dedicated configuration classes within the \Configurations\ directory. A new \GlobalExceptionHandler\ provides structured JSON error responses, while \LoggerConfig\ integrates Serilog. Service registration is now handled by \ServiceConfigs\ and \MediatorConfig\, which sets up the Mediator pipeline with logging and caching behaviors. Additionally, \CachingOptions\ and \OptionConfigs\ manage application settings and dependency injection for features like email and cookies, while \MiddlewareConfig\ orchestrates the request pipeline, including database seeding and health checks.
sample/src/NimblePros.SampleToDo.Web/Configurations · high confidence
Centralizes infrastructure service registration and query implementations
The sample application's infrastructure layer now consolidates service registration into a single extension method, separating dependencies for development, testing, and production environments. This includes registering Entity Framework Core with SQLite, the domain event dispatcher interceptor, and specific query handlers (such as ListContributorsQueryService) alongside email senders and repositories. Global using directives are also introduced to simplify namespace imports across the project.
sample/src/NimblePros.SampleToDo.Infrastructure · medium confidence
Database schema updated for SQL Server identity columns and .NET 10 compatibility
The database schema has been updated to support SQL Server's IDENTITY columns for the Contributors table, ensuring that the Id column is auto-generated by the database rather than the application. This change includes a new migration that alters column types to use SQL Server-specific types (e.g., nvarchar, int) while leaving SQLite unchanged, and updates the model snapshot to reflect these structural changes for .NET 10 compatibility.
src/Clean.Architecture.Infrastructure/Data/Migrations · high confidence
Email sending implementation updated to use MimeKit
The sample application's email infrastructure now includes a new MimeKit-based implementation (MimeKitEmailSender) for sending emails, while the legacy SmtpEmailSender is marked as obsolete. A configuration class (MailserverConfiguration) and a fake sender for testing (FakeEmailSender) have also been added to the email infrastructure layer.
sample/src/NimblePros.SampleToDo.Infrastructure/Email · medium confidence
Implement DeleteContributor use case with primary constructor syntax
The DeleteContributorHandler and DeleteContributorCommand are introduced in the Clean.Architecture.UseCases.Contributors.Delete namespace. The command is a C\# record with a primary constructor, and the handler uses primary constructor injection for IDeleteContributorService, delegating to the service to perform the deletion. This reflects a shift toward using primary constructors for dependency injection in the application layer.
src/Clean.Architecture.UseCases/Contributors/Delete · high confidence
Implement domain event dispatching via EF Core interceptor
The application now automatically dispatches domain events after a database transaction is successfully saved. An \EventDispatchInterceptor\ is used to intercept \SaveChanges\ operations, ensuring that any pending domain events on tracked entities are processed immediately after the database commit. This replaces the previous synchronous \SaveChanges\ implementation with an async-aware approach that integrates with the domain event dispatcher.
src/Clean.Architecture.Infrastructure/Data · high confidence
Infrastructure project introduces centralized service registration and global usings
The Infrastructure layer now provides a dedicated \InfrastructureServiceExtensions\ class that registers all infrastructure services, including the \EventDispatchInterceptor\ for domain events, Entity Framework context configuration (supporting both SQL Server and SQLite), and repository implementations. Additionally, a \GlobalUsings.cs\ file consolidates common namespace imports across the project.
src/Clean.Architecture.Infrastructure · medium confidence
Introduce ContributorDto record with PhoneNumber
A new ContributorDto record has been added to the Contributors use-case layer, exposing the Id, Name, and PhoneNumber fields. This change introduces the PhoneNumber property to the data transfer object, aligning with the addition of a phone number value object in the shared kernel.
src/Clean.Architecture.UseCases/Contributors · high confidence
Introduced global usings and shared constants for cleaner code
Added GlobalUsings.cs files to both the Core and UseCases projects to centralize common namespace imports, reducing boilerplate in individual files. Additionally, a Constants.cs file was added to the UseCases project to define shared configuration values like DEFAULT\_PAGE\_SIZE and MAX\_PAGE\_SIZE, and a PagedResult record was introduced to standardize pagination responses.
src/Clean.Architecture.Core, src/Clean.Architecture.UseCases · high confidence
Introduces EF Core-based data access with domain event dispatching
The sample application's data layer has been implemented using Entity Framework Core. A new AppDbContext defines the database context and entity sets for ToDoItems, Projects, and Contributors. An EfRepository class provides a generic repository implementation built on Ardalis.Specification. Additionally, an EventDispatchInterceptor is introduced to automatically dispatch domain events after successful database saves, ensuring that domain events are processed as part of the persistence pipeline.
sample/src/NimblePros.SampleToDo.Infrastructure/Data · high confidence
Migrate sample app to .NET 10 and vanilla DI
The sample application has been updated to target .NET 10. The core project now uses a static \Localization\ class to expose \IStringLocalizer\ to static contexts, and service registration is handled via vanilla .NET DI in \CoreServiceExtensions.cs\ rather than Autofac. Additionally, global usings are consolidated in \GlobalUsings.cs\ to reduce repetitive namespace declarations.
sample/src/NimblePros.SampleToDo.Core · high confidence
Migrate to .NET 10 and FastEndpoints with new API helpers
The web project has been upgraded to .NET 10 and replaced the previous dependency injection and endpoint frameworks with FastEndpoints and native DI. This introduces a new \ResultExtensions\ utility that maps internal \Result\ objects to ASP.NET Core \TypedResults\ for standard CRUD operations, simplifying how API endpoints handle success, validation, and error states. The \Program.cs\ entry point is streamlined to configure FastEndpoints, Swagger, and Serilog logging, while global usings and configuration files (\appsettings.json\, \api.http\) are updated to reflect the new architecture and development environment settings.
src/Clean.Architecture.Web · high confidence
Refactored Contributors List use case to use a dedicated query service
The ListContributors use case has been refactored to depend on a new IListContributorsQueryService interface, separating the data-fetching logic from the handler. The ListContributorsHandler now delegates to this service via constructor injection, and the ListContributorsQuery record has been updated to align with the new structure.
src/Clean.Architecture.UseCases/Contributors/List · high confidence
Sample app upgraded to .NET 10 with new solution and build configuration
The sample application has been upgraded to target .NET 10. This change introduces a new solution file (\.slnx\) that explicitly defines the project structure, including the Aspire host, core, infrastructure, service defaults, use cases, and web layers, along with associated unit, integration, and functional tests. Additionally, a \Directory.Build.props\ file is added to centrally manage package versions, enable nullable and implicit usings, and treat warnings as errors, while an \.editorconfig\ file enforces consistent coding conventions and formatting rules across the sample codebase.
sample · high confidence
Test coverage
Add ContributorByIdSpec test for contributor lookup; Added functional test infrastructure for the sample app; Added functional tests for Contributor API endpoints; Added functional tests for Contributor CRUD operations; Added functional tests for Projects endpoints; Added initial Aspire integration test structure; Added integration tests for EF Core repository operations; Added integration tests for the Entity Framework repository; Added test for ContributorByIdSpec; Added test infrastructure for unit testing; Added unit tests for Core domain and services; Added unit tests for contributor use-case handlers; Added unit tests for domain aggregates, services, and handlers; Added unit tests for the CreateContributorHandler; Functional tests migrate to xUnit v3 and Testcontainers.
Dependencies
Upgrade to .NET 10 and centralize package versions
The project has been upgraded to target .NET 10, with all NuGet package versions centralized in Directory.Packages.props files for both the main solution and the sample app. This includes updating core libraries such as FastEndpoints to 8.1.0, xunit.v3 to 3.2.2, and Microsoft.EntityFrameworkCore packages to 10.0.7. The change also introduces .NET Aspire support by adding Aspire host and service default projects, along with OpenTelemetry and resilience packages, while migrating test projects to use xunit v3 and Shouldly for assertions.
(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 71 → 71 (+0.0)
- Rubric changed (rubric-2026.08.18 → rubric-2026.08.19) — scores are not directly comparable.
Lenses
- Code Health 83 → 83 (+0.0)
- Architecture 80 → 80 (+0.0)
- Maturity 74 → 74 (+0.0)
- Readiness 81 → 81 (+0.0)
- Security 66 → 66 (+0.0)
- Performance 74 → 74 (+0.0)
Findings
- No change — the same findings as the prior survey.
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
ardalis/CleanArchitecture 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 5 August 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit a064d0b369b719ba03da71da1560d208d7e02e03 — the exact code this score is about.
- Scored under rubric-2026.08.19 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer latest.