jarvis-ai-framework 1.0.0

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.
Files changed (240) hide show
  1. package/AGENTS.md +416 -0
  2. package/LICENSE +21 -0
  3. package/README.md +190 -0
  4. package/agents/AGENTS.md +234 -0
  5. package/agents/README.md +309 -0
  6. package/agents/engineering/data/eng.data-engineer.agent.md +309 -0
  7. package/agents/engineering/eng.agent.md +303 -0
  8. package/agents/engineering/eng.bug-hunter.md +386 -0
  9. package/agents/engineering/eng.cybersecurity.agent.md +503 -0
  10. package/agents/engineering/eng.dev-code-reviewer.md +148 -0
  11. package/agents/engineering/eng.docs-writer.md +152 -0
  12. package/agents/engineering/eng.frontend.agent.md +117 -0
  13. package/agents/engineering/eng.rpa.agent.md +215 -0
  14. package/agents/engineering/eng.tech-analyst.agent.md +102 -0
  15. package/agents/engineering/eng.ux-designer.agent.md +193 -0
  16. package/agents/engineering/qa/eng.qa.cypress-specialist.md +109 -0
  17. package/agents/engineering/qa/eng.qa.quality-champion-task-agent.md +85 -0
  18. package/agents/engineering/qa/eng.qa.quality-strategist.md +111 -0
  19. package/agents/engineering/qa/eng.qa.test-architect.md +400 -0
  20. package/agents/engineering/qa/eng.qa.test-planner.md +477 -0
  21. package/agents/engineering/qa/eng.qa.testing-engineer.md +339 -0
  22. package/agents/product/prod.pm-checker.md +52 -0
  23. package/bin/commands/docs-publish.js +184 -0
  24. package/bin/commands/docs-sync.js +139 -0
  25. package/bin/commands/info.js +87 -0
  26. package/bin/commands/init.js +237 -0
  27. package/bin/commands/install-rtk.js +90 -0
  28. package/bin/commands/list.js +48 -0
  29. package/bin/commands/qa-signoff.js +112 -0
  30. package/bin/commands/whoami.js +43 -0
  31. package/bin/jarvis.js +159 -0
  32. package/bin/lib/auth/session.js +56 -0
  33. package/bin/lib/config/constants.js +123 -0
  34. package/bin/lib/config/ide-config.js +233 -0
  35. package/bin/lib/core/scanner.js +124 -0
  36. package/bin/lib/core/sync-engine.js +551 -0
  37. package/bin/lib/docs/fetch-file.sh +41 -0
  38. package/bin/lib/docs/publish-file.sh +284 -0
  39. package/bin/lib/docs/validate-frontmatter.js +157 -0
  40. package/bin/lib/env-loader.js +198 -0
  41. package/bin/lib/tasks/comment.js +131 -0
  42. package/bin/lib/utils/git-parser.js +145 -0
  43. package/bin/lib/utils/logger.js +104 -0
  44. package/bin/lib/utils/npmrc-parser.js +106 -0
  45. package/bin/lib/utils/paths.js +55 -0
  46. package/bin/lib/utils/ui.js +59 -0
  47. package/bin/lib/vcs/api.js +312 -0
  48. package/bin/lib/vcs/create-issue.js +43 -0
  49. package/bin/lib/vcs/create-merge.js +43 -0
  50. package/bin/lib/vcs/fetch-raw.js +30 -0
  51. package/bin/postinstall.js +41 -0
  52. package/members.md +25 -0
  53. package/package.json +55 -0
  54. package/rules/AGENTS.md +205 -0
  55. package/rules/engineering/data/data-rules.md +200 -0
  56. package/rules/engineering/eng-rules.md +243 -0
  57. package/rules/engineering/eng-security-rules.md +186 -0
  58. package/rules/engineering/eng.breakdown-subtasks-rules.md +585 -0
  59. package/rules/engineering/eng.bump-rules.md +27 -0
  60. package/rules/engineering/eng.docs-scraping-rules.md +64 -0
  61. package/rules/engineering/eng.downstream-flow-rules.md +297 -0
  62. package/rules/engineering/eng.integrations-rules.md +73 -0
  63. package/rules/engineering/eng.plan-rules.md +333 -0
  64. package/rules/engineering/eng.pr-rules.md +359 -0
  65. package/rules/engineering/eng.pre-pr-rules.md +103 -0
  66. package/rules/engineering/eng.start-rules.md +246 -0
  67. package/rules/engineering/eng.tech-spec-rules.md +968 -0
  68. package/rules/engineering/eng.work-rules.md +312 -0
  69. package/rules/engineering/frontend/eng.frontend-rules.md +147 -0
  70. package/rules/engineering/qa/eng.qa.cypress-standards-rules.md +259 -0
  71. package/rules/engineering/qa/eng.qa.exploratory-session-rules.md +137 -0
  72. package/rules/engineering/qa/eng.qa.quality-gate-scoring-rules.md +181 -0
  73. package/rules/engineering/qa/eng.qa.tech-spec-validation-criteria-rules.md +120 -0
  74. package/rules/engineering/rpa/eng.rpa-rules.md +230 -0
  75. package/rules/product/README.md +24 -0
  76. package/rules/product/prod-rules.md +151 -0
  77. package/rules/rtk-rules.md +68 -0
  78. package/skills/AGENTS.md +290 -0
  79. package/skills/SKILLS-ROADMAP.md +333 -0
  80. package/skills/churn-audit/SKILL.md +385 -0
  81. package/skills/context-detect/SKILL.md +399 -0
  82. package/skills/context-detect/assets/context-profile-template.md +127 -0
  83. package/skills/docs-central/README.md +310 -0
  84. package/skills/docs-central/SKILL.md +423 -0
  85. package/skills/docs-index/SKILL.md +377 -0
  86. package/skills/eng-ai-engineer/SKILL.md +296 -0
  87. package/skills/eng-arch-c4/SKILL.md +358 -0
  88. package/skills/eng-arch-c4/assets/example-code.md +189 -0
  89. package/skills/eng-arch-c4/assets/example-component.md +105 -0
  90. package/skills/eng-arch-c4/assets/example-container.md +104 -0
  91. package/skills/eng-arch-c4/assets/example-context.md +81 -0
  92. package/skills/eng-backend/SKILL.md +776 -0
  93. package/skills/eng-browser-extension-builder/SKILL.md +385 -0
  94. package/skills/eng-cybersecurity/SKILL.md +645 -0
  95. package/skills/eng-data-bi/SKILL.md +199 -0
  96. package/skills/eng-data-debug/SKILL.md +307 -0
  97. package/skills/eng-data-engineer/SKILL.md +256 -0
  98. package/skills/eng-data-onboard/SKILL.md +310 -0
  99. package/skills/eng-data-orchestrator/SKILL.md +426 -0
  100. package/skills/eng-design-system/SKILL.md +619 -0
  101. package/skills/eng-docs-write/SKILL.md +312 -0
  102. package/skills/eng-frontend/SKILL.md +913 -0
  103. package/skills/eng-jira-comment/SKILL.md +17 -0
  104. package/skills/eng-microfrontend/SKILL.md +602 -0
  105. package/skills/eng-ms-trace/SKILL.md +469 -0
  106. package/skills/eng-nestjs/SKILL.md +791 -0
  107. package/skills/eng-performance-engineer/SKILL.md +312 -0
  108. package/skills/eng-pr/SKILL.md +339 -0
  109. package/skills/eng-qa-a11y-audit/SKILL.md +269 -0
  110. package/skills/eng-qa-bug-report/SKILL.md +1088 -0
  111. package/skills/eng-qa-bug-report/TASK_MANAGERS.md +138 -0
  112. package/skills/eng-qa-cypress-e2e/SKILL.md +177 -0
  113. package/skills/eng-qa-dev-guide/SKILL.md +164 -0
  114. package/skills/eng-qa-e2e/SKILL.md +400 -0
  115. package/skills/eng-qa-e2e-spec-writer/SKILL.md +322 -0
  116. package/skills/eng-qa-exploratory/SKILL.md +188 -0
  117. package/skills/eng-qa-gate/SKILL.md +370 -0
  118. package/skills/eng-qa-gate/assets/checklist-validacao.md +291 -0
  119. package/skills/eng-qa-graphql-contract/SKILL.md +256 -0
  120. package/skills/eng-qa-quality-report/SKILL.md +412 -0
  121. package/skills/eng-qa-test-plan/SKILL.md +466 -0
  122. package/skills/eng-qa-test-plan/assets/test-coverage-template.md +92 -0
  123. package/skills/eng-qa-test-plan/assets/test-patterns.md +178 -0
  124. package/skills/eng-qa-testsprite/SKILL.md +325 -0
  125. package/skills/eng-qa-testsprite/references/testsprite-mcp.md +224 -0
  126. package/skills/eng-qa-unit-test/SKILL.md +471 -0
  127. package/skills/eng-rabbitmq/SKILL.md +661 -0
  128. package/skills/eng-scraper/SKILL.md +683 -0
  129. package/skills/eng-scraper-robot-builder/SKILL.md +370 -0
  130. package/skills/eng-security-patch/SKILL.md +378 -0
  131. package/skills/eng-security-triage/SKILL.md +266 -0
  132. package/skills/eng-task-comment/SKILL.md +60 -0
  133. package/skills/eng-tech-analyst/SKILL.md +529 -0
  134. package/skills/eng-threat-model/SKILL.md +161 -0
  135. package/skills/init-jarvis/SKILL.md +1304 -0
  136. package/skills/init-jarvis/assets/mcp-configs.md +389 -0
  137. package/skills/init-jarvis/assets/onboarding-checklist.md +104 -0
  138. package/skills/init-jarvis/assets/setup-guide.md +360 -0
  139. package/skills/lovable-prompt-generator/SKILL.md +304 -0
  140. package/skills/prod-roadmap-report/README.md +303 -0
  141. package/skills/prod-roadmap-report/SKILL.md +198 -0
  142. package/skills/prod-roadmap-report/commands/status.compiled.single.team.md +23 -0
  143. package/skills/prod-roadmap-report/commands/status.list.projects.md +17 -0
  144. package/skills/prod-roadmap-report/commands/status.memory.md +192 -0
  145. package/skills/prod-roadmap-report/commands/status.roadmap.preview.md +94 -0
  146. package/skills/prod-roadmap-report/references/detailed-guide.md +236 -0
  147. package/skills/prod-roadmap-report/rules/detailed-guide.md +237 -0
  148. package/skills/prod-roadmap-report/rules/status-report-rules.md +44 -0
  149. package/skills/prod-roadmap-report/templates/template-multiple-teams-compiled-status.md +53 -0
  150. package/skills/prod-roadmap-report/templates/template-projects-list.md +23 -0
  151. package/skills/prod-roadmap-report/templates/template-single-team-compiled-status.md +60 -0
  152. package/skills/prod-roadmap-report/templates/template-single-team-status.md +49 -0
  153. package/skills/prod-specs/SKILL.md +108 -0
  154. package/skills/prod-specs/references/prod.spec.clarify.md +176 -0
  155. package/skills/prod-specs/references/prod.spec.epic.md +107 -0
  156. package/skills/prod-specs/references/prod.spec.frd.md +135 -0
  157. package/skills/prod-specs/references/prod.spec.issue.md +145 -0
  158. package/skills/prod-specs/references/prod.spec.prd.md +118 -0
  159. package/skills/prod-specs/rules/prod-spec-rules.md +186 -0
  160. package/skills/prod-specs/templates/prod-breakdown-template.md +136 -0
  161. package/skills/prod-specs/templates/prod-epic-template.md +76 -0
  162. package/skills/prod-specs/templates/prod-frd-template.md +172 -0
  163. package/skills/prod-specs/templates/prod-issue-template.md +68 -0
  164. package/skills/prod-specs/templates/prod-prd-full-template.md +159 -0
  165. package/skills/prod-specs/templates/prod-prd-template.md +173 -0
  166. package/skills/prod-specs-update/SKILL.md +272 -0
  167. package/skills/report-issue/SKILL.md +156 -0
  168. package/taxonomy.md +270 -0
  169. package/templates/AGENTS.md +189 -0
  170. package/templates/CDD aplicado a Prompts.md +182 -0
  171. package/templates/ENV-template.md +187 -0
  172. package/templates/engineering/AGENTS-template.md +71 -0
  173. package/templates/engineering/ARD-template.md +193 -0
  174. package/templates/engineering/CONTACTS-template.md +135 -0
  175. package/templates/engineering/PR-template.md +40 -0
  176. package/templates/engineering/RFC-Playbook.md +325 -0
  177. package/templates/engineering/RFC-template.md +199 -0
  178. package/templates/engineering/architecture-template.md +277 -0
  179. package/templates/engineering/breakdown-subtasks-template.md +582 -0
  180. package/templates/engineering/c4-model-template.md +516 -0
  181. package/templates/engineering/data-contract-template.md +135 -0
  182. package/templates/engineering/data-pipeline-template.md +163 -0
  183. package/templates/engineering/plan-template.md +255 -0
  184. package/templates/engineering/qa/eng.qa.quality-gate-examples-template.md +311 -0
  185. package/templates/engineering/qa/eng.qa.quality-gate-report-template.md +249 -0
  186. package/templates/engineering/qa/qa.cypress-test-template.md +172 -0
  187. package/templates/engineering/qa/qa.exploratory-session-template.md +148 -0
  188. package/templates/engineering/qa/qa.quality-report-template.md +130 -0
  189. package/templates/engineering/qa/qa.release-signoff-template.md +54 -0
  190. package/templates/engineering/qa/qa.sprint-plan-template.md +49 -0
  191. package/templates/engineering/swagger-template.md +145 -0
  192. package/templates/engineering/tech-spec-template.md +497 -0
  193. package/templates/engineering/work-progress-template.md +155 -0
  194. package/workflows/AGENTS.md +240 -0
  195. package/workflows/README.md +160 -0
  196. package/workflows/all-tools.md +11 -0
  197. package/workflows/engineering/data/data.contract.md +202 -0
  198. package/workflows/engineering/data/data.new-pipeline.md +234 -0
  199. package/workflows/engineering/eng.breakdown-subtasks.md +420 -0
  200. package/workflows/engineering/eng.bug-audit.md +591 -0
  201. package/workflows/engineering/eng.build-tech-spec.md +1116 -0
  202. package/workflows/engineering/eng.create-ard-from-code.md +259 -0
  203. package/workflows/engineering/eng.create-ard.md +382 -0
  204. package/workflows/engineering/eng.create-rfc.md +245 -0
  205. package/workflows/engineering/eng.debug.md +479 -0
  206. package/workflows/engineering/eng.docs.md +40 -0
  207. package/workflows/engineering/eng.light-arch.md +84 -0
  208. package/workflows/engineering/eng.plan.md +213 -0
  209. package/workflows/engineering/eng.pr.md +466 -0
  210. package/workflows/engineering/eng.pre-pr.md +167 -0
  211. package/workflows/engineering/eng.review.md +185 -0
  212. package/workflows/engineering/eng.rpa.robot.md +342 -0
  213. package/workflows/engineering/eng.security-audit.md +312 -0
  214. package/workflows/engineering/eng.security-incident.md +275 -0
  215. package/workflows/engineering/eng.security-pipeline.md +210 -0
  216. package/workflows/engineering/eng.security-review.md +235 -0
  217. package/workflows/engineering/eng.start.md +494 -0
  218. package/workflows/engineering/eng.work.md +558 -0
  219. package/workflows/engineering/frontend/eng.frontend-component.md +190 -0
  220. package/workflows/engineering/frontend/eng.frontend-perf-audit.md +375 -0
  221. package/workflows/engineering/frontend/eng.frontend-review.md +185 -0
  222. package/workflows/engineering/qa/eng.qa-dev-quality-guide.md +51 -0
  223. package/workflows/engineering/qa/eng.qa-e2e-test-generation.md +51 -0
  224. package/workflows/engineering/qa/eng.qa-exploratory-session.md +60 -0
  225. package/workflows/engineering/qa/eng.qa-quality-gate-validation.md +202 -0
  226. package/workflows/engineering/qa/eng.qa-quality-report.md +83 -0
  227. package/workflows/engineering/qa/eng.qa-refinement-entry.md +83 -0
  228. package/workflows/engineering/qa/eng.qa-release-signoff.md +170 -0
  229. package/workflows/engineering/qa/eng.qa-sprint-planning.md +100 -0
  230. package/workflows/engineering/ta/eng.ta.atendimento.md +93 -0
  231. package/workflows/product/prod.roadmap.preview.md +110 -0
  232. package/workflows/product/prod.spec.breakdown.md +163 -0
  233. package/workflows/product/prod.spec.clarify.md +178 -0
  234. package/workflows/product/prod.spec.epic.md +154 -0
  235. package/workflows/product/prod.spec.frd.md +96 -0
  236. package/workflows/product/prod.spec.issue.md +145 -0
  237. package/workflows/product/prod.spec.md +60 -0
  238. package/workflows/product/prod.spec.prd.md +100 -0
  239. package/workflows/taxonomy.md +92 -0
  240. package/workflows/warm-up.md +574 -0
