Compare commits

...

2 Commits

Author SHA1 Message Date
3fa59306c2 docs: add security policy
Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
2026-03-05 05:59:26 -05:00
697b36900b docs: standardize documentation structure
- CLAUDE.md: universal development guidelines
- README.md: project description (consistent template)
- CONTRIBUTING.md: contribution workflow
- CHANGELOG.md: version history

Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
2026-03-05 05:53:27 -05:00
8 changed files with 211 additions and 602 deletions

17
CHANGELOG.md Normal file
View File

@ -0,0 +1,17 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Initial project setup
### Changed
### Fixed
### Removed

180
CLAUDE.md
View File

@ -1,155 +1,79 @@
# dotnet-cqrs -- Development Guide # Development Guidelines
## Overview Universal development practices for all Svrnty/a-gent repositories.
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). ## Engineering Principles
## Tech Stack ### KISS (Keep It Simple)
- Prefer straightforward control flow over clever meta-programming
- Keep error paths obvious and localized
- **Framework:** .NET 10 / C# 14 ### YAGNI (You Aren't Gonna Need It)
- **Packages:** 10 NuGet packages + 1 sample project - Do not add features without concrete accepted use case
- **gRPC:** Grpc.AspNetCore 2.68+, source-generated service implementations - Do not introduce speculative abstractions
- **Validation:** FluentValidation 11.11.0
- **Dynamic queries:** PoweredSoft.DynamicQuery 3.0.1
## Build & Test ### DRY + Rule of Three
- Duplicate small logic when it preserves clarity
- Extract shared utilities only after 3+ repeated patterns
```bash ### SRP + ISP (Single Responsibility + Interface Segregation)
# Restore dependencies - Keep each module focused on one concern
dotnet restore - Avoid "god modules" mixing multiple responsibilities
# Build entire solution ### Fail Fast + Explicit Errors
dotnet build - Prefer explicit errors for unsupported states
- Document fallback behavior when intentional
# Build in Release mode ### Secure by Default
dotnet build -c Release - Deny-by-default for access boundaries
- Never log secrets or sensitive payloads
# Create NuGet packages ## Agent Workflow
dotnet pack -c Release -o ./artifacts -p:Version=1.0.0
```
No test projects currently. When adding tests: `tests/` directory, `.Tests` suffix. 1. **Read before write** - Inspect existing code before editing
2. **Define scope** - One concern per PR
3. **Implement minimal patch** - Apply KISS/YAGNI explicitly
4. **Validate** - Run lint, format, test before commit
5. **Document impact** - Note behavior changes and risks
## Solution Structure ## Branch Strategy
**Abstractions (interfaces only):** - All repos use `JP` branch for active development
- `Svrnty.CQRS.Abstractions` — Core interfaces (ICommandHandler, IQueryHandler) - Always verify current branch before committing
- `Svrnty.CQRS.DynamicQuery.Abstractions` — Dynamic query interfaces (multi-targets netstandard2.1 + net10.0)
- `Svrnty.CQRS.Grpc.Abstractions` — gRPC-specific contracts
**Implementation:** ## Commit Rules
- `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
### Metadata-Driven Discovery
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
- **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
- `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
## Conventions
- 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
## Key Files
- 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 via GitHub Actions on release: `.github/workflows/publish-nugets.yml`
## What NOT to Do
- 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
## Critical Rules
### Commit Authorship
All AI-authored commits MUST use: All AI-authored commits MUST use:
``` ```
Co-Authored-By: Svrnty Inc. <eng@svrnty.com> Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
``` ```
NEVER use: NEVER use third-party AI tool/company names in commits.
- 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
### Documentation References ## PR Discipline
- Do NOT reference third-party AI tool names as product names in any documentation - Clear, scoped commit messages
- Use "agent runtime", "agent CLI", or "Svrnty runtime" instead - Small PRs preferred
- CLAUDE.md files keep their filename (industry standard) but content must not - Never commit personal/sensitive data
mention third-party AI tool names as products - Reference related repos for cross-repo changes
### Branch Strategy ## Validation
- All repos use the `JP` branch for active development Run before every commit:
- Always check which branch you're on before committing - Format check (language-specific)
- Lint check (language-specific)
- Test suite
### Cross-Repo Changes ## Anti-Patterns
- If a change spans multiple repos, commit to each repo separately - Do NOT add heavy dependencies for minor convenience
- Reference the related repo in commit messages when relevant - Do NOT mix formatting-only with functional changes
- Run tests in each affected repo before committing - Do NOT modify unrelated modules "while here"
- Do NOT bypass failing checks without explanation
## Documentation Triad ## Cross-Repo Changes
This repo maintains three canonical files. Keep them in sync. When changes span multiple repos:
1. Commit to each repo separately
### PROJECT.md — What & Why 2. Reference related repo in commit message
- User perspective. No code, no architecture. 3. Run tests in each affected repo before commit
- Update when: features added/removed, scope changes, user-facing behaviour changes.
### GRAPH.md — Architecture
- Unicode cascade diagrams. Entire file IS the diagram.
- Update when: modules added/removed, data flow changes, API surface changes.
### CLAUDE.md — How to Work Here
- Agent development guide for this repository.
- Update when: build commands change, conventions change, new patterns established.
## GRAPH.md Maintenance
This repo contains a `GRAPH.md` file with unicode cascade diagrams showing the
architecture. **You MUST update GRAPH.md whenever you**:
- Add, remove, or rename modules, directories, or major components
- Change data flow, dependencies, or integration points
- Modify the public API surface or protocol contracts
Keep the diagrams accurate. They are read by non-technical stakeholders.

