Skip to content
CAI
Software that uses CAICheck a score

pwoltschk/PragmaticCleanArchitecture

44.3

Weak · 20 September 2026

2.6k

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 a project and work item management application built on .NET 8 Clean Architecture, providing a Blazor WebAssembly frontend and a RESTful API backend. It enables users to create, update, and track projects and work items through a Kanban-style interface, with full support for role-based access control and user management. The platform handles identity via ASP.NET Core Identity and Duende IdentityServer, automatically notifying assigned users via email when work items are created or modified.

How it got here

2021–2022 — Initial Clean Architecture scaffolding

25 changes.

The project was initialized as a .NET 8 Clean Architecture application, establishing the foundational structure across Domain, Application, Infrastructure, and Web layers. Core features for project and work item management were implemented, including Blazor WebAssembly UI, API endpoints with IdentityServer authentication, and Entity Framework Core data access with audit logging.

2023–2024 — Core domain and identity implementation

20 changes.

This period focused on establishing the foundational architecture by introducing Domain-Driven Design primitives, value objects, and a comprehensive identity management system with role-based authorization. It also implemented core business capabilities for project and work item management, including API endpoints, UI components, and automated email notifications triggered by domain events.

Features

Add common application exception classes

Introduced two new exception types in the Application layer to improve error handling: NotFoundException, which provides a clear message when an entity is not found by name and key, and ValidationException, which aggregates FluentValidation failures into a dictionary mapping property names to their respective error messages.

src/Application/Common/Exceptions · high confidence

Add query to retrieve all projects

Users can now retrieve a list of all projects via the new GetProjectsQuery. This query uses the IRepository abstraction to fetch all Project entities asynchronously, supporting cancellation for better resource management.

src/Application/Projects/Queries · high confidence

Add query to retrieve all work items

Users can now retrieve a list of all work items via the new GetWorkItemsQuery. This query leverages the IRepository abstraction to fetch WorkItem entities asynchronously, supporting cancellation for better responsiveness during long-running operations.

src/Application/WorkItems/Queries · high confidence

Added application-level pipeline behaviors for validation, logging, and exception handling

The application now includes three new MediatR pipeline behaviors in the common layer. ValidationBehavior automatically validates incoming requests using FluentValidation validators and throws a ValidationException if any rules fail. LoggingBehavior intercepts requests to log the request name, current user ID, and request data for audit and debugging purposes. UnhandledExceptionBehavior wraps request handling to catch and log any unhandled exceptions before re-throwing them, ensuring errors are captured without disrupting the call stack.

src/Application/Common/Behaviours · high confidence

Added common service interfaces for identity, email, and user context

New interfaces have been introduced in the common services layer to define contracts for core application capabilities. IIdentityService now exposes methods for managing roles (create, update, delete, list) and users (retrieve, update, delete). IEmailService provides a contract for sending emails, and IUserContext defines a property to access the current user's ID, supporting the retrieval of user context within the application.

src/Application/Common/Services · high confidence

Added email sending infrastructure service

A new EmailService implementation has been added to the Infrastructure layer to handle email delivery. This service implements the IEmailService interface and currently logs email details (subject, content, and recipient address) using Serilog rather than sending actual messages, providing a placeholder for future email integration.

src/Infrastructure/Emails · high confidence

Added role management commands and queries

The application now supports full role management through new CQRS handlers. Users can retrieve a list of roles via the GetRoles query, and perform create, update, and delete operations on roles using the corresponding commands. These changes rely on the IIdentityService to execute the underlying identity operations.

src/Application/Roles · high confidence

Added user management commands and queries

The application now supports retrieving individual and list views of users, as well as updating and deleting user accounts. New query handlers allow fetching a single user by ID or retrieving a collection of all users, while command handlers enable modifying user details and removing users from the system via the identity service.

src/Application/Users · high confidence

Automatic audit logging and domain event dispatching in database operations

Two new Entity Framework Core interceptors have been added to automatically handle cross-cutting concerns during data persistence. The AuditableEntityInterceptor now automatically populates CreatedBy, CreatedOn, UpdatedBy, and UpdatedOn fields on entities implementing AuditableEntity by injecting the current user context. Additionally, the DomainEventsDispatcherInterceptor ensures that domain events raised on AggregateRoot entities are published via MediatR immediately after a save operation completes, with events cleared from the entities to prevent duplicate processing.

src/Infrastructure/Data/Interceptors · high confidence

