@girardelli/architect 2.2.0 → 5.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 (212) hide show
  1. package/README.md +105 -116
  2. package/architect-run.sh +431 -0
  3. package/assets/banner-v3.html +561 -0
  4. package/dist/agent-generator/context-enricher.d.ts +58 -0
  5. package/dist/agent-generator/context-enricher.d.ts.map +1 -0
  6. package/dist/agent-generator/context-enricher.js +613 -0
  7. package/dist/agent-generator/context-enricher.js.map +1 -0
  8. package/dist/agent-generator/domain-inferrer.d.ts +52 -0
  9. package/dist/agent-generator/domain-inferrer.d.ts.map +1 -0
  10. package/dist/agent-generator/domain-inferrer.js +585 -0
  11. package/dist/agent-generator/domain-inferrer.js.map +1 -0
  12. package/dist/agent-generator/framework-detector.d.ts +40 -0
  13. package/dist/agent-generator/framework-detector.d.ts.map +1 -0
  14. package/dist/agent-generator/framework-detector.js +611 -0
  15. package/dist/agent-generator/framework-detector.js.map +1 -0
  16. package/dist/agent-generator/index.d.ts +47 -0
  17. package/dist/agent-generator/index.d.ts.map +1 -0
  18. package/dist/agent-generator/index.js +545 -0
  19. package/dist/agent-generator/index.js.map +1 -0
  20. package/dist/agent-generator/stack-detector.d.ts +14 -0
  21. package/dist/agent-generator/stack-detector.d.ts.map +1 -0
  22. package/dist/agent-generator/stack-detector.js +124 -0
  23. package/dist/agent-generator/stack-detector.js.map +1 -0
  24. package/dist/agent-generator/templates/core/agents.d.ts +17 -0
  25. package/dist/agent-generator/templates/core/agents.d.ts.map +1 -0
  26. package/dist/agent-generator/templates/core/agents.js +1256 -0
  27. package/dist/agent-generator/templates/core/agents.js.map +1 -0
  28. package/dist/agent-generator/templates/core/architecture-rules.d.ts +7 -0
  29. package/dist/agent-generator/templates/core/architecture-rules.d.ts.map +1 -0
  30. package/dist/agent-generator/templates/core/architecture-rules.js +274 -0
  31. package/dist/agent-generator/templates/core/architecture-rules.js.map +1 -0
  32. package/dist/agent-generator/templates/core/general-rules.d.ts +8 -0
  33. package/dist/agent-generator/templates/core/general-rules.d.ts.map +1 -0
  34. package/dist/agent-generator/templates/core/general-rules.js +301 -0
  35. package/dist/agent-generator/templates/core/general-rules.js.map +1 -0
  36. package/dist/agent-generator/templates/core/hooks-generator.d.ts +21 -0
  37. package/dist/agent-generator/templates/core/hooks-generator.d.ts.map +1 -0
  38. package/dist/agent-generator/templates/core/hooks-generator.js +233 -0
  39. package/dist/agent-generator/templates/core/hooks-generator.js.map +1 -0
  40. package/dist/agent-generator/templates/core/index-md.d.ts +7 -0
  41. package/dist/agent-generator/templates/core/index-md.d.ts.map +1 -0
  42. package/dist/agent-generator/templates/core/index-md.js +246 -0
  43. package/dist/agent-generator/templates/core/index-md.js.map +1 -0
  44. package/dist/agent-generator/templates/core/orchestrator.d.ts +8 -0
  45. package/dist/agent-generator/templates/core/orchestrator.d.ts.map +1 -0
  46. package/dist/agent-generator/templates/core/orchestrator.js +422 -0
  47. package/dist/agent-generator/templates/core/orchestrator.js.map +1 -0
  48. package/dist/agent-generator/templates/core/preflight.d.ts +8 -0
  49. package/dist/agent-generator/templates/core/preflight.d.ts.map +1 -0
  50. package/dist/agent-generator/templates/core/preflight.js +213 -0
  51. package/dist/agent-generator/templates/core/preflight.js.map +1 -0
  52. package/dist/agent-generator/templates/core/quality-gates.d.ts +11 -0
  53. package/dist/agent-generator/templates/core/quality-gates.d.ts.map +1 -0
  54. package/dist/agent-generator/templates/core/quality-gates.js +254 -0
  55. package/dist/agent-generator/templates/core/quality-gates.js.map +1 -0
  56. package/dist/agent-generator/templates/core/security-rules.d.ts +7 -0
  57. package/dist/agent-generator/templates/core/security-rules.d.ts.map +1 -0
  58. package/dist/agent-generator/templates/core/security-rules.js +528 -0
  59. package/dist/agent-generator/templates/core/security-rules.js.map +1 -0
  60. package/dist/agent-generator/templates/core/skills-generator.d.ts +19 -0
  61. package/dist/agent-generator/templates/core/skills-generator.d.ts.map +1 -0
  62. package/dist/agent-generator/templates/core/skills-generator.js +546 -0
  63. package/dist/agent-generator/templates/core/skills-generator.js.map +1 -0
  64. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts +7 -0
  65. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts.map +1 -0
  66. package/dist/agent-generator/templates/core/workflow-fix-bug.js +237 -0
  67. package/dist/agent-generator/templates/core/workflow-fix-bug.js.map +1 -0
  68. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts +8 -0
  69. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts.map +1 -0
  70. package/dist/agent-generator/templates/core/workflow-new-feature.js +321 -0
  71. package/dist/agent-generator/templates/core/workflow-new-feature.js.map +1 -0
  72. package/dist/agent-generator/templates/core/workflow-review.d.ts +7 -0
  73. package/dist/agent-generator/templates/core/workflow-review.d.ts.map +1 -0
  74. package/dist/agent-generator/templates/core/workflow-review.js +104 -0
  75. package/dist/agent-generator/templates/core/workflow-review.js.map +1 -0
  76. package/dist/agent-generator/templates/domain/index.d.ts +22 -0
  77. package/dist/agent-generator/templates/domain/index.d.ts.map +1 -0
  78. package/dist/agent-generator/templates/domain/index.js +1176 -0
  79. package/dist/agent-generator/templates/domain/index.js.map +1 -0
  80. package/dist/agent-generator/templates/stack/index.d.ts +8 -0
  81. package/dist/agent-generator/templates/stack/index.d.ts.map +1 -0
  82. package/dist/agent-generator/templates/stack/index.js +695 -0
  83. package/dist/agent-generator/templates/stack/index.js.map +1 -0
  84. package/dist/agent-generator/templates/template-helpers.d.ts +75 -0
  85. package/dist/agent-generator/templates/template-helpers.d.ts.map +1 -0
  86. package/dist/agent-generator/templates/template-helpers.js +726 -0
  87. package/dist/agent-generator/templates/template-helpers.js.map +1 -0
  88. package/dist/agent-generator/types.d.ts +196 -0
  89. package/dist/agent-generator/types.d.ts.map +1 -0
  90. package/dist/agent-generator/types.js +27 -0
  91. package/dist/agent-generator/types.js.map +1 -0
  92. package/dist/analyzer.d.ts +5 -0
  93. package/dist/analyzer.d.ts.map +1 -1
  94. package/dist/analyzer.js +46 -5
  95. package/dist/analyzer.js.map +1 -1
  96. package/dist/analyzers/forecast.d.ts +85 -0
  97. package/dist/analyzers/forecast.d.ts.map +1 -0
  98. package/dist/analyzers/forecast.js +337 -0
  99. package/dist/analyzers/forecast.js.map +1 -0
  100. package/dist/analyzers/git-cache.d.ts +7 -0
  101. package/dist/analyzers/git-cache.d.ts.map +1 -0
  102. package/dist/analyzers/git-cache.js +41 -0
  103. package/dist/analyzers/git-cache.js.map +1 -0
  104. package/dist/analyzers/git-history.d.ts +113 -0
  105. package/dist/analyzers/git-history.d.ts.map +1 -0
  106. package/dist/analyzers/git-history.js +333 -0
  107. package/dist/analyzers/git-history.js.map +1 -0
  108. package/dist/analyzers/index.d.ts +10 -0
  109. package/dist/analyzers/index.d.ts.map +1 -0
  110. package/dist/analyzers/index.js +7 -0
  111. package/dist/analyzers/index.js.map +1 -0
  112. package/dist/analyzers/temporal-scorer.d.ts +72 -0
  113. package/dist/analyzers/temporal-scorer.d.ts.map +1 -0
  114. package/dist/analyzers/temporal-scorer.js +140 -0
  115. package/dist/analyzers/temporal-scorer.js.map +1 -0
  116. package/dist/anti-patterns.d.ts +7 -0
  117. package/dist/anti-patterns.d.ts.map +1 -1
  118. package/dist/anti-patterns.js +25 -6
  119. package/dist/anti-patterns.js.map +1 -1
  120. package/dist/cli.d.ts +2 -3
  121. package/dist/cli.d.ts.map +1 -1
  122. package/dist/cli.js +275 -113
  123. package/dist/cli.js.map +1 -1
  124. package/dist/config.d.ts +6 -0
  125. package/dist/config.d.ts.map +1 -1
  126. package/dist/config.js +48 -11
  127. package/dist/config.js.map +1 -1
  128. package/dist/html-reporter.d.ts +3 -1
  129. package/dist/html-reporter.d.ts.map +1 -1
  130. package/dist/html-reporter.js +248 -12
  131. package/dist/html-reporter.js.map +1 -1
  132. package/dist/index.d.ts +16 -3
  133. package/dist/index.d.ts.map +1 -1
  134. package/dist/index.js +63 -4
  135. package/dist/index.js.map +1 -1
  136. package/dist/project-summarizer.d.ts +38 -0
  137. package/dist/project-summarizer.d.ts.map +1 -0
  138. package/dist/project-summarizer.js +463 -0
  139. package/dist/project-summarizer.js.map +1 -0
  140. package/dist/refactor-reporter.js +1 -1
  141. package/dist/scanner.d.ts +8 -2
  142. package/dist/scanner.d.ts.map +1 -1
  143. package/dist/scanner.js +153 -113
  144. package/dist/scanner.js.map +1 -1
  145. package/dist/scorer.d.ts.map +1 -1
  146. package/dist/scorer.js +24 -11
  147. package/dist/scorer.js.map +1 -1
  148. package/dist/types.d.ts +29 -0
  149. package/dist/types.d.ts.map +1 -1
  150. package/package.json +12 -3
  151. package/src/agent-generator/context-enricher.ts +672 -0
  152. package/src/agent-generator/domain-inferrer.ts +635 -0
  153. package/src/agent-generator/framework-detector.ts +669 -0
  154. package/src/agent-generator/index.ts +634 -0
  155. package/src/agent-generator/stack-detector.ts +115 -0
  156. package/src/agent-generator/templates/core/agents.ts +1296 -0
  157. package/src/agent-generator/templates/core/architecture-rules.ts +287 -0
  158. package/src/agent-generator/templates/core/general-rules.ts +306 -0
  159. package/src/agent-generator/templates/core/hooks-generator.ts +242 -0
  160. package/src/agent-generator/templates/core/index-md.ts +260 -0
  161. package/src/agent-generator/templates/core/orchestrator.ts +459 -0
  162. package/src/agent-generator/templates/core/preflight.ts +215 -0
  163. package/src/agent-generator/templates/core/quality-gates.ts +256 -0
  164. package/src/agent-generator/templates/core/security-rules.ts +543 -0
  165. package/src/agent-generator/templates/core/skills-generator.ts +585 -0
  166. package/src/agent-generator/templates/core/workflow-fix-bug.ts +239 -0
  167. package/src/agent-generator/templates/core/workflow-new-feature.ts +323 -0
  168. package/src/agent-generator/templates/core/workflow-review.ts +106 -0
  169. package/src/agent-generator/templates/domain/index.ts +1201 -0
  170. package/src/agent-generator/templates/stack/index.ts +705 -0
  171. package/src/agent-generator/templates/template-helpers.ts +776 -0
  172. package/src/agent-generator/types.ts +232 -0
  173. package/src/analyzer.ts +51 -5
  174. package/src/analyzers/forecast.ts +496 -0
  175. package/src/analyzers/git-cache.ts +52 -0
  176. package/src/analyzers/git-history.ts +488 -0
  177. package/src/analyzers/index.ts +33 -0
  178. package/src/analyzers/temporal-scorer.ts +227 -0
  179. package/src/anti-patterns.ts +29 -6
  180. package/src/cli.ts +316 -117
  181. package/src/config.ts +52 -11
  182. package/src/html-reporter.ts +263 -13
  183. package/src/index.ts +93 -10
  184. package/src/project-summarizer.ts +521 -0
  185. package/src/refactor-reporter.ts +1 -1
  186. package/src/scanner.ts +136 -90
  187. package/src/scorer.ts +26 -11
  188. package/src/types.ts +27 -0
  189. package/tests/agent-generator.test.ts +427 -0
  190. package/tests/analyzers-integration.test.ts +174 -0
  191. package/tests/architect-adapter-enrichment.test.ts +9 -0
  192. package/tests/context-enricher.test.ts +971 -0
  193. package/tests/fixtures/monorepo/package.json +6 -0
  194. package/tests/fixtures/monorepo/packages/app/package.json +12 -0
  195. package/tests/fixtures/monorepo/packages/app/src/index.ts +6 -0
  196. package/tests/fixtures/monorepo/packages/core/package.json +7 -0
  197. package/tests/fixtures/monorepo/packages/core/src/index.ts +7 -0
  198. package/tests/forecast.test.ts +509 -0
  199. package/tests/framework-detector.test.ts +1172 -0
  200. package/tests/git-history.test.ts +254 -0
  201. package/tests/monorepo-scan.test.ts +170 -0
  202. package/tests/scanner.test.ts +7 -8
  203. package/tests/scorer.test.ts +594 -0
  204. package/tests/stack-detector.test.ts +241 -0
  205. package/tests/template-generation.test.ts +706 -0
  206. package/tests/template-helpers.test.ts +1152 -0
  207. package/tests/temporal-scorer.test.ts +307 -0
  208. package/dist/agent-generator.d.ts +0 -106
  209. package/dist/agent-generator.d.ts.map +0 -1
  210. package/dist/agent-generator.js +0 -1398
  211. package/dist/agent-generator.js.map +0 -1
  212. package/src/agent-generator.ts +0 -1526
