# 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 logic - `Svrnty.CQRS.MinimalApi` - Minimal API endpoint mapping for commands/queries - `Svrnty.CQRS.DynamicQuery` - PoweredSoft.DynamicQuery integration for advanced filtering - `Svrnty.CQRS.DynamicQuery.MinimalApi` - Minimal API endpoint mapping for dynamic queries - `Svrnty.CQRS.FluentValidation` - Validation integration helpers - `Svrnty.CQRS.Grpc` - gRPC service implementation support - `Svrnty.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 ```bash 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 `.Tests` suffix (e.g., `Svrnty.CQRS.Tests`) ## Architecture ### Metadata-Driven Discovery The framework uses a **metadata pattern** for runtime discovery: 1. `services.AddCommand()` registers the handler in DI and creates `ICommandMeta` metadata as a singleton 2. Discovery services (`ICommandDiscovery`, `IQueryDiscovery`) query all registered metadata from DI 3. Endpoint mapping (HTTP and gRPC) uses discovery to dynamically generate endpoints at startup **Key Files:** - `Svrnty.CQRS.Abstractions/Discovery/` - Metadata interfaces - `Svrnty.CQRS/Discovery/` - Discovery implementations - `Svrnty.CQRS.MinimalApi/EndpointRouteBuilderExtensions.cs` - HTTP endpoint generation - `Svrnty.CQRS.DynamicQuery.MinimalApi/EndpointRouteBuilderExtensions.cs` - Dynamic query endpoint generation - `Svrnty.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: ```csharp 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. ```bash # 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:** 1. Add interface to appropriate Abstractions project 2. Implement in corresponding implementation project 3. Update ServiceCollectionExtensions with registration method 4. When extending discovery, create corresponding metadata classes (implement ICommandMeta/IQueryMeta) 5. 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 fields - **`extension`**: Reserved for extension containers; use `@extension` for identifiers ## Important Implementation Notes 1. **Async Everywhere**: All handlers are async. Always support CancellationToken. 2. **Generic Type Safety**: Framework relies heavily on generics. Maintain strong typing. 3. **Endpoint Mapping Timing**: Discovery services must be registered before calling `UseSvrntyCqrs()`. 4. **AOT Compatibility**: `IsAotCompatible` is 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.cs` in 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/`