jarvis-ai-framework 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +12 -9
- package/agents/AGENTS.md +9 -1
- package/agents/README.md +2 -2
- package/agents/engineering/data/eng.data-engineer.agent.md +2 -2
- package/agents/engineering/eng.agent.md +4 -6
- package/agents/engineering/eng.bug-hunter.md +10 -5
- package/agents/engineering/eng.cybersecurity.agent.md +2 -4
- package/agents/engineering/eng.dev-code-reviewer.md +4 -0
- package/agents/engineering/eng.docs-writer.md +3 -3
- package/agents/engineering/eng.frontend.agent.md +17 -8
- package/agents/engineering/eng.rpa.agent.md +3 -5
- package/agents/engineering/eng.ux-designer.agent.md +4 -0
- package/agents/engineering/qa/eng.qa.cypress-specialist.md +8 -5
- package/agents/engineering/qa/eng.qa.quality-champion-task-agent.md +4 -0
- package/agents/engineering/qa/eng.qa.quality-strategist.md +18 -8
- package/agents/engineering/qa/eng.qa.test-architect.md +17 -6
- package/agents/engineering/qa/eng.qa.test-planner.md +17 -8
- package/agents/engineering/qa/eng.qa.testing-engineer.md +26 -9
- package/agents/product/prod.discovery-interviewer.md +22 -3
- package/agents/product/prod.pm-checker.md +4 -0
- package/bin/commands/map.js +43 -0
- package/bin/commands/tokens.js +93 -0
- package/bin/jarvis.js +10 -0
- package/bin/lib/config/constants.js +11 -0
- package/bin/lib/core/profile-filter.js +113 -0
- package/bin/lib/core/scanner.js +2 -2
- package/bin/lib/core/token-report.js +90 -0
- package/bin/lib/flow-map/index.js +65 -0
- package/bin/lib/flow-map/parse.js +217 -0
- package/bin/lib/flow-map/render.js +86 -0
- package/bin/lib/flow-map/tree.js +199 -0
- package/members.md +1 -1
- package/package.json +4 -2
- package/rules/AGENTS.md +18 -7
- package/rules/engineering/eng-rules.md +2 -12
- package/rules/engineering/eng-security-rules.md +1 -2
- package/rules/engineering/eng.integrations-rules.md +0 -4
- package/rules/engineering/eng.skills-rules.md +0 -4
- package/rules/engineering/eng.specializations-rules.md +0 -4
- package/rules/product/README.md +1 -0
- package/rules/product/prod-rules.md +1 -4
- package/rules/product/prod.spec-rules.md +0 -4
- package/rules/rtk-rules.md +0 -1
- package/{rules → rules-on-demand}/engineering/eng.breakdown-subtasks-rules.md +0 -4
- package/{rules → rules-on-demand}/engineering/eng.plan-rules.md +0 -4
- package/{rules → rules-on-demand}/engineering/eng.pr-rules.md +0 -4
- package/{rules → rules-on-demand}/engineering/eng.pre-pr-rules.md +0 -4
- package/{rules → rules-on-demand}/engineering/eng.start-rules.md +0 -4
- package/{rules → rules-on-demand}/engineering/eng.tech-spec-rules.md +1 -2
- package/{rules → rules-on-demand}/engineering/eng.work-rules.md +0 -4
- package/skills/AGENTS.md +22 -21
- package/skills/SKILLS-ROADMAP.md +0 -4
- package/skills/eng-ai-engineer/SKILL.md +6 -0
- package/skills/eng-backend/SKILL.md +6 -0
- package/skills/eng-backend-arch-c4/SKILL.md +10 -4
- package/skills/eng-backend-microservices-trace/SKILL.md +6 -0
- package/skills/eng-backend-nestjs/SKILL.md +16 -461
- package/skills/eng-backend-nestjs/references/1-arquitetura-modulos.md +54 -0
- package/skills/eng-backend-nestjs/references/2-guards-autenticacao.md +118 -0
- package/skills/eng-backend-nestjs/references/3-interceptors-pipes-filters.md +113 -0
- package/skills/eng-backend-nestjs/references/4-config-logging.md +61 -0
- package/skills/eng-backend-nestjs/references/5-testes.md +83 -0
- package/skills/eng-backend-nestjs/references/6-problemas-comuns.md +53 -0
- package/skills/eng-backend-rabbitmq/SKILL.md +15 -298
- package/skills/eng-backend-rabbitmq/references/1-referencia-endpoints.md +28 -0
- package/skills/eng-backend-rabbitmq/references/2-codigo-consumer-producer.md +90 -0
- package/skills/eng-backend-rabbitmq/references/3-arquiteturas-comuns.md +101 -0
- package/skills/eng-backend-rabbitmq/references/4-troubleshooting.md +93 -0
- package/skills/eng-data-bi/SKILL.md +6 -0
- package/skills/eng-data-debug/SKILL.md +6 -0
- package/skills/eng-data-engineer/SKILL.md +16 -7
- package/skills/eng-data-onboard/SKILL.md +6 -0
- package/skills/eng-data-orchestrator/SKILL.md +6 -0
- package/skills/eng-devops-performance-engineer/SKILL.md +6 -0
- package/skills/eng-frontend/SKILL.md +6 -0
- package/skills/eng-frontend-design-system/SKILL.md +13 -479
- package/skills/eng-frontend-design-system/references/1-estrutura-pacote.md +57 -0
- package/skills/eng-frontend-design-system/references/2-tokens.md +116 -0
- package/skills/eng-frontend-design-system/references/3-componentes.md +165 -0
- package/skills/eng-frontend-design-system/references/4-storybook.md +85 -0
- package/skills/eng-frontend-design-system/references/5-auditoria-versionamento.md +76 -0
- package/skills/eng-frontend-microfrontend/SKILL.md +17 -457
- package/skills/eng-frontend-microfrontend/references/1-criando-remote.md +109 -0
- package/skills/eng-frontend-microfrontend/references/2-configurando-shell.md +70 -0
- package/skills/eng-frontend-microfrontend/references/3-contratos-interface.md +73 -0
- package/skills/eng-frontend-microfrontend/references/4-shared-dependencies.md +48 -0
- package/skills/eng-frontend-microfrontend/references/5-event-bus.md +59 -0
- package/skills/eng-frontend-microfrontend/references/6-monorepo-deploy.md +77 -0
- package/skills/eng-frontend-microfrontend/references/7-troubleshooting.md +45 -0
- package/skills/eng-global-browser-extension-builder/SKILL.md +6 -0
- package/skills/eng-global-docs-write/SKILL.md +10 -5
- package/skills/eng-global-jira-comment/SKILL.md +6 -0
- package/skills/eng-global-pr/SKILL.md +7 -1
- package/skills/eng-global-task-comment/SKILL.md +6 -0
- package/skills/eng-qa-a11y-audit/SKILL.md +10 -4
- package/skills/eng-qa-bug-report/SKILL.md +18 -230
- package/skills/eng-qa-bug-report/references/1-integracao-task-managers.md +148 -0
- package/skills/eng-qa-bug-report/references/2-exemplos-de-uso.md +46 -0
- package/skills/eng-qa-bug-report/references/3-bug-to-test.md +45 -0
- package/skills/eng-qa-cypress-e2e/SKILL.md +6 -0
- package/skills/eng-qa-dev-guide/SKILL.md +9 -1
- package/skills/eng-qa-e2e/SKILL.md +9 -3
- package/skills/eng-qa-e2e-spec-writer/SKILL.md +15 -9
- package/skills/eng-qa-exploratory/SKILL.md +16 -9
- package/skills/eng-qa-gate/SKILL.md +11 -5
- package/skills/eng-qa-gate/assets/checklist-validacao.md +1 -1
- package/skills/eng-qa-graphql-contract/SKILL.md +9 -3
- package/skills/eng-qa-quality-report/SKILL.md +9 -3
- package/skills/eng-qa-test-plan/SKILL.md +6 -0
- package/skills/eng-qa-testsprite/SKILL.md +10 -4
- package/skills/eng-qa-unit-test/SKILL.md +7 -1
- package/skills/eng-scraper/SKILL.md +12 -436
- package/skills/eng-scraper/references/1-puppeteer.md +140 -0
- package/skills/eng-scraper/references/2-playwright-cheerio-pdf.md +82 -0
- package/skills/eng-scraper/references/3-anti-bot.md +94 -0
- package/skills/eng-scraper/references/4-resiliencia-etl-monitoramento.md +137 -0
- package/skills/eng-scraper-robot-builder/SKILL.md +6 -0
- package/skills/eng-security-cybersecurity/SKILL.md +13 -409
- package/skills/eng-security-cybersecurity/references/1-owasp-top-10.md +331 -0
- package/skills/eng-security-cybersecurity/references/2-secrets-management.md +31 -0
- package/skills/eng-security-cybersecurity/references/3-input-validation.md +43 -0
- package/skills/eng-security-cybersecurity/references/4-compliance.md +20 -0
- package/skills/eng-security-patch/SKILL.md +6 -0
- package/skills/eng-security-threat-model/SKILL.md +6 -0
- package/skills/eng-security-triage/SKILL.md +6 -0
- package/skills/jarvis-context-detect/SKILL.md +6 -0
- package/skills/jarvis-create-specialization/SKILL.md +6 -0
- package/skills/jarvis-docs-central/SKILL.md +6 -0
- package/skills/jarvis-docs-index/SKILL.md +10 -2
- package/skills/jarvis-evolution-architect/SKILL.md +439 -0
- package/skills/jarvis-evolution-architect/references/exemplos.md +297 -0
- package/skills/jarvis-evolution-architect/references/guia-de-uso.md +355 -0
- package/skills/jarvis-evolution-architect/references/lentes-e-conceitos.md +292 -0
- package/skills/jarvis-evolution-architect/references/visao-geral.md +272 -0
- package/skills/jarvis-init/SKILL.md +14 -7
- package/skills/jarvis-list-specializations/SKILL.md +6 -0
- package/skills/jarvis-report-issue/SKILL.md +6 -0
- package/skills/product-roadmap-report/SKILL.md +8 -0
- package/skills/product-specs/SKILL.md +9 -0
- package/skills/product-specs-update/SKILL.md +6 -0
- package/taxonomy.md +12 -12
- package/templates/AGENTS.md +2 -0
- package/templates/engineering/tech-spec-delivery-template.md +179 -0
- package/workflows/AGENTS.md +12 -2
- package/workflows/README.md +18 -16
- package/workflows/all-tools.md +7 -1
- package/workflows/engineering/data/data.contract.md +8 -0
- package/workflows/engineering/data/data.new-pipeline.md +10 -0
- package/workflows/engineering/eng.breakdown-subtasks.md +9 -0
- package/workflows/engineering/eng.bug-audit.md +9 -2
- package/workflows/engineering/eng.build-tech-spec.md +17 -146
- package/workflows/engineering/eng.create-ard-from-code.md +8 -0
- package/workflows/engineering/eng.create-ard.md +8 -0
- package/workflows/engineering/eng.create-rfc.md +7 -0
- package/workflows/engineering/eng.debug.md +3 -3
- package/workflows/engineering/eng.docs.md +9 -0
- package/workflows/engineering/eng.light-arch.md +7 -0
- package/workflows/engineering/eng.plan.md +15 -2
- package/workflows/engineering/eng.pr.md +19 -7
- package/workflows/engineering/eng.pre-pr.md +27 -1
- package/workflows/engineering/eng.review.md +13 -0
- package/workflows/engineering/eng.rpa.robot.md +16 -0
- package/workflows/engineering/eng.security-audit.md +7 -0
- package/workflows/engineering/eng.security-incident.md +6 -0
- package/workflows/engineering/eng.security-pipeline.md +9 -0
- package/workflows/engineering/eng.security-review.md +6 -0
- package/workflows/engineering/eng.start.md +22 -6
- package/workflows/engineering/eng.work.md +18 -2
- package/workflows/engineering/frontend/eng.frontend-component.md +7 -0
- package/workflows/engineering/frontend/eng.frontend-perf-audit.md +8 -0
- package/workflows/engineering/frontend/eng.frontend-review.md +8 -0
- package/workflows/engineering/qa/eng.qa-dev-quality-guide.md +6 -0
- package/workflows/engineering/qa/eng.qa-e2e-test-generation.md +6 -0
- package/workflows/engineering/qa/eng.qa-exploratory-session.md +8 -0
- package/workflows/engineering/qa/eng.qa-quality-gate-validation.md +7 -0
- package/workflows/engineering/qa/eng.qa-quality-report.md +7 -0
- package/workflows/engineering/qa/eng.qa-refinement-entry.md +7 -0
- package/workflows/engineering/qa/eng.qa-release-signoff.md +6 -0
- package/workflows/engineering/qa/eng.qa-sprint-planning.md +6 -0
- package/workflows/product/prod.roadmap.preview.md +9 -0
- package/workflows/product/prod.spec.ard.md +97 -0
- package/workflows/product/prod.spec.breakdown.md +10 -0
- package/workflows/product/prod.spec.clarify.md +8 -2
- package/workflows/product/prod.spec.discovery.md +10 -0
- package/workflows/product/prod.spec.epic.md +8 -0
- package/workflows/product/prod.spec.frd.md +7 -0
- package/workflows/product/prod.spec.issue.md +6 -0
- package/workflows/product/prod.spec.md +15 -1
- package/workflows/product/prod.spec.prd.md +7 -0
- package/workflows/taxonomy.md +58 -6
- package/workflows/warm-up.md +24 -9
- package/rules/engineering/eng.downstream-flow-rules.md +0 -297
package/skills/SKILLS-ROADMAP.md
CHANGED
|
@@ -221,10 +221,6 @@ Removidas: `checkin`, `checkout`, `daily`, `task-log`, `send-priority`, `sent-pr
|
|
|
221
221
|
- **Trigger**: auto-report de bugs no framework Jarvis via GitLab API
|
|
222
222
|
- **Status**: `criado`
|
|
223
223
|
|
|
224
|
-
### `skill-creator` ✅
|
|
225
|
-
- **Trigger**: criação de novos skills
|
|
226
|
-
- **Status**: `criado`
|
|
227
|
-
|
|
228
224
|
### `jarvis-docs-index` / `jarvis-docs-central` / `jarvis-context-detect` ✅
|
|
229
225
|
- **Trigger**: indexação de docs, sync com repo central, detecção de contexto
|
|
230
226
|
- **Status**: `criado`
|
|
@@ -205,6 +205,12 @@ Sempre avaliar tradeoffs antes de escolher modelo:
|
|
|
205
205
|
- Plano de rollout gradual com métricas de avaliação
|
|
206
206
|
- Documentar comportamento do sistema de IA
|
|
207
207
|
|
|
208
|
+
### Skills invocados durante a execução do skill
|
|
209
|
+
|
|
210
|
+
| Passo | Skill | Condição |
|
|
211
|
+
|-------|-------|----------|
|
|
212
|
+
| — | Nenhuma — skill autocontida | — |
|
|
213
|
+
|
|
208
214
|
---
|
|
209
215
|
|
|
210
216
|
## Comportamentos Esperados
|
|
@@ -154,6 +154,12 @@ Depurar um problema? → tema 12 (erros e logging)
|
|
|
154
154
|
4. **Testar**: cobrir o caso feliz, os casos de erro e os limites
|
|
155
155
|
5. **Validar**: percorrer o checklist de conclusão abaixo
|
|
156
156
|
|
|
157
|
+
### Skills invocados durante a execução do skill
|
|
158
|
+
|
|
159
|
+
| Passo | Skill | Condição |
|
|
160
|
+
|-------|-------|----------|
|
|
161
|
+
| — | Nenhuma — skill autocontida | — |
|
|
162
|
+
|
|
157
163
|
---
|
|
158
164
|
|
|
159
165
|
## Base Universal
|
|
@@ -32,10 +32,10 @@ Criar e manter documentação de arquitetura usando os 4 níveis do C4:
|
|
|
32
32
|
**Exemplos de uso:**
|
|
33
33
|
|
|
34
34
|
```
|
|
35
|
-
/arch-c4 context # Criar/Atualizar diagrama de contexto
|
|
36
|
-
/arch-c4 container # Criar/Atualizar diagrama de containers
|
|
37
|
-
/arch-c4 component api-backend # Detalhar componentes de um container
|
|
38
|
-
/arch-c4 code user-service # Diagrama de código (raro)
|
|
35
|
+
/eng-backend-arch-c4 context # Criar/Atualizar diagrama de contexto
|
|
36
|
+
/eng-backend-arch-c4 container # Criar/Atualizar diagrama de containers
|
|
37
|
+
/eng-backend-arch-c4 component api-backend # Detalhar componentes de um container
|
|
38
|
+
/eng-backend-arch-c4 code user-service # Diagrama de código (raro)
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Recursos
|
|
@@ -259,6 +259,12 @@ git diff origin/main --name-only | grep -E "docker|config|src/(domain|infrastruc
|
|
|
259
259
|
| Novo container/serviço | Container | Adicionar |
|
|
260
260
|
| Novo módulo/componente | Component | Atualizar |
|
|
261
261
|
|
|
262
|
+
### Skills invocados durante a execução do skill
|
|
263
|
+
|
|
264
|
+
| Passo | Skill | Condição |
|
|
265
|
+
|-------|-------|----------|
|
|
266
|
+
| — | Nenhuma — skill autocontida | — |
|
|
267
|
+
|
|
262
268
|
---
|
|
263
269
|
|
|
264
270
|
## Integração com ADRs
|
|
@@ -411,6 +411,12 @@ Ao concluir, retornar:
|
|
|
411
411
|
- Se inconclusivo: `→ eng.debug Passo 3 (Plano de Investigação) — coletar logs de {serviços}`
|
|
412
412
|
- Se bug multi-serviço complexo: `→ eng.plan {TASK_MANAGER_KEY} — múltiplos componentes afetados`
|
|
413
413
|
|
|
414
|
+
### Skills invocados durante a execução do skill
|
|
415
|
+
|
|
416
|
+
| Passo | Skill | Condição |
|
|
417
|
+
|-------|-------|----------|
|
|
418
|
+
| — | Nenhuma — skill autocontida | — |
|
|
419
|
+
|
|
414
420
|
---
|
|
415
421
|
|
|
416
422
|
## Regras
|
|
@@ -77,8 +77,8 @@ Use este skill quando:
|
|
|
77
77
|
**NÃO usar quando:**
|
|
78
78
|
- A tarefa é sobre design de APIs, paginação, RabbitMQ, caching → usar `eng-backend`
|
|
79
79
|
- A tarefa envolve scraping ou extração de dados → usar `eng-scraper`
|
|
80
|
-
- A tarefa é puramente de banco de dados (queries, migrations, schema) →
|
|
81
|
-
- Problema é de TypeScript puro (tipos, generics) →
|
|
80
|
+
- A tarefa é puramente de banco de dados (queries, migrations, schema) → ainda não há skill específico; seguir `eng-backend`
|
|
81
|
+
- Problema é de TypeScript puro (tipos, generics) → ainda não há skill específico; seguir as convenções de TypeScript do projeto
|
|
82
82
|
|
|
83
83
|
---
|
|
84
84
|
|
|
@@ -249,469 +249,24 @@ find src -name "*.module.ts" | head -10
|
|
|
249
249
|
find src -name "*.spec.ts" | head -5
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
-
###
|
|
252
|
+
### Referências (leia só o tema que a tarefa pedir)
|
|
253
253
|
|
|
254
|
-
|
|
254
|
+
Leia **só** o arquivo do tema que a tarefa pedir; o restante fica fora do contexto.
|
|
255
255
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
providers: [UserService, UserRepository],
|
|
265
|
-
exports: [UserService], // exportar apenas o que outros módulos precisam
|
|
266
|
-
})
|
|
267
|
-
export class UserModule {}
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
#### Módulo global (para providers transversais)
|
|
271
|
-
|
|
272
|
-
```typescript
|
|
273
|
-
// ✅ Módulo global — disponível sem importar
|
|
274
|
-
@Global()
|
|
275
|
-
@Module({
|
|
276
|
-
providers: [LoggerService],
|
|
277
|
-
exports: [LoggerService],
|
|
278
|
-
})
|
|
279
|
-
export class LoggerModule {}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
#### Módulo dinâmico
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
// ✅ Módulo dinâmico para configuração em runtime
|
|
286
|
-
@Module({})
|
|
287
|
-
export class HttpClientModule {
|
|
288
|
-
static forRoot(options: HttpClientOptions): DynamicModule {
|
|
289
|
-
return {
|
|
290
|
-
module: HttpClientModule,
|
|
291
|
-
providers: [
|
|
292
|
-
{ provide: HTTP_CLIENT_OPTIONS, useValue: options },
|
|
293
|
-
HttpClientService,
|
|
294
|
-
],
|
|
295
|
-
exports: [HttpClientService],
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
### Guards
|
|
304
|
-
|
|
305
|
-
Guards determinam se uma requisição deve ser processada. Executam **antes** dos interceptors.
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
// ✅ Guard de autenticação JWT
|
|
309
|
-
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'
|
|
310
|
-
import { JwtService } from '@nestjs/jwt'
|
|
311
|
-
import { Request } from 'express'
|
|
312
|
-
|
|
313
|
-
@Injectable()
|
|
314
|
-
export class JwtAuthGuard implements CanActivate {
|
|
315
|
-
constructor(private readonly jwtService: JwtService) {}
|
|
316
|
-
|
|
317
|
-
canActivate(context: ExecutionContext): boolean {
|
|
318
|
-
const request = context.switchToHttp().getRequest<Request>()
|
|
319
|
-
const token = this.extractTokenFromHeader(request)
|
|
320
|
-
|
|
321
|
-
if (!token) throw new UnauthorizedException('Token não fornecido')
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
const payload = this.jwtService.verify(token)
|
|
325
|
-
request['user'] = payload
|
|
326
|
-
return true
|
|
327
|
-
} catch {
|
|
328
|
-
throw new UnauthorizedException('Token inválido ou expirado')
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
private extractTokenFromHeader(request: Request): string | undefined {
|
|
333
|
-
const [type, token] = request.headers.authorization?.split(' ') ?? []
|
|
334
|
-
return type === 'Bearer' ? token : undefined
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
```typescript
|
|
340
|
-
// ✅ Guard de roles (RBAC)
|
|
341
|
-
@Injectable()
|
|
342
|
-
export class RolesGuard implements CanActivate {
|
|
343
|
-
constructor(private readonly reflector: Reflector) {}
|
|
344
|
-
|
|
345
|
-
canActivate(context: ExecutionContext): boolean {
|
|
346
|
-
const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
|
|
347
|
-
context.getHandler(),
|
|
348
|
-
context.getClass(),
|
|
349
|
-
])
|
|
350
|
-
|
|
351
|
-
if (!requiredRoles) return true
|
|
352
|
-
|
|
353
|
-
const { user } = context.switchToHttp().getRequest()
|
|
354
|
-
return requiredRoles.some((role) => user.roles?.includes(role))
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
```typescript
|
|
360
|
-
// ✅ Decorator combinado (Auth + Roles)
|
|
361
|
-
export const Auth = (...roles: string[]) =>
|
|
362
|
-
applyDecorators(
|
|
363
|
-
UseGuards(JwtAuthGuard, RolesGuard),
|
|
364
|
-
SetMetadata('roles', roles),
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
// Uso na rota
|
|
368
|
-
@Auth('admin')
|
|
369
|
-
@Delete(':id')
|
|
370
|
-
async remove(@Param('id') id: string) { ... }
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### Interceptors
|
|
376
|
-
|
|
377
|
-
Interceptors executam antes E depois do route handler. Ideais para logging, transformação de resposta, caching.
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
// ✅ Interceptor de logging de requisições
|
|
381
|
-
@Injectable()
|
|
382
|
-
export class LoggingInterceptor implements NestInterceptor {
|
|
383
|
-
private readonly logger = new Logger(LoggingInterceptor.name)
|
|
384
|
-
|
|
385
|
-
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
|
386
|
-
const request = context.switchToHttp().getRequest()
|
|
387
|
-
const { method, url } = request
|
|
388
|
-
const start = Date.now()
|
|
389
|
-
|
|
390
|
-
return next.handle().pipe(
|
|
391
|
-
tap(() => {
|
|
392
|
-
const ms = Date.now() - start
|
|
393
|
-
this.logger.log(`${method} ${url} — ${ms}ms`)
|
|
394
|
-
}),
|
|
395
|
-
)
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
```typescript
|
|
401
|
-
// ✅ Interceptor de transformação de resposta
|
|
402
|
-
@Injectable()
|
|
403
|
-
export class TransformInterceptor<T> implements NestInterceptor<T, { data: T }> {
|
|
404
|
-
intercept(context: ExecutionContext, next: CallHandler): Observable<{ data: T }> {
|
|
405
|
-
return next.handle().pipe(
|
|
406
|
-
map((data) => ({ data }))
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
---
|
|
413
|
-
|
|
414
|
-
### Pipes e Validação
|
|
415
|
-
|
|
416
|
-
Pipes validam e transformam dados de entrada **antes** do route handler.
|
|
417
|
-
|
|
418
|
-
```typescript
|
|
419
|
-
// ✅ Configuração global de ValidationPipe (no main.ts)
|
|
420
|
-
app.useGlobalPipes(
|
|
421
|
-
new ValidationPipe({
|
|
422
|
-
whitelist: true, // remove campos não declarados no DTO
|
|
423
|
-
forbidNonWhitelisted: true, // lança erro se campos extras existirem
|
|
424
|
-
transform: true, // transforma payload para instância do DTO
|
|
425
|
-
transformOptions: {
|
|
426
|
-
enableImplicitConversion: true,
|
|
427
|
-
},
|
|
428
|
-
}),
|
|
429
|
-
)
|
|
430
|
-
```
|
|
431
|
-
|
|
432
|
-
```typescript
|
|
433
|
-
// ✅ DTO com class-validator
|
|
434
|
-
export class CreateUserDto {
|
|
435
|
-
@IsString()
|
|
436
|
-
@MinLength(2)
|
|
437
|
-
name: string
|
|
438
|
-
|
|
439
|
-
@IsEmail()
|
|
440
|
-
email: string
|
|
441
|
-
|
|
442
|
-
@IsOptional()
|
|
443
|
-
@IsEnum(['admin', 'editor', 'viewer'])
|
|
444
|
-
role?: string
|
|
445
|
-
}
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
---
|
|
256
|
+
| Tema | Quando ler | Arquivo |
|
|
257
|
+
|------|-----------|---------|
|
|
258
|
+
| Arquitetura de Módulos (NestJS) | A tarefa criar ou reorganizar módulos, providers e injeção de dependência | `references/1-arquitetura-modulos.md` |
|
|
259
|
+
| Guards e Autenticação (Passport + JWT) | A tarefa envolver guards, roles/permissões ou autenticação com Passport e JWT | `references/2-guards-autenticacao.md` |
|
|
260
|
+
| Interceptors, Pipes e Exception Filters | A tarefa envolver interceptors, validação com pipes ou tratamento de exceções | `references/3-interceptors-pipes-filters.md` |
|
|
261
|
+
| ConfigModule e Logging | A tarefa envolver variáveis de ambiente (ConfigModule) ou logging | `references/4-config-logging.md` |
|
|
262
|
+
| Testes (NestJS) | A tarefa envolver testes unitários, de integração ou e2e | `references/5-testes.md` |
|
|
263
|
+
| Problemas Comuns e Soluções | Houver erro de injeção de dependência, dependência circular, estratégia de autenticação, conexão com banco, escopo de provider ou guard não aplicado | `references/6-problemas-comuns.md` |
|
|
449
264
|
|
|
450
|
-
###
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
// ✅ ConfigModule com validação via Joi
|
|
454
|
-
@Module({
|
|
455
|
-
imports: [
|
|
456
|
-
ConfigModule.forRoot({
|
|
457
|
-
isGlobal: true,
|
|
458
|
-
envFilePath: '.env',
|
|
459
|
-
validationSchema: Joi.object({
|
|
460
|
-
NODE_ENV: Joi.string().valid('development', 'production', 'test').default('development'),
|
|
461
|
-
PORT: Joi.number().default(3000),
|
|
462
|
-
DATABASE_URL: Joi.string().required(),
|
|
463
|
-
JWT_SECRET: Joi.string().min(32).required(),
|
|
464
|
-
MESSAGE_BROKER_URL: Joi.string().required(),
|
|
465
|
-
}),
|
|
466
|
-
}),
|
|
467
|
-
],
|
|
468
|
-
})
|
|
469
|
-
export class AppModule {}
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
```typescript
|
|
473
|
-
// ✅ Usar ConfigService em vez de process.env diretamente
|
|
474
|
-
@Injectable()
|
|
475
|
-
export class DatabaseService {
|
|
476
|
-
constructor(private readonly configService: ConfigService) {}
|
|
477
|
-
|
|
478
|
-
getUrl(): string {
|
|
479
|
-
return this.configService.getOrThrow<string>('DATABASE_URL')
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
---
|
|
485
|
-
|
|
486
|
-
### Autenticação (Passport + JWT)
|
|
487
|
-
|
|
488
|
-
```typescript
|
|
489
|
-
// ✅ JWT Strategy
|
|
490
|
-
import { ExtractJwt, Strategy } from 'passport-jwt' // importar de 'passport-jwt', NÃO 'passport-local'
|
|
491
|
-
|
|
492
|
-
@Injectable()
|
|
493
|
-
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
494
|
-
constructor(configService: ConfigService) {
|
|
495
|
-
super({
|
|
496
|
-
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
497
|
-
ignoreExpiration: false,
|
|
498
|
-
secretOrKey: configService.getOrThrow('JWT_SECRET'),
|
|
499
|
-
})
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
async validate(payload: { sub: string; email: string }) {
|
|
503
|
-
return { userId: payload.sub, email: payload.email }
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
```typescript
|
|
509
|
-
// ✅ AuthModule
|
|
510
|
-
@Module({
|
|
511
|
-
imports: [
|
|
512
|
-
PassportModule,
|
|
513
|
-
JwtModule.registerAsync({
|
|
514
|
-
inject: [ConfigService],
|
|
515
|
-
useFactory: (configService: ConfigService) => ({
|
|
516
|
-
secret: configService.getOrThrow('JWT_SECRET'),
|
|
517
|
-
signOptions: { expiresIn: '15m' },
|
|
518
|
-
}),
|
|
519
|
-
}),
|
|
520
|
-
],
|
|
521
|
-
providers: [AuthService, JwtStrategy],
|
|
522
|
-
exports: [JwtModule],
|
|
523
|
-
})
|
|
524
|
-
export class AuthModule {}
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
---
|
|
528
|
-
|
|
529
|
-
### Exception Filters
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
// ✅ Exception filter customizado para erros de negócio
|
|
533
|
-
@Catch(HttpException)
|
|
534
|
-
export class HttpExceptionFilter implements ExceptionFilter {
|
|
535
|
-
private readonly logger = new Logger(HttpExceptionFilter.name)
|
|
536
|
-
|
|
537
|
-
catch(exception: HttpException, host: ArgumentsHost): void {
|
|
538
|
-
const ctx = host.switchToHttp()
|
|
539
|
-
const response = ctx.getResponse<Response>()
|
|
540
|
-
const request = ctx.getRequest<Request>()
|
|
541
|
-
const status = exception.getStatus()
|
|
542
|
-
const exceptionResponse = exception.getResponse()
|
|
543
|
-
|
|
544
|
-
const body = {
|
|
545
|
-
statusCode: status,
|
|
546
|
-
timestamp: new Date().toISOString(),
|
|
547
|
-
path: request.url,
|
|
548
|
-
error: typeof exceptionResponse === 'string'
|
|
549
|
-
? exceptionResponse
|
|
550
|
-
: (exceptionResponse as Record<string, unknown>).message,
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
if (status >= 500) {
|
|
554
|
-
this.logger.error({ exception, path: request.url }, 'Erro interno')
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
response.status(status).json(body)
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
---
|
|
563
|
-
|
|
564
|
-
### Testes
|
|
565
|
-
|
|
566
|
-
> **Obrigatório**: Antes de escrever qualquer teste, verificar se existe schematic ou modelo no projeto (ver Padrão 5).
|
|
567
|
-
> Consultar o guia: (guia de testes do projeto)
|
|
568
|
-
|
|
569
|
-
#### Service — teste unitário
|
|
570
|
-
|
|
571
|
-
```typescript
|
|
572
|
-
import { Test, TestingModule } from '@nestjs/testing'
|
|
573
|
-
import { UserService } from './user.service'
|
|
574
|
-
import { getRepositoryToken } from '@nestjs/typeorm'
|
|
575
|
-
import { UserEntity } from './user.entity'
|
|
576
|
-
|
|
577
|
-
describe('UserService', () => {
|
|
578
|
-
let service: UserService
|
|
579
|
-
|
|
580
|
-
const mockRepository = {
|
|
581
|
-
findOne: jest.fn(),
|
|
582
|
-
save: jest.fn(),
|
|
583
|
-
create: jest.fn(),
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
beforeEach(async () => {
|
|
587
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
588
|
-
providers: [
|
|
589
|
-
UserService,
|
|
590
|
-
{
|
|
591
|
-
provide: getRepositoryToken(UserEntity), // ✅ token correto para TypeORM
|
|
592
|
-
useValue: mockRepository,
|
|
593
|
-
},
|
|
594
|
-
],
|
|
595
|
-
}).compile()
|
|
596
|
-
|
|
597
|
-
service = module.get<UserService>(UserService)
|
|
598
|
-
})
|
|
599
|
-
|
|
600
|
-
afterEach(() => jest.clearAllMocks())
|
|
601
|
-
|
|
602
|
-
it('lança NotFoundException quando usuário não existe', async () => {
|
|
603
|
-
mockRepository.findOne.mockResolvedValue(null)
|
|
604
|
-
await expect(service.findById('id-inexistente')).rejects.toThrow('Usuário não encontrado')
|
|
605
|
-
})
|
|
606
|
-
})
|
|
607
|
-
```
|
|
608
|
-
|
|
609
|
-
#### Controller — teste de integração (Supertest)
|
|
610
|
-
|
|
611
|
-
```typescript
|
|
612
|
-
import { Test, TestingModule } from '@nestjs/testing'
|
|
613
|
-
import { INestApplication, ValidationPipe } from '@nestjs/common'
|
|
614
|
-
import * as request from 'supertest'
|
|
615
|
-
|
|
616
|
-
describe('UserController (integração)', () => {
|
|
617
|
-
let app: INestApplication
|
|
618
|
-
|
|
619
|
-
beforeAll(async () => {
|
|
620
|
-
const module: TestingModule = await Test.createTestingModule({
|
|
621
|
-
imports: [UserModule],
|
|
622
|
-
})
|
|
623
|
-
.overrideProvider(UserService)
|
|
624
|
-
.useValue({ findById: jest.fn().mockResolvedValue({ id: '1', name: 'Test' }) })
|
|
625
|
-
.compile()
|
|
626
|
-
|
|
627
|
-
app = module.createNestApplication()
|
|
628
|
-
app.useGlobalPipes(new ValidationPipe({ whitelist: true }))
|
|
629
|
-
await app.init()
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
afterAll(() => app.close())
|
|
633
|
-
|
|
634
|
-
it('GET /users/:id → 200', async () => {
|
|
635
|
-
const response = await request(app.getHttpServer()).get('/users/1')
|
|
636
|
-
expect(response.status).toBe(200)
|
|
637
|
-
expect(response.body.data.id).toBe('1')
|
|
638
|
-
})
|
|
639
|
-
})
|
|
640
|
-
```
|
|
641
|
-
|
|
642
|
-
---
|
|
643
|
-
|
|
644
|
-
### Logging
|
|
645
|
-
|
|
646
|
-
Consultar o guia de logs do projeto antes de implementar logging:
|
|
647
|
-
`(guia de logs do projeto)`
|
|
648
|
-
|
|
649
|
-
```typescript
|
|
650
|
-
// ✅ Logger padrão NestJS
|
|
651
|
-
import { Logger } from '@nestjs/common'
|
|
652
|
-
|
|
653
|
-
@Injectable()
|
|
654
|
-
export class UserService {
|
|
655
|
-
private readonly logger = new Logger(UserService.name)
|
|
656
|
-
|
|
657
|
-
async findById(id: string) {
|
|
658
|
-
this.logger.log(`Buscando usuário ${id}`)
|
|
659
|
-
// ...
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
---
|
|
665
|
-
|
|
666
|
-
## Problemas Comuns e Soluções
|
|
667
|
-
|
|
668
|
-
### "Nest can't resolve dependencies of [Service] (?, +)"
|
|
669
|
-
1. O `?` indica a posição do parâmetro faltando no construtor
|
|
670
|
-
2. Verificar se o provider está em `providers[]` do módulo
|
|
671
|
-
3. Se usado em outro módulo, verificar `exports[]` do módulo de origem
|
|
672
|
-
4. Erros de digitação em barrel exports (`index.ts`) também causam este erro
|
|
673
|
-
|
|
674
|
-
### "Circular dependency detected"
|
|
675
|
-
**Proibido usar `forwardRef`.** Seguir obrigatoriamente:
|
|
676
|
-
1. Refatorar a estrutura de módulos — rever responsabilidades
|
|
677
|
-
2. Extrair lógica compartilhada para um terceiro módulo
|
|
678
|
-
3. Ajustar escopo do provider como última alternativa
|
|
679
|
-
|
|
680
|
-
### "Unknown authentication strategy 'jwt'"
|
|
681
|
-
1. Importar `Strategy` de `'passport-jwt'`, **não** de `'passport-local'`
|
|
682
|
-
2. Garantir que `JWT_SECRET` no `JwtModule` bate com `secretOrKey` na `JwtStrategy`
|
|
683
|
-
3. Verificar formato do header: `Authorization: Bearer <token>`
|
|
684
|
-
|
|
685
|
-
### "[TypeOrmModule] Unable to connect to the database"
|
|
686
|
-
Frequentemente enganoso — verificar:
|
|
687
|
-
1. Sintaxe das entities (ex: `@Column()` não `@Column('description')`)
|
|
688
|
-
2. Decorators faltando em propriedades das entities
|
|
689
|
-
3. Configuração de host/porta/credenciais
|
|
690
|
-
|
|
691
|
-
### "Nest can't resolve dependencies of the Repository (testing)"
|
|
692
|
-
```typescript
|
|
693
|
-
// ✅ Usar getRepositoryToken para mockar repositórios TypeORM em testes
|
|
694
|
-
{ provide: getRepositoryToken(UserEntity), useValue: mockRepo }
|
|
695
|
-
```
|
|
696
|
-
|
|
697
|
-
### "secretOrPrivateKey must have a value" (JWT)
|
|
698
|
-
1. Definir `JWT_SECRET` nas variáveis de ambiente
|
|
699
|
-
2. Verificar que `ConfigModule` carrega antes do `JwtModule`
|
|
700
|
-
3. Usar `ConfigService` para configuração dinâmica
|
|
701
|
-
|
|
702
|
-
### Guard não está sendo aplicado
|
|
703
|
-
```typescript
|
|
704
|
-
// ✅ Guard global com acesso ao DI — usar APP_GUARD, não useGlobalGuards()
|
|
705
|
-
@Module({
|
|
706
|
-
providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],
|
|
707
|
-
})
|
|
708
|
-
export class AppModule {}
|
|
709
|
-
```
|
|
265
|
+
### Skills invocados durante a execução do skill
|
|
710
266
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
- `TRANSIENT` → nova instância por injeção
|
|
267
|
+
| Passo | Skill | Condição |
|
|
268
|
+
|-------|-------|----------|
|
|
269
|
+
| — | Nenhuma — skill autocontida | — |
|
|
715
270
|
|
|
716
271
|
---
|
|
717
272
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Arquitetura de Módulos (NestJS)
|
|
2
|
+
|
|
3
|
+
> Parte do skill `eng-backend-nestjs`. Leia este arquivo quando a tarefa criar ou reorganizar módulos, providers e injeção de dependência.
|
|
4
|
+
|
|
5
|
+
### Arquitetura de Módulos
|
|
6
|
+
|
|
7
|
+
#### Estrutura de módulo de feature
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ✅ Padrão de módulo de feature
|
|
11
|
+
@Module({
|
|
12
|
+
imports: [
|
|
13
|
+
TypeOrmModule.forFeature([UserEntity]),
|
|
14
|
+
CommonModule,
|
|
15
|
+
],
|
|
16
|
+
controllers: [UserController],
|
|
17
|
+
providers: [UserService, UserRepository],
|
|
18
|
+
exports: [UserService], // exportar apenas o que outros módulos precisam
|
|
19
|
+
})
|
|
20
|
+
export class UserModule {}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
#### Módulo global (para providers transversais)
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// ✅ Módulo global — disponível sem importar
|
|
27
|
+
@Global()
|
|
28
|
+
@Module({
|
|
29
|
+
providers: [LoggerService],
|
|
30
|
+
exports: [LoggerService],
|
|
31
|
+
})
|
|
32
|
+
export class LoggerModule {}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### Módulo dinâmico
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// ✅ Módulo dinâmico para configuração em runtime
|
|
39
|
+
@Module({})
|
|
40
|
+
export class HttpClientModule {
|
|
41
|
+
static forRoot(options: HttpClientOptions): DynamicModule {
|
|
42
|
+
return {
|
|
43
|
+
module: HttpClientModule,
|
|
44
|
+
providers: [
|
|
45
|
+
{ provide: HTTP_CLIENT_OPTIONS, useValue: options },
|
|
46
|
+
HttpClientService,
|
|
47
|
+
],
|
|
48
|
+
exports: [HttpClientService],
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|