@@ -0,0 +1,1201 @@
1
+ import { TemplateContext, EnrichedTemplateContext } from '../../types.js';
2
+
3
+ /**
4
+ * Domain templates — C4, BDD, TDD, ADR, Threat Model.
5
+ * Reutilizable templates referenced by workflows and agents.
6
+ */
7
+
8
+ /**
9
+ * Helper to safely extract enriched context
10
+ */
11
+ function getEnriched(ctx?: TemplateContext): Partial<EnrichedTemplateContext> {
12
+ if (ctx && 'domain' in ctx) {
13
+ return ctx as EnrichedTemplateContext;
14
+ }
15
+ return {};
16
+ }
17
+
18
+ /**
19
+ * Generate C4 Architecture template with optional pre-filled examples
20
+ */
21
+ export function generateC4Template(ctx?: EnrichedTemplateContext | TemplateContext): string {
22
+ const enriched = getEnriched(ctx);
23
+ const domain = enriched.domain;
24
+ const modules = enriched.modules || [];
25
+ const endpoints = enriched.endpoints || [];
26
+ const integrations = domain?.integrations || [];
27
+
28
+ // Build Level 1 content
29
+ let level1Content = `Atores:
30
+ - [ator 1]: [descrição do papel]
31
+ - [ator 2]: [descrição do papel]`;
32
+
33
+ if (domain?.businessEntities && domain.businessEntities.length > 0) {
34
+ const actorsFromEntities = domain.businessEntities.slice(0, 2).map((e) => `- ${e.name}: Entidade de negócio`).join('\n');
35
+ level1Content = `Atores:\n${actorsFromEntities}`;
36
+ }
37
+
38
+ let externalSystems = `- [sistema 1]: [como interage]
39
+ - [sistema 2]: [como interage]`;
40
+
41
+ if (integrations.length > 0) {
42
+ externalSystems = integrations
43
+ .map((i) => `- ${i.name} (${i.type}): Integração de negócio`)
44
+ .join('\n');
45
+ }
46
+
47
+ // Build Level 2 content
48
+ let containerDiagram = `┌──────────────┐ ┌──────────────┐ ┌──────────────┐
49
+ │ Frontend │───▶│ Backend │───▶│ Database │
50
+ │ (Web/App) │ │ (API) │ │ (PostgreSQL)│
51
+ └──────────────┘ └──────────────┘ └──────────────┘
52
+
53
+
54
+ ┌──────────────┐
55
+ │ External │
56
+ │ Service │
57
+ └──────────────┘`;
58
+
59
+ if (ctx && 'stack' in ctx && ctx.stack) {
60
+ const stack = ctx.stack;
61
+ let frontendLabel = stack.hasFrontend ? `${stack.frameworks[0] || 'Frontend'}` : '[Frontend]';
62
+ let backendLabel = stack.frameworks[1] || 'Backend';
63
+ let dbLabel = '[Database]';
64
+ if (stack.hasDatabase) {
65
+ dbLabel = stack.frameworks.includes('PostgreSQL') ? 'PostgreSQL' : 'Database';
66
+ }
67
+
68
+ containerDiagram = `┌──────────────┐ ┌──────────────┐ ┌──────────────┐
69
+ │ ${frontendLabel.padEnd(11)}│───▶│ ${backendLabel.padEnd(11)}│───▶│ ${dbLabel.padEnd(11)}│
70
+ └──────────────┘ └──────────────┘ └──────────────┘`;
71
+ }
72
+
73
+ // Build Level 3 content
74
+ let componentContent = `Módulo: [nome]
75
+ ├── Controller: [nome] — [responsabilidade]
76
+ ├── Service: [nome] — [responsabilidade]
77
+ ├── Entity: [nome] — [campos principais]
78
+ ├── DTO: [nome] — [campos de request/response]
79
+ └── Tests: [lista de testes]`;
80
+
81
+ if (modules.length > 0) {
82
+ const firstModule = modules[0];
83
+ const controllers = firstModule.controllers.slice(0, 2).join(', ') || '[Controllers]';
84
+ const services = firstModule.services.slice(0, 2).join(', ') || '[Services]';
85
+ const entities = firstModule.entities.slice(0, 1).join(', ') || '[Entities]';
86
+
87
+ componentContent = `Módulo: ${firstModule.name}
88
+ ├── Controller: ${controllers} — Expõe endpoints REST
89
+ ├── Service: ${services} — Lógica de negócio
90
+ ├── Entity: ${entities} — Persistência de dados
91
+ ├── DTO: [Request/Response]
92
+ └── Tests: ${firstModule.testFiles.length > 0 ? 'Implementados' : 'Pendentes'}`;
93
+ }
94
+
95
+ // Build Level 4 content — framework-aware code example
96
+ const stack = ctx && 'stack' in ctx ? ctx.stack : undefined;
97
+ const langs = stack ? stack.languages.map((l) => l.toLowerCase()) : [];
98
+ const isPython = langs.includes('python');
99
+ const isDart = langs.includes('dart');
100
+ const isJava = langs.includes('java') || langs.includes('kotlin');
101
+ const isGo = langs.includes('go');
102
+ const isRust = langs.includes('rust');
103
+
104
+ let level4Lang = 'typescript';
105
+ let level4Content = `interface IExemploService {
106
+ metodo(param: Tipo): Promise<Retorno>;
107
+ }`;
108
+
109
+ if (isPython) {
110
+ level4Lang = 'python';
111
+ level4Content = `class IExemploService(ABC):
112
+ @abstractmethod
113
+ async def metodo(self, param: Tipo) -> Retorno:
114
+ ...`;
115
+ } else if (isDart) {
116
+ level4Lang = 'dart';
117
+ level4Content = `abstract class IExemploService {
118
+ Future<Retorno> metodo(Tipo param);
119
+ }`;
120
+ } else if (isJava) {
121
+ level4Lang = 'java';
122
+ level4Content = `public interface IExemploService {
123
+ Retorno metodo(Tipo param);
124
+ }`;
125
+ } else if (isGo) {
126
+ level4Lang = 'go';
127
+ level4Content = `type ExemploService interface {
128
+ Metodo(param Tipo) (Retorno, error)
129
+ }`;
130
+ } else if (isRust) {
131
+ level4Lang = 'rust';
132
+ level4Content = `trait ExemploService {
133
+ fn metodo(&self, param: Tipo) -> Result<Retorno, Error>;
134
+ }`;
135
+ }
136
+
137
+ if (endpoints.length > 0) {
138
+ const firstEndpoint = endpoints[0];
139
+ if (isPython) {
140
+ level4Content = `class I${firstEndpoint.handler}Service(ABC):
141
+ # ${firstEndpoint.method} ${firstEndpoint.path}
142
+ @abstractmethod
143
+ async def handle_${firstEndpoint.handler.toLowerCase()}(self, req: Request) -> Response:
144
+ ...`;
145
+ } else if (isDart) {
146
+ level4Content = `abstract class I${firstEndpoint.handler}Service {
147
+ // ${firstEndpoint.method} ${firstEndpoint.path}
148
+ Future<Response> handle${firstEndpoint.handler}(Request req);
149
+ }`;
150
+ } else if (isJava) {
151
+ level4Content = `public interface I${firstEndpoint.handler}Service {
152
+ // ${firstEndpoint.method} ${firstEndpoint.path}
153
+ Response handle${firstEndpoint.handler}(Request req);
154
+ }`;
155
+ } else if (isGo) {
156
+ level4Content = `type ${firstEndpoint.handler}Service interface {
157
+ // ${firstEndpoint.method} ${firstEndpoint.path}
158
+ Handle${firstEndpoint.handler}(req *Request) (*Response, error)
159
+ }`;
160
+ } else {
161
+ level4Content = `interface I${firstEndpoint.handler}Service {
162
+ // ${firstEndpoint.method} ${firstEndpoint.path}
163
+ handle${firstEndpoint.handler}(req: Request): Promise<Response>;
164
+ }`;
165
+ }
166
+ }
167
+
168
+ return `# 🏗️ Template: Arquitetura C4
169
+
170
+ > Preencher os 4 níveis relevantes para a feature/mudança.
171
+
172
+ ---
173
+
174
+ ## Nível 1 — Contexto
175
+
176
+ > Visão de pássaro: quem são os atores e sistemas envolvidos?
177
+
178
+ \`\`\`
179
+ ${level1Content}
180
+
181
+ Sistemas Externos:
182
+ ${externalSystems}
183
+
184
+ Fluxo de dados:
185
+ [ator] → [sistema] → [nosso sistema] → [resposta]
186
+ \`\`\`
187
+
188
+ ---
189
+
190
+ ## Nível 2 — Container
191
+
192
+ > Quais serviços, apps, bancos de dados são tocados?
193
+
194
+ \`\`\`
195
+ ${containerDiagram}
196
+ \`\`\`
197
+
198
+ ---
199
+
200
+ ## Nível 3 — Componente
201
+
202
+ > Quais módulos, classes, serviços são criados ou modificados?
203
+
204
+ \`\`\`
205
+ ${componentContent}
206
+ \`\`\`
207
+
208
+ ---
209
+
210
+ ## Nível 4 — Código (se complexo)
211
+
212
+ > Interfaces, tipos, contratos. Apenas para decisões complexas.
213
+
214
+ \`\`\`${level4Lang}
215
+ ${level4Content}
216
+ \`\`\`
217
+
218
+ ---
219
+
220
+ ## Decisões Arquiteturais
221
+
222
+ Se a decisão é significativa → criar ADR separado (ver template ADR).
223
+ `;
224
+ }
225
+
226
+ /**
227
+ * Generate BDD template with optional pre-filled examples from project domain
228
+ */
229
+ export function generateBddTemplate(ctx?: EnrichedTemplateContext | TemplateContext): string {
230
+ const enriched = getEnriched(ctx);
231
+ const domain = enriched.domain;
232
+ const businessEntities = domain?.businessEntities || [];
233
+ const compliance = domain?.compliance || [];
234
+
235
+ let featureName = '[Nome da Feature]';
236
+ let exampleScenario = ` Scenario: [cenário principal - sucesso]
237
+ Given [contexto / pré-condição]
238
+ And [contexto adicional, se necessário]
239
+ When [ação do usuário]
240
+ Then [resultado esperado]
241
+ And [efeito colateral, se houver]`;
242
+
243
+ // Generate example scenario from first business entity
244
+ if (businessEntities.length > 0) {
245
+ const entity = businessEntities[0];
246
+ featureName = `Criar e Validar ${entity.name}`;
247
+ exampleScenario = ` Scenario: Criar ${entity.name} com sucesso
248
+ Given o usuário está no formulário de criação de ${entity.name}
249
+ And todos os campos obrigatórios estão vazios
250
+ When o usuário preenche os campos corretamente
251
+ Then a entidade é persistida no banco de dados
252
+ And uma mensagem de sucesso é exibida ao usuário`;
253
+ }
254
+
255
+ let complianceScenario = ` Scenario: [cenário de acesso negado]
256
+ Given [usuário sem permissão]
257
+ When [tenta acessar recurso]
258
+ Then [resposta 403 / redirect]`;
259
+
260
+ // Add compliance-specific scenario if applicable
261
+ if (compliance.length > 0) {
262
+ const comp = compliance[0];
263
+ if (comp.name === 'LGPD') {
264
+ complianceScenario = ` Scenario: Usuário solicita exclusão de dados sob LGPD
265
+ Given um usuário autenticado no sistema
266
+ When o usuário solicita a exclusão de seus dados pessoais
267
+ Then todos os seus registros são anonimizados ou removidos
268
+ And a solicitação é registrada em audit log`;
269
+ } else if (comp.name === 'HIPAA') {
270
+ complianceScenario = ` Scenario: Acesso a dados sensíveis de paciente
271
+ Given um profissional de saúde autenticado
272
+ When o profissional acessa registros de paciente
273
+ Then o acesso é registrado com timestamp e usuário
274
+ And a ação é auditada para compliance`;
275
+ }
276
+ }
277
+
278
+ let domainSpecificSection = '';
279
+ if (domain?.domain === 'fintech' || domain?.domain === 'payment') {
280
+ domainSpecificSection = `
281
+
282
+ # ── Cenários de Fintech ──
283
+
284
+ Scenario: Transação com saldo insuficiente
285
+ Given a conta do usuário tem saldo de R$ 50
286
+ When o usuário tenta transferir R$ 100
287
+ Then a transação é rejeitada
288
+ And a mensagem "Saldo insuficiente" é exibida
289
+
290
+ Scenario: Taxa de câmbio atualizada
291
+ Given uma transação internacional está pendente
292
+ When a taxa de câmbio muda de 5.0 para 5.2
293
+ Then o valor em reais é recalculado
294
+ And o usuário é notificado da mudança`;
295
+ } else if (domain?.domain === 'tax' || domain?.subDomain === 'tax-processing') {
296
+ domainSpecificSection = `
297
+
298
+ # ── Cenários de Impostos ──
299
+
300
+ Scenario: Calcular imposto sobre renda
301
+ Given um contribuinte com rendimento mensal de R$ 5000
302
+ When o sistema calcula o imposto devido
303
+ Then o valor segue a tabela progressiva do IRPF
304
+ And o resultado é salvo no banco de dados
305
+
306
+ Scenario: Gerar DARF automático
307
+ Given uma obrigação de imposto vencendo amanhã
308
+ When o sistema processa as obrigações pendentes
309
+ Then um DARF é gerado automaticamente
310
+ And uma notificação é enviada ao contribuinte`;
311
+ }
312
+
313
+ return `# 🧪 Template: BDD — Behavior-Driven Development
314
+
315
+ > Um cenário para cada critério de aceite + cenários de erro + edge cases.
316
+
317
+ ---
318
+
319
+ ## Feature: ${featureName}
320
+
321
+ \`\`\`gherkin
322
+ Feature: ${featureName}
323
+ Como usuário,
324
+ Quero interagir com ${businessEntities[0]?.name || 'o sistema'},
325
+ Para alcançar meu objetivo de negócio.
326
+
327
+ # ── Happy Path ──
328
+
329
+ ${exampleScenario}
330
+
331
+ # ── Validações ──
332
+
333
+ Scenario: Validação de dados obrigatórios
334
+ Given um formulário de criação
335
+ When o usuário tenta enviar sem preencher campos obrigatórios
336
+ Then mensagens de erro são exibidas para cada campo
337
+
338
+ # ── Edge Cases ──
339
+
340
+ Scenario: Lidar com valores boundary
341
+ Given o sistema aceita valores de 0 a 999999.99
342
+ When o usuário tenta inserir um valor fora do range
343
+ Then um erro de validação é retornado
344
+
345
+ # ── Permissões ──
346
+
347
+ ${complianceScenario}${domainSpecificSection}
348
+ \`\`\`
349
+
350
+ ---
351
+
352
+ ## Checklist
353
+
354
+ \`\`\`
355
+ □ Cada critério de aceite tem ≥ 1 cenário
356
+ □ Happy path coberto
357
+ □ Error paths cobertos
358
+ □ Edge cases cobertos
359
+ □ Permissões/autenticação cobertos
360
+ □ Cenários são independentes entre si
361
+ \`\`\`
362
+ `;
363
+ }
364
+
365
+ /**
366
+ * Generate TDD template with optional pre-filled examples
367
+ */
368
+ export function generateTddTemplate(ctx?: EnrichedTemplateContext | TemplateContext): string {
369
+ const enriched = getEnriched(ctx);
370
+ const modules = enriched.modules || [];
371
+ const endpoints = enriched.endpoints || [];
372
+ const stack = ctx && 'stack' in ctx ? ctx.stack : undefined;
373
+
374
+ let testFramework = 'jest';
375
+ let exampleTest = ` it('should [resultado esperado] when [condição]', () => {
376
+ // Arrange
377
+ const input = ...;
378
+
379
+ // Act
380
+ const result = metodo(input);
381
+
382
+ // Assert
383
+ expect(result).toEqual(expected);
384
+ });`;
385
+
386
+ // Detect test framework from stack (case-insensitive comparison)
387
+ if (stack) {
388
+ const langs = stack.languages.map((l) => l.toLowerCase());
389
+ if (langs.includes('python')) {
390
+ testFramework = 'pytest';
391
+ } else if (langs.includes('dart')) {
392
+ testFramework = 'flutter_test';
393
+ } else if (langs.includes('java') || langs.includes('kotlin')) {
394
+ testFramework = 'junit';
395
+ } else if (langs.includes('go')) {
396
+ testFramework = 'go_test';
397
+ } else if (langs.includes('rust')) {
398
+ testFramework = 'cargo_test';
399
+ }
400
+ }
401
+
402
+ let moduleName = '[Nome do Módulo/Classe]';
403
+ let methodName = '[método/função]';
404
+ let exampleModule = modules[0];
405
+
406
+ if (exampleModule) {
407
+ moduleName = exampleModule.name;
408
+ const service = exampleModule.services[0] || 'Service';
409
+ methodName = `create${service.replace('Service', '')}`;
410
+
411
+ if (testFramework === 'pytest') {
412
+ exampleTest = ` def test_should_create_entity_successfully(self):
413
+ # Arrange
414
+ input_data = {"name": "Test Entity"}
415
+
416
+ # Act
417
+ result = service.${methodName}(input_data)
418
+
419
+ # Assert
420
+ assert result is not None
421
+ assert result.name == "Test Entity"`;
422
+ } else if (testFramework === 'flutter_test') {
423
+ exampleTest = ` test('should create entity successfully', () async {
424
+ // Arrange
425
+ final input = CreateRequest(name: 'Test');
426
+
427
+ // Act
428
+ final result = await service.${methodName}(input);
429
+
430
+ // Assert
431
+ expect(result, isNotNull);
432
+ expect(result.name, equals('Test'));
433
+ });`;
434
+ } else if (testFramework === 'go_test') {
435
+ exampleTest = `func TestShould_Create${moduleName}_Successfully(t *testing.T) {
436
+ // Arrange
437
+ input := ${moduleName}Input{Name: "Test Entity"}
438
+
439
+ // Act
440
+ result, err := service.${methodName}(input)
441
+
442
+ // Assert
443
+ assert.NoError(t, err)
444
+ assert.NotNil(t, result)
445
+ assert.Equal(t, "Test Entity", result.Name)
446
+ }`;
447
+ } else if (testFramework === 'cargo_test') {
448
+ exampleTest = `#[test]
449
+ fn test_should_create_${moduleName.toLowerCase()}_successfully() {
450
+ // Arrange
451
+ let input = ${moduleName}Input { name: "Test Entity".to_string() };
452
+
453
+ // Act
454
+ let result = service.${methodName}(&input);
455
+
456
+ // Assert
457
+ assert!(result.is_ok());
458
+ assert_eq!(result.unwrap().name, "Test Entity");
459
+ }`;
460
+ } else if (testFramework === 'junit') {
461
+ exampleTest = ` @Test
462
+ void shouldCreate${moduleName}Successfully() {
463
+ // Arrange
464
+ var input = new ${moduleName}Input("Test Entity");
465
+
466
+ // Act
467
+ var result = service.${methodName}(input);
468
+
469
+ // Assert
470
+ assertNotNull(result);
471
+ assertEquals("Test Entity", result.getName());
472
+ }`;
473
+ } else {
474
+ exampleTest = ` it('should create ${moduleName} successfully', () => {
475
+ // Arrange
476
+ const input = { name: 'Test Entity' };
477
+
478
+ // Act
479
+ const result = service.${methodName}(input);
480
+
481
+ // Assert
482
+ expect(result).toBeDefined();
483
+ expect(result.name).toBe('Test Entity');
484
+ });`;
485
+ }
486
+ }
487
+
488
+ let endpointTest = '';
489
+ if (endpoints.length > 0) {
490
+ const endpoint = endpoints[0];
491
+ if (testFramework === 'pytest') {
492
+ endpointTest = `
493
+
494
+ def test_${endpoint.method.toLowerCase()}_${endpoint.path.replace(/\//g, '_')}():
495
+ """Test ${endpoint.method} ${endpoint.path}"""
496
+ # Arrange
497
+ client = TestClient(app)
498
+
499
+ # Act
500
+ response = client.${endpoint.method.toLowerCase()}("${endpoint.path}")
501
+
502
+ # Assert
503
+ assert response.status_code == 200`;
504
+ } else if (testFramework === 'flutter_test') {
505
+ endpointTest = `
506
+
507
+ testWidgets('should ${endpoint.method.toLowerCase()} ${endpoint.path} correctly', (WidgetTester tester) async {
508
+ // Arrange
509
+ when(mockClient.${endpoint.method.toLowerCase()}(endpoint)).thenAnswer((_) async => Response('{}', 200));
510
+
511
+ // Act
512
+ final result = await client.${endpoint.method.toLowerCase()}(endpoint);
513
+
514
+ // Assert
515
+ expect(result.statusCode, equals(200));
516
+ });`;
517
+ } else if (testFramework === 'go_test') {
518
+ endpointTest = `
519
+
520
+ func Test_${endpoint.method}_${endpoint.path.replace(/\//g, '_')}(t *testing.T) {
521
+ // Arrange
522
+ req := httptest.NewRequest("${endpoint.method}", "${endpoint.path}", nil)
523
+ w := httptest.NewRecorder()
524
+
525
+ // Act
526
+ handler.ServeHTTP(w, req)
527
+
528
+ // Assert
529
+ assert.Equal(t, http.StatusOK, w.Code)
530
+ }`;
531
+ } else if (testFramework === 'cargo_test') {
532
+ endpointTest = `
533
+
534
+ #[actix_web::test]
535
+ async fn test_${endpoint.method.toLowerCase()}_${endpoint.path.replace(/\//g, '_')}() {
536
+ // Arrange
537
+ let app = test::init_service(App::new().configure(routes)).await;
538
+ let req = test::TestRequest::${endpoint.method.toLowerCase()}().uri("${endpoint.path}").to_request();
539
+
540
+ // Act
541
+ let resp = test::call_service(&app, req).await;
542
+
543
+ // Assert
544
+ assert!(resp.status().is_success());
545
+ }`;
546
+ } else if (testFramework === 'junit') {
547
+ endpointTest = `
548
+
549
+ @Test
550
+ void should${endpoint.method}${endpoint.handler}Correctly() throws Exception {
551
+ // Act & Assert
552
+ mockMvc.perform(${endpoint.method.toLowerCase()}("${endpoint.path}"))
553
+ .andExpect(status().isOk());
554
+ }`;
555
+ } else {
556
+ endpointTest = `
557
+
558
+ it('should ${endpoint.method.toLowerCase()} ${endpoint.path} correctly', async () => {
559
+ // Arrange
560
+ const endpoint = '${endpoint.path}';
561
+
562
+ // Act
563
+ const response = await request(app).${endpoint.method.toLowerCase()}(endpoint);
564
+
565
+ // Assert
566
+ expect(response.status).toBe(200);
567
+ });`;
568
+ }
569
+ }
570
+
571
+ const structureLabel = testFramework === 'pytest' ? 'def test_' : testFramework === 'flutter_test' ? 'test(' : 'describe(';
572
+ const openingBracket = testFramework === 'pytest' ? ':' : testFramework === 'flutter_test' ? ', () async {' : ", () => {";
573
+
574
+ return `# 🔬 Template: TDD — Test-Driven Development
575
+
576
+ > RED → GREEN → REFACTOR. Nesta ordem. Sempre.
577
+
578
+ ---
579
+
580
+ ## Estrutura de Testes (${testFramework})
581
+
582
+ \`\`\`${testFramework === 'pytest' ? 'python' : testFramework === 'flutter_test' ? 'dart' : testFramework === 'go_test' ? 'go' : testFramework === 'cargo_test' ? 'rust' : testFramework === 'junit' ? 'java' : 'typescript'}
583
+ ${
584
+ testFramework === 'pytest'
585
+ ? `import pytest
586
+ from app.services.${moduleName.toLowerCase()} import ${moduleName}Service
587
+
588
+ class Test${moduleName}:
589
+ """Testes para ${moduleName}"""
590
+
591
+ ${exampleTest}
592
+
593
+ def test_should_throw_error_when_invalid_input(self):
594
+ # Arrange
595
+ invalid_input = None
596
+
597
+ # Act & Assert
598
+ with pytest.raises(ValueError):
599
+ service.${methodName}(invalid_input)`
600
+ : testFramework === 'flutter_test'
601
+ ? `import 'package:flutter_test/flutter_test.dart';
602
+ import 'package:${moduleName.toLowerCase()}/services/${moduleName.toLowerCase()}_service.dart';
603
+
604
+ void main() {
605
+ group('${moduleName}Service', () {
606
+
607
+ ${exampleTest}
608
+
609
+ test('should throw exception when input is invalid', () {
610
+ // Arrange
611
+ final invalid = null;
612
+
613
+ // Act & Assert
614
+ expect(() => service.${methodName}(invalid), throwsException);
615
+ });${endpointTest}
616
+ });
617
+ }`
618
+ : testFramework === 'go_test'
619
+ ? `package ${moduleName.toLowerCase()}_test
620
+
621
+ import (
622
+ "testing"
623
+ "net/http"
624
+ "net/http/httptest"
625
+ "github.com/stretchr/testify/assert"
626
+ )
627
+
628
+ // ── Happy Path ──
629
+ ${exampleTest}
630
+
631
+ // ── Error Path ──
632
+ func TestShould_Return_Error_When_InvalidInput(t *testing.T) {
633
+ // Arrange
634
+ input := ${moduleName}Input{}
635
+
636
+ // Act
637
+ _, err := service.${methodName}(input)
638
+
639
+ // Assert
640
+ assert.Error(t, err)
641
+ }${endpointTest}`
642
+ : testFramework === 'cargo_test'
643
+ ? `#[cfg(test)]
644
+ mod tests {
645
+ use super::*;
646
+
647
+ // ── Happy Path ──
648
+ ${exampleTest}
649
+
650
+ // ── Error Path ──
651
+ #[test]
652
+ fn test_should_return_error_when_invalid_input() {
653
+ // Arrange
654
+ let input = ${moduleName}Input { name: "".to_string() };
655
+
656
+ // Act
657
+ let result = service.${methodName}(&input);
658
+
659
+ // Assert
660
+ assert!(result.is_err());
661
+ }${endpointTest}
662
+ }`
663
+ : testFramework === 'junit'
664
+ ? `import org.junit.jupiter.api.Test;
665
+ import static org.junit.jupiter.api.Assertions.*;
666
+
667
+ class ${moduleName}Test {
668
+
669
+ // ── Happy Path ──
670
+ ${exampleTest}
671
+
672
+ // ── Error Path ──
673
+ @Test
674
+ void shouldThrowWhenInvalidInput() {
675
+ // Arrange
676
+ var invalidInput = new ${moduleName}Input(null);
677
+
678
+ // Act & Assert
679
+ assertThrows(IllegalArgumentException.class,
680
+ () -> service.${methodName}(invalidInput));
681
+ }${endpointTest}
682
+ }`
683
+ : `describe('${moduleName}', () => {
684
+
685
+ describe('${methodName}', () => {
686
+
687
+ // ── Happy Path ──
688
+ ${exampleTest}
689
+
690
+ // ── Error Path ──
691
+ it('should throw [erro] when [condição inválida]', () => {
692
+ // Arrange
693
+ const invalidInput = undefined;
694
+
695
+ // Act & Assert
696
+ expect(() => service.${methodName}(invalidInput)).toThrow(Error);
697
+ });
698
+
699
+ // ── Boundary ──
700
+ it('should handle empty input', () => {
701
+ // Arrange
702
+ const boundaryInput = {};
703
+
704
+ // Act
705
+ const result = service.${methodName}(boundaryInput);
706
+
707
+ // Assert
708
+ expect(result).toBeDefined();
709
+ });${endpointTest}
710
+ });
711
+ });`
712
+ }
713
+ \`\`\`
714
+
715
+ ---
716
+
717
+ ## Ciclo TDD
718
+
719
+ \`\`\`
720
+ 1. RED: Escrever teste que FALHA
721
+ 2. GREEN: Escrever código MÍNIMO para passar
722
+ 3. REFACTOR: Melhorar sem quebrar testes
723
+ 4. REPEAT
724
+ \`\`\`
725
+
726
+ ---
727
+
728
+ ## Checklist
729
+
730
+ \`\`\`
731
+ □ Teste escrito ANTES do código
732
+ □ Teste falha antes da implementação (RED)
733
+ □ Implementação mínima para passar (GREEN)
734
+ □ Refatoração sem quebrar testes (REFACTOR)
735
+ □ Happy path coberto
736
+ □ Error path coberto
737
+ □ Boundary cases cobertos
738
+ □ Cobertura atinge o mínimo do projeto
739
+ \`\`\`
740
+ `;
741
+ }
742
+
743
+ /**
744
+ * Generate ADR template with optional pre-filled examples from tech stack
745
+ */
746
+ export function generateAdrTemplate(ctx?: EnrichedTemplateContext | TemplateContext): string {
747
+ const enriched = getEnriched(ctx);
748
+ const stack = ctx && 'stack' in ctx ? ctx.stack : undefined;
749
+ const domain = enriched.domain;
750
+
751
+ let exampleDecision = '[Título da Decisão]';
752
+ let contextDescription = '[descrever o contexto de negócio e técnico]';
753
+ let decisionDescription = '[descrever a decisão claramente]';
754
+ let alternativeOne = '[alternativa 1]';
755
+ let alternativeTwo = '[alternativa 2]';
756
+
757
+ // Generate tech stack specific examples (framework-aware)
758
+ if (stack) {
759
+ const framework = stack.frameworks[0] || 'Backend Framework';
760
+ const database = stack.frameworks.find((f) => ['PostgreSQL', 'MongoDB', 'MySQL', 'SQLite', 'Redis'].includes(f)) || 'PostgreSQL';
761
+ const adrLangs = stack.languages.map((l) => l.toLowerCase());
762
+ const adrIsPython = adrLangs.includes('python');
763
+ const adrIsDart = adrLangs.includes('dart');
764
+ const adrIsGo = adrLangs.includes('go');
765
+ const adrIsJava = adrLangs.includes('java') || adrLangs.includes('kotlin');
766
+
767
+ exampleDecision = `Uso de ${framework} para Backend`;
768
+
769
+ if (adrIsPython) {
770
+ contextDescription = `O projeto requer uma API REST escalável com Python. Precisamos escolher um framework que:
771
+ - Suporte async/await nativo
772
+ - Tenha tipagem com Pydantic e validação automática
773
+ - Tenha comunidade ativa e documentação excelente`;
774
+ decisionDescription = `Decidimos usar ${framework} como framework backend principal. ${framework} oferece:
775
+ - Async/await nativo com alto desempenho
776
+ - Validação automática via Pydantic
777
+ - Documentação OpenAPI/Swagger automática
778
+ - Suporte a bancos de dados (SQLAlchemy, Tortoise ORM, etc.)`;
779
+ alternativeOne = 'Django REST Framework';
780
+ alternativeTwo = 'Flask + extensões';
781
+ } else if (adrIsDart) {
782
+ contextDescription = `O projeto requer um aplicativo mobile multiplataforma. Precisamos escolher um framework que:
783
+ - Suporte iOS e Android com um único codebase
784
+ - Tenha hot-reload e boa experiência de desenvolvimento
785
+ - Tenha widgets nativos e alta performance`;
786
+ decisionDescription = `Decidimos usar ${framework} como framework principal. ${framework} oferece:
787
+ - UI declarativa com widgets nativos
788
+ - Hot-reload para desenvolvimento rápido
789
+ - Compilação nativa para iOS e Android
790
+ - Ecossistema de pacotes via pub.dev`;
791
+ alternativeOne = 'React Native';
792
+ alternativeTwo = 'Kotlin Multiplatform';
793
+ } else if (adrIsGo) {
794
+ contextDescription = `O projeto requer um serviço backend de alta performance. Precisamos escolher uma stack que:
795
+ - Tenha concorrência nativa eficiente
796
+ - Suporte compilação estática e deploy simplificado
797
+ - Tenha forte tipagem e performance previsível`;
798
+ decisionDescription = `Decidimos usar ${framework} como framework principal. ${framework} oferece:
799
+ - Goroutines para concorrência eficiente
800
+ - Binário estático único para deploy
801
+ - Performance previsível e baixo footprint
802
+ - Ecossistema robusto de middleware`;
803
+ alternativeOne = 'net/http padrão + chi router';
804
+ alternativeTwo = 'Fiber (Express-like para Go)';
805
+ } else if (adrIsJava) {
806
+ contextDescription = `O projeto requer uma API REST enterprise-grade. Precisamos escolher um framework que:
807
+ - Suporte injeção de dependência nativa
808
+ - Tenha ecossistema maduro e produção comprovada
809
+ - Tenha integração com bancos de dados (JPA/Hibernate)`;
810
+ decisionDescription = `Decidimos usar ${framework} como framework backend principal. ${framework} oferece:
811
+ - Injeção de dependência nativa
812
+ - Ecossistema maduro com milhares de extensões
813
+ - Suporte a JPA/Hibernate para persistência
814
+ - Segurança via Spring Security / equivalente`;
815
+ alternativeOne = 'Quarkus (nativo GraalVM)';
816
+ alternativeTwo = 'Micronaut';
817
+ } else {
818
+ contextDescription = `O projeto requer uma API REST escalável com TypeScript. Precisamos escolher um framework que:
819
+ - Suporte TypeScript nativo
820
+ - Tenha decorators e dependency injection
821
+ - Tenha comunidade ativa e documentação excelente`;
822
+ decisionDescription = `Decidimos usar ${framework} como framework backend principal. ${framework} oferece:
823
+ - Arquitetura modular built-in
824
+ - Decorators para roteamento e middleware
825
+ - Injeção de dependência nativa
826
+ - Suporte a bancos de dados (TypeORM, Prisma, etc.)`;
827
+ alternativeOne = 'Express.js + middleware customizado';
828
+ alternativeTwo = 'Fastify';
829
+ }
830
+
831
+ // Add database-specific ADR if applicable
832
+ let dbDecision = '';
833
+ if (database) {
834
+ dbDecision = `
835
+
836
+ ---
837
+
838
+ ## ADR-002: Banco de Dados ${database}
839
+
840
+ **Status:** accepted
841
+ **Data:** 2024-01-15
842
+ **Autores:** [equipe técnica]
843
+
844
+ ### Contexto
845
+
846
+ Precisamos escolher um banco de dados relacional que:
847
+ - Suporte transações ACID
848
+ - Tenha integração com ${framework}
849
+ - Permita escalabilidade horizontal
850
+
851
+ ### Decisão
852
+
853
+ Escolhemos ${database} como banco de dados principal por:
854
+ - Suporte a JSON nativo
855
+ - Excelente performance em leitura/escrita
856
+ - Integração com ${adrIsPython ? 'SQLAlchemy/Alembic' : adrIsJava ? 'JPA/Hibernate' : adrIsGo ? 'GORM/sqlx' : 'TypeORM/Prisma'} é padrão
857
+
858
+ ### Alternativas Consideradas
859
+
860
+ | # | Alternativa | Prós | Contras |
861
+ |---|-----------|------|---------|
862
+ | 1 | MySQL | Popular, estável | Menos recursos avançados |
863
+ | 2 | MongoDB | Escalável | Sem ACID nativo, schema dinâmico |`;
864
+ return `# 📋 Template: ADR — Architecture Decision Record
865
+
866
+ > Use quando uma decisão técnica é significativa ou controversa.
867
+
868
+ ---
869
+
870
+ ## ADR-001: ${exampleDecision}
871
+
872
+ **Status:** proposed | accepted | deprecated | superseded by ADR-YYY
873
+ **Data:** YYYY-MM-DD
874
+ **Autores:** [quem participou da decisão]
875
+
876
+ ---
877
+
878
+ ### Contexto
879
+
880
+ > Qual é o problema ou necessidade que levou a esta decisão?
881
+
882
+ ${contextDescription}
883
+
884
+ ---
885
+
886
+ ### Decisão
887
+
888
+ > O que foi decidido?
889
+
890
+ ${decisionDescription}
891
+
892
+ ---
893
+
894
+ ### Alternativas Consideradas
895
+
896
+ | # | Alternativa | Prós | Contras | Por que descartada |
897
+ |---|-----------|------|---------|-------------------|
898
+ | 1 | ${alternativeOne} | [prós] | [contras] | [motivo] |
899
+ | 2 | ${alternativeTwo} | [prós] | [contras] | [motivo] |
900
+
901
+ ---
902
+
903
+ ### Consequências
904
+
905
+ **Positivas:**
906
+ - Arquitetura clara e escalável
907
+ - Código mais organizado e testável
908
+ - Comunidade ativa para suporte
909
+
910
+ **Negativas:**
911
+ - Curva de aprendizado para novos desenvolvedores
912
+ - Overhead de dependências
913
+
914
+ **Riscos:**
915
+ - Atualização de versões major — probabilidade: média
916
+
917
+ ---
918
+
919
+ ### Notas
920
+
921
+ - Revisar em 6 meses se a decisão continua válida
922
+ ${dbDecision}`;
923
+ }
924
+ }
925
+
926
+ // Add domain-specific ADR section
927
+ let domainAdrs = '';
928
+ if (domain?.domain === 'fintech') {
929
+ domainAdrs = `
930
+
931
+ ---
932
+
933
+ ## ADR-XXX: Criptografia de CPF e Dados Sensíveis
934
+
935
+ **Status:** proposed
936
+ **Data:** YYYY-MM-DD
937
+ **Autores:** [equipe de segurança]
938
+
939
+ ### Contexto
940
+
941
+ Dados de clientes (CPF, CNPJ, dados bancários) são críticos para fintech.
942
+ Precisamos de criptografia de dados sensíveis at-rest.
943
+
944
+ ### Decisão
945
+
946
+ Usar AES-256 para criptografia de dados sensíveis com chaves armazenadas no vault.
947
+
948
+ ### Alternativas Consideradas
949
+
950
+ | # | Alternativa | Segurança | Complexidade |
951
+ |---|-----------|----------|--------------|
952
+ | 1 | AES-256 | Alta | Média |
953
+ | 2 | RSA | Muito Alta | Alta |
954
+ | 3 | Nenhuma | Baixa | Baixa |`;
955
+ } else if (domain?.domain === 'healthtech') {
956
+ domainAdrs = `
957
+
958
+ ---
959
+
960
+ ## ADR-XXX: Conformidade HIPAA em Armazenamento
961
+
962
+ **Status:** proposed
963
+ **Data:** YYYY-MM-DD
964
+ **Autores:** [equipe de compliance]
965
+
966
+ ### Contexto
967
+
968
+ Dados de saúde devem estar em conformidade com HIPAA.
969
+ Precisamos garantir criptografia, auditoria e retenção apropriada.
970
+
971
+ ### Decisão
972
+
973
+ Implementar criptografia AES-256, logging de acesso e retenção de dados por 7 anos.`;
974
+ }
975
+
976
+ return `# 📋 Template: ADR — Architecture Decision Record
977
+
978
+ > Use quando uma decisão técnica é significativa ou controversa.
979
+
980
+ ---
981
+
982
+ ## ADR-XXX: ${exampleDecision}
983
+
984
+ **Status:** proposed | accepted | deprecated | superseded by ADR-YYY
985
+ **Data:** YYYY-MM-DD
986
+ **Autores:** [quem participou da decisão]
987
+
988
+ ---
989
+
990
+ ### Contexto
991
+
992
+ > Qual é o problema ou necessidade que levou a esta decisão?
993
+
994
+ ${contextDescription}
995
+
996
+ ---
997
+
998
+ ### Decisão
999
+
1000
+ > O que foi decidido?
1001
+
1002
+ ${decisionDescription}
1003
+
1004
+ ---
1005
+
1006
+ ### Alternativas Consideradas
1007
+
1008
+ | # | Alternativa | Prós | Contras | Por que descartada |
1009
+ |---|-----------|------|---------|-------------------|
1010
+ | 1 | ${alternativeOne} | [prós] | [contras] | [motivo] |
1011
+ | 2 | ${alternativeTwo} | [prós] | [contras] | [motivo] |
1012
+
1013
+ ---
1014
+
1015
+ ### Consequências
1016
+
1017
+ **Positivas:**
1018
+ - [consequência positiva 1]
1019
+ - [consequência positiva 2]
1020
+
1021
+ **Negativas:**
1022
+ - [consequência negativa 1]
1023
+ - [mitigação: como minimizar]
1024
+
1025
+ **Riscos:**
1026
+ - [risco 1] — probabilidade: [alta/média/baixa]
1027
+
1028
+ ---
1029
+
1030
+ ### Notas
1031
+
1032
+ - [qualquer informação adicional]${domainAdrs}
1033
+ `;
1034
+ }
1035
+
1036
+ /**
1037
+ * Generate Threat Model template with optional pre-filled domain-specific threats
1038
+ */
1039
+ export function generateThreatModelTemplate(ctx?: EnrichedTemplateContext | TemplateContext): string {
1040
+ const enriched = getEnriched(ctx);
1041
+ const domain = enriched.domain;
1042
+ const businessEntities = domain?.businessEntities || [];
1043
+ const compliance = domain?.compliance || [];
1044
+
1045
+ let featureName = '[Nome]';
1046
+ let actors = `| [ator 1] | [alto/médio/baixo] | [dados/recursos] |`;
1047
+ let sensitiveData = `| [dado 1] | PII / Financeiro / Auth | [como proteger] |`;
1048
+ let domainSpecificThreats = '';
1049
+
1050
+ // Generate domain-specific actors and threats
1051
+ if (domain?.domain === 'fintech') {
1052
+ featureName = 'Transferência Bancária';
1053
+ actors = `| Usuário | Alto | Conta bancária, saldo |
1054
+ | Sistema Interno | Alto | Todas as transações |
1055
+ | Banco Parceiro | Médio | Dados de rota |
1056
+ | Auditor (interno) | Médio | Logs de transações |`;
1057
+
1058
+ sensitiveData = `| CPF | PII | AES-256 at-rest, TLS in-transit |
1059
+ | Número de Conta | Financeiro | AES-256 + masking |
1060
+ | Saldo | Financeiro | Hash verificável |
1061
+ | Histórico de Transações | Auditoria | Criptografado, signed |`;
1062
+
1063
+ domainSpecificThreats = `
1064
+
1065
+ ---
1066
+
1067
+ ## Ameaças Específicas de Fintech
1068
+
1069
+ | Ameaça | Descrição | Mitigação |
1070
+ |--------|-----------|-----------|
1071
+ | Falsificação de Identidade | Hacker usa CPF falso para abrir conta | Validação com gov API, SMS 2FA |
1072
+ | Tamperização de Saldo | Atacante modifica saldo direto no DB | Checksums, transações com assinatura |
1073
+ | Roubo de Sessão | Hijack de cookie de autenticação | HTTPS, SameSite cookie, token rotation |
1074
+ | Negação de Transferência | Usuário nega ter feito transação | Auditoria, e-mail de confirmação |
1075
+ | Bloqueio de Serviço | DDoS na API de transações | Rate limiting, WAF, CDN |
1076
+ | Escalonamento de Permissão | Admin faz transferência não autorizada | RBAC, audit logging, segregação |`;
1077
+ } else if (domain?.domain === 'tax' || domain?.subDomain === 'tax-processing') {
1078
+ featureName = 'Cálculo e Envio de Imposto';
1079
+ actors = `| Contribuinte | Alto | Declaração, CPF, rendimentos |
1080
+ | Contador | Médio | Dados do cliente, acesso a declaração |
1081
+ | Receita Federal | Médio | Declaração enviada, comprovantes |
1082
+ | Auditor Interno | Médio | Logs de processamento, erros |`;
1083
+
1084
+ sensitiveData = `| CPF/CNPJ | PII | AES-256, masking em logs |
1085
+ | Rendimentos Totais | Financeiro | Criptografado |
1086
+ | Deduções e Benefícios | Pessoal | Criptografado |
1087
+ | Histórico de Envios | Auditoria | Signed, imutável |`;
1088
+
1089
+ domainSpecificThreats = `
1090
+
1091
+ ---
1092
+
1093
+ ## Ameaças Específicas de Impostos
1094
+
1095
+ | Ameaça | Descrição | Mitigação |
1096
+ |--------|-----------|-----------|
1097
+ | Falsificação de Receita | Declarar rendimento falso | Cruzamento com dados da Receita Federal |
1098
+ | Tamperização de Cálculo | Hacker reduz imposto devido | Validação automática, recálculo periódico |
1099
+ | Vazamento de Dados | Exposição de CPF/rendimento | Criptografia, LGPD compliance |
1100
+ | Negação de Envio | Usuário nega envio ao fisco | Timestamp assinado, audit log |
1101
+ | Indisponibilidade na Época | Servidor cai no último dia | SLA 99.9%, failover automático |
1102
+ | Acesso não Autorizado | Contador acessa dado de cliente errado | RBAC granular, segregação de dados |`;
1103
+ } else if (domain?.domain === 'healthtech') {
1104
+ featureName = 'Acesso a Histórico Médico';
1105
+ actors = `| Paciente | Alto | Histórico médico, exames, receitas |
1106
+ | Médico | Alto | Prontuário do paciente |
1107
+ | Farmacêutico | Médio | Prescrições, alergias |
1108
+ | Auditor Compliance | Médio | Logs de acesso, consentimento |`;
1109
+
1110
+ sensitiveData = `| Nome Paciente | PII | Criptografado, HIPAA compliant |
1111
+ | Histórico Médico | Saúde | AES-256, acesso restrito |
1112
+ | Medicamentos | Saúde | Criptografado, masking em logs |
1113
+ | Resultado de Exames | Saúde | Criptografado, assinado digitalmente |`;
1114
+
1115
+ domainSpecificThreats = `
1116
+
1117
+ ---
1118
+
1119
+ ## Ameaças Específicas de Healthtech
1120
+
1121
+ | Ameaça | Descrição | Mitigação |
1122
+ |--------|-----------|-----------|
1123
+ | Acesso não Autorizado | Outro médico lê prontuário | RBAC por especialidade, audit |
1124
+ | Adulteração de Histórico | Alterar resultado de exame | Blockchain/assinatura digital |
1125
+ | Vazamento de Dados | Exposição de histórico médico | Criptografia, isolamento de rede |
1126
+ | Negação de Diagnóstico | Paciente nega consentimento | Digital signature + timestamp |
1127
+ | Indisponibilidade | Sistema cai durante consulta | Backup em tempo real, SLA 99.95% |
1128
+ | Privilégio Elevado | Admin lê dados de qualquer paciente | Segregação de funções, logging |`;
1129
+ }
1130
+
1131
+ return `# 🛡️ Template: Threat Model (STRIDE)
1132
+
1133
+ > Use para features que lidam com dados sensíveis, pagamentos, autenticação.
1134
+
1135
+ ---
1136
+
1137
+ ## Feature: ${featureName}
1138
+
1139
+ ### Atores e Assets
1140
+
1141
+ | Ator | Nível de Confiança | Assets que Acessa |
1142
+ |------|-------------------|------------------|
1143
+ ${actors}
1144
+
1145
+ ---
1146
+
1147
+ ### Análise STRIDE
1148
+
1149
+ | Categoria | Ameaça | Probabilidade | Impacto | Mitigação |
1150
+ |-----------|--------|-------------|---------|-----------|
1151
+ | **S**poofing | Identidade falsa / autenticação fraca | M | A | MFA, JWT assinado, validação gov |
1152
+ | **T**ampering | Alteração de dados em trânsito/repouso | M | A | HTTPS, assinatura digital, checksums |
1153
+ | **R**epudiation | Negar ação realizada | M | A | Audit log detalhado com timestamp |
1154
+ | **I**nformation Disclosure | Vazamento de dados sensíveis | A | A | Criptografia AES-256, LGPD compliance |
1155
+ | **D**enial of Service | Serviço indisponível (DDoS, travamento) | M | A | Rate limiting, WAF, scaling automático |
1156
+ | **E**levation of Privilege | Escalar permissão (user → admin) | M | A | RBAC granular, segregação de funções |
1157
+
1158
+ ---
1159
+
1160
+ ### Dados Sensíveis
1161
+
1162
+ | Dado | Classificação | Proteção |
1163
+ |------|-------------|----------|
1164
+ ${sensitiveData}
1165
+
1166
+ ---
1167
+
1168
+ ### Conformidade e Requisitos Regulatórios
1169
+
1170
+ ${
1171
+ compliance.length > 0
1172
+ ? `| Regulamento | Aplicável | Verificação |
1173
+ |-------------|-----------|-------------|
1174
+ ${compliance.map((c) => `| ${c.name} | Sim | ${c.mandatoryChecks[0] || 'Auditoria'} |`).join('\n')}`
1175
+ : `| Regulamento | Aplicável | Verificação |
1176
+ |-------------|-----------|-------------|
1177
+ | LGPD (dados pessoais) | Depende | Consentimento, direito ao esquecimento |
1178
+ | Conformidade de Dados | Depende | Criptografia, HTTPS, audit logs |`
1179
+ }
1180
+
1181
+ ---
1182
+
1183
+ ### Checklist de Segurança
1184
+
1185
+ \`\`\`
1186
+ □ Input validado e sanitizado
1187
+ □ Output encodado (XSS prevention)
1188
+ □ Queries parametrizadas (SQL injection)
1189
+ □ Autenticação obrigatória (MFA quando sensível)
1190
+ □ Autorização por role/permission (RBAC)
1191
+ □ Dados sensíveis criptografados at rest (AES-256)
1192
+ □ Dados sensíveis criptografados in transit (TLS 1.2+)
1193
+ □ Rate limiting implementado
1194
+ □ Audit log para ações sensíveis (timestamp + usuário)
1195
+ □ Secrets em variáveis de ambiente (não hardcoded)
1196
+ □ Consentimento e transparência (LGPD/GDPR)
1197
+ □ Testes de penetração agendados
1198
+ \`\`\`
1199
+ ${domainSpecificThreats}
1200
+ `;
1201
+ }