NilavPatel/Todo.CQRS
34.5
Weak · 20 September 2026
1.8k
lines of production code
C#
primary language
4
measurements over time
What this system is
This system is a modular .NET application for managing todo items, built on an Event Sourcing architecture using EventStore for persistence. It exposes asynchronous REST APIs for creating, updating, completing, and querying todo items, while a background processor asynchronously consumes domain events to maintain SQL-based read models. The solution is structured into distinct modules and a shared framework to handle command dispatch, event projection, and infrastructure concerns.
Features
Added SQL schema for TodoItems table
A new SQL script (Database/todo.sql) has been added to the database layer. This script creates a 'Todo' database and a 'TodoItems' table containing columns for Id (uniqueidentifier), Version (int), Title (nvarchar), and IsComplete (bit). This provides the underlying storage structure for the Todo feature.
Database · high confidence
Added event handlers for Todo item domain and integration events
The application now includes handlers for Todo item lifecycle events. The \TodoItemEventHandler\ processes domain events (creation, completion status changes, title updates) by persisting the corresponding changes to the database via a unit of work. Additionally, a \TodoItemIntegrationEventHandler\ has been added to process integration events, currently implemented as a placeholder that delays processing.
Modules/Todo/Todo.Application/EventHandlers · high confidence
Introduce Todo background processor with EventStore and SQL connectivity
A new background processor service for the Todo module has been added, designed to consume events from an EventStore and persist read-model updates to a SQL Server database. The application initializes by registering framework services, connecting to the EventStore via TCP, and configuring a SQL Server context for data persistence, enabling asynchronous processing of Todo-related events.
Modules/Todo/Todo.BackgroundProcessor · high confidence
Removals
Removal of legacy CQRS and Event Sourcing infrastructure
The framework has removed its core Command Query Responsibility Segregation (CQRS) and Event Sourcing components, including the \AggregateHandler\, \BaseController\, \SaveEventsHandler\, \AggregateRepository\, and the \EventStoreContext\ (Entity Framework Core DbContext). This eliminates the built-in capability to persist domain events to a database and automatically publish them via the event bus, as well as the base controller abstraction for handling commands.
Todo.Framework · high confidence
Removal of legacy TodoItem command handler
The \TodoItemHandler\ class, which previously managed \CreateTodoItem\ and \MarkTodoItemAsComplete\ commands within the \Todo.Domain\ layer, has been removed. This change eliminates the specific command handling logic for these operations from the domain infrastructure.
Todo.Domain · high confidence
Architecture
Solution structure reorganized into modules and renamed projects
The solution has been restructured to support a modular architecture. Projects such as Todo.Webapi, Todo.Domain, Todo.Contracts, and Todo.Application are now nested under a Modules/Todo folder, while the shared infrastructure code has been moved to a top-level Framework project. Additionally, a new Todo.BackgroundProcessor project has been added, and the previous Todo.ReadModels and Todo.Projections projects have been replaced by Todo.Application.
(repo-wide) · high confidence
Behavioural changes
Async query support and new endpoint for completed items in Todo module
The TodoItemQueryController has been moved to the Modules/Todo location and updated to use asynchronous operations via the new IReadRepository interface, replacing the previous synchronous IBaseRepository. This change enables the controller to await database calls, improving responsiveness. Additionally, a new GET endpoint, GetCompletedTodoItems, has been added to retrieve only completed todo items using a specification filter.
Modules/Todo/Todo.Webapi/QueryControllers · high confidence
Framework refactored to Event Sourcing with EventStore and background processing
The Framework has been restructured to support an Event Sourcing architecture, replacing the previous SQL-based persistence with EventStore. This introduces an AggregateRepository that persists domain events and snapshots to EventStore, a SessionRepository for in-memory aggregate tracking, and a BackgroundEventProcessor that consumes events from EventStore streams and publishes them via an IntegrationEventBus. The framework now includes a CheckpointStore to track processing positions, a SnapshotStrategy for periodic state snapshots, and a unified Serializer for event data. Command and event handling have been updated to be fully asynchronous, and the RegistrarService now wires up these new components for dependency injection.
Framework · high confidence
Migrate Todo module to EventStore and automate handler registration
The Todo WebAPI now uses an EventStore for persistence instead of a standard SQL database, with the connection configured in appsettings.json. Startup logic has been refactored to replace manual service registrations with automated discovery: command and domain event handlers are now registered automatically from the 'Todo.Application' assembly, and framework services are initialized via a centralized registrar. This simplifies the configuration and ensures new handlers are picked up without manual DI setup.
Modules/Todo/Todo.Webapi · high confidence
New commands for uncompleting and updating todo items
The Todo module now supports marking items as incomplete and updating their titles. Two new command classes, MarkTodoItemAsUnComplete and UpdateTodoItemTitle, have been added alongside the existing MarkTodoItemAsComplete command. All three commands now include a Version property, enabling optimistic concurrency control to prevent race conditions when multiple users modify the same item. The UpdateTodoItemTitle command also accepts a Title string to set the new name.
Modules/Todo/Todo.Contracts · high confidence
Removal of legacy TodoItemProjection handler
The \TodoItemProjection\ class, which previously handled \TodoItemCreated\ and \TodoItemMarkedAsComplete\ events to update the read model, has been removed from the \Todo.Projections\ module. This change eliminates the specific projection logic for these events in this location.
Todo.Projections · high confidence
Todo API endpoints refactored to use asynchronous command execution
The TodoItem controller has been moved to the Modules/Todo structure and renamed to TodoItemCommandController. The implementation now uses asynchronous methods (Task\<ICommandResult\>) for all endpoints, calling SubmitAsync on the command bus instead of the synchronous Submit method. Additionally, two new endpoints have been added: MarkTodoItemAsUnComplete and UpdateTodoItemTitle, allowing users to unmark items as complete and update item titles.
Modules/Todo/Todo.Webapi/CommandControllers · high confidence
Todo command handling refactored to use session-based repository
The Todo application's command handling has been restructured to use a new \ISessionRepository\ abstraction instead of the previous unit-of-work pattern. The \TodoItemCommandHandler\ now manages persistence for creating, completing, uncompleting, and updating todo items through this session interface, which handles adding entities and committing changes. Additionally, the read-model context (\TodoContext\) has been moved into the \Modules/Todo/Todo.Application/ReadModels\ directory and its namespace updated to reflect this new module structure.
Modules/Todo/Todo.Application/CommandHandlers · high confidence
Todo items can now be uncompleted, have titles updated, and use snapshots
The Todo module now supports marking items as uncompleted and updating their titles, in addition to the existing ability to mark them as complete. These new actions trigger specific domain events (TodoItemMarkedAsUnComplete, TodoItemTitleUpdated) that update the item's state. Internally, the TodoItem aggregate has been refactored to use a snapshotting mechanism (SnapshotAggregateRoot) to optimize performance, and validation errors now throw specific DomainValidationException types instead of generic Exceptions.
Todo · high confidence
Dependencies
Project structure reorganization and dependency updates
The solution has been reorganized into a modular structure under a new 'Modules' directory, with the core 'Framework' project moved to the root level. Several projects were renamed or relocated (e.g., Todo.Projections to Todo.Application, Todo.ReadModels deleted) to better reflect their responsibilities. Dependencies were updated to .NET 5.0, with the Framework project adding EventStore.Client and Microsoft.Extensions packages, while other modules like Todo.Webapi and Todo.Application added Microsoft.EntityFrameworkCore.SqlServer. A package.json was introduced to simplify running and building the WebAPI and BackgroundProcessor services.
(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 33 → 34 (+1.1)
- Rubric changed (rubric-2026.08.18 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 57 → 57 (-0.6)
- Architecture 74 → 67 (-7.6)
- Maturity 50 → 50 (+0.0)
- Readiness 18 → 17 (-0.7)
- Security 39 → 37 (-1.2)
- Domain Modelling 86 (new)
- Event-Driven 100 (new)
Resolved (10)
- Inconsistent casing for the same property name: 'isPagingEnabled' (lowercase 'i') vs standard PascalCase 'IsPagingEnabled'.
- Medium CVE: Microsoft.Data.SqlClient 2.0.1
- Redundant event types for state transitions. Having separate event types for 'MarkedAsComplete' and 'MarkedAsUnComplete' is inconsistent with the command pattern where 'MarkTodoItemAsComplete' and 'MarkTodoItemAsUnComplete' are distinct commands. However, in an event-sourced or CQRS model, it is often cleaner to have a single 'TodoItemStatusChanged' event with a 'Status' enum, or at least consistent naming. The current naming is slightly verbose but acceptable. A more significant inconsistency is the naming of the commands: 'MarkTodoItemAsComplete' vs 'MarkTodoItemAsUnComplete'. The 'Un' prefix is less common than using a 'SetStatus' or 'UpdateStatus' command that handles both states. However, the most glaring issue is the lack of symmetry in the event types: 'TodoItemMarkedAsComplete' and 'TodoItemMarkedAsUnComplete' are parallel, but the command types use 'MarkTodoItemAs...' while the event types use 'TodoItemMarkedAs...'. This is a minor naming convention inconsistency between commands and events.
- The configuration guide is real but it does not explain how to run the background processor or connect the web app to the event-store cluster. (Docs/EventStore_Config.md)
- Typo in namespace/assembly name 'CommandHanders' and 'EventHanders' (missing 'l' in Handlers).
- Typo in type name 'TodoItemSpanshot' (missing 'h' in Snapshot) compared to the correct 'TodoItem'.
- XML-doc coverage: Todo.BackgroundProcessor (Modules/Todo/Todo.BackgroundProcessor/Todo.BackgroundProcessor.csproj)
- misleading comment (Framework/Repository/SpecificationEvaluator.cs)
- misleading comment (Modules/Todo/Todo.BackgroundProcessor/Program.cs)
- single-maintainer — knowledge-concentration (bus factor) risk
New (15)
- 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 net5.0
- Naming inconsistency: 'UnComplete' is not standard English; 'Incomplete' is the correct antonym for 'Complete'.
- Scanner failed to run — not a clean result
- Scanner failed to run — not a clean result
- The method ExistAsync is used to check for existence. The standard C# convention for boolean-returning methods is ExistsAsync or IsPresentAsync. ExistAsync is grammatically incorrect (should be 'Exists').
- The namespace Todo.Application.CommandHanders and Todo.Application.EventHanders uses the misspelling 'Handers' instead of 'Handlers'. This is a consistent typo across these namespaces, but it is an inconsistency with standard English spelling conventions.
- The property OccuredOn uses the misspelling 'Occured' (missing the second 'r'). This is inconsistent with standard English spelling and other properties like FullName.
- The property isPagingEnabled starts with a lowercase letter. In C#, properties should typically start with an uppercase letter (PascalCase). This is inconsistent with other properties in the codebase like IsComplete, Id, Title, etc.
- The term 'UnComplete' is used instead of 'Uncompleted' or 'Incomplete'. While 'UnComplete' might be a domain-specific term, it is grammatically non-standard compared to 'Complete'. More importantly, it is inconsistent with the adjective form 'Uncompleted' if that was intended, or 'Incomplete'. However, since it is used consistently across Commands, Events, and Domain methods, it is a stylistic choice. But wait, looking at MarkTodoItemAsComplete, the parallel is MarkTodoItemAsUnComplete. This is internally consistent but linguistically awkward. A stronger inconsistency is found in TodoItemSpanshot vs Snapshot.
- The type TodoItemSpanshot appears to be a typo for TodoItemSnapshot. It is used inconsistently alongside the standard Snapshot type in the Framework.Snapshotting namespace. The misspelling 'Spanshot' is used for the domain model, while 'Snapshot' is used for the framework infrastructure.
- WriteOnlyPrivateField (Framework/Repository/UnitOfWork.cs)
- redundant comment (Framework/Repository/SpecificationEvaluator.cs)
API surface
- Unchanged — 2 HTTP endpoints
Architecture
- Unchanged — 3 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
NilavPatel/Todo.CQRS 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 8aafdc09bca8a438a12783a16711491cde7a0365 — 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.