Email notification on work item assignment

When a work item is assigned, the system now automatically sends an email notification to the assigned user. This is implemented via a new domain event handler that triggers upon the WorkItemAssignedDomainEvent, retrieving the work item details and invoking the email service to deliver the message.

src/Application/WorkItems/Events · high confidence

Infrastructure service registration and identity setup

The Infrastructure layer now registers its core services via a new \ServiceCollectionExtensions\ class. This includes configuring the \ApplicationDbContext\ with SQL Server, registering interceptors for auditing (\AuditableEntityInterceptor\) and domain event dispatching (\DomainEventsDispatcherInterceptor\), and setting up ASP.NET Core Identity with Entity Framework Core stores. Additionally, it configures IdentityServer4 for API authorization with a custom profile service, and registers scoped services for identity (\IIdentityService\), email (\IEmailService\), and repositories for \Project\ and \WorkItem\ entities.

src/Infrastructure · high confidence

Initial API server setup with IdentityServer authentication and OpenAPI generation

The ApiServer web application has been initialized, introducing a complete request pipeline that includes IdentityServer for JWT-based authentication and authorization, along with Serilog for console logging. The server is configured to serve Blazor static files and Razor pages, while NSwag is set up to generate an OpenAPI specification at /api/v1/openapi.json and produce C\# client proxies for the UI layer. Additionally, the application includes logic to automatically initialize and seed the database upon startup.

src/Web/ApiServer · high confidence

Initial Blazor WebAssembly UI with API clients and validation

The UI layer has been established as a Blazor WebAssembly application, replacing previous implementations. This change introduces auto-generated API clients (via NSwag) for interacting with backend services, including project, work item, user, and role endpoints. It configures authentication and authorization using ASP.NET Core WebAssembly Authentication, integrating custom authorization handlers and policy providers. Additionally, client-side input validation is implemented for Project and Work Item DTOs using FluentValidation, and drag-and-drop functionality is enabled for the Kanban board.

src/Web/UI · high confidence

Initial database context, repository layer, and seed data for project management

The application now includes a foundational data access layer. The \ApplicationDbContext\ integrates with ASP.NET Core Identity and Duende IdentityServer, utilizing custom interceptors for auditing and domain event dispatching. Concrete repositories for \Project\ and \WorkItem\ entities have been implemented to handle CRUD operations. Additionally, an initialiser class provides database migration/creation logic and seeds the database with default roles (Administrator, Manager), a default admin user, and sample project/work item data.

src/Infrastructure/Data · high confidence

Initial project scaffolding and documentation

The repository has been initialized with the foundational structure for a .NET 8 Clean Architecture application, including the solution file defining the ApiServer, Application, Domain, and Infrastructure layers, along with corresponding unit test projects. This initial commit also establishes the project's governance and operational guidelines by adding the .editorconfig for code formatting, a Dockerfile for containerization, and standard open-source documentation files such as the README, CONTRIBUTING, CODE\_OF\_CONDUCT, LICENSE, and SECURITY policies.

(repo-wide) · high confidence

Introduce command handlers and validators for project CRUD operations

Added command handlers and validators for creating, updating, and deleting projects within the Application layer. The CreateProjectCommand includes a validator that enforces unique project titles by checking against existing records, while the Update and Delete commands utilize the IRepository abstraction to manage project entities, ensuring proper cancellation token flow and error handling for missing resources.

src/Application/Projects/Commands · high confidence

Introduce core domain entities for project and user management

Added new domain entities to define the core data model: Project and WorkItem (with title, description, priority, stage, and assignment details), User (with email and role associations), Role (with permission lists), and a Permission helper for claim generation. These entities establish the foundational structure for project tracking, user identity, and role-based access control within the application.

src/Domain/Entities · high confidence

Introduce web UI pages for project, work item, user, and role management

The web application now includes dedicated Razor pages for managing core entities. Users can view and edit projects via the Project page (including create, edit, and delete dialogs) and manage work items through a Kanban-style ProjectBoard and a list-based WorkItems page, supporting creation, editing, deletion, and stage updates. Administrative capabilities are added with a UserManager page for listing, editing, and deleting users, and a RoleManager page for creating, editing, and deleting roles with permission assignments. An Authentication page handles remote authentication flows, and the Index page serves as the default landing view. All pages enforce authorization using specific permissions (e.g., ReadProjects, WriteUsers, WriteRoles) and rely on injected client services for data operations.

src/Web/UI/Pages · high confidence

Introduces UserContext to extract user identity from HTTP context

A new UserContext class has been added to the ApiServer.Identity namespace to provide a standardized way of retrieving the current user's identifier. It implements the IUserContext interface and uses IHttpContextAccessor to read the NameIdentifier claim from the current HTTP request's user principal, returning "n/a" if the context is unavailable.

src/Web/ApiServer/Identity · high confidence

Introduces core Domain-Driven Design primitives

Adds foundational classes to the domain layer to support DDD patterns: AggregateRoot now tracks and exposes domain events via a collection, AuditableEntity provides standard audit fields (Id, CreatedOn, CreatedBy, UpdatedOn, UpdatedBy), ValueObject implements value-based equality and hashing, and IRepository defines a generic interface for entity persistence with cancellation token support.

src/Domain/Primitives · high confidence

Introduction of API view models for projects, work items, users, and roles

New Data Transfer Objects (DTOs) and view models have been added to the ApiServer to structure the data returned by the API. This includes ProjectDto and ProjectsViewModel for project listings, WorkItemDto and WorkItemsViewModel for work items (featuring fields like stage, priority, and iteration), UserDto and UsersViewModel for user data, and RoleDto and RolesViewModel for role and permission information. These models define the shape of the API responses for these core entities.

src/Web/ApiServer/ViewModels · high confidence

Introduction of WorkItemAssigned domain event

A new domain event, WorkItemAssignedDomainEvent, has been added to the system. This event is triggered when a work item is assigned, carrying the ID of the affected work item to allow other parts of the application to react to this state change.

src/Domain/Events · high confidence

Introduction of custom mapping infrastructure for API view models

The ApiServer/Mapper module now provides a generic IMapper interface and specific implementations to translate between Domain entities (such as User, Role, Project, and WorkItem) and their corresponding API ViewModels/DTOs. This change introduces dedicated mappers for users, roles, projects, and work items, enabling the API layer to properly serialize domain data into structured responses (e.g., UserDetailsViewModel, ProjectsViewModel) while handling value objects like Email and Priority.

src/Web/ApiServer/Mapper · high confidence

Introduction of structured API exception handling and user login UI

This change introduces a new \ApiExceptionFilterAttribute\ that standardizes how the API server responds to errors, specifically mapping \ValidationException\ and \NotFoundException\ to appropriate HTTP 400 and 404 responses with RFC-compliant problem details, while also handling invalid model states. Additionally, a \\_LoginPartial.cshtml\ view component is added to the shared views, providing the navigation UI for user registration, login, and logout actions via ASP.NET Core Identity.

src/Web/ApiServer/Filters · high confidence

New Identity Management API Endpoints for Roles and Users

The API now exposes dedicated controllers for managing identity resources. The RolesController provides endpoints to list, create, update, and delete roles under the /api/Identity/Routes path, enforcing specific read/write permissions. The UsersController handles user management under /api/Admin/Users, allowing administrators to retrieve user lists, fetch individual user details (including associated roles), update user information, and delete users, with access controlled by dedicated user permissions.

src/Web/ApiServer/Controllers/Identity · high confidence

New domain value objects for Email, Priority, and Stage

The domain layer now includes three new value objects to enforce type safety and validation for core business concepts. The Email value object validates format using a regex and normalizes input to lowercase. The Priority value object provides a fixed set of levels (Low, Medium, High) accessible via static properties or factory methods. The Stage value object defines workflow states (Planned, In Progress, Completed) with similar factory access. These objects replace raw strings or integers in the domain model, ensuring consistent validation and equality checks.

src/Domain/ValueObjects · high confidence

New identity service and custom profile service for user and role management

The application now includes a new \IdentityService\ implementation in the Infrastructure layer that handles core user and role operations, including retrieving users and roles with their associated permissions, creating, updating, and deleting roles, and updating user details. Additionally, a \CustomProfileService\ has been added to integrate with Duende IdentityServer, ensuring that user claims (including sub, name, and role-based permissions) are correctly issued during authentication and that user activity status is validated.

src/Infrastructure/Identity · high confidence

New permission-aware authorization components

The UI now includes an AuthorizeWrapper component that allows conditional rendering based on specific user permissions, and a PermissionAccountClaimsPrincipalFactory that extracts permission data from the remote user's additional properties and adds them as claims to the user's identity.

src/Web/UI/Identity · high confidence

New project and work item management UI components

This change introduces a new set of Blazor UI components for managing projects and work items. For projects, it adds a list view with selection and action buttons, along with reusable dialogs for creating/editing and deleting projects. For work items, it provides a Kanban board layout with draggable columns, individual work item cards displaying status and priority, and comprehensive dialogs for creating and editing work items (including assignment, priority, stage, and date fields).

src/Web/UI/Components · high confidence

New request models for creating and updating work items

The application now exposes specific request DTOs for work item operations. CreateWorkItemRequest allows users to initiate a new work item with an optional project association and a title. UpdateWorkItemRequest enables modifying existing work items, supporting changes to the title, description, iteration, assigned user, priority, and stage, as well as updating the start date and project association.

src/Application/WorkItems/Requests · high confidence

New shared UI components for authentication, layout, and navigation

The application now includes a set of shared Razor components that define the core user interface structure. MainLayout.razor provides the page skeleton with a sidebar and a top row that displays the authenticated user's name and a logout button, while LoginDisplay.razor offers an alternative login/logout interface. NavMenu.razor implements the sidebar navigation, restricting access to Projects, Work Items, Roles, Users, and Settings based on specific permissions (ReadProjects, ReadRoles, ReadUsers, WriteProjects) via an AuthorizeWrapper. Supporting styles for the layout and menu are included in corresponding CSS files, and RedirectToLogin.razor handles unauthenticated redirects to the login page.

src/Web/UI/Shared · high confidence

New shared authorization framework with permission-based policies

The src/Web/Shared location now includes a complete authorization subsystem (Shared.Identity namespace) that enables permission-based access control. This adds a custom AuthorizeAttribute for declarative policy application, a CustomAuthorizationRequirement and CustomAuthorizationHandler to validate user claims against specific permissions, and a CustomAuthorizationPolicyProvider that caches policies and dynamically creates them for known permissions defined in the Permission class (ReadRoles, WriteRoles, WriteUsers, ReadUsers, ReadProjects, WriteProjects). This centralizes authorization logic for reuse across web components.

src/Web/Shared · high confidence

Work item creation, deletion, and update capabilities

Users can now create, delete, and update work items through the application layer. The new CreateWorkItemCommand allows adding new items with a project ID and title, while DeleteWorkItemCommand handles removal by ID. The UpdateWorkItemCommand enables editing existing work items, including fields like title, project, assignee, iteration, priority, description, start date, and stage; it also automatically triggers a domain event when a work item is assigned to a user for the first time.

src/Application/WorkItems/Commands · high confidence

Behavioural changes

API endpoints for Projects and Work Items now require authentication and role-based authorization

The Project and Work Item controllers in the ApiServer now inherit from a new CustomControllerBase that enforces global authentication via the \[Authorize\] attribute. Additionally, specific endpoints are protected by granular permissions: reading projects or work items requires the ReadProjects permission, while creating, updating, or deleting these resources requires the WriteProjects permission. This ensures that all interactions with project and work item data are secured and restricted to users with the appropriate roles.

src/Web/ApiServer/Controllers · high confidence

Add request models and validation for creating and updating projects

Users can now submit project creation and update operations with structured request data. New request models (CreateProjectRequest and UpdateProjectRequest) define the input shape, including a Title field for both operations and an Id field for updates. Validation rules enforce that the Title is not empty and does not exceed 150 characters, ensuring data integrity before processing.

src/Application/Projects/Requests · high confidence

Application layer initialization with MediatR, validation, and Serilog

The Application layer now bootstraps its core infrastructure via a new ServiceCollectionExtensions class. This setup registers MediatR for command/query handling and FluentValidation for request validation, while injecting global pipeline behaviors to automatically validate requests and catch unhandled exceptions. It also registers a specific domain event handler for work item assignments and initializes Serilog for console-based structured logging, making these capabilities available to the rest of the application.

src/Application · high confidence

Configures Project and WorkItem entity mappings with cascade deletion and value object storage

The application now explicitly defines Entity Framework Core configurations for the Project and WorkItem entities. For Projects, the Title field is enforced as a required string with a maximum length of 150 characters, and the relationship to WorkItems is configured to cascade delete, meaning deleting a Project will automatically remove its associated WorkItems. For WorkItems, the Title is similarly constrained, while the Description allows up to 8000 characters. Additionally, the Priority and Stage properties are mapped as owned value objects, storing their internal fields (Level, Name, Id) in dedicated columns (PriorityLevel, PriorityName, StageId) within the WorkItem table, ensuring these composite values are persisted as part of the WorkItem record rather than as separate entities.

