- Add path-specific rules for commands/queries, dynamic queries, validation, and gRPC - Add /add-command, /add-query, /add-dynamic-query scaffolding skills - Add project settings with post-edit formatting, proto validation, and build-gate hooks - Add .editorconfig codifying existing code style conventions - Trim CLAUDE.md from 414 to 130 lines (domain details moved to rules) - Add .harness-version tracking for the shared claude-harness repo Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.1 KiB
CLAUDE.md
This file provides guidance to AI agents when working with code in this repository.
For domain-specific patterns (commands, queries, validation, gRPC, dynamic queries), see .claude/rules/.
For scaffolding commands, see .claude/skills/ (/add-command, /add-query, /add-dynamic-query).
Project Overview
This is Svrnty.CQRS, a modern implementation of Command Query Responsibility Segregation (CQRS) for .NET 10. It was forked from PoweredSoft.CQRS and provides:
- CQRS pattern implementation with command/query handlers exposed via HTTP or gRPC
- Automatic HTTP endpoint generation via Minimal API
- Automatic gRPC endpoint generation with source generators and Google Rich Error Model validation
- Dynamic query capabilities (filtering, sorting, grouping, aggregation)
- FluentValidation support with RFC 7807 Problem Details (HTTP) and Google Rich Error Model (gRPC)
Solution Structure
The solution contains projects organized by responsibility:
Abstractions (interfaces and contracts only):
Svrnty.CQRS.Abstractions- Core interfaces (ICommandHandler, IQueryHandler, discovery contracts)Svrnty.CQRS.DynamicQuery.Abstractions- Dynamic query interfaces (multi-targets netstandard2.1 and net10.0)Svrnty.CQRS.Grpc.Abstractions- gRPC-specific interfaces and contracts
Implementation:
Svrnty.CQRS- Core discovery and registration logicSvrnty.CQRS.MinimalApi- Minimal API endpoint mapping for commands/queriesSvrnty.CQRS.DynamicQuery- PoweredSoft.DynamicQuery integration for advanced filteringSvrnty.CQRS.DynamicQuery.MinimalApi- Minimal API endpoint mapping for dynamic queriesSvrnty.CQRS.FluentValidation- Validation integration helpersSvrnty.CQRS.Grpc- gRPC service implementation supportSvrnty.CQRS.Grpc.Generators- Source generator for .proto files and gRPC service implementations
Sample:
Svrnty.Sample- Demo project showcasing both HTTP and gRPC endpoints
Key Design Principle: Abstractions projects contain ONLY interfaces/attributes with minimal dependencies. Implementation projects depend on abstractions.
Build Commands
dotnet restore # Restore dependencies
dotnet build # Build entire solution
dotnet build -c Release # Build in Release mode
dotnet pack -c Release -o ./artifacts -p:Version=1.0.0 # Create NuGet packages
Testing
No test projects currently exist. When adding tests:
- Place them in a
tests/directory - Name them with
.Testssuffix (e.g.,Svrnty.CQRS.Tests)
Architecture
Metadata-Driven Discovery
The framework uses a metadata pattern for runtime discovery:
services.AddCommand<TCommand, THandler>()registers the handler in DI and createsICommandMetametadata as a singleton- Discovery services (
ICommandDiscovery,IQueryDiscovery) query all registered metadata from DI - Endpoint mapping (HTTP and gRPC) uses discovery to dynamically generate endpoints at startup
Key Files:
Svrnty.CQRS.Abstractions/Discovery/- Metadata interfacesSvrnty.CQRS/Discovery/- Discovery implementationsSvrnty.CQRS.MinimalApi/EndpointRouteBuilderExtensions.cs- HTTP endpoint generationSvrnty.CQRS.DynamicQuery.MinimalApi/EndpointRouteBuilderExtensions.cs- Dynamic query endpoint generationSvrnty.CQRS.Grpc.Generators/- gRPC service generation via source generators
Integration
Commands and queries can be exposed via HTTP (Minimal API), gRPC, or both simultaneously. The fluent configuration API handles all wiring:
builder.Services.AddSvrntyCqrs(cqrs =>
{
cqrs.AddGrpc(grpc => grpc.EnableReflection());
cqrs.AddMinimalApi();
});
app.UseSvrntyCqrs(); // Maps all endpoints
See Svrnty.Sample/Program.cs for a complete working example.
Package Configuration
- Target Framework:
net10.0(except DynamicQuery.Abstractions:netstandard2.1;net10.0) - Language Version: C# 14
- Authors: David Lebee, Mathias Beaulieu-Duncan
- Repository: https://git.openharbor.io/svrnty/dotnet-cqrs
Key Dependencies
- Microsoft.Extensions.DependencyInjection.Abstractions: 10.0.0
- FluentValidation: 11.11.0
- PoweredSoft.DynamicQuery: 3.0.1
- Grpc.AspNetCore: 2.68.0+
- Grpc.StatusProto: 2.71.0+ (Rich Error Model)
- Microsoft.CodeAnalysis.CSharp: 5.0.0-2.final (source generators, targets netstandard2.0)
Publishing
NuGet packages publish automatically via GitHub Actions (.github/workflows/publish-nugets.yml) when a release is created. Tag becomes the version.
# Manual publish
dotnet pack -c Release -o ./artifacts -p:Version=1.2.3
dotnet nuget push ./artifacts/*.nupkg --source https://api.nuget.org/v3/index.json --api-key YOUR_KEY
Development Workflow
Adding a New Feature to the Framework:
- Add interface to appropriate Abstractions project
- Implement in corresponding implementation project
- Update ServiceCollectionExtensions with registration method
- When extending discovery, create corresponding metadata classes (implement ICommandMeta/IQueryMeta)
- Update package version and release notes
C# 14 Language Features
The project uses C# 14. Be aware of these reserved keywords:
field: Contextual keyword in property accessors for implicit backing fieldsextension: Reserved for extension containers; use@extensionfor identifiers
Important Implementation Notes
- Async Everywhere: All handlers are async. Always support CancellationToken.
- Generic Type Safety: Framework relies heavily on generics. Maintain strong typing.
- Endpoint Mapping Timing: Discovery services must be registered before calling
UseSvrntyCqrs(). - AOT Compatibility:
IsAotCompatibleis set but not enforced — many dependencies are not AOT-compatible.
Common Code Locations
- Handler interfaces:
Svrnty.CQRS.Abstractions/ICommandHandler.cs,IQueryHandler.cs - Discovery:
Svrnty.CQRS/Discovery/ - Service registration:
*/ServiceCollectionExtensions.csin each project - HTTP endpoints:
Svrnty.CQRS.MinimalApi/EndpointRouteBuilderExtensions.cs - Dynamic queries:
Svrnty.CQRS.DynamicQuery/DynamicQueryHandler.cs - gRPC generators:
Svrnty.CQRS.Grpc.Generators/ - Sample:
Svrnty.Sample/