docs: add perfecto-managed documentation triad v1.0.0

Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
This commit is contained in:
Svrnty 2026-02-28 12:33:15 -05:00
parent 16ca6f722b
commit 7e12f73160
2 changed files with 135 additions and 367 deletions

460
CLAUDE.md
View File

@ -1,50 +1,19 @@
# CLAUDE.md
<!-- perfecto:v1.0.0:2026-02-28 -->
# dotnet-cqrs -- Development Guide
This file provides guidance to AI agents when working with code in this repository.
## Overview
## Commit Authorship
Svrnty.CQRS — modern CQRS implementation for .NET 10. Forked from PoweredSoft.CQRS. Provides command/query handlers exposed via HTTP (Minimal API) or gRPC (source-generated), dynamic query capabilities, FluentValidation with RFC 7807 (HTTP) and Google Rich Error Model (gRPC).
All AI-authored commits MUST use:
## Tech Stack
```
Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
```
- **Framework:** .NET 10 / C# 14
- **Packages:** 10 NuGet packages + 1 sample project
- **gRPC:** Grpc.AspNetCore 2.68+, source-generated service implementations
- **Validation:** FluentValidation 11.11.0
- **Dynamic queries:** PoweredSoft.DynamicQuery 3.0.1
## 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)
- AOT (Ahead-of-Time) compilation compatibility for core packages (where dependencies allow)
## Solution Structure
The solution contains 11 projects organized by responsibility (10 packages + 1 sample project):
**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 (recommended for HTTP)
- `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 Projects:**
- `Svrnty.Sample` - Comprehensive 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. This allows consumers to reference abstractions without pulling in heavy implementation dependencies.
## Build Commands
## Build & Test
```bash
# Restore dependencies
@ -56,369 +25,126 @@ dotnet build
# Build in Release mode
dotnet build -c Release
# Create NuGet packages (with version)
# Create NuGet packages
dotnet pack -c Release -o ./artifacts -p:Version=1.0.0
# Build specific project
dotnet build Svrnty.CQRS/Svrnty.CQRS.csproj
```
## Testing
No test projects currently. When adding tests: `tests/` directory, `.Tests` suffix.
This repository does not currently contain test projects. When adding tests:
- Place them in a `tests/` directory or alongside source projects
- Name them with `.Tests` suffix (e.g., `Svrnty.CQRS.Tests`)
## Solution Structure
**Abstractions (interfaces only):**
- `Svrnty.CQRS.Abstractions` — Core interfaces (ICommandHandler, IQueryHandler)
- `Svrnty.CQRS.DynamicQuery.Abstractions` — Dynamic query interfaces (multi-targets netstandard2.1 + net10.0)
- `Svrnty.CQRS.Grpc.Abstractions` — gRPC-specific contracts
**Implementation:**
- `Svrnty.CQRS` — Core discovery and registration
- `Svrnty.CQRS.MinimalApi` — HTTP endpoint mapping
- `Svrnty.CQRS.DynamicQuery` — PoweredSoft.DynamicQuery integration
- `Svrnty.CQRS.DynamicQuery.MinimalApi` — Dynamic query HTTP endpoints
- `Svrnty.CQRS.FluentValidation` — Validation helpers
- `Svrnty.CQRS.Grpc` — gRPC service support
- `Svrnty.CQRS.Grpc.Generators` — Source generator for .proto + gRPC service implementations
**Sample:** `Svrnty.Sample` — HTTP + gRPC demo
## Architecture
### Core CQRS Pattern
The framework uses handler interfaces that follow this pattern:
```csharp
// Command with no result
ICommandHandler<TCommand>
Task HandleAsync(TCommand command, CancellationToken cancellationToken = default)
// Command with result
ICommandHandler<TCommand, TResult>
Task<TResult> HandleAsync(TCommand command, CancellationToken cancellationToken = default)
// Query (always returns result)
IQueryHandler<TQuery, TResult>
Task<TResult> HandleAsync(TQuery query, CancellationToken cancellationToken = default)
```
### Metadata-Driven Discovery
The framework uses a **metadata pattern** for runtime discovery:
1. When you register a handler using `services.AddCommand<TCommand, THandler>()`, it:
- Registers the handler in DI as `ICommandHandler<TCommand, THandler>`
- Creates metadata (`ICommandMeta`) describing the command type, handler type, and result type
- Stores metadata as singleton in DI
2. Discovery services (`ICommandDiscovery`, `IQueryDiscovery`) implemented in `Svrnty.CQRS`:
- Query all registered metadata from DI container
- Provide lookup methods: `GetCommand(string name)`, `GetCommands()`, etc.
3. Endpoint mapping (HTTP and gRPC) uses discovery to:
- Enumerate all registered commands/queries
- Dynamically generate endpoints at application startup
- Apply naming conventions (convert to lowerCamelCase)
- Generate gRPC service implementations via source generators
**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
1. `services.AddCommand<TCommand, THandler>()` registers handler + creates `ICommandMeta`
2. `ICommandDiscovery` / `IQueryDiscovery` query all registered metadata from DI
3. Endpoint mapping (HTTP/gRPC) uses discovery to dynamically generate endpoints at startup
### Integration Options
There are two primary integration options for exposing commands and queries:
#### Option 1: gRPC (Recommended for performance-critical scenarios)
The **Svrnty.CQRS.Grpc** package with **Svrnty.CQRS.Grpc.Generators** source generator provides high-performance gRPC endpoints:
**Registration:**
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register CQRS services
builder.Services.AddSvrntyCQRS();
builder.Services.AddDefaultCommandDiscovery();
builder.Services.AddDefaultQueryDiscovery();
// Add your commands and queries
builder.Services.AddCommand<AddUserCommand, int, AddUserCommandHandler>();
builder.Services.AddCommand<RemoveUserCommand, RemoveUserCommandHandler>();
// Add gRPC support
builder.Services.AddGrpc();
var app = builder.Build();
// Map auto-generated gRPC service implementations
app.MapGrpcService<CommandServiceImpl>();
app.MapGrpcService<QueryServiceImpl>();
// Enable gRPC reflection for tools like grpcurl
app.MapGrpcReflectionService();
app.Run();
```
**How It Works:**
1. Define `.proto` files in `Protos/` directory with your commands/queries as messages
2. Source generator automatically creates `CommandServiceImpl` and `QueryServiceImpl` implementations
3. Property names in C# commands must match proto field names (case-insensitive)
4. FluentValidation is automatically integrated with **Google Rich Error Model** for structured validation errors
5. Validation errors return `google.rpc.Status` with `BadRequest` containing `FieldViolations`
**Features:**
- High-performance binary protocol
- Automatic service implementation generation at compile time
- Google Rich Error Model for structured validation errors
- Full FluentValidation integration
- gRPC reflection support for development tools
- Suitable for microservices, internal APIs, and low-latency scenarios
**Key Files:**
- `Svrnty.CQRS.Grpc/` - Runtime support for gRPC services
- `Svrnty.CQRS.Grpc.Generators/` - Source generator for service implementations
#### Option 2: HTTP via Minimal API (Recommended for web/browser scenarios)
The **Svrnty.CQRS.MinimalApi** package provides HTTP endpoints for CQRS commands and queries:
**Registration:**
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register CQRS services
builder.Services.AddSvrntyCQRS();
builder.Services.AddDefaultCommandDiscovery();
builder.Services.AddDefaultQueryDiscovery();
// Add your commands and queries
builder.Services.AddCommand<CreatePersonCommand, CreatePersonCommandHandler>();
builder.Services.AddQuery<PersonQuery, IQueryable<Person>, PersonQueryHandler>();
// Add Swagger (optional)
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Map endpoints (this creates routes automatically)
app.MapSvrntyCommands(); // Maps all commands to POST /api/command/{name}
app.MapSvrntyQueries(); // Maps all queries to POST/GET /api/query/{name}
app.Run();
```
**How It Works:**
1. Extension methods iterate through `ICommandDiscovery` and `IQueryDiscovery`
2. For each command/query, creates Minimal API endpoints using `MapPost()`/`MapGet()`
3. Applies naming conventions (lowerCamelCase)
4. Respects `[CommandControllerIgnore]` and `[QueryControllerIgnore]` attributes
5. Integrates with `ICommandAuthorizationService` and `IQueryAuthorizationService`
6. Supports OpenAPI/Swagger documentation
**Features:**
- Queries support both POST (with JSON body) and GET (with query string parameters)
- Commands only support POST with JSON body
- Authorization via authorization services (returns 401/403 status codes)
- Customizable route prefixes: `MapSvrntyCommands("my-prefix")`
- Automatic OpenAPI tags: "Commands" and "Queries"
- RFC 7807 Problem Details for validation errors
- Full Swagger/OpenAPI support
**Key Files:**
- `Svrnty.CQRS.MinimalApi/EndpointRouteBuilderExtensions.cs` - Main implementation
#### Option 3: Both gRPC and HTTP (Dual Protocol Support)
You can enable both protocols simultaneously, allowing clients to choose their preferred protocol:
```csharp
var builder = WebApplication.CreateBuilder(args);
// Register CQRS services
builder.Services.AddSvrntyCQRS();
builder.Services.AddDefaultCommandDiscovery();
builder.Services.AddDefaultQueryDiscovery();
// Add commands and queries
AddCommands(builder.Services);
AddQueries(builder.Services);
// Add both gRPC and HTTP support
builder.Services.AddGrpc();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Map both gRPC and HTTP endpoints
app.MapGrpcService<CommandServiceImpl>();
app.MapGrpcService<QueryServiceImpl>();
app.MapGrpcReflectionService();
app.MapSvrntyCommands();
app.MapSvrntyQueries();
app.Run();
```
**Benefits:**
- Single codebase supports multiple protocols
- gRPC for high-performance, low-latency scenarios (microservices, internal APIs)
- HTTP for web browsers, legacy clients, and public APIs
- Same commands, queries, and validation logic for both protocols
- Swagger UI available for HTTP endpoints, gRPC reflection for gRPC clients
- **gRPC** (recommended for performance): Source-generated `CommandServiceImpl` / `QueryServiceImpl`
- **HTTP** (recommended for web): `MapSvrntyCommands()` / `MapSvrntyQueries()` via Minimal API
- **Both**: Dual protocol support in single codebase
### Dynamic Query System
Dynamic queries provide OData-like filtering capabilities:
- `IDynamicQuery<TSource, TDestination>` with filters, sorts, groups, aggregates
- `IQueryableProvider<TSource>` provides base IQueryable
- `IAlterQueryableService<TSource, TDestination>` for middleware (security filters)
- Up to 5 interceptors per query type
**Core Components:**
- `IDynamicQuery<TSource, TDestination>` - Interface with GetFilters(), GetSorts(), GetGroups(), GetAggregates()
- `IQueryableProvider<TSource>` - Provides base IQueryable to query against
- `IAlterQueryableService<TSource, TDestination>` - Middleware to modify queries (e.g., security filters)
- `DynamicQueryHandler<TSource, TDestination>` - Executes queries using PoweredSoft.DynamicQuery
## Conventions
**Request Flow:**
1. HTTP request with filters/sorts/aggregates
2. Minimal API endpoint receives request
3. DynamicQueryHandler gets base queryable from IQueryableProvider
4. Applies alterations from all registered IAlterQueryableService instances
5. Builds PoweredSoft query criteria
6. Executes and returns IQueryExecutionResult
- Abstractions contain ONLY interfaces/attributes with minimal dependencies
- Handler naming: strip "Command"/"Query" suffix, convert to lowerCamelCase (e.g. `CreatePersonCommand``createPerson`)
- All handlers are async with CancellationToken support
- Endpoint mapping happens at startup — discovery must be registered first
- FluentValidation: HTTP returns RFC 7807, gRPC returns Google Rich Error Model
**Registration Example:**
```csharp
// Register dynamic query
services.AddDynamicQuery<Person, PersonDto>()
.AddDynamicQueryWithProvider<Person, PersonQueryableProvider>()
.AddAlterQueryable<Person, PersonDto, SecurityFilter>();
## Key Files
// Map dynamic query endpoints
app.MapSvrntyDynamicQueries(); // Creates POST/GET /api/query/{queryName} endpoints
```
**Key Files:**
- `Svrnty.CQRS.DynamicQuery/DynamicQueryHandler.cs` - Query execution logic
- `Svrnty.CQRS.DynamicQuery.MinimalApi/EndpointRouteBuilderExtensions.cs` - HTTP endpoint mapping
## Package Configuration
All projects target .NET 10.0 and use C# 14, sharing common configuration:
- **Target Framework**: `net10.0` (except DynamicQuery.Abstractions which multi-targets `netstandard2.1;net10.0`)
- **Language Version**: C# 14
- **IsAotCompatible**: Currently set but not enforced (many dependencies are not AOT-compatible yet)
- **Symbols**: Portable debug symbols with source, published as `.snupkg`
- **NuGet metadata**: Icon, README, license (MIT), and repository URL included in packages
- **Authors**: David Lebee, Mathias Beaulieu-Duncan
- **Repository**: https://git.openharbor.io/svrnty/dotnet-cqrs
### Package Dependencies
**Core Dependencies:**
- **Microsoft.Extensions.DependencyInjection.Abstractions**: 10.0.0
- **FluentValidation**: 11.11.0
- **PoweredSoft.DynamicQuery**: 3.0.1
- **Pluralize.NET**: 1.0.2
**gRPC Dependencies (for Svrnty.CQRS.Grpc):**
- **Grpc.AspNetCore**: 2.68.0 or later
- **Grpc.AspNetCore.Server.Reflection**: 2.71.0 or later (optional, for reflection)
- **Grpc.StatusProto**: 2.71.0 or later (for Rich Error Model validation)
- **Grpc.Tools**: 2.76.0 or later (for .proto compilation)
**Source Generator Dependencies (for Svrnty.CQRS.Grpc.Generators):**
- **Microsoft.CodeAnalysis.CSharp**: 5.0.0-2.final
- **Microsoft.CodeAnalysis.Analyzers**: 3.11.0
- **Microsoft.Build.Utilities.Core**: 17.0.0
- Targets: netstandard2.0 (for Roslyn compatibility)
- Handler interfaces: `Svrnty.CQRS.Abstractions/ICommandHandler.cs`, `IQueryHandler.cs`
- Discovery: `Svrnty.CQRS/Discovery/`
- Registration: `*/ServiceCollectionExtensions.cs`
- HTTP endpoints: `Svrnty.CQRS.MinimalApi/EndpointRouteBuilderExtensions.cs`
- gRPC generators: `Svrnty.CQRS.Grpc.Generators/`
## Publishing
NuGet packages are published automatically via GitHub Actions when a release is created:
NuGet packages via GitHub Actions on release: `.github/workflows/publish-nugets.yml`
**Workflow:** `.github/workflows/publish-nugets.yml`
1. Triggered on release publication
2. Extracts version from release tag
3. Runs `dotnet pack -c Release -p:Version={tag}`
4. Pushes to NuGet.org using `NUGET_API_KEY` secret
## What NOT to Do
**Manual publish:**
```bash
# Create packages with specific version
dotnet pack -c Release -o ./artifacts -p:Version=1.2.3
- Do NOT modify abstractions projects to add implementation dependencies
- Do NOT skip CancellationToken in handler signatures
- Do NOT call `MapSvrntyCommands()` before registering discovery services
- Do NOT add heavy dependencies to abstractions packages
# Push to NuGet
dotnet nuget push ./artifacts/*.nupkg --source https://api.nuget.org/v3/index.json --api-key YOUR_KEY
## Critical Rules
### Commit Authorship
All AI-authored commits MUST use:
```
Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
```
## Development Workflow
NEVER use:
- Third-party AI tool names (e.g. "Claude") in any Co-Authored-By
- Third-party AI company names (e.g. "Anthropic") in any Co-Authored-By
- Third-party AI tool names in commit messages
**Adding a New Command/Query Handler:**
### Documentation References
1. Create command/query POCO in consumer project
2. Implement handler: `ICommandHandler<TCommand, TResult>`
3. Register in DI: `services.AddCommand<CreatePersonCommand, CreatePersonCommandHandler>()`
4. (Optional) Add validator: `services.AddTransient<IValidator<CreatePersonCommand>, Validator>()`
5. Controller endpoint is automatically generated
- Do NOT reference third-party AI tool names as product names in any documentation
- Use "agent runtime", "agent CLI", or "Svrnty runtime" instead
- CLAUDE.md files keep their filename (industry standard) but content must not
mention third-party AI tool names as products
**Adding a New Feature to Framework:**
### Branch Strategy
1. Add interface to appropriate Abstractions project
2. Implement in corresponding implementation project
3. Update ServiceCollectionExtensions with registration method
4. Ensure all projects maintain AOT compatibility (unless AspNetCore-specific)
5. Update package version and release notes
- All repos use the `JP` branch for active development
- Always check which branch you're on before committing
**Naming Conventions:**
### Cross-Repo Changes
- Commands/Queries: Use `[CommandName]` or `[QueryName]` attribute for custom names
- Default naming: Strips "Command"/"Query" suffix, converts to lowerCamelCase
- Example: `CreatePersonCommand` -> `createPerson` endpoint
- If a change spans multiple repos, commit to each repo separately
- Reference the related repo in commit messages when relevant
- Run tests in each affected repo before committing
## C# 14 Language Features
## Documentation Triad
The project now uses C# 14, which introduces several new features. Be aware of these breaking changes:
This repo maintains three canonical files. Keep them in sync.
**Potential Breaking Changes:**
- **`field` keyword**: New contextual keyword in property accessors for implicit backing fields
- **`extension` keyword**: Reserved for extension containers; use `@extension` for identifiers
- **`partial` return type**: Cannot use `partial` as return type without escaping
- **Span<T> overload resolution**: New implicit conversions may select different overloads
- **`scoped` as lambda modifier**: Always treated as modifier in lambda parameters
### PROJECT.md — What & Why
- User perspective. No code, no architecture.
- Update when: features added/removed, scope changes, user-facing behaviour changes.
**New Features Available:**
- Extension members (static extension members and extension properties)
- Implicit span conversions
- Unbound generic types with `nameof`
- Lambda parameter modifiers without type specification
- Partial instance constructors and events
- Null-conditional assignment (`?.=` and `?[]=`)
### GRAPH.md — Architecture
- Unicode cascade diagrams. Entire file IS the diagram.
- Update when: modules added/removed, data flow changes, API surface changes.
The codebase currently compiles without warnings on C# 14.
## Important Implementation Notes
1. **AOT Compatibility**: Currently not enforced. The `IsAotCompatible` property is set on some projects but many dependencies (including FluentValidation, PoweredSoft.DynamicQuery) are not AOT-compatible. Future work may address this.
2. **Async Everywhere**: All handlers are async. Always support CancellationToken.
3. **Generic Type Safety**: Framework relies heavily on generics for compile-time safety. When adding features, maintain strong typing.
4. **Metadata Pattern**: When extending discovery, always create corresponding metadata classes (implement ICommandMeta/IQueryMeta).
5. **Endpoint Mapping Timing**: Endpoints are mapped at application startup. Discovery services must be registered before calling `MapSvrntyCommands()`/`MapSvrntyQueries()` or mapping gRPC services.
6. **FluentValidation Integration**:
- For HTTP: Validation happens automatically in the Minimal API pipeline. Errors return RFC 7807 Problem Details.
- For gRPC: Validation happens automatically via source-generated services. Errors return Google Rich Error Model with structured FieldViolations.
- The framework REGISTERS validators in DI; actual validation execution is handled by the endpoint implementations.
7. **DynamicQuery Interceptors**: Support up to 5 interceptors per query type. Interceptors modify PoweredSoft DynamicQuery behavior.
## Common Code Locations
- Handler interfaces: `Svrnty.CQRS.Abstractions/ICommandHandler.cs`, `IQueryHandler.cs`
- Discovery implementations: `Svrnty.CQRS/Discovery/`
- Service registration: `*/ServiceCollectionExtensions.cs` in each project
- HTTP endpoint mapping: `Svrnty.CQRS.MinimalApi/EndpointRouteBuilderExtensions.cs`
- Dynamic query logic: `Svrnty.CQRS.DynamicQuery/DynamicQueryHandler.cs`
- Dynamic query endpoints: `Svrnty.CQRS.DynamicQuery.MinimalApi/EndpointRouteBuilderExtensions.cs`
- gRPC support: `Svrnty.CQRS.Grpc/` runtime, `Svrnty.CQRS.Grpc.Generators/` source generators
- Sample application: `Svrnty.Sample/` - demonstrates both HTTP and gRPC integration
### CLAUDE.md — How to Work Here
- Assembled by perfecto from shared fragments + repo body.
- To update repo content: edit `perfecto/repo/<name>.body.md` then run `perfecto build <name>`
- To update shared conventions: edit `JP/CLAUDE.md`, update `perfecto/shared/`, then run `perfecto build --all`
## GRAPH.md Maintenance

42
PROJECT.md Normal file
View File

@ -0,0 +1,42 @@
# dotnet-cqrs
> Modern CQRS implementation for .NET 10 with HTTP and gRPC endpoint generation.
## Purpose
Svrnty.CQRS provides a framework for implementing the Command Query Responsibility Segregation pattern in .NET applications. It automatically generates HTTP endpoints (via Minimal API) and gRPC service implementations (via source generators) from registered command and query handlers.
## What It Does
- **Automatic HTTP endpoints** — registers handlers, generates REST endpoints at startup
- **Automatic gRPC services** — source-generated service implementations from .proto files
- **Dynamic queries** — OData-like filtering, sorting, grouping, and aggregation
- **Validation** — FluentValidation with RFC 7807 (HTTP) and Google Rich Error Model (gRPC)
- **Dual protocol** — same handlers serve both HTTP and gRPC simultaneously
## How It Works
1. Define a command/query as a C# class
2. Implement a handler (`ICommandHandler<T>` or `IQueryHandler<T, R>`)
3. Register with DI: `services.AddCommand<T, Handler>()`
4. Framework creates metadata and discovery services at startup
5. `MapSvrntyCommands()` generates HTTP endpoints; `MapGrpcService<>()` maps gRPC services
## Key Concepts
| Term | Meaning |
|------|---------|
| Command | An action that changes state (always POST) |
| Query | A request for data (POST or GET) |
| Discovery | Runtime service that enumerates all registered commands/queries |
| Source Generator | Compile-time code generation for gRPC service implementations |
| Dynamic Query | OData-like filtering with IQueryable providers and interceptors |
## Current Status
| Phase | Status | Description |
|-------|--------|-------------|
| 0 | Done | Core CQRS, Minimal API, FluentValidation |
| 1 | Done | gRPC support, source generators |
| 2 | Done | Dynamic queries, dual protocol |
| 3 | Planned | Test suite, AOT compatibility |