src/Infrastructure/Data/Configurations · high confidence

Database schema updates for audit tracking, work item stages, and project detachment

The database schema has evolved through several migrations: the initial creation established Projects and WorkItems with cascade deletion; subsequent updates added audit columns (CreatedBy, CreatedOn, UpdatedBy, UpdatedOn) to both entities and constrained their titles to 150 characters. WorkItems gained a Stage column, which was later refactored to include StageId, PriorityLevel, PriorityName, and StageName columns. Finally, the mandatory link between WorkItems and Projects was relaxed by making ProjectId nullable and removing the cascade delete behavior, allowing work items to exist independently of a project.

src/Infrastructure/Migrations · high confidence

Frontend UI styling updated to Bootstrap 5

The user interface styles have been updated to use Bootstrap 5.1.0, replacing the previous version. This change brings modern CSS utilities, updated form controls, and new component styles to the application, ensuring a consistent and responsive look and feel across all pages.

src/Web/UI/wwwroot · high confidence

Test coverage

Added unit tests for Identity infrastructure services; Added unit tests for Project and WorkItem application commands, queries, and events; Added unit tests for ValidationBehavior; Added unit tests for Web layer API server components; Added unit tests for domain primitives and value objects.

Dependencies

Upgrade to .NET 8 and add application dependencies

The project has been upgraded to target .NET 8.0 across all application and test projects. This change introduces several new dependencies to support the application's architecture and features, including MediatR for messaging, FluentValidation for input validation, Serilog for logging, and Entity Framework Core for data access. The UI layer now utilizes Blazor WebAssembly components, supported by packages for drag-and-drop functionality and authentication. Test projects have also been updated to use .NET 8 and include necessary testing frameworks like MSTest, Moq, and FluentAssertions.

(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 42 → 44 (+2.3)
  • Rubric changed (rubric-2026.08.17 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 81 → 81 (-0.0)
  • Architecture 82 → 82 (+0.1)
  • Maturity 70 → 54 (-16.5)
  • Readiness 54 → 53 (-0.3)
  • Security 73 → 82 (+9.6)
  • Domain Modelling 27 → 35 (+7.9)
  • Event-Driven 100 → 100 (+0.0)
  • Accessibility 41 → 40 (-1.3)

Resolved (17)

  • Bounded contexts not declared
  • Change coupling: DeleteWorkItem.cs ↔ UpdateWorkItem.cs (src/Application/WorkItems/Commands/DeleteWorkItem.cs)
  • High CVE: System.Text.Json 8.0.0
  • High CVE: System.Text.Json 8.0.0
  • 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)
  • LLM evaluation failed
  • Low CVE: Microsoft.Identity.Client 4.56.0
  • Medium CVE: Azure.Identity 1.10.3
  • Medium CVE: Azure.Identity 1.10.3
  • No exposed public API
  • Outdated: Blazored.FluentValidation
  • The README describes a single application and its features without an Installation or Usage section that would be expected for a .NET 8 Clean Architecture example. (README.md)
  • dormant codebase — no living knowledge left to concentrate

New (17)

  • CoverageExclusion (src/Infrastructure/Data/ApplicationDbContextInitialiser.cs)
  • Documentation: no architecture or design documentation (README.md)
  • Documentation: no licence statement (README.md)
  • Duplicated block (18 lines × 2) (src/Domain/Entities/Permission.cs)
  • Duplicated block (6–11 lines × 2) (src/Domain/Entities/WorkItem.cs)
  • High CVE: System.Text.Json 8.0.0
  • 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: Azure.Identity 1.10.3
  • Medium IaC: WD-DOCKER-0003 (Dockerfile)
  • Medium IaC: WD-DOCKER-0003 (Dockerfile)
  • No dependency advisory monitoring
  • PR-triggered workflow without a permissions block
  • misleading comment (src/Application/WorkItems/Events/WorkItemAssignedDomainEventHandler.cs)

API surface

  • Unchanged — 13 HTTP endpoints

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

Survey your own repository

pwoltschk/PragmaticCleanArchitecture 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 20 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 d0fb6e70cf82a852b0418b113ef7f2bcd43a6c23 — 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.