소스 정보
- 저장소
- mitkox/ai-coding-factory
- 최근 소스 활동
- 2026년 1월 9일 18:48
- 감지된 SKILL.md 언어
- 영어
- 스타
- 170
- 포크
- 63
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/mitkox/ai-coding-factory --skill net-cqrs명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
SOC 직업 분류 기준
| name | net-cqrs |
| description | Implement CQRS pattern with MediatR for .NET applications |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":".net-developers","framework":"aspnetcore","patterns":"cqrs, mediator, event-sourcing"} |
I help you implement CQRS (Command Query Responsibility Segregation):
Use this skill when:
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.0" />
using MediatR;
public interface ICommand<out TResult> : IRequest<TResult>
{
}
public interface ICommandHandler<in TCommand, TResult> : IRequestHandler<TCommand, TResult>
where TCommand : ICommand<TResult>
{
}
public record CreateOrderCommand(
Guid CustomerId,
List<OrderItemDto> Items,
string ShippingAddress
) : ICommand<OrderDto>;
public class CreateOrderCommandHandler : ICommandHandler<CreateOrderCommand, OrderDto>
{
private readonly IOrderRepository _orderRepository;
private readonly IMapper _mapper;
private readonly IPublisher _publisher;
public CreateOrderCommandHandler(
IOrderRepository orderRepository,
IMapper mapper,
IPublisher publisher)
{
_orderRepository = orderRepository;
_mapper = mapper;
_publisher = publisher;
}
public async Task<OrderDto> Handle(
CreateOrderCommand request,
CancellationToken cancellationToken)
{
var order = Order.Create(
request.CustomerId,
request.Items.Select(i => new OrderItem(i.ProductId, i.Quantity, i.Price)),
request.ShippingAddress);
await _orderRepository.AddAsync(order, cancellationToken);
// Publish domain events
foreach (var domainEvent in order.DomainEvents)
{
await _publisher.Publish(domainEvent, cancellationToken);
}
order.ClearDomainEvents();
return _mapper.Map<OrderDto>(order);
}
}
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
{
public CreateOrderCommandValidator()
{
RuleFor(x => x.CustomerId)
.NotEmpty()
.WithMessage("Customer ID is required");
RuleFor(x => x.Items)
.NotEmpty()
.WithMessage("At least one item is required");
RuleForEach(x => x.Items)
.ChildRules(item =>
{
item.RuleFor(x => x.Quantity)
.GreaterThan(0)
.WithMessage("Quantity must be greater than 0");
item.RuleFor(x => x.Price)
.GreaterThan(0)
.WithMessage("Price must be greater than 0");
});
RuleFor(x => x.ShippingAddress)
.NotEmpty()
.MaximumLength(500)
.WithMessage("Shipping address is required (max 500 characters)");
}
}
using MediatR;
public interface IQuery<out TResult> : IRequest<TResult>
{
}
public interface IQueryHandler<in TQuery, TResult> : IRequestHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
}
public record GetOrderByIdQuery(Guid OrderId) : IQuery<OrderDto?>;
public class GetOrderByIdQueryHandler : IQueryHandler<GetOrderByIdQuery, OrderDto?>
{
private readonly IOrderReadRepository _orderReadRepository;
private readonly IMapper _mapper;
public GetOrderByIdQueryHandler(
IOrderReadRepository orderReadRepository,
IMapper mapper)
{
_orderReadRepository = orderReadRepository;
_mapper = mapper;
}
public async Task<OrderDto?> Handle(
GetOrderByIdQuery request,
CancellationToken cancellationToken)
{
var order = await _orderReadRepository.GetByIdAsync(
request.OrderId,
cancellationToken);
return order is null ? null : _mapper.Map<OrderDto>(order);
}
}
public record GetOrdersQuery(
Guid? CustomerId,
DateTime? FromDate,
DateTime? ToDate,
int Page = 1,
int PageSize = 10
) : IQuery<PaginatedList<OrderSummaryDto>>;
public class GetOrdersQueryHandler : IQueryHandler<GetOrdersQuery, PaginatedList<OrderSummaryDto>>
{
private readonly IOrderReadRepository _repository;
public GetOrdersQueryHandler(IOrderReadRepository repository)
{
_repository = repository;
}
public async Task<PaginatedList<OrderSummaryDto>> Handle(
GetOrdersQuery request,
CancellationToken cancellationToken)
{
return await _repository.GetPaginatedAsync(
request.CustomerId,
request.FromDate,
request.ToDate,
request.Page,
request.PageSize,
cancellationToken);
}
}
public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
if (!_validators.Any())
return await next();
var context = new ValidationContext<TRequest>(request);
var validationResults = await Task.WhenAll(
_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.SelectMany(r => r.Errors)
.Where(f => f is not null)
.ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
return await next();
}
}
public class TransactionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : ICommand<TResponse>
{
private readonly IUnitOfWork _unitOfWork;
private readonly ILogger<TransactionBehaviour<TRequest, TResponse>> _logger;
public TransactionBehaviour(
IUnitOfWork unitOfWork,
ILogger<TransactionBehaviour<TRequest, TResponse>> logger)
{
_unitOfWork = unitOfWork;
_logger = logger;
}
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken cancellationToken)
{
var typeName = typeof(TRequest).Name;
try
{
await _unitOfWork.BeginTransactionAsync(cancellationToken);
_logger.LogInformation("Begin transaction for {CommandName}", typeName);
var response = await next();
await _unitOfWork.CommitTransactionAsync(cancellationToken);
_logger.LogInformation("Committed transaction for {CommandName}", typeName);
return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during transaction for {CommandName}", typeName);
await _unitOfWork.RollbackTransactionAsync(cancellationToken);
throw;
}
}
}
public class OrderCreatedEventHandler : INotificationHandler<OrderCreatedEvent>
{
private readonly IEmailService _emailService;
private readonly ILogger<OrderCreatedEventHandler> _logger;
public OrderCreatedEventHandler(
IEmailService emailService,
ILogger<OrderCreatedEventHandler> logger)
{
_emailService = emailService;
_logger = logger;
}
public async Task Handle(
OrderCreatedEvent notification,
CancellationToken cancellationToken)
{
_logger.LogInformation(
"Processing OrderCreatedEvent for Order {OrderId}",
notification.OrderId);
await _emailService.SendOrderConfirmationAsync(
notification.OrderId,
notification.CustomerEmail,
cancellationToken);
}
}
services.AddMediatR(cfg =>
{
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
// Add behaviors in order of execution
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(LoggingBehaviour<,>));
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>));
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(TransactionBehaviour<,>));
});
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
Use net-cqrs skill to:
1. Create command with handler and validator
2. Create query with pagination support
3. Set up MediatR pipeline behaviors
4. Implement domain event handlers
5. Configure transaction behavior for commands
I will generate complete CQRS implementation following Clean Architecture principles.