Skills de
arquitetura e testes NestJS.
20 skills para Claude Code: 11 de arquitetura (Clean Architecture + Feature-Based) e 9 de testes unitários (100% coverage por artefato). Sem reinventar padrões — código consistente e testado desde o primeiro commit.
Agentes de IA geram código errado — até você mostrar o padrão certo.
Sem contexto arquitetural, o agente adivinha. Ele mistura lógica de negócio no controller, esquece o soft delete, não sabe o que é Resposta<T>. As skills ensinam o padrão real do projeto de uma vez.
Código sem padrão
Sem skill, o agente inventa estrutura. DTOs entram em use cases, controllers têm lógica de negócio, soft delete some, auditoria é esquecida.
Revisões intermináveis
Cada PR novo corrigi os mesmos erros. Nomenclatura inconsistente, camadas violadas, padrões de injeção diferentes em cada módulo.
Skills por camada
11 arquivos SKILL.md — um por camada — descrevem o que o código real faz. O agente lê, segue, e gera código revisável desde a primeira versão.
Regra de ouro: as dependências sempre apontam para dentro. HTTP → Controllers → Use Cases → Domain ← Infrastructure. O domínio não conhece NestJS, Sequelize, nem nada externo.
Uma skill por camada. Cada uma descreve o código real.
Skills são arquivos SKILL.md em .claude/skills/<nome>/. O agente os descobre automaticamente e os aplica quando o prompt do usuário casa com a descrição da skill.
Skill Transversal
consulte primeiro ao criar qualquer módulo novo| Skill | Comando | O que cobre |
|---|---|---|
| arquitetura-geral | /arquitetura-geral | Estrutura completa, fluxo HTTP→DB, regras de dependência, onde cada artefato vai, como criar um módulo do zero, divergências documentadas |
Camada HTTP
interfaces/controllers/ · interfaces/dtos/| Skill | Comando | O que cobre |
|---|---|---|
| controller | /controller | @withApmAndTransaction em todo método, useTransaction: true para escrita, transformInput para DTO→Entidade, @DocumentApiEndpoint, @JwtExport(), versionamento v1/ |
| application | /application | DTOs com class-validator e class-transformer, estrutura input/output, quando criar sub-módulos, regras da camada application |
Lógica de Negócio
use-cases/ · domain/entities/| Skill | Comando | O que cobre |
|---|---|---|
| use-case | /use-case | Padrão orquestrador + sub use case, implements IGenericUseCase, método único executar(), logging INICIO/FIM obrigatório, retorno Resposta<T>, @Inject('IXyzRepository'), transação como parâmetro |
| entidade | /entidade | Dois tipos: entidade de domínio (input/output, static fromDto(), sem decorators) e entidade de banco (campos de auditoria obrigatórios, sem fromDto()) |
Infraestrutura de Dados
infra/database/ · shared/adapters/| Skill | Comando | O que cobre |
|---|---|---|
| adapter | /adapter | Interfaces TypeScript puras (sem implementação), prefixo I, Transaction obrigatório em escrita, incluirDesativados? em leitura, token string para DI |
| model | /model | @Table({ tableName, schema, timestamps: false }), field: 'snake_case' obrigatório, campos de auditoria em todo model, relacionamentos, nunca exportar fora de infra/ |
| infra | /infra | Mappers toDomain() e toPersistence(), decorator @withApmAndTransaction, @JwtExport(), @DocumentApiEndpoint(), @Public(), serviços externos |
| repository | /repository | Soft delete obrigatório em toda leitura, campos de auditoria em escrita, retorno via mapper.toDomain(), repositório custom com padrão 3 passos (count → ids → detalhes) |
Módulos e Código Compartilhado
[feature].module.ts · shared/| Skill | Comando | O que cobre |
|---|---|---|
| modules | /modules | Imports obrigatórios (ConfigModule, PinoLoggerModule, DatabaseModule, ApmModule, SharedModule), guards por módulo, token string para repos, como registrar no AppModule |
| shared | /shared | Regra de inclusão (2+ módulos), o que SharedModule exporta, IGenericUseCase, utilitários, enums compartilhados, decisão local vs. shared |
| domain | /domain | Dois locais de domínio (por módulo vs. shared), entidades de banco em shared/domain/entities/database/[schema]/, enums, funções puras, JwtPayload e Resposta<T>, tabela de decisão |
11 passos. Do zero a um módulo funcionando.
Para criar um módulo completo, execute as skills nesta sequência. Cada passo produz artefatos que o próximo consome.
Entender a estrutura
Consulte /arquitetura-geral antes de qualquer outra coisa. Ela define onde cada artefato vai, quais são os imports obrigatórios e as regras de dependência entre camadas.
Criar entidade de banco
Em shared/domain/entities/database/[schema]/. Campos de auditoria obrigatórios: createdBy, createdDt, updatedBy, deletedBy, deletedDt. Sem decorators.
Criar adapter (contrato do repositório)
Interface TypeScript pura em shared/adapters/database/[schema]/. Prefixo I. Transaction obrigatório em escrita. Token string habilita múltiplas implementações e mocking.
Criar Model Sequelize
@Table({ tableName, schema, timestamps: false }). Campo field: 'snake_case' para cada coluna com nome diferente. Campos de auditoria em todo model. Nunca exportar fora de infra/.
Criar Mapper
Dois métodos: toDomain(model): Entity para Model→Entidade e toPersistence(entity): Partial<Model> para Entidade→Model. O repositório nunca retorna model direto — sempre passa pelo mapper.
Criar Repositório
@Injectable() + implements IXyzRepository. Soft delete obrigatório em toda leitura: where: { deletedDt: null }. Campos de auditoria em escrita. Retorno via mapper.toDomain(model).
Criar entidade de input
Em application/[feature]/domain/entities/input/. TypeScript puro, sem decorators. static fromDto(dto): ThisClass obrigatório. O controller chama esse método para converter DTO em entidade.
Criar DTOs
Em application/[feature]/interfaces/dtos/. Decorators class-validator (@IsString, @IsNumber) e class-transformer (@Transform, @Type). DTOs nunca entram em use cases.
Criar Use Cases
Padrão orquestrador + sub use case base. implements IGenericUseCase. Método único executar(input, transaction?). Retorno Resposta<T>. Logging INICIO/FIM obrigatório. Mensagem em UPPERCASE.
Criar Controller
@withApmAndTransaction em todo método público. useTransaction: true para escrita, false para leitura. transformInput: dto => Entidade.fromDto(dto). Sem lógica de negócio.
Criar Module e registrar no AppModule
Imports obrigatórios + SequelizeModule.forFeature([...models]). Guards por módulo. Repositórios via token string. Use cases como classe direta. Adicionar ao AppModule.
Oito padrões que o agente não pode ignorar.
Estes padrões são verificados em toda revisão de PR. As skills os descrevem em detalhe — aqui está o resumo executivo.
Envelope de retorno
Todo use case retorna Resposta<T> com statusCode, mensagem (UPPERCASE) e dados. Nunca HttpException em use case.
'LISTA_CRIADA_COM_SUCESSO'Resposta.sucesso(id)- Consistente em toda a cadeia
Decorator de controller
Todo método público de controller usa esse decorator. Ele configura APM, abre/fecha transação e converte DTO em entidade via transformInput.
useTransaction: truepara escritauseTransaction: falsepara leituratransformInput: dto => Entidade.fromDto(dto)
Toda leitura filtra deletados
Nenhuma query de leitura retorna registros deletados. Filtro obrigatório em todo findOne, findAll e query customizada.
where: { deletedDt: null }- Exceção: queries com
incluirDesativados - Auditoria em desativação:
deletedDt+deletedBy
Campos obrigatórios em banco
Toda entidade de banco e model Sequelize tem os 5 campos de auditoria. Repositório popula os campos corretos em cada operação.
createdBy+createdDt— criarupdatedBy+updatedDt— atualizardeletedBy+deletedDt— desativar
Injeção de repositórios
Use cases nunca importam a classe concreta do repositório. Sempre via token string, que permite trocar a implementação ou mockar sem alterar o use case.
@Inject('IListaRepository')- Type hint: a interface
IListaRepository - Provider:
{ provide: 'IListaRepository', useClass: ... }
Método único de use case
Todo use case expõe um único método público: async executar(input, transaction?). Sem execute(), sem outros métodos expostos. Interface previsível e descobrível.
- Recebe entidade de domínio (nunca DTO)
- Transação como parâmetro opcional
- Implementa
IGenericUseCase
Transformação no controller
A conversão de DTO em entidade de domínio ocorre exclusivamente no controller, via static fromDto(dto) da entidade. Use cases nunca recebem DTOs.
Entidade.fromDto(dto)- Se a API mudar, só o DTO e o controller são alterados
- Use cases permanecem estáveis
INICIO e FIM obrigatórios
Todo use case loga o início e o fim da operação com contexto. Facilita rastreamento em APM (Elastic APM integrado) e debugging em produção.
this.logger.log('INICIO', { input })this.logger.log('FIM', { resultado })this.logger.setContext(UseCase.name)no construtor
Anti-patterns mais comuns. HttpException dentro de use cases (use Resposta<T>), lógica de negócio no controller, DTOs passando para use cases, leitura sem filtrar soft delete, repositório retornando model direto sem mapper, use case gigante sem sub use cases.
9 skills que geram testes com 100% de coverage.
Cada artefato da arquitetura tem uma skill de testes correspondente. O agente lê o arquivo-fonte, identifica o padrão, escreve o spec, roda o Jest e itera até cobrir 100% de Stmts, Lines, Branches e Functions.
Testes incompletos
Sem saber o padrão de cada artefato, o agente gera testes rasos. Branches de ?? e ternários ficam descobertos. @Transform não é testado. Coverage fica em 60–70%.
Protocolo por tipo
Cada skill conhece o protocolo do artefato: onde importar reflect-metadata, quando usar plainToInstance, como mockar withApmAndTransaction, quais branches cobrir.
100% por arquivo
Meta de 100% Stmts/Lines/Branches/Functions por arquivo. Threshold global de 80% no CI. O agente roda, verifica e itera automaticamente.
Entidades e Domínio
shared/domain/entities/ · application/*/domain/entities/ · application/*/interfaces/dtos/| Skill | Alvo | Padrão chave | Linguagem |
|---|---|---|---|
| entity-test-generator | src/shared/domain/entities/database/ | POJOs puros, sem reflect-metadata, cobre campos de auditoria |
inglês |
| domain-input-test-generator | src/application/*/domain/entities/input/ | Cobre fromDto(), operadores ??, ternários, ?.length — todos os ramos |
português |
| domain-output-test-generator | src/application/*/domain/entities/output/ | 1 a 10+ classes por arquivo, um describe por classe exportada |
português |
| dto-input-test-generator | src/application/*/interfaces/dtos/input/ | import 'reflect-metadata' + plainToInstance + validate() obrigatórios, cobre @Transform com ambos os ramos |
português |
| dto-output-test-generator | src/application/*/interfaces/dtos/output/ | 3 tipos: A=simples, B=herda entidade, C=construtor com defaults | português |
Camada HTTP
src/application/*/interfaces/controllers/| Skill | Alvo | Padrão chave | Linguagem |
|---|---|---|---|
| controller-test-generator | src/application/*/interfaces/controllers/ |
jest.mock(withApmAndTransaction) obrigatório,
Test.createTestingModule com controllers: [...],
entidade passada diretamente (transformInput mockado),
cobre branch de JWT e erro do use case
|
português |
Atenção: sem o mock de withApmAndTransaction, o decorator tenta acessar APM e Sequelize — os testes falham com erros de conexão. A skill já inclui esse mock como primeira linha.
Lógica de Negócio
src/application/*/use-cases/| Skill | Alvo | Padrão chave | Linguagem |
|---|---|---|---|
| use-case-test-generator | src/application/*/use-cases/ |
Padrão A (instanciação direta) ou B (NestJS module),
protocolo 10 passos com check de coverage,
testa retorno Resposta<T> completo (statusCode + mensagem + dados),
token string nos providers: { provide: 'IFooRepository', useValue: mock }
|
português |
Infraestrutura
src/infra/database/mappers/ · src/infra/services/| Skill | Alvo | Padrão chave | Linguagem |
|---|---|---|---|
| mapper-test-generator | src/infra/database/mappers/ | 3 padrões: A=new Model(), B=Model.build(), C=custom row de raw query; protocolo 9 passos |
inglês |
| infra-services-test-generator | src/infra/services/ | jest.mock('axios'), helper createService() quando env vars no construtor, 3 padrões (HTTP+PinoLogger, thin proxy, repo+HTTP), protocolo 11 passos |
inglês |
Meta 100%
Cada skill exige 100% de Stmts, Lines, Branches e Functions no arquivo que acabou de gerar. O agente roda npx jest --coverage e itera até atingir.
- Stmts: 100%
- Lines: 100%
- Branches: 100%
- Functions: 100%
Threshold 80%
O pipeline de CI falha se o coverage global cair abaixo de 80% em qualquer métrica. Configurado em jest.config.js via coverageThreshold.
- Mínimo global: 80%
- Configurado em
jest.config.js - Bloqueante no CI/CD
Specs em test/, imports por alias. Todo spec fica em test/ espelhando a estrutura de src/. Imports usam o alias src/ configurado no Jest — nunca caminhos relativos como ../../.
test/application/listas/use-cases/criar-lista/ ← espelha src/application/listas/use-cases/criar-lista/
Dois prompts. Do zero às skills instaladas.
Cole o prompt no Claude Code dentro da pasta do projeto. O agente executa de forma autônoma — lê o boilerplate existente, cria as 11 skills, testa a instalação.
Prompt de Instalação das 11 Skills
cole no Claude Code dentro da raiz do projeto NestJSExecute este prompt uma única vez por máquina. O agente lê o boilerplate real do projeto e gera as 11 skills com base no código concreto — não em exemplos genéricos.
# PROMPT — Criar as 11 Skills de Arquitetura NestJS
Você está dentro de um projeto NestJS que usa Clean Architecture + Feature-Based.
Leia o código real em `src/` e o boilerplate em `boilerplate/src/application/listas/`
antes de criar qualquer skill. Quando docs e código divergirem, o código prevalece.
## 0. Leitura obrigatória antes de começar
Leia nesta ordem (sem criar nada ainda):
1. `docs/arquitetura-oficial/00-INDICE.md`
2. `docs/arquitetura-oficial/01-visao-geral.md`
3. `docs/arquitetura-oficial/03-estrutura-de-modulo.md`
4. `docs/arquitetura-oficial/04-camada-application.md`
5. `docs/arquitetura-oficial/05-camada-infra.md`
6. `docs/arquitetura-oficial/06-camada-shared.md`
7. `docs/arquitetura-oficial/skills/README.md`
8. `boilerplate/src/application/listas/` (leia todos os arquivos)
9. Um módulo real em `src/application/` de sua escolha (leia tudo)
## 1. Criar as 11 skills em `.claude/skills/`
Para cada skill abaixo, crie `.claude/skills//SKILL.md` com:
- Frontmatter: `name`, `description` (acionado pelo agente automaticamente)
- O que a skill ensina (padrões concretos do código real, não genéricos)
- Template base com código real do boilerplate
- Anti-patterns específicos desta camada
- Referência ao(s) arquivo(s) de boilerplate correspondentes
### Skills a criar:
1. **arquitetura-geral** — visão macro, fluxo HTTP→DB, regras de dependência,
onde cada artefato vai, como criar um módulo do zero, divergências documentadas
2. **controller** — estrutura com `withApmAndTransaction` em todo método,
`useTransaction: true/false`, `transformInput`, `@DocumentApiEndpoint`,
`@JwtExport()`, versionamento `v1/`, o que o controller NÃO pode fazer
3. **use-case** — orquestrador + sub use case, `implements IGenericUseCase`,
método único `executar()`, logging INICIO/FIM, `Resposta` com mensagem
UPPERCASE, `@Inject('IXyzRepository')`, transação como parâmetro
4. **entidade** — dois tipos distintos: entidade de domínio (input/output,
`static fromDto()`, sem decorators) e entidade de banco (auditoria obrigatória,
sem `fromDto()`). Localização correta de cada uma.
5. **adapter** — interfaces TypeScript puras, prefixo `I`, `Transaction`
em escrita, `incluirDesativados?` em leitura, por que usar token string
6. **repository** — `implements IXyzRepository`, soft delete obrigatório
em toda leitura, campos de auditoria em escrita, retorno via mapper,
padrão 3 passos para queries customizadas (count → ids → detalhes)
7. **model** — `@Table({ tableName, schema, timestamps: false })`,
`field: 'snake_case'`, campos de auditoria obrigatórios, relacionamentos,
nunca exportar fora de `infra/`
8. **infra** — mappers `toDomain()` e `toPersistence()`, decorator
`withApmAndTransaction` e seus parâmetros, `@JwtExport()`,
`@DocumentApiEndpoint()`, `@Public()`, serviços externos
9. **modules** — imports obrigatórios, `SequelizeModule.forFeature()`,
guards por módulo, token string para repos, como adicionar ao AppModule
10. **shared** — regra de inclusão (2+ módulos), o que `SharedModule` exporta,
`IGenericUseCase`, utilitários, enums, decisão local vs. shared
11. **domain** — dois locais de domínio, entidades de banco em
`shared/domain/entities/database/[schema]/`, enums, funções puras,
`JwtPayload`, `Resposta`, tabela de decisão "onde colocar este artefato?"
## 2. Convenções dos arquivos SKILL.md
- `description` deve descrever quando o agente deve aplicar a skill
automaticamente (ex: "Use quando criar um endpoint HTTP em NestJS seguindo
Clean Architecture. Trigger: criar controller, endpoint, route handler.")
- Templates devem usar código do boilerplate, não exemplos inventados
- Documentar divergências conhecidas entre docs e código real como alertas
- Máximo 600 linhas por skill. Se exceder, divida em sub-seções
## 3. Verificação após criação
Após criar todas as 11 skills:
1. Liste o conteúdo de `.claude/skills/` — devem existir 11 pastas
2. Teste uma skill: pergunte "Crie um controller para um módulo de avaliações"
e verifique se o agente usa os padrões corretos sem precisar de instrução
3. Reporte quais skills foram criadas e quais padrões cada uma capturou
## Regras inegociáveis
- Nunca inventar padrões não encontrados no código real
- Quando código e docs divergirem, sempre documentar na skill e usar o código
- Skills descrevem o projeto específico, não Clean Architecture genérica
- Incluir pelo menos um exemplo de código real (do boilerplate) em cada skill
Como usar as skills no dia a dia
após instalar — fluxo diário de um devCom as skills instaladas, o agente aplica os padrões automaticamente. Você pode invocar explicitamente ou deixar o agente detectar pelo contexto da instrução.
Invocação explícita: prefixe sua instrução com o nome da skill. Invocação implícita: o agente detecta pelo contexto — "crie um endpoint" dispara /controller automaticamente.
# Criar um módulo completo do zero
"Quero criar um módulo chamado 'avaliacoes' para o sistema.
Siga a skill /arquitetura-geral para estrutura geral,
/entidade para a entidade de banco, /adapter para o contrato."
# Criar apenas um use case
"Crie um use case para listar avaliações por fornecedor.
O use case deve seguir /use-case — orquestrador com sub use case base."
# Criar um endpoint
"Adicione um endpoint POST /v1/avaliacoes no controller de avaliações.
Siga /controller — com withApmAndTransaction e transformInput."
# Verificar padrões antes de revisar um PR
"Revise os arquivos abaixo e verifique se seguem os padrões de
/repository (soft delete, auditoria) e /use-case (Resposta<T>, logging)."
# Criar estrutura de pastas de um sub-módulo
"Preciso criar um sub-módulo 'respostas' dentro do módulo 'avaliacoes'.
Consulte /application para a estrutura correta de sub-módulos."
Dica para revisores de PR. Antes de revisar, diga ao agente: "Verifique se este código segue os padrões das skills de /controller, /use-case e /repository." O agente lista as violações antes de você precisar procurar manualmente.
Como saber que o módulo está correto.
Use este checklist antes de abrir um PR. O agente pode executar esta verificação por você — basta pedir.
- Soft delete em toda leitura de repositório
where: { deletedDt: null, deletedBy: null }em todo findOne e findAll - Campos de auditoria em toda entidade de banco e model
createdBy,createdDt,updatedBy,deletedBy,deletedDt - Use cases retornam
Resposta<T>— nuncaHttpExceptionMensagem em UPPERCASE:'AVALIACAO_CRIADA_COM_SUCESSO' - Controllers têm
@withApmAndTransactionem todos os métodosuseTransaction: truepara escrita,falsepara leitura - DTOs ficam apenas em controllers — nunca em use cases ou repositórios Transformação ocorre via
Entidade.fromDto(dto)no controller - Repositórios injetados via token string
@Inject('IXyzRepository')— não a classe concreta - Logging no use case: INICIO e FIM com contexto
this.logger.setContext(UseCase.name)no construtor - Module tem todos os imports obrigatórios
ConfigModule,PinoLoggerModule,DatabaseModule,ApmModule,SharedModule - Entidade de domínio tem
static fromDto()Controller chamaMinhaEntidade.fromDto(dto) - Model registrado em
SequelizeModule.forFeature([...models])no módulo Sem isso o Sequelize não injeta o model
A partir daqui, o time escala. Cada dev novo recebe as skills, lê a skill /arquitetura-geral e começa a produzir código revisável. O agente conhece os padrões. Você revisa regras de negócio, não arquitetura.