This skill should be used when the user wants to create a new command, add a new operation, create a new use case, or implement a new write action in the rep-adb-api repository. Activate when the user mentions "criar command", "novo command", "criar operação", "implementar command", "adicionar command", "registrar command", or describes a new action that modifies state (create, update, delete, cancel, confirm, send, approve, reject, register).
Para criar um Command completo são necessários:
AdB.Application/Commands/{Entidade}/{Entidade}CommandHandler.cs existente (ou criar novo)AdB.API/Configurations/DependencyInjections/CommandsDIConfig.csCaminho: src/AdB.Application/Commands/{Entidade}/{Verbo}{Entidade}Command.cs
using AdB.Core.Messages;
using AdB.Messages;
using FluentValidation;
using Newtonsoft.Json;
using NSwag.Annotations;
namespace AdB.Application.Commands.{Entidade};
public class {Verbo}{Entidade}Command : Command
{
// Propriedades injetadas pelo Controller (não expostas na API)
[JsonIgnore, SwaggerIgnore]
public Guid {EntidadeRelacionada}Id { get; set; }
// Propriedades do body da request
public string Campo1 { get; set; }
public Guid Campo2Id { get; set; }
public override bool Validar()
{
ValidationResult = new {Verbo}{Entidade}CommandValidation().Validate(this);
return ValidationResult.IsValid;
}
internal class {Verbo}{Entidade}CommandValidation : AbstractValidatorBase<{Verbo}{Entidade}Command>
{
public {Verbo}{Entidade}CommandValidation()
{
RuleFor(x => x.Campo1)
.NotEmpty()
.WithMessage(ValidationResource.Obrigatorio.FormatField(new string[] { TermsResource.Campo1 }))
.MaximumLength(300)
.WithMessage(ValidationResource.MaximoCaracteres.FormatField(new string[] { TermsResource.Campo1, "300" }));
RuleFor(x => x.Campo2Id)
.NotEmpty()
.WithMessage(ValidationResource.Obrigatorio.FormatField(new string[] { TermsResource.Campo2 }));
}
}
}
Command (que já implementa IRequest<CommandResult>)Validar() chamando a nested class de validação[JsonIgnore, SwaggerIgnore] em propriedades setadas pelo controller (ex: IDs extraídos do token/rota)AbstractValidatorBase<T> (não AbstractValidator<T>)ValidationResource e TermsResource para mensagens — nunca strings literaisSe já existe um {Entidade}CommandHandler.cs, adicionar uma nova implementação de IRequestHandler:
public class {Entidade}CommandHandler : CommandHandler,
IRequestHandler<ComandoExistente1Command, CommandResult>,
IRequestHandler<ComandoExistente2Command, CommandResult>,
IRequestHandler<{Verbo}{Entidade}Command, CommandResult> // ← Adicionar aqui
{
// ... dependências existentes ...
// Adicionar novo Handle method
public async Task<CommandResult> Handle({Verbo}{Entidade}Command request, CancellationToken cancellationToken)
{
if (!request.Validar()) return request.ValidationResult;
// 1. Buscar entidades necessárias
var entidade = await _{entidade}Repository.ObterPorId(request.{Entidade}Id);
if (entidade is null)
return LancarErro(ValidationResource.NaoLocalizado, TermsResource.{Entidade});
// 2. Regras de negócio / validações adicionais
if (entidade.Cancelado)
return LancarErro("Não é possível operar em uma entidade cancelada");
// 3. Chamar método de domínio na entidade
entidade.{Verbo}(request.Campo1, request.Campo2Id);
// 4. Persistir
_{entidade}Repository.Atualizar(entidade);
var result = await PersistirDados(_{entidade}Repository.UnitOfWork);
// 5. Side effects (notificações, logs, eventos) — só após persistência bem-sucedida
if (result.IsValid)
{
await _mediator.Send(new CadastrarLogConsultoriaCommand(...));
await _discordService.Notificar{Verbo}{Entidade}(...);
}
return result;
}
}
Caminho: src/AdB.Application/Commands/{Entidade}/{Entidade}CommandHandler.cs
using AdB.Core.Messages;
using AdB.Domain.Interfaces;
using AdB.Messages;
using MediatR;
namespace AdB.Application.Commands.{Entidade};
public class {Entidade}CommandHandler : CommandHandler,
IRequestHandler<{Verbo}{Entidade}Command, CommandResult>
{
private readonly I{Entidade}Repository _{entidade}Repository;
private readonly IMediator _mediator;
public {Entidade}CommandHandler(
I{Entidade}Repository {entidade}Repository,
IMediator mediator)
{
_{entidade}Repository = {entidade}Repository;
_mediator = mediator;
}
public async Task<CommandResult> Handle({Verbo}{Entidade}Command request, CancellationToken cancellationToken)
{
if (!request.Validar()) return request.ValidationResult;
// Implementação...
return await PersistirDados(_{entidade}Repository.UnitOfWork);
}
}
CommandHandler (nunca implementar IRequestHandler sem herdar CommandHandler)if (!request.Validar()) return request.ValidationResult; como primeira linhaPersistirDados(repository.UnitOfWork) para commitar — nunca chamar Commit() diretamentePersistirDados e condicionais ao result.IsValidawait _mediator.Send(new OutroCommand(...))Arquivo: src/AdB.API/Configurations/DependencyInjections/CommandsDIConfig.cs
// Adicionar dentro do método RegisterCommandServices()
services.AddScoped<IRequestHandler<{Verbo}{Entidade}Command, CommandResult>, {Entidade}CommandHandler>();
Nota: Se o Handler já está registrado para outros commands da mesma entidade, apenas adicionar a nova linha para o novo command.
{Verbo}{Entidade}Command.cs criado em AdB.Application/Commands/{Entidade}/CommandValidar() implementado com nested class de validaçãoAbstractValidatorBase<T>, ValidationResource e TermsResourceIRequestHandler<{Verbo}{Entidade}Command, CommandResult>request.Validar() antes de qualquer lógicaPersistirDados() para persistênciaCommandsDIConfig.csSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer