Code review: IoC, RESTful, Contracts, Security (OWASP), Clean Architecture, SOLID.
Skill para validação de código implementado contra padrões do projeto.
Use para: Validar código, identificar violações, auto-corrigir (autopilot) Não use para: Implementar código, planejamento, discovery
Referência: Sempre consultar CLAUDE.md para padrões gerais do projeto.
ANTES de iniciar qualquer revisão, você DEVE criar uma lista de todos usando TodoWrite.
O agente de code-review DEVE criar todos para cada categoria de validação e para cada arquivo alterado. Isso garante:
Carregar ANTES de revisar:
.fnd/skills/backend-development/SKILL.md.fnd/skills/database-development/SKILL.md.fnd/skills/frontend-development/SKILL.md.fnd/skills/ux-design/SKILL.md.fnd/skills/security-audit/SKILL.mdViolação de arquitetura = CRITICAL BLOCKER. Corrigir ANTES de qualquer outra validação.
{"source":"CLAUDE.md → ## Architecture Contract"}
{"validation":[ "Para CADA arquivo novo/modificado:", "1. Identificar layer/package do arquivo", "2. Grep imports de @org/* (ou alias do projeto)", "3. Verificar contra regras de Imports do contrato", "4. Verificar se artefato está no package correto (Placement)" ]}
{"examples":[ {"violation":"interfaces importa database","fix":"mover artefato ou ajustar import"}, {"violation":"DTO de service contract em database","fix":"mover DTO para interfaces"}, {"violation":"domain importa qualquer coisa","fix":"remover import, domain tem zero deps"} ]}
Código sem IoC correto NÃO funciona em runtime.
{"iocChecklist":{"Service":{"decorator":"@Injectable()","providers":"feature module","exports":false,"controllers":false,"indexTs":false},"Repository":{"decorator":"@Injectable()","providers":"db module","exports":"db module","controllers":false,"indexTs":"libs/"},"Handler":{"decorator":"@Injectable()","providers":"feature module","exports":false,"controllers":false,"indexTs":"NUNCA"},"Guard":{"decorator":"@Injectable()","providers":"feature/global","exports":false,"controllers":false,"indexTs":false},"Controller":{"decorator":"@Controller()","providers":false,"exports":false,"controllers":"feature module","indexTs":false}}}
{"iocChecks":[
{"component":"Service","validations":[
"tem @Injectable()",
"registrado em providers[] do módulo",
"módulo importado em AppModule.imports[]"
]},
{"component":"Repository","validations":[
"tem @Injectable()",
"registrado em providers[] do módulo database",
"registrado em exports[] do módulo database",
"exportado no index.ts de libs/app-database/src/",
"tipo adicionado em Database.ts se nova tabela"
]},
{"component":"CommandHandler","validations":[
"tem @Injectable()",
"registrado em providers[] do módulo feature",
"NÃO exportado em index.ts (implementation detail)",
"Command exportado (contrato público)"
]},
{"component":"EventHandler","validations":[
"tem @Injectable()",
"registrado em providers[] do módulo feature",
"NÃO exportado em index.ts (implementation detail)",
"Event exportado se cross-module"
]},
{"component":"Controller","validations":[
"tem @Controller('prefix')",
"registrado em controllers[] do módulo",
"guards aplicados (@UseGuards)",
"módulo importado em AppModule.imports[]"
]},
{"component":"Module","validations":[
"importa módulos necessários (SharedModule, DatabaseModule)",
"registra todos providers",
"registra todos controllers",
"importado em AppModule.imports[]"
]}
]}
{"iocFiles":[
{"file":"apps/backend/src/app.module.ts","check":"imports[] contém módulo"},
{"file":"[feature].module.ts","check":"providers[], controllers[], imports[]"},
{"file":"libs/app-database/src/app-database.module.ts","check":"providers[], exports[] para repos"},
{"file":"libs/app-database/src/index.ts","check":"exports de repos públicos"},
{"file":"libs/app-database/src/types/Database.ts","check":"tipos de tabelas novas"},
{"file":"libs/domain/src/index.ts","check":"exports de entities/enums novos"}
]}
{"errors":[ {"err":"Nest can't resolve dependencies of X","cause":"X não está em providers[] ou dependência de X não registrada","fix":"adicionar X e suas dependências em providers[]"}, {"err":"X is not a provider","cause":"falta @Injectable() ou não registrado","fix":"adicionar decorator e registrar em providers[]"}, {"err":"Module X not found","cause":"módulo não importado em AppModule","fix":"adicionar em AppModule.imports[]"}, {"err":"Repository not found","cause":"repo não exportado em exports[] do db module","fix":"adicionar em exports[] de AppDatabaseModule"}, {"err":"404 on endpoint","cause":"controller não registrado ou módulo não importado","fix":"verificar controllers[] e AppModule.imports[]"} ]}
{"check":[{"rule":"HTTP method","correct":"GET read, POST create, DELETE remove","wrong":"POST for read"},{"rule":"URL","correct":"/users (noun)","wrong":"/getUsers (verb)"},{"rule":"Status","correct":"201 POST, 204 DELETE","wrong":"200 for all"}]}
{"frontendBackend":[{"backend":"Date","frontend":"string"},{"backend":"Enum","frontend":"union type"},{"rule":"sync required/optional fields"}]}
{"jsonb":["NO double parse","NO double stringify","Kysely handles automatically"]}
{"checks":[{"cat":"Injection","check":"parametrized queries"},{"cat":"Auth","check":"guards applied"},{"cat":"DataExposure","check":"no secrets in logs"},{"cat":"AccessControl","check":"filter by account_id"},{"cat":"XSS","check":"outputs sanitized"}]}
{"multiTenant":["EVERY query filters account_id","account_id from JWT not body"]}
{"checks":["SRP: one class one responsibility","OCP: open for extension, closed for modification","LSP: subtypes substitutable","ISP: specific interfaces over general","DIP: depend on abstractions"]}
{"checks":["no any type","DTOs follow naming","no console.log (use logger)","no commented code","no unused imports","exception handling"]}
{"checks":["migration created","has up and down","Kysely types updated","entity exported","repository exported"]}
{"checks":["new vars in .env.example","example values not real","use IConfigurationService not process.env"]}
{"weights":{"archContract":20,"ioc":15,"restful":10,"contracts":15,"security":15,"solid":10,"quality":10,"database":5}}
{"status":{"8-10":"APPROVED","6-7":"NEEDS ATTENTION","4-5":"NEEDS FIXES","0-3":"CRITICAL"}}
bash .fnd/scripts/feature-status.shOBRIGATÓRIO: Criar TodoWrite com lista de validações:
Exemplo de todos a criar:
- [ ] Carregar contexto e identificar arquivos alterados
- [ ] Validar Architecture Contract: imports entre packages
- [ ] Validar Architecture Contract: placement de artefatos
- [ ] Validar IoC: verificar @Injectable em novos services
- [ ] Validar IoC: verificar providers[] nos módulos
- [ ] Validar IoC: verificar exports[] para repositórios
- [ ] Validar IoC: verificar imports[] em AppModule
- [ ] Validar IoC: verificar barrel exports (index.ts)
- [ ] Validar RESTful: métodos HTTP corretos
- [ ] Validar RESTful: status codes corretos
- [ ] Validar Contracts: tipos sincronizados frontend/backend
- [ ] Validar Security: multi-tenancy (account_id)
- [ ] Validar Security: guards aplicados
- [ ] Validar Quality: sem any, sem console.log
- [ ] Validar Database: migrations, tipos Kysely
- [ ] Corrigir issues encontrados
- [ ] Verificar build compila
- [ ] Gerar relatório de review
Para CADA arquivo alterado, validar na ordem:
Architecture Contract (PRIMEIRO - mais crítico)
in_progress## Architecture Contract do CLAUDE.mdcompletedIoC Configuration (segundo mais crítico)
in_progresscompletedRESTful Compliance
Contract Validation
Security (OWASP)
SOLID Principles
Code Quality
Database
in_progresscompletedCreate docs/features/${featureId}/review.md
# Code Review: [Feature]
**Date:** [date] | **Status:** ✅ APPROVED
## Score
| Category | Score | Status |
|----------|-------|--------|
| Arch Contract | X/10 | ✅ |
| IoC | X/10 | ✅ |
| RESTful | X/10 | ✅ |
| Contracts | X/10 | ✅ |
| Security | X/10 | ✅ |
| SOLID | X/10 | ✅ |
| Quality | X/10 | ✅ |
| Database | X/10 | ✅ |
| **OVERALL** | **X/10** | **✅** |
## Issues Found & Fixed
### Issue #1: [Title]
**Category:** [cat] | **File:** `path:line` | **Severity:** 🔴 Critical
**Problem:** [code before]
**Fix:** [code after]
**Status:** ✅ FIXED
## Build Status
- [x] Backend compiles
- [x] Frontend compiles
Do:
Dont:
Novo Service criado? Verificar:
@Injectable() no serviceproviders: [NovoService] no móduloimports: [FeatureModule] no AppModuleNovo Repository criado? Verificar:
@Injectable() no repositoryproviders: [NovoRepository] no AppDatabaseModuleexports: [NovoRepository] no AppDatabaseModuleexport { NovoRepository } no index.ts de libs/app-database/src/Novo Handler criado? Verificar:
@Injectable() no handlerproviders: [NovoHandler] no módulo da featureNovo Controller criado? Verificar:
@Controller('prefix') no controllercontrollers: [NovoController] no módulo@UseGuards(JwtAuthGuard) aplicadoimports: [FeatureModule] no AppModuleNova Entity/Enum criado? Verificar:
export { NovaEntity } no index.ts de libs/domain/src/Nova Tabela criada? Verificar: