O que eu faço
Eu guio o orquestrador para criar novas funcionalidades (não modificar as existentes) com análise prévia de reutilização, configuração e compatibilidade. Ao contrário dos refactors, aqui não há código prévio a preservar: o design começa a partir dos requisitos do usuário.
Quando usar este skill (em vez de refactor-protocol):
- O usuário pede um endpoint, serviço, job, handler, evento ou configuração que NÃO existe
- A tarefa é criação pura, não modificação de comportamento existente
- O resultado adiciona arquivos ao repositório, não altera a assinatura dos existentes
Quando NÃO usar este skill (usar refactor-protocol em vez disso):
- Modificar a assinatura de um serviço existente
- Alterar o comportamento de um endpoint que já existe
- Renomear, extrair ou mover código
FASE 0 — Validação de estrutura (sempre a primeira)
- Carregar o skill
project-structuree executar a validação completa - Detectar o tipo de host:
FUNCTIONS|WEBAPP|NUGET_LIBRARY - Agir conforme o resultado:
| Status | Ação |
|---|---|
HARD_BLOCK | Parar. Informar o usuário. |
NUGET_LIBRARY | Criar um endpoint HTTP é inesperado. Perguntar: "Deseja adicionar uma operação pública à biblioteca ou realmente há um host que não detectei?" |
PREGUNTA | Resolver as perguntas antes de continuar |
OK / WARNING | Continuar para a FASE 1 |
FASE 1 — Coleta de requisitos
O orquestrador infere o que puder da descrição do usuário ($ARGUMENTS) e só pergunta
o que não estiver claro. Não fazer perguntas cuja resposta já esteja na descrição.
1.1 Nome, propósito e tipo da funcionalidade
- Endpoint HTTP (Function/Controller):
[VERBO] /rota — descrição - Serviço de domínio: nome do serviço e responsabilidade
- Job/Event handler: trigger + ação
- Opção de configuração: nome da opção e seu propósito
1.2 Classificação READ vs MUTATION
Determinar se a funcionalidade muda estado ou é somente leitura. Isso afeta:
- Onde os DTOs de response vão
- Se é necessário transação / idempotência
- Quais testes são necessários
| Tipo | Características | Implicação |
|---|---|---|
| READ-ONLY | GET, retorna dados existentes, não escreve | DTOs efêmeros, testes mínimos |
| MUTATION | POST/PUT/DELETE, escreve ou muda estado | Requer testes de sucesso + erro |
1.3 Coleta de input/output esperado
- Request: estrutura do body ou query params
- Response: estrutura do body de resposta, status codes
- Erros: quais erros devem ser mapeados para quais status codes
FASE 1.5 — Análise de reutilização (CRÍTICA, não pular)
Objetivo: detectar se a funcionalidade já existe parcial ou totalmente antes de criar qualquer coisa.
Passos
- Buscar serviços existentes em
*.Impl/com@exploreusando o domínio da funcionalidade - Buscar métodos candidatos que cubram 80%+ do comportamento necessário:
- Existe um método que já retorna o dado necessário com um filtro trivial?
- Existe um método que poderia ser sobrecarregado para adicionar o caso?
- Buscar endpoints similares em
*.API/com a mesma forma de request/response
Árvore de decisão
Existe método que cobre 100% do caso?
├── SIM → NÃO criar método novo. Criar apenas:
│ · Endpoint (Function/Controller) em *.API/
│ · DTO Request/Response exclusivo em *.API/
│ · Teste do shape do response
│
Existe método quase-ideal (filtro, paginação, ordenação)?
├── SIM → considerar:
│ ├── Adicionar parâmetro opcional ao método existente (com valor padrão)
│ ├── Criar overload com assinatura mais específica
│ └── Criar método de extensão que envolva o existente
└── NÃO → continuar com criação de método novo
Existe serviço relacionado mas diferente (ex.: responsabilidade similar)?
├── SIM → perguntar ao usuário: "Estendo o [CSXxxService] ou crio um novo [CSYyyService]?"
└── NÃO → criar serviço novo
Saída esperada desta fase
Uma destas três decisões, apresentada ao usuário antes de continuar:
- Reutilização pura: a funcionalidade se implementa como wrapper de um método existente
- Extensão: adicionar overload/método a um serviço existente
- Criação nova: serviço e métodos novos (justificar por que não se pode reutilizar)
FASE 1.6 — Análise de configuração (NOVA)
Objetivo: detectar se a funcionalidade requer parâmetros configuráveis e, se sim, onde defini-los.
Perguntas-chave
- A funcionalidade tem valores padrão razoáveis sem configuração externa?
- Existem limiares, paginação, timeouts, ou flags que deveriam ser configuráveis por ambiente?
- Conecta-se a um sistema externo com URL/chave/secret?
- Precisa de feature flags para rollout gradual?
Árvore de decisão
A funcionalidade requer configuração?
├── NÃO → não criar IXxxOptions, não tocar em AddCustomConfiguration
└── SIM → continuar
Que tipo de configuração?
├── Connection string ou segredo
│ └── Usar IConfiguration com nome em appsettings.json (gerenciado por AddCustomConfiguration)
├── Valor simples (limiar, timeout, flag)
│ └── Criar IXxxOptions em *.Impl/ (interface) + adicionar a AddCustomConfiguration<T>("chave")
└── Lista de valores (allowed origins, mappings)
└── Criar IXxxOptions com propriedade do tipo IEnumerable<T>
Convenção do projeto
O projeto usa AddCustomConfiguration<IXxxOptions>("config-section") em IoCExtensions.cs
(linhas 43-45 do projeto atual). As interfaces ficam em *.Impl/ e são referenciadas a partir de
*.Impl/Services/.
Saída esperada
Se a funcionalidade requer configuração, apresentar ao usuário:
- Nome da interface (ex.:
IPendingPaymentOptions) - Propriedades com seus tipos e valores padrão
- Seção em
appsettings.json(ex.:"RAMBLA.PendingPayment") - Modificação de
IoCExtensions.AddCSLevelBooking()
Se NÃO requer, indicar explicitamente no plano.
FASE 1.7 — Análise de impacto na API pública
Objetivo: evitar quebrar consumidores existentes.
Se a funcionalidade reutiliza um método existente
- O método se mantém com a mesma assinatura? → sem impacto
- Adiciona-se um parâmetro opcional? → verificar se nenhum call site quebra
- Adiciona-se um overload? → verificar se o compilador resolve sem ambiguidade
- Renomeia-se? → buscar todos os call sites com
grepe migrar
Se a funcionalidade adiciona um serviço novo
- O serviço é registrado na DI? → assegurar registro em
IoCExtensions - Algum serviço existente tem dependência circular potencial? → verificar
Se a funcionalidade adiciona um endpoint novo
- A rota colide com outra rota existente? → verificar
- O método HTTP é coerente com REST? (GET para leitura, POST para mutação)
FASE 1.8 — PREFLIGHT de testes de regressão (obrigatório)
Objetivo: antes de gerar código novo ou modificar existente, verificar que os componentes que vão ser tocados (mesmo que tangencialmente) têm cobertura de testes. Se não tiverem, criá-la e executá-la antes de iniciar a implementação.
Passos
-
Identificar superfície tangencial: a partir da FASE 1.5 (reutilização vs extensão vs novo), listar:
- Serviços existentes cujos métodos vão ser estendidos ou sobrecarregados
- Interfaces existentes que vão ser modificadas
- Endpoints existentes que podem ser afetados por routing/DI
- Qualquer arquivo existente que vai ser editado (não criado)
-
Para cada componente existente que vai ser tocado:
- Buscar testes em
src/*.Test*/**que o exercitem - Se tiver cobertura → OK, continuar
- Se não tiver cobertura → HARD BLOCK:
- Invocar
@refactor-worker-testspara criar testes de caracterização do comportamento atual - Invocar
@refactor-verifierpara confirmar que passam em verde - Commit separado:
test(characterization): add characterization tests for <classes>
- Invocar
- Buscar testes em
-
Se a funcionalidade é 100% criação nova (não toca arquivos existentes):
- Não há superfície de regressão → pular PREFLIGHT
- Mas os testes da nova funcionalidade são criados na FASE 4 e devem passar na FASE 5
Critério de fechamento (FASE 5)
Para dar a funcionalidade como correta, @refactor-verifier deve confirmar que passam:
- Testes novos da funcionalidade (serviço + endpoint)
- Testes existentes dos componentes tangenciais (regressão)
Se algum falhar, a funcionalidade não pode ser fechada.
FASE 2 — Árvore de decisão: o que criar e onde
Aplicar a decisão da FASE 1.5 (reutilização / extensão / novo) mais a FASE 1.6 (config).
Para endpoint READ-ONLY com reutilização
*.API/
+ {Nome}Function.cs — Function/Controller novo
+ {Nome}Request.cs — exclusivo de apresentação
+ {Nome}Response.cs — exclusivo de apresentação
*.Test*/
+ {Nome}FunctionTests.cs — teste de shape do response (NÃO lógica)
Para endpoint MUTATION com serviço novo
*.Contracts/
+ ICS{Nome}Service.cs — interface do serviço
+ {Nome}Request.cs — se Request compartilhado
+ {Nome}Response.cs — se Response compartilhado
*.Impl/
+ CS{Nome}Service.cs — implementação
+ I{Nome}Options.cs — SÓ se FASE 1.6 detectou config
*.API/
+ {Nome}Function.cs — Function/Controller
+ {Nome}Request.cs — exclusivo (se não foi colocado em Contracts)
+ {Nome}Response.cs — exclusivo (se não foi colocado em Contracts)
*.Test*/
+ CS{Nome}ServiceTests.cs — happy path + pelo menos um erro
Para extensão de serviço existente
*.Contracts/
~ ICS{Nome}Service.cs — adicionar assinatura do método (ou criar overload)
*.Impl/
~ CS{Nome}Service.cs — implementar o novo método/overload
*.API/
+ {Nome}Function.cs — Function/Controller novo
+ {Nome}Request.cs — se exclusivo
+ {Nome}Response.cs — se exclusivo
*.Test*/
+ (ou ~) testes do serviço — adicionar caso para o novo método
FASE 3 — Plano de criação
Antes de invocar workers, o orquestrador apresenta este plano ao usuário e espera confirmação explícita:
[PLANO DE CRIAÇÃO] Funcionalidade: <nome> — <descrição breve>
Host: <FUNCTIONS | WEBAPP>
Classificação: <READ-ONLY | MUTATION>
Estratégia: <REUTILIZAÇÃO | EXTENSÃO | NOVO>
Análise de reutilização (FASE 1.5):
· Serviço candidato: <ICSXxxService> ou "nenhum"
· Método candidato: <XxxService.YyyMethod> ou "nenhum"
· Decisão: <REUTILIZAÇÃO | EXTENSÃO | NOVO>
Análise de configuração (FASE 1.6):
· Requer config: <SIM | NÃO>
· Se sim: <IXxxOptions + seção appsettings>
Impacto na API pública (FASE 1.7):
· Call sites afetados: <lista> ou "nenhum"
· Breaking change: <SIM | NÃO>
Artefatos a criar:
*.Contracts/ ([N] arquivos):
+ ICS{Nome}Service.cs — nova interface (ou: adicionar método a IXxx)
+ {Nome}Request.cs — se tipo compartilhado
+ {Nome}Response.cs — se tipo compartilhado
*.Impl/ ([N] arquivos):
+ CS{Nome}Service.cs — implementação do serviço
+ I{Nome}Options.cs — SÓ se requer config (FASE 1.6)
*.API/ ([N] arquivos):
+ {Nome}Function.cs — Azure Function (ou: {Nome}Controller.cs)
+ {Nome}Request.cs — se tipo exclusivo
+ {Nome}Response.cs — se tipo exclusivo
*.Test*/ ([N] arquivos):
+ CS{Nome}ServiceTests.cs — testes do serviço (happy path + erro)
+ {Nome}FunctionTests.cs — testes do endpoint (se aplicável)
Modificações em arquivos existentes:
~ src/.../IoCExtensions.cs — registrar serviço e opções (se aplicável)
Ordem de execução: Contracts → Impl → Presentation → Tests
Prosseguir?
Sem aprovação explícita do usuário, não invocar workers.
FASE 4 — Execução
Ordem dos workers
@refactor-worker-contracts— só se houver novos tipos ou assinaturas em*.Contracts/@refactor-worker-impl— sempre que houver código em*.Impl/@refactor-worker-presentation— sempre que houver um endpoint@refactor-worker-tests— sempre ao final
Nota: NÃO invocar
@refactor-worker-crosscuttinga menos que a funcionalidade exponha um novo Service Gateway. Isso é um caso raro em criação; geralmente é em refactors.
Instruções para cada worker
Incluir no prompt:
- O plano completo (FASE 3)
- Os padrões do projeto: ler um arquivo similar antes de criar
- A lista exata de arquivos com seu conteúdo esperado
- Se a FASE 1.6 detectou config: o caminho de
IXxxOptionse a seção de configuração
FASE 5 — Verificação e commit
- Invocar
@refactor-verifier - Se PASS → propor commit com formato:
feat(<escopo>): add funcionalidade <nome-curto> - Adicionada interface ICS{Nome}Service e implementação CS{Nome}Service - Adicionado Function/Controller {VERBO} /{rota} - Adicionados contratos {Nome}Request/{Nome}Response - Adicionado I{Nome}Options para nova configuração (se aplicável) - Adicionados testes de unidade para CS{Nome}Service - Se FAIL → identificar camada com falha, re-invocar worker, re-verificar
Padrões por host
FUNCTIONS — Azure Functions Isolated Worker
Antes de criar a Function, ler uma Function HTTP existente e copiar seu estilo. Exemplo típico:
public class {Nome}Function
{
private readonly I{Nome}Service _{campo};
public {Nome}Function(I{Nome}Service {campo}) => _{campo} = {campo};
[Function("{Nome}Function")]
public async Task<HttpResponseData> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "{rota}")] HttpRequestData req)
{
var request = await req.ReadFromJsonAsync<{Nome}Request>();
var result = await _{campo}.ExecuteAsync(request);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(result);
return response;
}
}
Verificar antes de criar:
AuthorizationLevel.FunctionouAuthorizationLevel.Anonymous?- Routing em snake_case?
- Nome da Function compatível com convenção do projeto?