Marketplace
cqrs-architecture
CQRS pattern implementation and query optimization
allowed_tools: Read, Glob, Grep, Write, Edit
$ Installer
git clone https://github.com/melodic-software/claude-code-plugins /tmp/claude-code-plugins && cp -r /tmp/claude-code-plugins/plugins/event-modeling/skills/cqrs-architecture ~/.claude/skills/claude-code-plugins// tip: Run this command in your terminal to install the skill
SKILL.md
name: cqrs-architecture description: CQRS pattern implementation and query optimization allowed-tools: Read, Glob, Grep, Write, Edit
CQRS Architecture Skill
Design and implement Command Query Responsibility Segregation patterns for scalable systems.
MANDATORY: Documentation-First Approach
Before implementing CQRS:
- Invoke
docs-managementskill for CQRS patterns - Verify patterns via MCP servers (perplexity, context7)
- Base guidance on established CQRS literature
CQRS Fundamentals
Traditional vs CQRS:
TRADITIONAL (Single Model):
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Domain Model โ
โ (Reads + Writes) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ Database โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CQRS (Separated Models):
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
โ Command Side โ โ Query Side โ
โ (Write Model) โ โ (Read Model) โ
โโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโค
โ Domain Logic โ โ DTO/Views โ
โ Aggregates โ โ Projections โ
โโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโค
โ Write DB โโโโโบโ Read DB โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ
CQRS Levels
Level 1: Logical Separation
Same database, separate code paths:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโค
โ Command Handlers โ Query Handlers โ
โ - Validation โ - Direct SQL โ
โ - Domain Logic โ - Projections โ
โ - Events โ - DTOs โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโค
โ Single Database โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Benefits:
โ Clean separation in code
โ Simple deployment
โ Single source of truth
โ Good starting point
Level 2: Separate Read Models
Same write DB, separate read DB:
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Command Side โ โ Query Side โ
โโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโค
โ Command Handler โ โ Query Handler โ
โ Domain Model โ โ DTOs โ
โโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโค
โ Write Database โโโโโบโ Read Database โ
โ (Normalized) โsyncโ (Denormalized) โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
Benefits:
โ Optimized read performance
โ Scale reads independently
โ Different storage technologies
โ Eventually consistent reads
Level 3: Event-Sourced CQRS
Event store as write model, projections as read:
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Command Side โ โ Query Side โ
โโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโค
โ Command Handler โ โ Query Handler โ
โ Aggregate โ โ Read Models โ
โโโโโโโโโโโโโโโโโโโค โโโโโโโโโโโโโโโโโโโค
โ Event Store โโโโโบโ Multiple Read โ
โ (Append-only) โ โ Databases โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
Benefits:
โ Complete audit trail
โ Temporal queries
โ Multiple projections
โ Rebuild read models
Command Side Design
Command Structure
// Command Definition
public record PlaceOrderCommand(
Guid CustomerId,
List<OrderItemDto> Items,
string ShippingAddress
) : ICommand<OrderId>;
// Command Handler
public class PlaceOrderHandler : ICommandHandler<PlaceOrderCommand, OrderId>
{
private readonly IOrderRepository _repository;
private readonly IEventPublisher _events;
public async Task<OrderId> HandleAsync(
PlaceOrderCommand command,
CancellationToken ct)
{
// Validation
if (!command.Items.Any())
throw new ValidationException("Order must have items");
// Domain logic
var order = Order.Create(
command.CustomerId,
command.Items.Select(i => new OrderItem(i.ProductId, i.Quantity)));
// Persistence
await _repository.SaveAsync(order, ct);
// Publish events
await _events.PublishAsync(order.GetDomainEvents(), ct);
return order.Id;
}
}
Command Patterns
Command Best Practices:
NAMING:
- Imperative: PlaceOrder, CancelOrder, UpdateAddress
- Include context: not just "Create" but "CreateOrder"
STRUCTURE:
- Immutable (records)
- Only data needed for operation
- No business logic in command
VALIDATION:
- Input validation in handler
- Business validation in domain
- Return meaningful errors
IDEMPOTENCY:
- Include idempotency key
- Handle duplicate submissions
- Return same result for retries
Query Side Design
Query Structure
// Query Definition
public record GetOrderByIdQuery(Guid OrderId) : IQuery<OrderDetailsDto>;
// Query Handler
public class GetOrderByIdHandler : IQueryHandler<GetOrderByIdQuery, OrderDetailsDto>
{
private readonly IReadDbContext _db;
public async Task<OrderDetailsDto> HandleAsync(
GetOrderByIdQuery query,
CancellationToken ct)
{
var order = await _db.OrderDetails
.Where(o => o.OrderId == query.OrderId)
.Select(o => new OrderDetailsDto
{
OrderId = o.OrderId,
CustomerName = o.Customer.Name,
Items = o.Items.Select(i => new OrderItemDto
{
ProductName = i.ProductName,
Quantity = i.Quantity,
Price = i.Price
}).ToList(),
Status = o.Status,
TotalAmount = o.TotalAmount
})
.FirstOrDefaultAsync(ct);
return order ?? throw new NotFoundException("Order not found");
}
}
Read Model Optimization
Query Optimization Strategies:
1. DENORMALIZATION
- Pre-join data
- Store calculated values
- Flatten hierarchies
2. MATERIALIZED VIEWS
- Database-managed
- Automatically updated
- Query-optimized
3. CACHING
- In-memory for hot data
- Distributed for shared
- Invalidate on events
4. SPECIALIZED STORES
- ElasticSearch for search
- Redis for real-time
- ClickHouse for analytics
Synchronization Patterns
Projection from Events
// Event-Driven Projection
public class OrderProjection : IEventHandler<OrderPlaced>, IEventHandler<OrderShipped>
{
private readonly IOrderViewRepository _views;
public async Task HandleAsync(OrderPlaced @event, CancellationToken ct)
{
var view = new OrderView
{
OrderId = @event.OrderId,
CustomerId = @event.CustomerId,
Status = "Placed",
PlacedAt = @event.Timestamp,
ItemCount = @event.Items.Count,
TotalAmount = @event.TotalAmount
};
await _views.InsertAsync(view, ct);
}
public async Task HandleAsync(OrderShipped @event, CancellationToken ct)
{
await _views.UpdateAsync(@event.OrderId, view =>
{
view.Status = "Shipped";
view.ShippedAt = @event.Timestamp;
view.TrackingNumber = @event.TrackingNumber;
}, ct);
}
}
Consistency Patterns
Consistency Options:
STRONG CONSISTENCY (Same Transaction):
โโโโโโโโโโโโ โโโโโโโโโโโโ
โ Command โโโโโบโ Read โ
โ DB โ โ Model โ
โ โ โ Update โ
โโโโโโโโโโโโดโโโโโดโโโโโโโโโโโ
Same Transaction
EVENTUAL CONSISTENCY (Async):
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ Command โโโโโบโ Message โโโโโบโ Read โ
โ DB โ โ Queue โ โ Model โ
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
Async, Eventually Consistent
HYBRID (Read-Your-Writes):
- Immediate read from command side
- Eventually consistent for others
- Version checking in queries
MediatR Implementation
Setup with MediatR
// Registration
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
});
// Command/Query Interfaces
public interface ICommand<TResult> : IRequest<TResult> { }
public interface IQuery<TResult> : IRequest<TResult> { }
// Handler Interfaces
public interface ICommandHandler<TCommand, TResult>
: IRequestHandler<TCommand, TResult>
where TCommand : ICommand<TResult> { }
public interface IQueryHandler<TQuery, TResult>
: IRequestHandler<TQuery, TResult>
where TQuery : IQuery<TResult> { }
Pipeline Behaviors
// Validation Behavior
public class ValidationBehavior<TRequest, TResponse>
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
var failures = _validators
.Select(v => v.Validate(request))
.SelectMany(r => r.Errors)
.Where(f => f != null)
.ToList();
if (failures.Any())
throw new ValidationException(failures);
return await next();
}
}
// Logging Behavior
public class LoggingBehavior<TRequest, TResponse>
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
_logger.LogInformation("Handling {RequestType}", typeof(TRequest).Name);
var response = await next();
_logger.LogInformation("Handled {RequestType}", typeof(TRequest).Name);
return response;
}
}
API Design with CQRS
REST API Pattern
[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
private readonly IMediator _mediator;
// Commands use POST/PUT/DELETE
[HttpPost]
public async Task<ActionResult<OrderId>> PlaceOrder(
[FromBody] PlaceOrderCommand command,
CancellationToken ct)
{
var orderId = await _mediator.Send(command, ct);
return CreatedAtAction(nameof(GetOrder), new { id = orderId }, orderId);
}
// Queries use GET
[HttpGet("{id}")]
public async Task<ActionResult<OrderDetailsDto>> GetOrder(
Guid id,
CancellationToken ct)
{
var order = await _mediator.Send(new GetOrderByIdQuery(id), ct);
return Ok(order);
}
[HttpGet]
public async Task<ActionResult<PagedResult<OrderSummaryDto>>> ListOrders(
[FromQuery] ListOrdersQuery query,
CancellationToken ct)
{
var orders = await _mediator.Send(query, ct);
return Ok(orders);
}
}
When to Use CQRS
Good Fit
CQRS Works Well For:
โ Complex reads AND writes
- Different optimization needs
- Read/write ratio imbalance
โ Multiple views of data
- Different query patterns
- Multiple UI requirements
โ Collaborative domains
- Many concurrent users
- Complex validation
โ Event-driven systems
- Microservices
- Async processing
โ Scalability requirements
- Independent read/write scaling
- Performance optimization
Poor Fit
CQRS May Not Fit:
โ Simple CRUD applications
- Overhead not justified
- Same model works fine
โ Small team/project
- Added complexity
- Maintenance burden
โ Strong consistency required
- Real-time requirements
- Financial transactions
โ Unknown query patterns
- Ad-hoc reporting
- BI requirements
Workflow
When implementing CQRS:
- Evaluate Fit: Is CQRS appropriate for this context?
- Choose Level: Logical, physical, or event-sourced?
- Design Commands: Identify write operations
- Design Queries: Identify read patterns
- Plan Sync: How will read models be updated?
- Implement Pipeline: Validation, logging, etc.
- Consider Consistency: What guarantees are needed?
- Test Both Sides: Command and query testing
References
For detailed guidance:
Last Updated: 2025-12-26
Repository

melodic-software
Author
melodic-software/claude-code-plugins/plugins/event-modeling/skills/cqrs-architecture
3
Stars
0
Forks
Updated6d ago
Added1w ago