- 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>
3.2 KiB
3.2 KiB
| paths | |||
|---|---|---|---|
|
gRPC Integration
Proto File Conventions
Proto files live in Protos/ directory. The source generator (Svrnty.CQRS.Grpc.Generators) auto-generates service implementations at compile time.
Service Structure
service CommandService {
rpc PlaceOrder (PlaceOrderCommandRequest) returns (PlaceOrderCommandResponse);
}
service QueryService {
rpc FetchUserById (FetchUserByIdQueryRequest) returns (FetchUserByIdQueryResponse);
}
service DynamicQueryService {
rpc QueryOrders (DynamicQueryOrdersRequest) returns (DynamicQueryOrdersResponse);
}
Naming Rules
- RPC method name: command/query name without the
Command/Querysuffix - Request message:
{Name}CommandRequestor{Name}QueryRequest - Response message:
{Name}CommandResponseor{Name}QueryResponse - Dynamic query request:
DynamicQuery{PluralEntity}Request - Dynamic query response:
DynamicQuery{PluralEntity}Response - Fields use
snake_case(proto convention), mapped case-insensitively to C#PascalCaseproperties
Field Mapping
C# property names must match proto field names (case-insensitive):
| C# Property | Proto Field |
|---|---|
UserId |
user_id |
Name |
name |
EmailAddress |
email_address |
OrderItems |
order_items |
Type Mapping
| C# | Proto |
|---|---|
int |
int32 |
long |
int64 |
string |
string |
bool |
bool |
double |
double |
float |
float |
List<T> |
repeated T |
| complex type | message |
Dynamic Query Messages (standard, reuse across entities)
message DynamicQueryFilter {
string path = 1;
int32 type = 2; // PoweredSoft.DynamicQuery.Core.FilterType
string value = 3;
repeated DynamicQueryFilter and = 4;
repeated DynamicQueryFilter or = 5;
}
message DynamicQuerySort {
string path = 1;
bool ascending = 2;
}
message DynamicQueryGroup {
string path = 1;
}
message DynamicQueryAggregate {
string path = 1;
int32 type = 2; // PoweredSoft.DynamicQuery.Core.AggregateType
}
Source Generator Behavior
The generator in Svrnty.CQRS.Grpc.Generators auto-creates:
CommandServiceImpl— implementsCommandService.CommandServiceBaseQueryServiceImpl— implementsQueryService.QueryServiceBaseDynamicQueryServiceImpl— implementsDynamicQueryService.DynamicQueryServiceBaseGrpcServiceRegistration— auto-registration code
Generated implementations handle:
- Request-to-POCO property mapping
- Validator invocation (if registered) with Google Rich Error Model errors
- Handler invocation with proper
CancellationToken - DI scope management via
IServiceScopeFactory
Validation in gRPC
Validation errors return google.rpc.Status with BadRequest detail containing FieldViolations. This is automatic — do not manually validate in handlers.
Registration
builder.Services.AddSvrntyCqrs(cqrs =>
{
cqrs.AddGrpc(grpc => grpc.EnableReflection()); // reflection for grpcurl/grpcui
});