52
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,52 @@
# Contributing
Thank you for your interest in contributing to this project.
## Development Guidelines
See [CLAUDE.md](./CLAUDE.md) for development practices, engineering principles, and coding standards.
## How to Contribute
1. **Fork & Clone**
```bash
git clone <your-fork-url>
cd <project>
git checkout JP
```
2. **Create a Branch**
```bash
git checkout -b feature/your-feature-name
```
3. **Make Changes**
- Follow the guidelines in CLAUDE.md
- Keep changes focused and minimal
- Write tests if applicable
4. **Validate**
- Run format checks
- Run lint checks
- Run test suite
5. **Commit**
```bash
git commit -m "feat: your change description"
```
AI-authored commits must include:
```
Co-Authored-By: Svrnty Inc. <eng@svrnty.com>
```
6. **Push & Create PR**
```bash
git push origin feature/your-feature-name
```
- Open a PR against the `JP` branch
- Provide clear description of changes
## Questions?
Open an issue for questions or discussions.

View File

@ -1,57 +0,0 @@
╔══════════════════════════════════════════════════════════╗
║ dotnet-cqrs Architecture ║
╚══════════════════════════════════════════════════════════╝
PACKAGE LAYERS
══════════════
┌─────────────────────────────────────────────────────┐
│ Abstractions (Interfaces) │
│ ICommandHandler<T> IQueryHandler<T,R>
│ ICommandDiscovery IQueryDiscovery │
│ IDynamicQuery<S,D> IQueryableProvider<S>
└─────────────────────────┬───────────────────────────┘
│ implements
┌─────────────────────────▼───────────────────────────┐
│ Core Implementation │
│ CQRS (discovery + dispatch) │
│ DynamicQuery (OData-like filter/sort/group) │
│ FluentValidation (validators → RFC 7807 errors) │
└─────────────────────────┬───────────────────────────┘
│ exposes via
┌─────────────────────────▼───────────────────────────┐
│ Protocol / Transport │
│ MinimalApi ─── HTTP endpoints (auto-mapped) │
│ Grpc ───────── gRPC endpoints (source-generated) │
│ Grpc.Generators ── compile-time codegen │
└─────────────────────────┬───────────────────────────┘
│ optional
┌─────────────────────────▼───────────────────────────┐
│ Extended Features │
│ Events + Events.RabbitMQ ── event sourcing │
│ Sagas + Sagas.RabbitMQ ─── long-running txns │
│ DynamicQuery.EF ────────── Entity Framework │
│ Notifications ──────────── real-time push │
└─────────────────────────────────────────────────────┘
METADATA-DRIVEN ENDPOINT FLOW
══════════════════════════════
Developer writes handler:
ICommandHandler<CreatePersonCommand, PersonResult>
DI registration (AddSvrntyCqrs)
Discovery auto-enumerates all handlers
┌────┴────────────────────┐
│ │
▼ ▼
HTTP: MapSvrntyCommands() gRPC: Source Generator
POST /api/command/ CommandServiceImpl
createPerson QueryServiceImpl
(compile-time generated)

View File

@ -1,42 +0,0 @@
# 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 |

290
README.md
View File

@ -1,282 +1,66 @@
> This project was originally initiated by [Powered Software Inc.](https://poweredsoft.com/) and was forked from the [PoweredSoft.CQRS](https://github.com/PoweredSoft/CQRS) Repository # Svrnty.CQRS
# CQRS > Modern CQRS framework for .NET with gRPC source generation and HTTP Minimal API support.
Our implementation of query and command responsibility segregation (CQRS).
## Where This Fits ## Where This Fits
This is a backend framework of the [Svrnty Agent System](../README.md). **Layer**: libs
**Layer**: Framework
**Depends on**: Nothing (standalone .NET framework) **Depends on**: Nothing (standalone .NET framework)
**Depended on by**: a-gent-app (backend services), flutter_cqrs_datasource (client) **Depended on by**: a-gent-app (backend services), flutter-cqrs-datasource (client)
**Git**: [git.openharbor.io/svrnty/dotnet-cqrs](https://git.openharbor.io/svrnty/dotnet-cqrs) **Git**: git.openharbor.io/svrnty/dotnet-cqrs.git
## Getting Started ## Tech Stack
> Install nuget package to your awesome project. - **Language**: C# 14 / .NET 10
- **Framework**: ASP.NET Core Minimal API, gRPC
- **Key Dependencies**: FluentValidation 11.x, Grpc.AspNetCore, PoweredSoft.DynamicQuery
| Package Name | NuGet | NuGet Install | ## Quick Start
|-----------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |-----------------------------------------------------------------------:|
| Svrnty.CQRS | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS/) | ```dotnet add package Svrnty.CQRS ``` |
| Svrnty.CQRS.MinimalApi | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.MinimalApi.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.MinimalApi/) | ```dotnet add package Svrnty.CQRS.MinimalApi ``` |
| Svrnty.CQRS.FluentValidation | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.FluentValidation.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.FluentValidation/) | ```dotnet add package Svrnty.CQRS.FluentValidation ``` |
| Svrnty.CQRS.DynamicQuery | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.DynamicQuery.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.DynamicQuery/) | ```dotnet add package Svrnty.CQRS.DynamicQuery ``` |
| Svrnty.CQRS.DynamicQuery.MinimalApi | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.DynamicQuery.MinimalApi.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.DynamicQuery.MinimalApi/) | ```dotnet add package Svrnty.CQRS.DynamicQuery.MinimalApi ``` |
| Svrnty.CQRS.Grpc | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Grpc.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Grpc/) | ```dotnet add package Svrnty.CQRS.Grpc ``` |
| Svrnty.CQRS.Grpc.Generators | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Grpc.Generators.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Grpc.Generators/) | ```dotnet add package Svrnty.CQRS.Grpc.Generators ``` |
> Abstractions Packages.
| Package Name | NuGet | NuGet Install |
| ---------------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -----------------------------------------------------: |
| Svrnty.CQRS.Abstractions | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Abstractions/) | ```dotnet add package Svrnty.CQRS.Abstractions ``` |
| Svrnty.CQRS.DynamicQuery.Abstractions | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.DynamicQuery.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.DynamicQuery.Abstractions/) | ```dotnet add package Svrnty.CQRS.DynamicQuery.Abstractions ``` |
| Svrnty.CQRS.Grpc.Abstractions | [![NuGet](https://img.shields.io/nuget/v/Svrnty.CQRS.Grpc.Abstractions.svg?style=flat-square&label=nuget)](https://www.nuget.org/packages/Svrnty.CQRS.Grpc.Abstractions/) | ```dotnet add package Svrnty.CQRS.Grpc.Abstractions ``` |
## Sample of startup code for gRPC (Recommended)
```csharp
using Svrnty.CQRS;
using Svrnty.CQRS.FluentValidation;
using Svrnty.CQRS.Grpc;
var builder = WebApplication.CreateBuilder(args);
// Register your commands with validators
builder.Services.AddCommand<AddUserCommand, int, AddUserCommandHandler, AddUserCommandValidator>();
builder.Services.AddCommand<RemoveUserCommand, RemoveUserCommandHandler>();
// Register your queries
builder.Services.AddQuery<FetchUserQuery, User, FetchUserQueryHandler>();
// Configure CQRS with gRPC support
builder.Services.AddSvrntyCqrs(cqrs =>
{
// Enable gRPC endpoints with reflection
cqrs.AddGrpc(grpc =>
{
grpc.EnableReflection();
});
});
var app = builder.Build();
// Map all configured CQRS endpoints
app.UseSvrntyCqrs();
app.Run();
```
### Important: gRPC Requirements
The gRPC implementation uses **Grpc.Tools** with `.proto` files and **source generators** for automatic service implementation:
#### 1. Install required packages:
```bash ```bash
dotnet add package Grpc.AspNetCore # Build
dotnet add package Grpc.AspNetCore.Server.Reflection dotnet build
dotnet add package Grpc.StatusProto # For Rich Error Model validation
# Run
dotnet run --project Svrnty.Sample
# Test
dotnet test
``` ```
#### 2. Add the source generator as an analyzer: ## Architecture
```bash 10 NuGet packages organized by concern:
dotnet add package Svrnty.CQRS.Grpc.Generators
```
The source generator is automatically configured as an analyzer when installed via NuGet and will generate both the `.proto` files and gRPC service implementations at compile time. - **Abstractions**: Core interfaces (ICommandHandler, IQueryHandler)
- **Core**: Discovery, registration, handler execution
- **MinimalApi**: HTTP endpoint mapping with RFC 7807 validation
- **Grpc**: gRPC service support with Google Rich Error Model
- **Grpc.Generators**: Source generator for .proto files and service implementations
- **DynamicQuery**: PoweredSoft integration for filtering, sorting, paging
- **FluentValidation**: Validator registration helpers
#### 3. Define your C# commands and queries: ## Configuration
```csharp ```csharp
public record AddUserCommand // Register handlers
{ builder.Services.AddCommand<CreateUserCommand, int, CreateUserCommandHandler>();
public required string Name { get; init; } builder.Services.AddQuery<GetUserQuery, User, GetUserQueryHandler>();
public required string Email { get; init; }
public int Age { get; init; }
}
public record RemoveUserCommand // Configure CQRS with gRPC + HTTP
{
public int UserId { get; init; }
}
```
**Notes:**
- The source generator automatically creates:
- `.proto` files in the `Protos/` directory from your C# commands and queries
- `CommandServiceImpl` and `QueryServiceImpl` implementations
- FluentValidation is automatically integrated with **Google Rich Error Model** for structured validation errors
- Validation errors return `google.rpc.Status` with `BadRequest` containing `FieldViolations`
- Use `record` types for commands/queries (immutable, value-based equality, more concise)
- No need for protobuf-net attributes - just define your C# types
## Sample of startup code for Minimal API (HTTP)
For HTTP scenarios (web browsers, public APIs), you can use the Minimal API approach:
```csharp
using Svrnty.CQRS;
using Svrnty.CQRS.FluentValidation;
using Svrnty.CQRS.MinimalApi;
var builder = WebApplication.CreateBuilder(args);
// Register your commands with validators
builder.Services.AddCommand<CreatePersonCommand, CreatePersonCommandHandler, CreatePersonCommandValidator>();
builder.Services.AddCommand<EchoCommand, string, EchoCommandHandler, EchoCommandValidator>();
// Register your queries
builder.Services.AddQuery<PersonQuery, IQueryable<Person>, PersonQueryHandler>();
// Configure CQRS with Minimal API support
builder.Services.AddSvrntyCqrs(cqrs => builder.Services.AddSvrntyCqrs(cqrs =>
{ {
// Enable Minimal API endpoints cqrs.AddGrpc(grpc => grpc.EnableReflection());
cqrs.AddMinimalApi(); cqrs.AddMinimalApi();
}); });
// Add Swagger (optional)
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// Map all configured CQRS endpoints (automatically creates POST /api/command/* and POST/GET /api/query/*)
app.UseSvrntyCqrs(); app.UseSvrntyCqrs();
app.Run();
``` ```
**Notes:** ## Contributing
- FluentValidation is automatically integrated with **RFC 7807 Problem Details** for structured validation errors
- Use `record` types for commands/queries (immutable, value-based equality, more concise)
- Supports both POST and GET (for queries) endpoints
- Automatically generates Swagger/OpenAPI documentation
## Sample enabling both gRPC and HTTP See [CLAUDE.md](./CLAUDE.md) for development guidelines.
You can enable both gRPC and traditional HTTP endpoints simultaneously, allowing clients to choose their preferred protocol: ## License
```csharp MIT OR Apache-2.0
using Svrnty.CQRS;
using Svrnty.CQRS.FluentValidation;
using Svrnty.CQRS.Grpc;
using Svrnty.CQRS.MinimalApi;
var builder = WebApplication.CreateBuilder(args);
// Register your commands with validators
builder.Services.AddCommand<AddUserCommand, int, AddUserCommandHandler, AddUserCommandValidator>();
builder.Services.AddCommand<RemoveUserCommand, RemoveUserCommandHandler>();
// Register your queries
builder.Services.AddQuery<FetchUserQuery, User, FetchUserQueryHandler>();
// Configure CQRS with both gRPC and Minimal API support
builder.Services.AddSvrntyCqrs(cqrs =>
{
// Enable gRPC endpoints with reflection
cqrs.AddGrpc(grpc =>
{
grpc.EnableReflection();
});
// Enable Minimal API endpoints
cqrs.AddMinimalApi();
});
// Add HTTP support with Swagger
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// Map all configured CQRS endpoints (both gRPC and HTTP)
app.UseSvrntyCqrs();
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
# Fluent Validation
FluentValidation is optional but recommended for command and query validation. The `Svrnty.CQRS.FluentValidation` package provides extension methods to simplify validator registration.
## With Svrnty.CQRS.FluentValidation (Recommended)
The package exposes extension method overloads that accept the validator as a generic parameter:
```bash
dotnet add package Svrnty.CQRS.FluentValidation
```
```csharp
using Svrnty.CQRS.FluentValidation; // Extension methods for validator registration
// Command with result - validator as last generic parameter
builder.Services.AddCommand<EchoCommand, string, EchoCommandHandler, EchoCommandValidator>();
// Command without result - validator included in generics
builder.Services.AddCommand<CreatePersonCommand, CreatePersonCommandHandler, CreatePersonCommandValidator>();
```
**Benefits:**
- **Single line registration** - Handler and validator registered together
- **Type safety** - Compiler ensures validator matches command type
- **Less boilerplate** - No need for separate `AddTransient<IValidator<T>>()` calls
- **Cleaner code** - Clear intent that validation is part of command pipeline
## Without Svrnty.CQRS.FluentValidation
If you prefer not to use the FluentValidation package, you need to register commands and validators separately:
```csharp
using FluentValidation;
using Svrnty.CQRS;
// Register command handler
builder.Services.AddCommand<EchoCommand, string, EchoCommandHandler>();
// Manually register validator
builder.Services.AddTransient<IValidator<EchoCommand>, EchoCommandValidator>();
```
# 2024-2025 Roadmap
| Task | Description | Status |
|----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|--------|
| Support .NET 10 | .NET 10 with C# 14 language support. | ✅ |
| Update FluentValidation | Upgrade FluentValidation to version 11.x for .NET 10 compatibility. | ✅ |
| Add gRPC Support with source generators | Implement gRPC endpoints with source generators and Google Rich Error Model for validation. | ✅ |
| Create a demo project (Svrnty.CQRS.Grpc.Sample) | Develop a comprehensive demo project showcasing gRPC and HTTP endpoints. | ✅ |
| Create a website for the Framework | Develop a website to host comprehensive documentation for the framework. | ⬜️ |
# 2026 Roadmap
| Task | Description | Status |
|----------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|--------|
| gRPC Compression Support | Smart message compression with automatic threshold detection and per-handler control. | ⬜️ |
| gRPC Metadata & Authorization Support | Expose ServerCallContext to handlers and integrate authorization services for gRPC endpoints. | ⬜️ |

View File

@ -1,122 +0,0 @@
# Saga Orchestration Roadmap
## Completed (Phase 1)
- [x] `Svrnty.CQRS.Sagas.Abstractions` - Core interfaces and contracts
- [x] `Svrnty.CQRS.Sagas` - Orchestration engine with fluent builder API
- [x] `Svrnty.CQRS.Sagas.RabbitMQ` - RabbitMQ message transport
---
## Phase 1d: Testing & Sample
### Unit Tests
- [ ] `SagaBuilder` step configuration tests
- [ ] `SagaOrchestrator` execution flow tests
- [ ] `SagaOrchestrator` compensation flow tests
- [ ] `InMemorySagaStateStore` persistence tests
- [ ] `RabbitMqSagaMessageBus` serialization tests
### Integration Tests
- [ ] End-to-end saga execution with RabbitMQ
- [ ] Multi-step saga with compensation scenario
- [ ] Concurrent saga execution tests
- [ ] Connection recovery tests
### Sample Implementation
- [ ] `OrderProcessingSaga` example in WarehouseManagement
- ReserveInventory step
- ProcessPayment step
- CreateShipment step
- Full compensation flow
---
## Phase 2: Persistence
### Svrnty.CQRS.Sagas.EntityFramework
- [ ] `EfCoreSagaStateStore` implementation
- [ ] `SagaState` entity configuration
- [ ] Migration support
- [ ] PostgreSQL/SQL Server compatibility
- [ ] Optimistic concurrency handling
### Configuration
```csharp
cqrs.AddSagas()
.UseEntityFramework<AppDbContext>();
```
---
## Phase 3: Reliability
### Saga Timeout Service
- [ ] `SagaTimeoutHostedService` - background service for stalled sagas
- [ ] Configurable timeout per saga type
- [ ] Automatic compensation trigger on timeout
- [ ] Dead letter handling for failed compensations
### Retry Policies
- [ ] Exponential backoff support
- [ ] Circuit breaker integration
- [ ] Polly integration option
### Idempotency
- [ ] Message deduplication
- [ ] Idempotent step execution
- [ ] Inbox/Outbox pattern support
---
## Phase 4: Observability
### OpenTelemetry Integration
- [ ] Distributed tracing for saga execution
- [ ] Span per saga step
- [ ] Correlation ID propagation
- [ ] Metrics (saga duration, success/failure rates)
### Saga Dashboard (Optional)
- [ ] Web UI for saga monitoring
- [ ] Real-time saga status
- [ ] Manual compensation trigger
- [ ] Saga history and audit log
---
## Phase 5: Flutter Integration
### gRPC Streaming for Saga Status
- [ ] `ISagaStatusStream` service
- [ ] Real-time saga progress updates
- [ ] Step completion notifications
- [ ] Error/compensation notifications
### Flutter Client
- [ ] Dart client for saga status streaming
- [ ] Saga progress widget components
---
## Phase 6: Alternative Transports
### Svrnty.CQRS.Sagas.AzureServiceBus
- [ ] Azure Service Bus message transport
- [ ] Topic/Subscription topology
- [ ] Dead letter queue handling
### Svrnty.CQRS.Sagas.Kafka
- [ ] Kafka message transport
- [ ] Consumer group management
- [ ] Partition key strategies
---
## Future Considerations
- **Event Sourcing**: Saga state as event stream
- **Saga Versioning**: Handle saga definition changes gracefully
- **Saga Composition**: Nested/child sagas
- **Saga Scheduling**: Delayed saga start
- **Multi-tenancy**: Tenant-aware saga execution

53
SECURITY.md Normal file
View File

@ -0,0 +1,53 @@
# Security Policy
## Reporting a Vulnerability
If you discover a security vulnerability, please report it responsibly.
**Do NOT open a public issue.**
### How to Report
Email: **security@svrnty.com**
Include:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Any suggested fixes (optional)
### Response Timeline
- **Acknowledgment**: Within 48 hours
- **Initial Assessment**: Within 7 days
- **Resolution Target**: Within 30 days (depending on severity)
### What to Expect
1. We will acknowledge receipt of your report
2. We will investigate and validate the issue
3. We will work on a fix and coordinate disclosure
4. We will credit you (if desired) when the fix is released
### Scope
This policy applies to:
- Code in this repository
- Dependencies we control
- Infrastructure we operate
### Out of Scope
- Third-party services or dependencies
- Social engineering attacks
- Physical security
## Supported Versions
Security updates are provided for the latest release only.
| Version | Supported |
|---------|-----------|
| Latest | Yes |
| Older | No |