jarvis-ai-framework 2.1.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 +10 -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 +19 -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 +6 -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
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Guards e Autenticação (Passport + JWT)
|
|
2
|
+
|
|
3
|
+
> Parte do skill `eng-backend-nestjs`. Leia este arquivo quando a tarefa envolver guards, roles/permissões ou autenticação com Passport e JWT.
|
|
4
|
+
|
|
5
|
+
### Guards
|
|
6
|
+
|
|
7
|
+
Guards determinam se uma requisição deve ser processada. Executam **antes** dos interceptors.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ✅ Guard de autenticação JWT
|
|
11
|
+
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'
|
|
12
|
+
import { JwtService } from '@nestjs/jwt'
|
|
13
|
+
import { Request } from 'express'
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class JwtAuthGuard implements CanActivate {
|
|
17
|
+
constructor(private readonly jwtService: JwtService) {}
|
|
18
|
+
|
|
19
|
+
canActivate(context: ExecutionContext): boolean {
|
|
20
|
+
const request = context.switchToHttp().getRequest<Request>()
|
|
21
|
+
const token = this.extractTokenFromHeader(request)
|
|
22
|
+
|
|
23
|
+
if (!token) throw new UnauthorizedException('Token não fornecido')
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const payload = this.jwtService.verify(token)
|
|
27
|
+
request['user'] = payload
|
|
28
|
+
return true
|
|
29
|
+
} catch {
|
|
30
|
+
throw new UnauthorizedException('Token inválido ou expirado')
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private extractTokenFromHeader(request: Request): string | undefined {
|
|
35
|
+
const [type, token] = request.headers.authorization?.split(' ') ?? []
|
|
36
|
+
return type === 'Bearer' ? token : undefined
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// ✅ Guard de roles (RBAC)
|
|
43
|
+
@Injectable()
|
|
44
|
+
export class RolesGuard implements CanActivate {
|
|
45
|
+
constructor(private readonly reflector: Reflector) {}
|
|
46
|
+
|
|
47
|
+
canActivate(context: ExecutionContext): boolean {
|
|
48
|
+
const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
|
|
49
|
+
context.getHandler(),
|
|
50
|
+
context.getClass(),
|
|
51
|
+
])
|
|
52
|
+
|
|
53
|
+
if (!requiredRoles) return true
|
|
54
|
+
|
|
55
|
+
const { user } = context.switchToHttp().getRequest()
|
|
56
|
+
return requiredRoles.some((role) => user.roles?.includes(role))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// ✅ Decorator combinado (Auth + Roles)
|
|
63
|
+
export const Auth = (...roles: string[]) =>
|
|
64
|
+
applyDecorators(
|
|
65
|
+
UseGuards(JwtAuthGuard, RolesGuard),
|
|
66
|
+
SetMetadata('roles', roles),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
// Uso na rota
|
|
70
|
+
@Auth('admin')
|
|
71
|
+
@Delete(':id')
|
|
72
|
+
async remove(@Param('id') id: string) { ... }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### Autenticação (Passport + JWT)
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// ✅ JWT Strategy
|
|
81
|
+
import { ExtractJwt, Strategy } from 'passport-jwt' // importar de 'passport-jwt', NÃO 'passport-local'
|
|
82
|
+
|
|
83
|
+
@Injectable()
|
|
84
|
+
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
85
|
+
constructor(configService: ConfigService) {
|
|
86
|
+
super({
|
|
87
|
+
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
88
|
+
ignoreExpiration: false,
|
|
89
|
+
secretOrKey: configService.getOrThrow('JWT_SECRET'),
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async validate(payload: { sub: string; email: string }) {
|
|
94
|
+
return { userId: payload.sub, email: payload.email }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// ✅ AuthModule
|
|
101
|
+
@Module({
|
|
102
|
+
imports: [
|
|
103
|
+
PassportModule,
|
|
104
|
+
JwtModule.registerAsync({
|
|
105
|
+
inject: [ConfigService],
|
|
106
|
+
useFactory: (configService: ConfigService) => ({
|
|
107
|
+
secret: configService.getOrThrow('JWT_SECRET'),
|
|
108
|
+
signOptions: { expiresIn: '15m' },
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
],
|
|
112
|
+
providers: [AuthService, JwtStrategy],
|
|
113
|
+
exports: [JwtModule],
|
|
114
|
+
})
|
|
115
|
+
export class AuthModule {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Interceptors, Pipes e Exception Filters
|
|
2
|
+
|
|
3
|
+
> Parte do skill `eng-backend-nestjs`. Leia este arquivo quando a tarefa envolver interceptors, validação com pipes ou tratamento de exceções.
|
|
4
|
+
|
|
5
|
+
### Interceptors
|
|
6
|
+
|
|
7
|
+
Interceptors executam antes E depois do route handler. Ideais para logging, transformação de resposta, caching.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// ✅ Interceptor de logging de requisições
|
|
11
|
+
@Injectable()
|
|
12
|
+
export class LoggingInterceptor implements NestInterceptor {
|
|
13
|
+
private readonly logger = new Logger(LoggingInterceptor.name)
|
|
14
|
+
|
|
15
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
|
16
|
+
const request = context.switchToHttp().getRequest()
|
|
17
|
+
const { method, url } = request
|
|
18
|
+
const start = Date.now()
|
|
19
|
+
|
|
20
|
+
return next.handle().pipe(
|
|
21
|
+
tap(() => {
|
|
22
|
+
const ms = Date.now() - start
|
|
23
|
+
this.logger.log(`${method} ${url} — ${ms}ms`)
|
|
24
|
+
}),
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// ✅ Interceptor de transformação de resposta
|
|
32
|
+
@Injectable()
|
|
33
|
+
export class TransformInterceptor<T> implements NestInterceptor<T, { data: T }> {
|
|
34
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<{ data: T }> {
|
|
35
|
+
return next.handle().pipe(
|
|
36
|
+
map((data) => ({ data }))
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
### Pipes e Validação
|
|
45
|
+
|
|
46
|
+
Pipes validam e transformam dados de entrada **antes** do route handler.
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// ✅ Configuração global de ValidationPipe (no main.ts)
|
|
50
|
+
app.useGlobalPipes(
|
|
51
|
+
new ValidationPipe({
|
|
52
|
+
whitelist: true, // remove campos não declarados no DTO
|
|
53
|
+
forbidNonWhitelisted: true, // lança erro se campos extras existirem
|
|
54
|
+
transform: true, // transforma payload para instância do DTO
|
|
55
|
+
transformOptions: {
|
|
56
|
+
enableImplicitConversion: true,
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// ✅ DTO com class-validator
|
|
64
|
+
export class CreateUserDto {
|
|
65
|
+
@IsString()
|
|
66
|
+
@MinLength(2)
|
|
67
|
+
name: string
|
|
68
|
+
|
|
69
|
+
@IsEmail()
|
|
70
|
+
email: string
|
|
71
|
+
|
|
72
|
+
@IsOptional()
|
|
73
|
+
@IsEnum(['admin', 'editor', 'viewer'])
|
|
74
|
+
role?: string
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### Exception Filters
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// ✅ Exception filter customizado para erros de negócio
|
|
84
|
+
@Catch(HttpException)
|
|
85
|
+
export class HttpExceptionFilter implements ExceptionFilter {
|
|
86
|
+
private readonly logger = new Logger(HttpExceptionFilter.name)
|
|
87
|
+
|
|
88
|
+
catch(exception: HttpException, host: ArgumentsHost): void {
|
|
89
|
+
const ctx = host.switchToHttp()
|
|
90
|
+
const response = ctx.getResponse<Response>()
|
|
91
|
+
const request = ctx.getRequest<Request>()
|
|
92
|
+
const status = exception.getStatus()
|
|
93
|
+
const exceptionResponse = exception.getResponse()
|
|
94
|
+
|
|
95
|
+
const body = {
|
|
96
|
+
statusCode: status,
|
|
97
|
+
timestamp: new Date().toISOString(),
|
|
98
|
+
path: request.url,
|
|
99
|
+
error: typeof exceptionResponse === 'string'
|
|
100
|
+
? exceptionResponse
|
|
101
|
+
: (exceptionResponse as Record<string, unknown>).message,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (status >= 500) {
|
|
105
|
+
this.logger.error({ exception, path: request.url }, 'Erro interno')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
response.status(status).json(body)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# ConfigModule e Logging
|
|
2
|
+
|
|
3
|
+
> Parte do skill `eng-backend-nestjs`. Leia este arquivo quando a tarefa envolver variáveis de ambiente (ConfigModule) ou logging.
|
|
4
|
+
|
|
5
|
+
### ConfigModule
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// ✅ ConfigModule com validação via Joi
|
|
9
|
+
@Module({
|
|
10
|
+
imports: [
|
|
11
|
+
ConfigModule.forRoot({
|
|
12
|
+
isGlobal: true,
|
|
13
|
+
envFilePath: '.env',
|
|
14
|
+
validationSchema: Joi.object({
|
|
15
|
+
NODE_ENV: Joi.string().valid('development', 'production', 'test').default('development'),
|
|
16
|
+
PORT: Joi.number().default(3000),
|
|
17
|
+
DATABASE_URL: Joi.string().required(),
|
|
18
|
+
JWT_SECRET: Joi.string().min(32).required(),
|
|
19
|
+
MESSAGE_BROKER_URL: Joi.string().required(),
|
|
20
|
+
}),
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
})
|
|
24
|
+
export class AppModule {}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
// ✅ Usar ConfigService em vez de process.env diretamente
|
|
29
|
+
@Injectable()
|
|
30
|
+
export class DatabaseService {
|
|
31
|
+
constructor(private readonly configService: ConfigService) {}
|
|
32
|
+
|
|
33
|
+
getUrl(): string {
|
|
34
|
+
return this.configService.getOrThrow<string>('DATABASE_URL')
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### Logging
|
|
42
|
+
|
|
43
|
+
Consultar o guia de logs do projeto antes de implementar logging:
|
|
44
|
+
`(guia de logs do projeto)`
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// ✅ Logger padrão NestJS
|
|
48
|
+
import { Logger } from '@nestjs/common'
|
|
49
|
+
|
|
50
|
+
@Injectable()
|
|
51
|
+
export class UserService {
|
|
52
|
+
private readonly logger = new Logger(UserService.name)
|
|
53
|
+
|
|
54
|
+
async findById(id: string) {
|
|
55
|
+
this.logger.log(`Buscando usuário ${id}`)
|
|
56
|
+
// ...
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Testes (NestJS)
|
|
2
|
+
|
|
3
|
+
> Parte do skill `eng-backend-nestjs`. Leia este arquivo quando a tarefa envolver testes unitários, de integração ou e2e.
|
|
4
|
+
|
|
5
|
+
### Testes
|
|
6
|
+
|
|
7
|
+
> **Obrigatório**: Antes de escrever qualquer teste, verificar se existe schematic ou modelo no projeto (ver Padrão 5).
|
|
8
|
+
> Consultar o guia: (guia de testes do projeto)
|
|
9
|
+
|
|
10
|
+
#### Service — teste unitário
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
import { Test, TestingModule } from '@nestjs/testing'
|
|
14
|
+
import { UserService } from './user.service'
|
|
15
|
+
import { getRepositoryToken } from '@nestjs/typeorm'
|
|
16
|
+
import { UserEntity } from './user.entity'
|
|
17
|
+
|
|
18
|
+
describe('UserService', () => {
|
|
19
|
+
let service: UserService
|
|
20
|
+
|
|
21
|
+
const mockRepository = {
|
|
22
|
+
findOne: jest.fn(),
|
|
23
|
+
save: jest.fn(),
|
|
24
|
+
create: jest.fn(),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
const module: TestingModule = await Test.createTestingModule({
|
|
29
|
+
providers: [
|
|
30
|
+
UserService,
|
|
31
|
+
{
|
|
32
|
+
provide: getRepositoryToken(UserEntity), // ✅ token correto para TypeORM
|
|
33
|
+
useValue: mockRepository,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
}).compile()
|
|
37
|
+
|
|
38
|
+
service = module.get<UserService>(UserService)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
afterEach(() => jest.clearAllMocks())
|
|
42
|
+
|
|
43
|
+
it('lança NotFoundException quando usuário não existe', async () => {
|
|
44
|
+
mockRepository.findOne.mockResolvedValue(null)
|
|
45
|
+
await expect(service.findById('id-inexistente')).rejects.toThrow('Usuário não encontrado')
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
#### Controller — teste de integração (Supertest)
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { Test, TestingModule } from '@nestjs/testing'
|
|
54
|
+
import { INestApplication, ValidationPipe } from '@nestjs/common'
|
|
55
|
+
import * as request from 'supertest'
|
|
56
|
+
|
|
57
|
+
describe('UserController (integração)', () => {
|
|
58
|
+
let app: INestApplication
|
|
59
|
+
|
|
60
|
+
beforeAll(async () => {
|
|
61
|
+
const module: TestingModule = await Test.createTestingModule({
|
|
62
|
+
imports: [UserModule],
|
|
63
|
+
})
|
|
64
|
+
.overrideProvider(UserService)
|
|
65
|
+
.useValue({ findById: jest.fn().mockResolvedValue({ id: '1', name: 'Test' }) })
|
|
66
|
+
.compile()
|
|
67
|
+
|
|
68
|
+
app = module.createNestApplication()
|
|
69
|
+
app.useGlobalPipes(new ValidationPipe({ whitelist: true }))
|
|
70
|
+
await app.init()
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
afterAll(() => app.close())
|
|
74
|
+
|
|
75
|
+
it('GET /users/:id → 200', async () => {
|
|
76
|
+
const response = await request(app.getHttpServer()).get('/users/1')
|
|
77
|
+
expect(response.status).toBe(200)
|
|
78
|
+
expect(response.body.data.id).toBe('1')
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Problemas Comuns e Soluções
|
|
2
|
+
|
|
3
|
+
> Parte do skill `eng-backend-nestjs`. Leia este arquivo quando 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.
|
|
4
|
+
|
|
5
|
+
## Problemas Comuns e Soluções
|
|
6
|
+
|
|
7
|
+
### "Nest can't resolve dependencies of [Service] (?, +)"
|
|
8
|
+
1. O `?` indica a posição do parâmetro faltando no construtor
|
|
9
|
+
2. Verificar se o provider está em `providers[]` do módulo
|
|
10
|
+
3. Se usado em outro módulo, verificar `exports[]` do módulo de origem
|
|
11
|
+
4. Erros de digitação em barrel exports (`index.ts`) também causam este erro
|
|
12
|
+
|
|
13
|
+
### "Circular dependency detected"
|
|
14
|
+
**Proibido usar `forwardRef`.** Seguir obrigatoriamente:
|
|
15
|
+
1. Refatorar a estrutura de módulos — rever responsabilidades
|
|
16
|
+
2. Extrair lógica compartilhada para um terceiro módulo
|
|
17
|
+
3. Ajustar escopo do provider como última alternativa
|
|
18
|
+
|
|
19
|
+
### "Unknown authentication strategy 'jwt'"
|
|
20
|
+
1. Importar `Strategy` de `'passport-jwt'`, **não** de `'passport-local'`
|
|
21
|
+
2. Garantir que `JWT_SECRET` no `JwtModule` bate com `secretOrKey` na `JwtStrategy`
|
|
22
|
+
3. Verificar formato do header: `Authorization: Bearer <token>`
|
|
23
|
+
|
|
24
|
+
### "[TypeOrmModule] Unable to connect to the database"
|
|
25
|
+
Frequentemente enganoso — verificar:
|
|
26
|
+
1. Sintaxe das entities (ex: `@Column()` não `@Column('description')`)
|
|
27
|
+
2. Decorators faltando em propriedades das entities
|
|
28
|
+
3. Configuração de host/porta/credenciais
|
|
29
|
+
|
|
30
|
+
### "Nest can't resolve dependencies of the Repository (testing)"
|
|
31
|
+
```typescript
|
|
32
|
+
// ✅ Usar getRepositoryToken para mockar repositórios TypeORM em testes
|
|
33
|
+
{ provide: getRepositoryToken(UserEntity), useValue: mockRepo }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### "secretOrPrivateKey must have a value" (JWT)
|
|
37
|
+
1. Definir `JWT_SECRET` nas variáveis de ambiente
|
|
38
|
+
2. Verificar que `ConfigModule` carrega antes do `JwtModule`
|
|
39
|
+
3. Usar `ConfigService` para configuração dinâmica
|
|
40
|
+
|
|
41
|
+
### Guard não está sendo aplicado
|
|
42
|
+
```typescript
|
|
43
|
+
// ✅ Guard global com acesso ao DI — usar APP_GUARD, não useGlobalGuards()
|
|
44
|
+
@Module({
|
|
45
|
+
providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }],
|
|
46
|
+
})
|
|
47
|
+
export class AppModule {}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Provider com escopo errado
|
|
51
|
+
- `DEFAULT` (Singleton) → instância única por aplicação
|
|
52
|
+
- `REQUEST` → nova instância por requisição (todos os providers injetados herdam o escopo)
|
|
53
|
+
- `TRANSIENT` → nova instância por injeção
|