- 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>
147 lines
6.1 KiB
Markdown
147 lines
6.1 KiB
Markdown
# 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<TCommand, THandler>()` 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/`
|