@@ -0,0 +1,776 @@
1
+ ---
2
+ name: eng-backend
3
+ description: >
4
+ Especialista em desenvolvimento backend: APIs REST/GraphQL, autenticação, workers, jobs,
5
+ integrações externas, caching e boas práticas de produção com NestJS e RabbitMQ.
6
+ Trigger: Use para APIs, auth, lógica de negócio, workers, jobs, integrações, caching ou backend em geral.
7
+ license: AGPL-3.0
8
+ compatibility: Designed for Claude Code (or similar products)
9
+ allowed-tools: Read Write Edit Glob Grep Bash
10
+ metadata:
11
+ author: jarvis-team
12
+ version: "1.0"
13
+ # Campos Claude Code-specific (não fazem parte da spec oficial agentskills.io):
14
+ argument-hint: "[endpoint|auth|worker|integração|refactor|debug] [contexto]"
15
+ disable-model-invocation: false
16
+ ---
17
+
18
+ # Eng Backend - Especialista em Desenvolvimento de Servidor
19
+
20
+ Você é um **especialista em desenvolvimento backend moderno** com domínio em APIs, autenticação/autorização, arquiteturas de serviços, workers assíncronos e integrações externas prontas para produção.
21
+
22
+ ## Objetivo
23
+
24
+ Construir backends confiáveis, seguros e escaláveis — desde endpoints simples até arquiteturas de serviços complexas com workers, filas e integrações de terceiros.
25
+
26
+ ## Entrada
27
+
28
+ - `$ARGUMENTS` - Operação, feature ou problema a resolver (ex: `criar-endpoint-produtos`, `implementar-jwt-refresh`, `worker-envio-email`, `integrar-stripe`, `otimizar-query-lenta`)
29
+
30
+ ## Recursos
31
+
32
+ - **ENV**: `$IDE/ENV.md` (variáveis de ambiente, incluindo MESSAGE_BROKER_URL e credenciais RabbitMQ)
33
+ - **Saída**: código no repositório atual (controllers, services, workers, testes)
34
+
35
+ ---
36
+
37
+ ## Pré-requisito
38
+
39
+ Verificar se o `ENV.md` existe e se as variáveis necessárias estão configuradas:
40
+
41
+ ```bash
42
+ # Verificar existência do ENV.md
43
+ cat $IDE/ENV.md
44
+
45
+ # Verificar credenciais do message broker (obrigatório para workers RabbitMQ)
46
+ grep "MESSAGE_BROKER" $IDE/ENV.md
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Quando Usar
52
+
53
+ Use este skill quando:
54
+ - Criar ou refatorar endpoints REST ou GraphQL
55
+ - Implementar autenticação (JWT, OAuth2, sessions) ou autorização (RBAC)
56
+ - Criar workers, jobs em background ou processamento assíncrono (RabbitMQ, cron)
57
+ - Integrar com APIs externas (webhooks, third-party, retry logic)
58
+ - Implementar caching (Redis, in-memory, invalidação)
59
+ - Aplicar boas práticas de API design (paginação, versionamento, idempotência)
60
+ - Escrever testes de backend (unitários, integração, mocks)
61
+
62
+ **NÃO usar quando:**
63
+ - A tarefa é exclusivamente de frontend, banco de dados ou infraestrutura
64
+ - Não há lógica de servidor, API ou processamento assíncrono envolvido
65
+
66
+ ---
67
+
68
+ ## Validação de Entrada
69
+
70
+ Se $ARGUMENTS está vazio, o skill funciona em modo interativo: solicitar ao usuário o contexto da tarefa backend antes de prosseguir.
71
+
72
+ ---
73
+
74
+ ## Padrões Críticos
75
+
76
+ ### Padrão 1: Ler o Projeto Antes de Escrever
77
+
78
+ ```bash
79
+ # Verificar framework e dependências
80
+ cat package.json | grep -E '"nest|amqplib|@golevelup/nestjs-rabbitmq|redis|prisma|typeorm|drizzle|jest|vitest"'
81
+
82
+ # Verificar estrutura de rotas/controllers
83
+ ls src/ 2>/dev/null
84
+
85
+ # Verificar como auth está implementada
86
+ grep -r "JwtModule\|passport\|jwt.sign\|jwt.verify" src/ --include="*.ts" -l
87
+ ```
88
+
89
+ ### Padrão 2: Segurança por Padrão
90
+
91
+ Toda API precisa considerar:
92
+
93
+ ```
94
+ 1. Validação de entrada → nunca confiar em dados externos
95
+ 2. Autenticação → verificar identidade antes de processar
96
+ 3. Autorização → verificar permissão após autenticação
97
+ 4. Rate limiting → proteger contra abuso
98
+ 5. Sanitização → prevenir injeção (SQL, NoSQL, command)
99
+ 6. Não expor detalhes de erro internos em produção
100
+ ```
101
+
102
+ ### Padrão 3: Tratamento de Erros Consistente
103
+
104
+ ```typescript
105
+ // ✅ Erro tipado com contexto
106
+ export class AppError extends Error {
107
+ constructor(
108
+ public readonly message: string,
109
+ public readonly statusCode: number = 500,
110
+ public readonly code: string = 'INTERNAL_ERROR'
111
+ ) {
112
+ super(message)
113
+ this.name = 'AppError'
114
+ }
115
+ }
116
+
117
+ // ✅ Erros de negócio explícitos
118
+ export class NotFoundError extends AppError {
119
+ constructor(resource: string, id: string) {
120
+ super(`${resource} com id '${id}' não encontrado`, 404, 'NOT_FOUND')
121
+ }
122
+ }
123
+
124
+ export class UnauthorizedError extends AppError {
125
+ constructor(message = 'Não autorizado') {
126
+ super(message, 401, 'UNAUTHORIZED')
127
+ }
128
+ }
129
+ ```
130
+
131
+ ### Padrão 4: Idempotência em Operações Críticas
132
+
133
+ ```typescript
134
+ // ✅ Idempotency key para mutations críticas (pagamentos, envios)
135
+ async function processPayment(idempotencyKey: string, data: PaymentData) {
136
+ const existing = await redis.get(`payment:idempotency:${idempotencyKey}`)
137
+ if (existing) return JSON.parse(existing)
138
+
139
+ const result = await stripe.charge(data)
140
+ await redis.set(`payment:idempotency:${idempotencyKey}`, JSON.stringify(result), 'EX', 86400)
141
+ return result
142
+ }
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Árvore de Decisão
148
+
149
+ ```
150
+ Criar/modificar endpoint? → Seção: API Design
151
+ Implementar autenticação? → Seção: Autenticação e Autorização
152
+ Criar worker ou job? → Seção: Workers e Jobs Assíncronos
153
+ Integrar API externa? → Seção: Integrações Externas
154
+ Implementar caching? → Seção: Caching
155
+ Escrever testes? → Seção: Testes
156
+ Debug de problema? → Seção: Debugging e Observabilidade
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Fluxo de Trabalho
162
+
163
+ ### API Design
164
+
165
+ #### REST — boas práticas
166
+
167
+ ```typescript
168
+ // ✅ Estrutura de rotas REST
169
+ GET /products → listar produtos (com paginação)
170
+ GET /products/:id → buscar produto por ID
171
+ POST /products → criar produto
172
+ PUT /products/:id → atualizar produto completo
173
+ PATCH /products/:id → atualizar produto parcialmente
174
+ DELETE /products/:id → remover produto
175
+
176
+ // ✅ Resposta padronizada
177
+ interface ApiResponse<T> {
178
+ data: T
179
+ meta?: {
180
+ page: number
181
+ pageSize: number
182
+ total: number
183
+ totalPages: number
184
+ }
185
+ }
186
+
187
+ // ✅ Erros padronizados
188
+ interface ApiError {
189
+ error: {
190
+ code: string // ex: "PRODUCT_NOT_FOUND"
191
+ message: string // mensagem legível
192
+ details?: unknown // erros de validação, etc.
193
+ }
194
+ }
195
+ ```
196
+
197
+ #### Paginação
198
+
199
+ ```typescript
200
+ // ✅ Cursor-based (recomendado para grandes volumes)
201
+ interface CursorPaginationParams {
202
+ cursor?: string // ID do último item retornado
203
+ limit?: number // default: 20, max: 100
204
+ }
205
+
206
+ // ✅ Offset-based (simples, para volumes menores)
207
+ interface OffsetPaginationParams {
208
+ page?: number // default: 1
209
+ pageSize?: number // default: 20, max: 100
210
+ }
211
+
212
+ // Implementação com Prisma
213
+ async function listProducts({ page = 1, pageSize = 20 }: OffsetPaginationParams) {
214
+ const [items, total] = await Promise.all([
215
+ prisma.product.findMany({
216
+ skip: (page - 1) * pageSize,
217
+ take: pageSize,
218
+ orderBy: { createdAt: 'desc' },
219
+ }),
220
+ prisma.product.count(),
221
+ ])
222
+
223
+ return {
224
+ data: items,
225
+ meta: { page, pageSize, total, totalPages: Math.ceil(total / pageSize) },
226
+ }
227
+ }
228
+ ```
229
+
230
+ #### Versionamento de API
231
+
232
+ ```typescript
233
+ // ✅ Versionamento por URL (mais explícito)
234
+ app.register(v1Routes, { prefix: '/api/v1' })
235
+ app.register(v2Routes, { prefix: '/api/v2' })
236
+
237
+ // ✅ Versionamento por header (para APIs internas)
238
+ // Accept: application/vnd.api+json;version=2
239
+ ```
240
+
241
+ ### Autenticação e Autorização
242
+
243
+ #### JWT com refresh token
244
+
245
+ ```typescript
246
+ // ✅ Par de tokens: access (curto) + refresh (longo)
247
+ const ACCESS_TOKEN_EXPIRY = '15m'
248
+ const REFRESH_TOKEN_EXPIRY = '7d'
249
+
250
+ async function generateTokens(userId: string) {
251
+ const accessToken = jwt.sign({ sub: userId, type: 'access' }, JWT_SECRET, {
252
+ expiresIn: ACCESS_TOKEN_EXPIRY,
253
+ })
254
+
255
+ const refreshToken = jwt.sign({ sub: userId, type: 'refresh' }, JWT_REFRESH_SECRET, {
256
+ expiresIn: REFRESH_TOKEN_EXPIRY,
257
+ })
258
+
259
+ // Armazenar refresh token no banco (para revogação)
260
+ await db.refreshToken.create({
261
+ data: { token: hashToken(refreshToken), userId, expiresAt: addDays(new Date(), 7) },
262
+ })
263
+
264
+ return { accessToken, refreshToken }
265
+ }
266
+
267
+ // ✅ Rota de refresh
268
+ async function refreshAccessToken(refreshToken: string) {
269
+ const payload = jwt.verify(refreshToken, JWT_REFRESH_SECRET)
270
+ const stored = await db.refreshToken.findUnique({ where: { token: hashToken(refreshToken) } })
271
+
272
+ if (!stored || stored.revokedAt || stored.expiresAt < new Date()) {
273
+ throw new UnauthorizedError('Refresh token inválido ou expirado')
274
+ }
275
+
276
+ return generateTokens(payload.sub)
277
+ }
278
+ ```
279
+
280
+ #### RBAC — Role-Based Access Control
281
+
282
+ ```typescript
283
+ // ✅ Definição de roles e permissões
284
+ const permissions = {
285
+ admin: ['products:read', 'products:write', 'products:delete', 'users:manage'],
286
+ editor: ['products:read', 'products:write'],
287
+ viewer: ['products:read'],
288
+ } as const
289
+
290
+ type Permission = (typeof permissions)[keyof typeof permissions][number]
291
+
292
+ // ✅ Middleware de autorização
293
+ function requirePermission(permission: Permission) {
294
+ return async (req: Request, res: Response, next: NextFunction) => {
295
+ const userPermissions = permissions[req.user.role] ?? []
296
+ if (!userPermissions.includes(permission)) {
297
+ throw new ForbiddenError(`Permissão '${permission}' necessária`)
298
+ }
299
+ next()
300
+ }
301
+ }
302
+
303
+ // Uso na rota
304
+ router.delete('/products/:id', authenticate, requirePermission('products:delete'), deleteProduct)
305
+ ```
306
+
307
+ #### OAuth2 — fluxo básico
308
+
309
+ ```typescript
310
+ // ✅ Authorization Code Flow (para apps com frontend)
311
+ // 1. Redirecionar para provider → GET /oauth/authorize?provider=github
312
+ // 2. Receber callback com code → GET /oauth/callback?code=xxx
313
+ // 3. Trocar code por token → POST ao provider
314
+ // 4. Buscar perfil do usuário → GET /user no provider
315
+ // 5. Criar/atualizar usuário local → gerar tokens da aplicação
316
+
317
+ async function handleOAuthCallback(provider: string, code: string) {
318
+ const { access_token } = await exchangeCodeForToken(provider, code)
319
+ const profile = await fetchUserProfile(provider, access_token)
320
+
321
+ const user = await upsertUser({
322
+ email: profile.email,
323
+ name: profile.name,
324
+ oauthProvider: provider,
325
+ oauthId: profile.id,
326
+ })
327
+
328
+ return generateTokens(user.id)
329
+ }
330
+ ```
331
+
332
+ ### Workers e Jobs Assíncronos
333
+
334
+ #### RabbitMQ com NestJS — padrão do projeto
335
+
336
+ O projeto usa RabbitMQ como broker de mensagens. Verificar variáveis no ENV.md:
337
+
338
+ ```bash
339
+ grep "MESSAGE_BROKER\|RABBITMQ" $IDE/ENV.md
340
+ ```
341
+
342
+ **Variáveis esperadas:** `MESSAGE_BROKER_URL`, `MESSAGE_BROKER_USER`, `MESSAGE_BROKER_PASS` (ou equivalentes — checar ENV.md).
343
+
344
+ ##### Publicar mensagem (Producer)
345
+
346
+ ```typescript
347
+ // ✅ NestJS com @golevelup/nestjs-rabbitmq
348
+ import { AmqpConnection } from '@golevelup/nestjs-rabbitmq'
349
+ import { Injectable } from '@nestjs/common'
350
+
351
+ @Injectable()
352
+ export class EmailProducerService {
353
+ constructor(private readonly amqpConnection: AmqpConnection) {}
354
+
355
+ async sendWelcomeEmail(to: string, name: string): Promise<void> {
356
+ await this.amqpConnection.publish(
357
+ 'email.exchange', // exchange
358
+ 'email.welcome', // routing key
359
+ { to, name }, // payload (serializado como JSON)
360
+ )
361
+ }
362
+ }
363
+ ```
364
+
365
+ ##### Consumir mensagem (Consumer / Worker)
366
+
367
+ ```typescript
368
+ // ✅ Consumer com @golevelup/nestjs-rabbitmq
369
+ import { RabbitSubscribe, Nack } from '@golevelup/nestjs-rabbitmq'
370
+ import { Injectable, Logger } from '@nestjs/common'
371
+
372
+ @Injectable()
373
+ export class EmailConsumerService {
374
+ private readonly logger = new Logger(EmailConsumerService.name)
375
+
376
+ @RabbitSubscribe({
377
+ exchange: 'email.exchange',
378
+ routingKey: 'email.welcome',
379
+ queue: 'email.welcome.queue',
380
+ queueOptions: {
381
+ durable: true,
382
+ deadLetterExchange: 'email.exchange.dlx',
383
+ },
384
+ })
385
+ async handleWelcomeEmail(payload: { to: string; name: string }): Promise<void | Nack> {
386
+ try {
387
+ await sendEmail({ to: payload.to, template: 'welcome', data: { name: payload.name } })
388
+ } catch (error) {
389
+ this.logger.error({ error, payload }, 'Falha ao processar email de boas-vindas')
390
+ return new Nack(false) // rejeitar sem requeue → vai para DLX
391
+ }
392
+ }
393
+ }
394
+ ```
395
+
396
+ ##### Configuração do módulo
397
+
398
+ ```typescript
399
+ // ✅ RabbitMQModule no AppModule
400
+ import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq'
401
+
402
+ RabbitMQModule.forRootAsync({
403
+ useFactory: (configService: ConfigService) => ({
404
+ uri: configService.getOrThrow('MESSAGE_BROKER_URL'),
405
+ exchanges: [
406
+ { name: 'email.exchange', type: 'direct', options: { durable: true } },
407
+ { name: 'email.exchange.dlx', type: 'direct', options: { durable: true } },
408
+ ],
409
+ connectionInitOptions: { wait: true },
410
+ }),
411
+ inject: [ConfigService],
412
+ })
413
+ ```
414
+
415
+ #### Cron jobs com NestJS
416
+
417
+ ```typescript
418
+ // ✅ @nestjs/schedule — decorator nativo
419
+ import { Injectable, Logger } from '@nestjs/common'
420
+ import { Cron, CronExpression } from '@nestjs/schedule'
421
+
422
+ @Injectable()
423
+ export class ReportSchedulerService {
424
+ private readonly logger = new Logger(ReportSchedulerService.name)
425
+
426
+ // Rodar às 9h todo dia útil (horário de São Paulo)
427
+ @Cron('0 9 * * 1-5', { timeZone: 'America/Sao_Paulo' })
428
+ async handleDailyReport(): Promise<void> {
429
+ this.logger.log('Iniciando relatório diário')
430
+ try {
431
+ await this.reportService.generateDaily()
432
+ } catch (error) {
433
+ this.logger.error({ error }, 'Falha ao gerar relatório diário')
434
+ }
435
+ }
436
+ }
437
+ ```
438
+
439
+ ### Integrações Externas
440
+
441
+ #### Padrão de integração robusta
442
+
443
+ ```typescript
444
+ // ✅ Cliente HTTP com retry e timeout
445
+ import axios, { AxiosInstance } from 'axios'
446
+ import axiosRetry from 'axios-retry'
447
+
448
+ function createHttpClient(baseURL: string): AxiosInstance {
449
+ const client = axios.create({
450
+ baseURL,
451
+ timeout: 10_000, // 10 segundos
452
+ headers: { 'Content-Type': 'application/json' },
453
+ })
454
+
455
+ // Retry automático para erros de rede e 5xx
456
+ axiosRetry(client, {
457
+ retries: 3,
458
+ retryDelay: axiosRetry.exponentialDelay,
459
+ retryCondition: (error) =>
460
+ axiosRetry.isNetworkError(error) ||
461
+ axiosRetry.isRetryableError(error),
462
+ })
463
+
464
+ return client
465
+ }
466
+ ```
467
+
468
+ #### Webhooks — receber e processar
469
+
470
+ ```typescript
471
+ // ✅ Verificação de assinatura (ex: Stripe)
472
+ function verifyWebhookSignature(payload: Buffer, signature: string, secret: string): boolean {
473
+ const expected = crypto
474
+ .createHmac('sha256', secret)
475
+ .update(payload)
476
+ .digest('hex')
477
+
478
+ // Comparação segura contra timing attacks
479
+ return crypto.timingSafeEqual(
480
+ Buffer.from(signature),
481
+ Buffer.from(expected)
482
+ )
483
+ }
484
+
485
+ // ✅ Controller NestJS para webhook com processamento assíncrono
486
+ @Controller('webhooks')
487
+ export class WebhookController {
488
+ constructor(private readonly stripeProducer: StripeEventProducerService) {}
489
+
490
+ @Post('stripe')
491
+ @HttpCode(200)
492
+ async handleStripe(
493
+ @Headers('stripe-signature') signature: string,
494
+ @Req() req: RawBodyRequest<Request>,
495
+ ) {
496
+ if (!verifyWebhookSignature(req.rawBody!, signature, process.env.STRIPE_WEBHOOK_SECRET!)) {
497
+ throw new BadRequestException('Assinatura inválida')
498
+ }
499
+
500
+ const event = JSON.parse(req.rawBody!.toString())
501
+
502
+ // Enfileirar no RabbitMQ — processar de forma assíncrona
503
+ await this.stripeProducer.publish('stripe.events', event.type, event)
504
+
505
+ return { received: true }
506
+ }
507
+ }
508
+ ```
509
+
510
+ ### Caching
511
+
512
+ #### Estratégias de cache com Redis
513
+
514
+ ```typescript
515
+ // ✅ Cache-aside (padrão mais comum)
516
+ async function getProduct(id: string): Promise<Product> {
517
+ const cacheKey = `product:${id}`
518
+
519
+ // 1. Verificar cache
520
+ const cached = await redis.get(cacheKey)
521
+ if (cached) return JSON.parse(cached)
522
+
523
+ // 2. Buscar no banco
524
+ const product = await db.product.findUniqueOrThrow({ where: { id } })
525
+
526
+ // 3. Armazenar no cache
527
+ await redis.set(cacheKey, JSON.stringify(product), 'EX', 300) // TTL: 5 minutos
528
+
529
+ return product
530
+ }
531
+
532
+ // ✅ Invalidar cache ao atualizar
533
+ async function updateProduct(id: string, data: UpdateProductDto): Promise<Product> {
534
+ const product = await db.product.update({ where: { id }, data })
535
+
536
+ // Invalidar cache deste produto e listas relacionadas
537
+ await redis.del(`product:${id}`)
538
+ await redis.del('products:list:*') // ou usar tags
539
+
540
+ return product
541
+ }
542
+ ```
543
+
544
+ #### Quando usar cada estratégia
545
+
546
+ | Estratégia | Quando usar |
547
+ |-----------|-------------|
548
+ | Cache-aside (lazy) | Dados lidos frequentemente, escritas ocasionais |
549
+ | Write-through | Dados críticos onde consistência é prioridade |
550
+ | Write-behind | Alta frequência de escrita, consistência eventual ok |
551
+ | TTL curto (< 1min) | Dados mutáveis com tolerância a leve stale |
552
+ | TTL longo (> 1h) | Dados estáticos ou de referência |
553
+ | Cache de sessão | User session, tokens temporários |
554
+
555
+ ### Testes
556
+
557
+ #### Testes unitários
558
+
559
+ ```typescript
560
+ import { describe, it, expect, vi, beforeEach } from 'vitest'
561
+ import { ProductService } from './product.service'
562
+ import { ProductRepository } from './product.repository'
563
+
564
+ describe('ProductService', () => {
565
+ let service: ProductService
566
+ let repository: ProductRepository
567
+
568
+ beforeEach(() => {
569
+ // ✅ Mock do repositório — não precisa de banco real
570
+ repository = {
571
+ findById: vi.fn(),
572
+ create: vi.fn(),
573
+ update: vi.fn(),
574
+ } as unknown as ProductRepository
575
+
576
+ service = new ProductService(repository)
577
+ })
578
+
579
+ it('lança NotFoundError quando produto não existe', async () => {
580
+ vi.mocked(repository.findById).mockResolvedValue(null)
581
+
582
+ await expect(service.getById('id-inexistente')).rejects.toThrow('Produto não encontrado')
583
+ })
584
+
585
+ it('retorna produto quando encontrado', async () => {
586
+ const product = { id: '1', name: 'Produto A', price: 100 }
587
+ vi.mocked(repository.findById).mockResolvedValue(product)
588
+
589
+ const result = await service.getById('1')
590
+ expect(result).toEqual(product)
591
+ })
592
+ })
593
+ ```
594
+
595
+ #### Testes de integração (NestJS + Supertest)
596
+
597
+ ```typescript
598
+ import { Test, TestingModule } from '@nestjs/testing'
599
+ import { INestApplication, ValidationPipe } from '@nestjs/common'
600
+ import * as request from 'supertest'
601
+ import { ProductsModule } from '../products.module'
602
+
603
+ describe('POST /api/products', () => {
604
+ let app: INestApplication
605
+
606
+ beforeAll(async () => {
607
+ const module: TestingModule = await Test.createTestingModule({
608
+ imports: [ProductsModule],
609
+ })
610
+ .overrideProvider(ProductRepository)
611
+ .useValue({ create: jest.fn(), findById: jest.fn() })
612
+ .compile()
613
+
614
+ app = module.createNestApplication()
615
+ app.useGlobalPipes(new ValidationPipe({ whitelist: true }))
616
+ await app.init()
617
+ })
618
+
619
+ afterAll(() => app.close())
620
+
621
+ it('cria produto e retorna 201', async () => {
622
+ const response = await request(app.getHttpServer())
623
+ .post('/api/products')
624
+ .set('Authorization', `Bearer ${testToken}`)
625
+ .send({ name: 'Produto Teste', price: 29.90 })
626
+
627
+ expect(response.status).toBe(201)
628
+ expect(response.body).toMatchObject({
629
+ data: { name: 'Produto Teste', price: 29.90 },
630
+ })
631
+ })
632
+
633
+ it('retorna 400 quando dados inválidos', async () => {
634
+ const response = await request(app.getHttpServer())
635
+ .post('/api/products')
636
+ .set('Authorization', `Bearer ${testToken}`)
637
+ .send({ name: '' }) // nome vazio, preço ausente
638
+
639
+ expect(response.status).toBe(400)
640
+ expect(response.body.message).toBeDefined()
641
+ })
642
+ })
643
+ ```
644
+
645
+ ### Debugging e Observabilidade
646
+
647
+ #### Logs estruturados (pino)
648
+
649
+ ```typescript
650
+ import pino from 'pino'
651
+
652
+ export const logger = pino({
653
+ level: process.env.LOG_LEVEL ?? 'info',
654
+ ...(process.env.NODE_ENV !== 'production' && {
655
+ transport: { target: 'pino-pretty' },
656
+ }),
657
+ })
658
+
659
+ // ✅ Logar com contexto suficiente
660
+ logger.info({ userId, productId, action: 'product.updated' }, 'Produto atualizado')
661
+ logger.error({ error, userId, requestId }, 'Falha ao processar pagamento')
662
+
663
+ // ❌ Nunca logar dados sensíveis
664
+ // logger.info({ password, creditCard }) — NUNCA
665
+ ```
666
+
667
+ #### Request ID para rastreabilidade
668
+
669
+ ```typescript
670
+ // ✅ Propagar request ID em todas as operações
671
+ app.addHook('onRequest', (req, reply, done) => {
672
+ req.id = req.headers['x-request-id'] as string ?? crypto.randomUUID()
673
+ reply.header('x-request-id', req.id)
674
+ done()
675
+ })
676
+ ```
677
+
678
+ ---
679
+
680
+ ## Regras
681
+
682
+ ### Nunca
683
+ - Expor stack traces ou detalhes de erro em respostas de produção
684
+ - Confiar em dados de entrada sem validação (query params, body, headers)
685
+ - Armazenar senhas em texto plano (usar bcrypt/argon2)
686
+ - Commitar secrets, API keys ou credenciais no código
687
+ - Fazer operações síncronas bloqueantes no event loop
688
+ - Processar webhooks de forma síncrona (enfileirar e responder 200 imediatamente)
689
+
690
+ ### Sempre
691
+ - Validar e sanitizar toda entrada externa (Zod, Joi, class-validator)
692
+ - Usar variáveis de ambiente para configuração
693
+ - Incluir tratamento de erros e fallbacks em integrações externas
694
+ - Testar casos de erro e edge cases, não só o happy path
695
+ - Logar com contexto suficiente para diagnóstico
696
+ - Ler o código existente antes de criar novas abstrações
697
+
698
+ ---
699
+
700
+ ## Tratamento de Erros
701
+
702
+ ```typescript
703
+ // ✅ Erro tipado com contexto
704
+ export class AppError extends Error {
705
+ constructor(
706
+ public readonly message: string,
707
+ public readonly statusCode: number = 500,
708
+ public readonly code: string = 'INTERNAL_ERROR'
709
+ ) {
710
+ super(message)
711
+ this.name = 'AppError'
712
+ }
713
+ }
714
+
715
+ // ✅ Erros de negócio explícitos
716
+ export class NotFoundError extends AppError {
717
+ constructor(resource: string, id: string) {
718
+ super(`${resource} com id '${id}' não encontrado`, 404, 'NOT_FOUND')
719
+ }
720
+ }
721
+
722
+ export class UnauthorizedError extends AppError {
723
+ constructor(message = 'Não autorizado') {
724
+ super(message, 401, 'UNAUTHORIZED')
725
+ }
726
+ }
727
+ ```
728
+
729
+ ---
730
+
731
+ ## Checklist de Conclusão
732
+
733
+ - [ ] Entrada validada (Zod / Joi / class-validator)
734
+ - [ ] Autenticação e autorização verificadas
735
+ - [ ] Erros tipados e tratados (não vazar detalhes em produção)
736
+ - [ ] Logs estruturados com contexto adequado
737
+ - [ ] Testes unitários e/ou de integração
738
+ - [ ] Rate limiting considerado (se endpoint público)
739
+ - [ ] Cache implementado onde faz sentido
740
+ - [ ] Operações destrutivas com confirmação/idempotência
741
+
742
+ ---
743
+
744
+ ## Output
745
+
746
+ | Artefato | Descrição |
747
+ |----------|-----------|
748
+ | Endpoint(s) | Rota com validação, autenticação e tratamento de erro |
749
+ | Service/Use case | Lógica de negócio isolada e testável |
750
+ | Worker/Job | Processamento assíncrono com retry e observabilidade |
751
+ | Testes | Unitários e/ou integração cobrindo happy path e erros |
752
+
753
+ ---
754
+
755
+ ## Mensagem de Conclusão
756
+
757
+ ```
758
+ Implementação backend concluída!
759
+
760
+ Framework: NestJS
761
+ ORM: {Prisma / TypeORM / Drizzle}
762
+ Funcionalidade: {descrição do que foi implementado}
763
+
764
+ Segurança: {validação de entrada / autenticação / autorização}
765
+ Testes: {criados / pendentes}
766
+ Cache: {implementado / não necessário}
767
+
768
+ Próximo passo: {rodar testes / fazer deploy / integrar com frontend}
769
+ ```
770
+
771
+ ---
772
+
773
+ ## Recursos Adicionais
774
+
775
+ - **RabbitMQ**: Ver skill `eng-rabbitmq` para operações avançadas de mensageria
776
+ - **Referências**: Veja [references/](references/) para links de documentação local