@girardelli/architect 2.2.0 → 4.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 (296) hide show
  1. package/README.md +105 -116
  2. package/__test_agent_output__/INDEX.md +1 -0
  3. package/__test_agent_output__/agents/AGENT-ORCHESTRATOR.md +1 -0
  4. package/__test_agent_output__/agents/DATABASE-ENGINEER.md +174 -0
  5. package/__test_agent_output__/agents/QA-TEST-ENGINEER.md +138 -0
  6. package/__test_agent_output__/agents/SECURITY-AUDITOR.md +106 -0
  7. package/__test_agent_output__/agents/TECH-DEBT-CONTROLLER.md +104 -0
  8. package/__test_agent_output__/agents/TYPESCRIPT-BACKEND-DEVELOPER.md +135 -0
  9. package/__test_agent_output__/guards/CODE-REVIEW-CHECKLIST.md +95 -0
  10. package/__test_agent_output__/guards/PREFLIGHT.md +200 -0
  11. package/__test_agent_output__/guards/QUALITY-GATES.md +1 -0
  12. package/__test_agent_output__/rules/00-general.md +229 -0
  13. package/__test_agent_output__/rules/01-architecture.md +191 -0
  14. package/__test_agent_output__/rules/02-security.md +402 -0
  15. package/__test_agent_output__/rules/03-nestjs.md +124 -0
  16. package/__test_agent_output__/templates/ADR.md +95 -0
  17. package/__test_agent_output__/templates/BDD.md +58 -0
  18. package/__test_agent_output__/templates/C4.md +68 -0
  19. package/__test_agent_output__/templates/TDD.md +86 -0
  20. package/__test_agent_output__/templates/THREAT-MODEL.md +82 -0
  21. package/__test_agent_output__/workflows/fix-bug.md +228 -0
  22. package/__test_agent_output__/workflows/new-feature.md +311 -0
  23. package/__test_agent_output__/workflows/review.md +95 -0
  24. package/__test_context_7RvUrO/src/modules/empty/empty.ts +0 -0
  25. package/__test_context_Rf5fNJ/src/modules/mixed/mixed.ts +5 -0
  26. package/__test_context_WRCnYH/src/modules/test/test.ts +10 -0
  27. package/__test_context_YsnVS3/src/modules/test/test.ts +10 -0
  28. package/__test_context_w7XZeH/src/modules/mixed/mixed.ts +5 -0
  29. package/__test_context_y5noh6/src/modules/empty/empty.ts +0 -0
  30. package/__test_framework__24OjAu/package.json +1 -0
  31. package/__test_framework__3ZDZsx/pyproject.toml +8 -0
  32. package/__test_framework__4T54Jn/package.json +1 -0
  33. package/__test_framework__4tlXu9/pyproject.toml +8 -0
  34. package/__test_framework__6boWqQ/Pipfile +6 -0
  35. package/__test_framework__6gygMU/pom.xml +10 -0
  36. package/__test_framework__6kxj0N/go.mod +8 -0
  37. package/__test_framework__7CEoXw/pom.xml +10 -0
  38. package/__test_framework__85DDz0/Pipfile +6 -0
  39. package/__test_framework__9WrRIr/pom.xml +7 -0
  40. package/__test_framework__ANqGKl/Gemfile +5 -0
  41. package/__test_framework__BCXTEM/go.mod +3 -0
  42. package/__test_framework__BHiPNq/setup.py +2 -0
  43. package/__test_framework__BqkiKv/package.json +1 -0
  44. package/__test_framework__C5yd8X/Pipfile.lock +1 -0
  45. package/__test_framework__C5yd8X/requirements.txt +1 -0
  46. package/__test_framework__C87d3a/manage.py +1 -0
  47. package/__test_framework__C87d3a/requirements.txt +2 -0
  48. package/__test_framework__DXNwc5/build.gradle +7 -0
  49. package/__test_framework__GhHSt3/build.gradle.kts +4 -0
  50. package/__test_framework__GzklJP/Cargo.toml +7 -0
  51. package/__test_framework__H4hd13/go.mod +8 -0
  52. package/__test_framework__HKjOXO/composer.json +1 -0
  53. package/__test_framework__HaDN45/Gemfile +3 -0
  54. package/__test_framework__IBO7YG/pyproject.toml +9 -0
  55. package/__test_framework__JwSOyF/pyproject.toml +6 -0
  56. package/__test_framework__K6HrCr/build.gradle +2 -0
  57. package/__test_framework__KzRPlh/pubspec.yaml +9 -0
  58. package/__test_framework__L6uIym/pyproject.toml +6 -0
  59. package/__test_framework__LOdoGK/requirements.txt +4 -0
  60. package/__test_framework__LgHzss/package.json +1 -0
  61. package/__test_framework__M76M6q/Gemfile +5 -0
  62. package/__test_framework__Mr9vWW/composer.json +1 -0
  63. package/__test_framework__N03Gnv/package.json +1 -0
  64. package/__test_framework__Num4UE/requirements +1 -0
  65. package/__test_framework__OAGw3Y/build.gradle +7 -0
  66. package/__test_framework__OQc8yG/pubspec.yaml +9 -0
  67. package/__test_framework__OwKZcd/requirements.txt +3 -0
  68. package/__test_framework__P0gFv7/requirements +1 -0
  69. package/__test_framework__PN55Rq/package.json +1 -0
  70. package/__test_framework__PQiqX8/pubspec.yaml +3 -0
  71. package/__test_framework__RBHsg7/composer.json +1 -0
  72. package/__test_framework__RHxif4/Cargo.toml +7 -0
  73. package/__test_framework__T0v0p1/Cargo.toml +4 -0
  74. package/__test_framework__Tu0clt/Pipfile.lock +1 -0
  75. package/__test_framework__Tu0clt/requirements.txt +1 -0
  76. package/__test_framework__TwDj9P/Cargo.toml +4 -0
  77. package/__test_framework__VQJNC4/pom.xml +7 -0
  78. package/__test_framework__W6sm05/package.json +1 -0
  79. package/__test_framework__W7vBLy/pyproject.toml +4 -0
  80. package/__test_framework__WNJOWT/setup.py +2 -0
  81. package/__test_framework__WSJs7U/package.json +1 -0
  82. package/__test_framework__YQ5VpA/build.gradle.kts +4 -0
  83. package/__test_framework__ZNEUEs/package.json +1 -0
  84. package/__test_framework__Znt922/pom.xml +7 -0
  85. package/__test_framework__azyg0h/pom.xml +7 -0
  86. package/__test_framework__c6otLr/package.json +1 -0
  87. package/__test_framework__cl9S9G/build.gradle +2 -0
  88. package/__test_framework__eilvV4/composer.json +1 -0
  89. package/__test_framework__gQZxXO/manage.py +1 -0
  90. package/__test_framework__gQZxXO/requirements.txt +2 -0
  91. package/__test_framework__ghvl26/poetry.lock +1 -0
  92. package/__test_framework__ghvl26/pyproject.toml +2 -0
  93. package/__test_framework__hR7b9U/Makefile +11 -0
  94. package/__test_framework__iESVsi/composer.json +1 -0
  95. package/__test_framework__jm6TJy/package.json +1 -0
  96. package/__test_framework__kBUpjs/pyproject.toml +9 -0
  97. package/__test_framework__kqoZrw/requirements.txt +4 -0
  98. package/__test_framework__lWkoyO/pyproject.toml +4 -0
  99. package/__test_framework__mTKnUO/package.json +1 -0
  100. package/__test_framework__nCeZwe/Makefile +11 -0
  101. package/__test_framework__oljsU0/package.json +1 -0
  102. package/__test_framework__osRG4q/go.mod +3 -0
  103. package/__test_framework__pCHH4F/package.json +1 -0
  104. package/__test_framework__pExx6E/Gemfile +3 -0
  105. package/__test_framework__pyBoGd/pyproject.toml +5 -0
  106. package/__test_framework__qw16VQ/package.json +1 -0
  107. package/__test_framework__rRayrG/package.json +1 -0
  108. package/__test_framework__s82zO5/package.json +1 -0
  109. package/__test_framework__tp8MFK/pyproject.toml +5 -0
  110. package/__test_framework__w44k4w/composer.json +1 -0
  111. package/__test_framework__yefPZY/poetry.lock +1 -0
  112. package/__test_framework__yefPZY/pyproject.toml +2 -0
  113. package/__test_framework__zCiyDT/requirements.txt +3 -0
  114. package/__test_framework__zGZN3j/pubspec.yaml +3 -0
  115. package/__test_framework__zXpnxL/package.json +1 -0
  116. package/architect-run.sh +431 -0
  117. package/assets/banner-v3.html +561 -0
  118. package/dist/agent-generator/context-enricher.d.ts +58 -0
  119. package/dist/agent-generator/context-enricher.d.ts.map +1 -0
  120. package/dist/agent-generator/context-enricher.js +581 -0
  121. package/dist/agent-generator/context-enricher.js.map +1 -0
  122. package/dist/agent-generator/domain-inferrer.d.ts +52 -0
  123. package/dist/agent-generator/domain-inferrer.d.ts.map +1 -0
  124. package/dist/agent-generator/domain-inferrer.js +575 -0
  125. package/dist/agent-generator/domain-inferrer.js.map +1 -0
  126. package/dist/agent-generator/framework-detector.d.ts +40 -0
  127. package/dist/agent-generator/framework-detector.d.ts.map +1 -0
  128. package/dist/agent-generator/framework-detector.js +611 -0
  129. package/dist/agent-generator/framework-detector.js.map +1 -0
  130. package/dist/agent-generator/index.d.ts +33 -0
  131. package/dist/agent-generator/index.d.ts.map +1 -0
  132. package/dist/agent-generator/index.js +477 -0
  133. package/dist/agent-generator/index.js.map +1 -0
  134. package/dist/agent-generator/stack-detector.d.ts +12 -0
  135. package/dist/agent-generator/stack-detector.d.ts.map +1 -0
  136. package/dist/agent-generator/stack-detector.js +128 -0
  137. package/dist/agent-generator/stack-detector.js.map +1 -0
  138. package/dist/agent-generator/templates/core/agents.d.ts +17 -0
  139. package/dist/agent-generator/templates/core/agents.d.ts.map +1 -0
  140. package/dist/agent-generator/templates/core/agents.js +1252 -0
  141. package/dist/agent-generator/templates/core/agents.js.map +1 -0
  142. package/dist/agent-generator/templates/core/architecture-rules.d.ts +7 -0
  143. package/dist/agent-generator/templates/core/architecture-rules.d.ts.map +1 -0
  144. package/dist/agent-generator/templates/core/architecture-rules.js +274 -0
  145. package/dist/agent-generator/templates/core/architecture-rules.js.map +1 -0
  146. package/dist/agent-generator/templates/core/general-rules.d.ts +8 -0
  147. package/dist/agent-generator/templates/core/general-rules.d.ts.map +1 -0
  148. package/dist/agent-generator/templates/core/general-rules.js +301 -0
  149. package/dist/agent-generator/templates/core/general-rules.js.map +1 -0
  150. package/dist/agent-generator/templates/core/index-md.d.ts +7 -0
  151. package/dist/agent-generator/templates/core/index-md.d.ts.map +1 -0
  152. package/dist/agent-generator/templates/core/index-md.js +246 -0
  153. package/dist/agent-generator/templates/core/index-md.js.map +1 -0
  154. package/dist/agent-generator/templates/core/orchestrator.d.ts +8 -0
  155. package/dist/agent-generator/templates/core/orchestrator.d.ts.map +1 -0
  156. package/dist/agent-generator/templates/core/orchestrator.js +422 -0
  157. package/dist/agent-generator/templates/core/orchestrator.js.map +1 -0
  158. package/dist/agent-generator/templates/core/preflight.d.ts +8 -0
  159. package/dist/agent-generator/templates/core/preflight.d.ts.map +1 -0
  160. package/dist/agent-generator/templates/core/preflight.js +213 -0
  161. package/dist/agent-generator/templates/core/preflight.js.map +1 -0
  162. package/dist/agent-generator/templates/core/quality-gates.d.ts +11 -0
  163. package/dist/agent-generator/templates/core/quality-gates.d.ts.map +1 -0
  164. package/dist/agent-generator/templates/core/quality-gates.js +254 -0
  165. package/dist/agent-generator/templates/core/quality-gates.js.map +1 -0
  166. package/dist/agent-generator/templates/core/security-rules.d.ts +7 -0
  167. package/dist/agent-generator/templates/core/security-rules.d.ts.map +1 -0
  168. package/dist/agent-generator/templates/core/security-rules.js +528 -0
  169. package/dist/agent-generator/templates/core/security-rules.js.map +1 -0
  170. package/dist/agent-generator/templates/core/skills-generator.d.ts +6 -0
  171. package/dist/agent-generator/templates/core/skills-generator.d.ts.map +1 -0
  172. package/dist/agent-generator/templates/core/skills-generator.js +207 -0
  173. package/dist/agent-generator/templates/core/skills-generator.js.map +1 -0
  174. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts +7 -0
  175. package/dist/agent-generator/templates/core/workflow-fix-bug.d.ts.map +1 -0
  176. package/dist/agent-generator/templates/core/workflow-fix-bug.js +237 -0
  177. package/dist/agent-generator/templates/core/workflow-fix-bug.js.map +1 -0
  178. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts +8 -0
  179. package/dist/agent-generator/templates/core/workflow-new-feature.d.ts.map +1 -0
  180. package/dist/agent-generator/templates/core/workflow-new-feature.js +321 -0
  181. package/dist/agent-generator/templates/core/workflow-new-feature.js.map +1 -0
  182. package/dist/agent-generator/templates/core/workflow-review.d.ts +7 -0
  183. package/dist/agent-generator/templates/core/workflow-review.d.ts.map +1 -0
  184. package/dist/agent-generator/templates/core/workflow-review.js +104 -0
  185. package/dist/agent-generator/templates/core/workflow-review.js.map +1 -0
  186. package/dist/agent-generator/templates/domain/index.d.ts +22 -0
  187. package/dist/agent-generator/templates/domain/index.d.ts.map +1 -0
  188. package/dist/agent-generator/templates/domain/index.js +1176 -0
  189. package/dist/agent-generator/templates/domain/index.js.map +1 -0
  190. package/dist/agent-generator/templates/stack/index.d.ts +8 -0
  191. package/dist/agent-generator/templates/stack/index.d.ts.map +1 -0
  192. package/dist/agent-generator/templates/stack/index.js +695 -0
  193. package/dist/agent-generator/templates/stack/index.js.map +1 -0
  194. package/dist/agent-generator/templates/template-helpers.d.ts +75 -0
  195. package/dist/agent-generator/templates/template-helpers.d.ts.map +1 -0
  196. package/dist/agent-generator/templates/template-helpers.js +726 -0
  197. package/dist/agent-generator/templates/template-helpers.js.map +1 -0
  198. package/dist/agent-generator/types.d.ts +196 -0
  199. package/dist/agent-generator/types.d.ts.map +1 -0
  200. package/dist/agent-generator/types.js +27 -0
  201. package/dist/agent-generator/types.js.map +1 -0
  202. package/dist/analyzer.d.ts +5 -0
  203. package/dist/analyzer.d.ts.map +1 -1
  204. package/dist/analyzer.js +35 -4
  205. package/dist/analyzer.js.map +1 -1
  206. package/dist/analyzers/forecast.d.ts +85 -0
  207. package/dist/analyzers/forecast.d.ts.map +1 -0
  208. package/dist/analyzers/forecast.js +337 -0
  209. package/dist/analyzers/forecast.js.map +1 -0
  210. package/dist/analyzers/git-cache.d.ts +7 -0
  211. package/dist/analyzers/git-cache.d.ts.map +1 -0
  212. package/dist/analyzers/git-cache.js +41 -0
  213. package/dist/analyzers/git-cache.js.map +1 -0
  214. package/dist/analyzers/git-history.d.ts +113 -0
  215. package/dist/analyzers/git-history.d.ts.map +1 -0
  216. package/dist/analyzers/git-history.js +333 -0
  217. package/dist/analyzers/git-history.js.map +1 -0
  218. package/dist/analyzers/index.d.ts +10 -0
  219. package/dist/analyzers/index.d.ts.map +1 -0
  220. package/dist/analyzers/index.js +7 -0
  221. package/dist/analyzers/index.js.map +1 -0
  222. package/dist/analyzers/temporal-scorer.d.ts +72 -0
  223. package/dist/analyzers/temporal-scorer.d.ts.map +1 -0
  224. package/dist/analyzers/temporal-scorer.js +140 -0
  225. package/dist/analyzers/temporal-scorer.js.map +1 -0
  226. package/dist/cli.d.ts +2 -3
  227. package/dist/cli.d.ts.map +1 -1
  228. package/dist/cli.js +275 -113
  229. package/dist/cli.js.map +1 -1
  230. package/dist/html-reporter.d.ts +3 -1
  231. package/dist/html-reporter.d.ts.map +1 -1
  232. package/dist/html-reporter.js +248 -12
  233. package/dist/html-reporter.js.map +1 -1
  234. package/dist/index.d.ts +16 -3
  235. package/dist/index.d.ts.map +1 -1
  236. package/dist/index.js +63 -4
  237. package/dist/index.js.map +1 -1
  238. package/dist/project-summarizer.d.ts +18 -0
  239. package/dist/project-summarizer.d.ts.map +1 -0
  240. package/dist/project-summarizer.js +306 -0
  241. package/dist/project-summarizer.js.map +1 -0
  242. package/dist/refactor-reporter.js +1 -1
  243. package/dist/types.d.ts +13 -0
  244. package/dist/types.d.ts.map +1 -1
  245. package/package.json +12 -3
  246. package/src/agent-generator/context-enricher.ts +643 -0
  247. package/src/agent-generator/domain-inferrer.ts +625 -0
  248. package/src/agent-generator/framework-detector.ts +669 -0
  249. package/src/agent-generator/index.ts +555 -0
  250. package/src/agent-generator/stack-detector.ts +103 -0
  251. package/src/agent-generator/templates/core/agents.ts +1293 -0
  252. package/src/agent-generator/templates/core/architecture-rules.ts +287 -0
  253. package/src/agent-generator/templates/core/general-rules.ts +306 -0
  254. package/src/agent-generator/templates/core/index-md.ts +260 -0
  255. package/src/agent-generator/templates/core/orchestrator.ts +459 -0
  256. package/src/agent-generator/templates/core/preflight.ts +215 -0
  257. package/src/agent-generator/templates/core/quality-gates.ts +256 -0
  258. package/src/agent-generator/templates/core/security-rules.ts +543 -0
  259. package/src/agent-generator/templates/core/skills-generator.ts +236 -0
  260. package/src/agent-generator/templates/core/workflow-fix-bug.ts +239 -0
  261. package/src/agent-generator/templates/core/workflow-new-feature.ts +323 -0
  262. package/src/agent-generator/templates/core/workflow-review.ts +106 -0
  263. package/src/agent-generator/templates/domain/index.ts +1201 -0
  264. package/src/agent-generator/templates/stack/index.ts +705 -0
  265. package/src/agent-generator/templates/template-helpers.ts +776 -0
  266. package/src/agent-generator/types.ts +232 -0
  267. package/src/analyzer.ts +38 -4
  268. package/src/analyzers/forecast.ts +496 -0
  269. package/src/analyzers/git-cache.ts +52 -0
  270. package/src/analyzers/git-history.ts +488 -0
  271. package/src/analyzers/index.ts +33 -0
  272. package/src/analyzers/temporal-scorer.ts +227 -0
  273. package/src/cli.ts +316 -117
  274. package/src/html-reporter.ts +263 -13
  275. package/src/index.ts +92 -9
  276. package/src/project-summarizer.ts +347 -0
  277. package/src/refactor-reporter.ts +1 -1
  278. package/src/types.ts +10 -0
  279. package/tests/agent-generator.test.ts +411 -0
  280. package/tests/analyzers-integration.test.ts +174 -0
  281. package/tests/architect-adapter-enrichment.test.ts +9 -0
  282. package/tests/context-enricher.test.ts +971 -0
  283. package/tests/forecast.test.ts +509 -0
  284. package/tests/framework-detector.test.ts +1172 -0
  285. package/tests/git-history.test.ts +254 -0
  286. package/tests/scanner.test.ts +7 -8
  287. package/tests/scorer.test.ts +588 -0
  288. package/tests/stack-detector.test.ts +241 -0
  289. package/tests/template-generation.test.ts +706 -0
  290. package/tests/template-helpers.test.ts +1152 -0
  291. package/tests/temporal-scorer.test.ts +307 -0
  292. package/dist/agent-generator.d.ts +0 -106
  293. package/dist/agent-generator.d.ts.map +0 -1
  294. package/dist/agent-generator.js +0 -1398
  295. package/dist/agent-generator.js.map +0 -1
  296. package/src/agent-generator.ts +0 -1526
@@ -0,0 +1,52 @@
1
+ import { AnalysisReport } from '../types.js';
2
+ import { DomainInsights } from './types.js';
3
+ /**
4
+ * DomainInferrer — Analyzes project metadata, file names, module structure,
5
+ * README content, and keywords to infer the business domain and context.
6
+ *
7
+ * This enables context-aware agent generation that understands WHAT the
8
+ * project does, not just HOW it's built.
9
+ */
10
+ export declare class DomainInferrer {
11
+ private static readonly DOMAIN_PATTERNS;
12
+ private static readonly COMPLIANCE_MAP;
13
+ /**
14
+ * Infer domain insights from the analysis report.
15
+ */
16
+ infer(report: AnalysisReport, projectPath: string): DomainInsights;
17
+ /**
18
+ * Extract all relevant keywords from the project.
19
+ */
20
+ private extractAllKeywords;
21
+ /**
22
+ * Classify project domain based on keyword matching.
23
+ */
24
+ private classifyDomain;
25
+ /**
26
+ * Extract business entities from model/entity/schema file names.
27
+ */
28
+ private extractBusinessEntities;
29
+ private inferEntityLayer;
30
+ /**
31
+ * Infer compliance requirements from domain and keywords.
32
+ */
33
+ private inferCompliance;
34
+ /**
35
+ * Detect external integrations from file names, imports, and keywords.
36
+ */
37
+ private detectIntegrations;
38
+ /**
39
+ * Build a human-readable description of the project.
40
+ */
41
+ private buildDescription;
42
+ /**
43
+ * Split camelCase, PascalCase, snake_case, kebab-case identifiers into parts.
44
+ */
45
+ /**
46
+ * Extract keywords from project files on disk (pyproject.toml, README.md, package.json).
47
+ * These provide high-value domain signals that the scanner may miss.
48
+ */
49
+ private extractKeywordsFromProjectFiles;
50
+ private splitIdentifier;
51
+ }
52
+ //# sourceMappingURL=domain-inferrer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-inferrer.d.ts","sourceRoot":"","sources":["../../src/agent-generator/domain-inferrer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EACL,cAAc,EAIf,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,qBAAa,cAAc;IAEzB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CA8ErC;IAGF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAuFpC;IAEF;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc;IA2BlE;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAwD1B;;OAEG;IACH,OAAO,CAAC,cAAc;IAgEtB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAqC/B,OAAO,CAAC,gBAAgB;IASxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAkDvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuD1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;OAEG;IACH;;;OAGG;IACH,OAAO,CAAC,+BAA+B;IAoFvC,OAAO,CAAC,eAAe;CAOxB"}
@@ -0,0 +1,575 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ /**
4
+ * DomainInferrer — Analyzes project metadata, file names, module structure,
5
+ * README content, and keywords to infer the business domain and context.
6
+ *
7
+ * This enables context-aware agent generation that understands WHAT the
8
+ * project does, not just HOW it's built.
9
+ */
10
+ export class DomainInferrer {
11
+ /**
12
+ * Infer domain insights from the analysis report.
13
+ */
14
+ infer(report, projectPath) {
15
+ const allKeywords = this.extractAllKeywords(report);
16
+ // Boost keywords from project files (pyproject.toml, README, package.json)
17
+ const fileKeywords = this.extractKeywordsFromProjectFiles(projectPath);
18
+ for (const kw of fileKeywords) {
19
+ if (!allKeywords.includes(kw))
20
+ allKeywords.push(kw);
21
+ }
22
+ const { domain, subDomain, confidence } = this.classifyDomain(allKeywords);
23
+ const businessEntities = this.extractBusinessEntities(report);
24
+ const compliance = this.inferCompliance(domain, subDomain, allKeywords);
25
+ const integrations = this.detectIntegrations(report, allKeywords);
26
+ const description = this.buildDescription(report, domain, subDomain);
27
+ return {
28
+ domain,
29
+ subDomain,
30
+ description,
31
+ businessEntities,
32
+ compliance,
33
+ integrations,
34
+ keywords: allKeywords,
35
+ confidence,
36
+ };
37
+ }
38
+ /**
39
+ * Extract all relevant keywords from the project.
40
+ */
41
+ extractAllKeywords(report) {
42
+ const keywords = new Set();
43
+ // From ProjectSummary keywords
44
+ if (report.projectSummary?.keywords) {
45
+ for (const kw of report.projectSummary.keywords) {
46
+ keywords.add(kw.toLowerCase());
47
+ }
48
+ }
49
+ // From module names
50
+ if (report.projectSummary?.modules) {
51
+ for (const mod of report.projectSummary.modules) {
52
+ keywords.add(mod.name.toLowerCase());
53
+ // Split camelCase/snake_case module names
54
+ for (const part of this.splitIdentifier(mod.name)) {
55
+ keywords.add(part.toLowerCase());
56
+ }
57
+ }
58
+ }
59
+ // From file paths — extract meaningful segments
60
+ for (const node of report.dependencyGraph.nodes) {
61
+ const segments = node.split('/').filter(s => !['src', 'lib', 'app', 'core', 'common', 'shared', 'utils', 'helpers',
62
+ 'index', 'main', '__init__', 'test', 'tests', 'spec', '__tests__',
63
+ 'node_modules', 'dist', 'build', '.git'].includes(s.toLowerCase()));
64
+ for (const seg of segments) {
65
+ const name = seg.replace(/\.[^.]+$/, ''); // remove extension
66
+ for (const part of this.splitIdentifier(name)) {
67
+ if (part.length > 2) {
68
+ keywords.add(part.toLowerCase());
69
+ }
70
+ }
71
+ }
72
+ }
73
+ // From project name
74
+ if (report.projectInfo.name) {
75
+ for (const part of this.splitIdentifier(report.projectInfo.name)) {
76
+ keywords.add(part.toLowerCase());
77
+ }
78
+ }
79
+ // From description/purpose
80
+ if (report.projectSummary?.description) {
81
+ const words = report.projectSummary.description.toLowerCase().split(/\s+/);
82
+ for (const w of words) {
83
+ if (w.length > 3)
84
+ keywords.add(w.replace(/[^a-z0-9]/g, ''));
85
+ }
86
+ }
87
+ return [...keywords].filter(k => k.length > 0);
88
+ }
89
+ /**
90
+ * Classify project domain based on keyword matching.
91
+ */
92
+ classifyDomain(keywords) {
93
+ let bestDomain = 'general';
94
+ let bestSubDomain = 'general';
95
+ let bestScore = 0;
96
+ let bestMaxPossible = 1;
97
+ for (const [domain, config] of Object.entries(DomainInferrer.DOMAIN_PATTERNS)) {
98
+ const matchedKeywords = config.keywords.filter(kw => keywords.some(k => k.includes(kw) || kw.includes(k)));
99
+ const score = matchedKeywords.length;
100
+ if (score > bestScore) {
101
+ bestScore = score;
102
+ bestDomain = domain;
103
+ bestMaxPossible = config.keywords.length;
104
+ // Find best sub-domain
105
+ let bestSubScore = 0;
106
+ for (const [subDomain, subKeywords] of Object.entries(config.subDomains)) {
107
+ const subMatched = subKeywords.filter(kw => keywords.some(k => k.includes(kw) || kw.includes(k))).length;
108
+ if (subMatched > bestSubScore) {
109
+ bestSubScore = subMatched;
110
+ bestSubDomain = subDomain;
111
+ }
112
+ }
113
+ }
114
+ }
115
+ // Confidence formula:
116
+ // - Base: matched keywords / min(total possible, 8) (lower denominator = easier to reach high confidence)
117
+ // - Boost: +0.1 if sub-domain also matched (cross-validation)
118
+ // - Boost: +0.1 if multiple entities or integrations hint at the same domain
119
+ // - Cap at 0.95 (never 100% without manual confirmation)
120
+ let confidence = bestScore > 0 ? Math.min(1, bestScore / Math.min(bestMaxPossible, 8)) : 0;
121
+ // Sub-domain match boost
122
+ if (bestSubDomain !== 'general' && bestSubDomain !== bestDomain) {
123
+ confidence = Math.min(1, confidence + 0.1);
124
+ }
125
+ // Second-best domain gap boost (high gap = more certain)
126
+ let secondBestScore = 0;
127
+ for (const [domain, config] of Object.entries(DomainInferrer.DOMAIN_PATTERNS)) {
128
+ if (domain === bestDomain)
129
+ continue;
130
+ const matchedKeywords = config.keywords.filter(kw => keywords.some(k => k.includes(kw) || kw.includes(k)));
131
+ if (matchedKeywords.length > secondBestScore) {
132
+ secondBestScore = matchedKeywords.length;
133
+ }
134
+ }
135
+ if (bestScore > 0 && bestScore >= secondBestScore * 2) {
136
+ confidence = Math.min(1, confidence + 0.1);
137
+ }
138
+ // Cap at 0.95
139
+ confidence = Math.min(0.95, confidence);
140
+ return { domain: bestDomain, subDomain: bestSubDomain, confidence };
141
+ }
142
+ /**
143
+ * Extract business entities from model/entity/schema file names.
144
+ */
145
+ extractBusinessEntities(report) {
146
+ const entities = [];
147
+ const entityPatterns = [
148
+ /(?:models?|entities|entity|schemas?)\/([^/]+)\./i,
149
+ /([^/]+)\.(model|entity|schema)\./i,
150
+ /([^/]+)\.models?\./i,
151
+ ];
152
+ for (const filePath of report.dependencyGraph.nodes) {
153
+ for (const pattern of entityPatterns) {
154
+ const match = filePath.match(pattern);
155
+ if (match) {
156
+ const name = match[1].replace(/[-_]/g, ' ').replace(/\b\w/g, l => l.toUpperCase()).trim();
157
+ if (name && name !== 'Index' && name !== 'Base' && name !== 'Init') {
158
+ const layer = this.inferEntityLayer(filePath);
159
+ entities.push({
160
+ name,
161
+ source: filePath,
162
+ fields: [], // Would need AST parsing for fields
163
+ relationships: [],
164
+ layer,
165
+ });
166
+ }
167
+ }
168
+ }
169
+ }
170
+ // Deduplicate by name
171
+ const seen = new Set();
172
+ return entities.filter(e => {
173
+ const key = e.name.toLowerCase();
174
+ if (seen.has(key))
175
+ return false;
176
+ seen.add(key);
177
+ return true;
178
+ });
179
+ }
180
+ inferEntityLayer(filePath) {
181
+ const lower = filePath.toLowerCase();
182
+ if (lower.includes('/model'))
183
+ return 'model';
184
+ if (lower.includes('/entity') || lower.includes('/entities'))
185
+ return 'entity';
186
+ if (lower.includes('/schema'))
187
+ return 'schema';
188
+ if (lower.includes('/dto'))
189
+ return 'dto';
190
+ return 'unknown';
191
+ }
192
+ /**
193
+ * Infer compliance requirements from domain and keywords.
194
+ */
195
+ inferCompliance(domain, subDomain, keywords) {
196
+ const requirements = [];
197
+ // Domain-level compliance
198
+ const domainCompliance = DomainInferrer.COMPLIANCE_MAP[domain];
199
+ if (domainCompliance) {
200
+ requirements.push(...domainCompliance);
201
+ }
202
+ // Sub-domain specific compliance
203
+ const subCompliance = DomainInferrer.COMPLIANCE_MAP[subDomain];
204
+ if (subCompliance) {
205
+ requirements.push(...subCompliance);
206
+ }
207
+ // Generic LGPD if Brazilian indicators found
208
+ const brIndicators = ['cpf', 'cnpj', 'cep', 'lgpd', 'brasil', 'brazil', 'pt-br', 'ptbr', 'receita'];
209
+ const hasBrazilianContext = keywords.some(k => brIndicators.some(br => k.includes(br)));
210
+ if (hasBrazilianContext && !requirements.some(r => r.name.includes('LGPD'))) {
211
+ requirements.push({
212
+ name: 'LGPD',
213
+ reason: 'Brazilian context detected — personal data processing requires LGPD compliance',
214
+ mandatoryChecks: [
215
+ 'Personal data encrypted at rest and in transit',
216
+ 'Consent management for data processing',
217
+ 'Right to deletion implementation',
218
+ 'Data breach notification procedures',
219
+ ],
220
+ });
221
+ }
222
+ // PII detection regardless of domain
223
+ const piiIndicators = ['email', 'password', 'phone', 'address', 'ssn', 'cpf', 'passport', 'birth'];
224
+ const hasPII = keywords.some(k => piiIndicators.some(p => k.includes(p)));
225
+ if (hasPII && !requirements.some(r => r.name === 'LGPD' || r.name === 'GDPR')) {
226
+ requirements.push({
227
+ name: 'PII-Protection',
228
+ reason: 'Personal Identifiable Information (PII) detected in project entities',
229
+ mandatoryChecks: [
230
+ 'PII fields encrypted at rest',
231
+ 'Access logging for PII data',
232
+ 'Data masking in logs and error messages',
233
+ 'Secure deletion procedures',
234
+ ],
235
+ });
236
+ }
237
+ return requirements;
238
+ }
239
+ /**
240
+ * Detect external integrations from file names, imports, and keywords.
241
+ */
242
+ detectIntegrations(report, keywords) {
243
+ const integrations = [];
244
+ const allFiles = report.dependencyGraph.nodes.join(' ').toLowerCase();
245
+ const integrationPatterns = [
246
+ // Payment
247
+ { name: 'Stripe', type: 'payment', signals: ['stripe'] },
248
+ { name: 'PagSeguro', type: 'payment', signals: ['pagseguro'] },
249
+ { name: 'Mercado Pago', type: 'payment', signals: ['mercadopago', 'mercado-pago'] },
250
+ { name: 'PIX', type: 'payment', signals: ['pix'] },
251
+ // Auth
252
+ { name: 'OAuth2/OIDC', type: 'auth', signals: ['oauth', 'oidc', 'openid'] },
253
+ { name: 'JWT', type: 'auth', signals: ['jwt', 'jsonwebtoken'] },
254
+ { name: 'Keycloak', type: 'auth', signals: ['keycloak'] },
255
+ { name: 'Auth0', type: 'auth', signals: ['auth0'] },
256
+ // Database
257
+ { name: 'PostgreSQL', type: 'database', signals: ['postgres', 'postgresql', 'pg'] },
258
+ { name: 'MongoDB', type: 'database', signals: ['mongo', 'mongodb', 'mongoose'] },
259
+ { name: 'Redis', type: 'database', signals: ['redis', 'ioredis'] },
260
+ { name: 'MySQL', type: 'database', signals: ['mysql', 'mysql2'] },
261
+ { name: 'SQLite', type: 'database', signals: ['sqlite'] },
262
+ // Queue/Messaging
263
+ { name: 'RabbitMQ', type: 'queue', signals: ['rabbitmq', 'amqp'] },
264
+ { name: 'Kafka', type: 'queue', signals: ['kafka'] },
265
+ { name: 'AWS SQS', type: 'queue', signals: ['sqs'] },
266
+ { name: 'BullMQ', type: 'queue', signals: ['bull', 'bullmq'] },
267
+ // Storage
268
+ { name: 'AWS S3', type: 'storage', signals: ['s3', 'aws-sdk'] },
269
+ { name: 'MinIO', type: 'storage', signals: ['minio'] },
270
+ // Government APIs
271
+ { name: 'Receita Federal', type: 'government', signals: ['receita', 'rfb', 'ecac', 'sefaz'] },
272
+ { name: 'SERPRO', type: 'government', signals: ['serpro'] },
273
+ { name: 'eSocial', type: 'government', signals: ['esocial'] },
274
+ // Other
275
+ { name: 'Email (SMTP)', type: 'other', signals: ['smtp', 'nodemailer', 'sendgrid', 'ses'] },
276
+ { name: 'ElasticSearch', type: 'other', signals: ['elastic', 'elasticsearch'] },
277
+ { name: 'Sentry', type: 'other', signals: ['sentry'] },
278
+ ];
279
+ for (const pattern of integrationPatterns) {
280
+ const matched = pattern.signals.find(s => allFiles.includes(s) || keywords.some(k => k.includes(s)));
281
+ if (matched) {
282
+ integrations.push({
283
+ name: pattern.name,
284
+ type: pattern.type,
285
+ detectedFrom: matched,
286
+ });
287
+ }
288
+ }
289
+ return integrations;
290
+ }
291
+ /**
292
+ * Build a human-readable description of the project.
293
+ */
294
+ buildDescription(report, domain, subDomain) {
295
+ const summary = report.projectSummary;
296
+ if (summary?.description && summary.description.length > 20) {
297
+ return summary.description;
298
+ }
299
+ const name = report.projectInfo.name || 'Project';
300
+ const langs = report.projectInfo.primaryLanguages.join('/');
301
+ const files = report.projectInfo.totalFiles;
302
+ const lines = report.projectInfo.totalLines.toLocaleString();
303
+ if (domain !== 'general') {
304
+ return `${name} — ${domain}/${subDomain} application built with ${langs}. ${files} files, ${lines} lines.`;
305
+ }
306
+ return `${name} — ${langs} application with ${files} files and ${lines} lines.`;
307
+ }
308
+ /**
309
+ * Split camelCase, PascalCase, snake_case, kebab-case identifiers into parts.
310
+ */
311
+ /**
312
+ * Extract keywords from project files on disk (pyproject.toml, README.md, package.json).
313
+ * These provide high-value domain signals that the scanner may miss.
314
+ */
315
+ extractKeywordsFromProjectFiles(projectPath) {
316
+ const keywords = [];
317
+ // pyproject.toml — description, classifiers, project name
318
+ const pyprojectPath = join(projectPath, 'pyproject.toml');
319
+ if (existsSync(pyprojectPath)) {
320
+ try {
321
+ const content = readFileSync(pyprojectPath, 'utf-8');
322
+ // Extract description
323
+ const descMatch = content.match(/description\s*=\s*"([^"]+)"/);
324
+ if (descMatch) {
325
+ const words = descMatch[1].toLowerCase().split(/\s+/);
326
+ for (const w of words) {
327
+ if (w.length > 3)
328
+ keywords.push(w.replace(/[^a-z0-9]/g, ''));
329
+ }
330
+ }
331
+ // Extract classifiers (e.g., "Topic :: Office/Business :: Financial")
332
+ const classifiers = content.match(/classifiers\s*=\s*\[([\s\S]*?)\]/);
333
+ if (classifiers) {
334
+ const topics = classifiers[1].match(/"Topic\s*::\s*([^"]+)"/g);
335
+ if (topics) {
336
+ for (const topic of topics) {
337
+ const parts = topic.replace(/"/g, '').split('::').map(p => p.trim().toLowerCase());
338
+ for (const p of parts) {
339
+ if (p.length > 3 && p !== 'topic')
340
+ keywords.push(p.replace(/[^a-z0-9]/g, ''));
341
+ }
342
+ }
343
+ }
344
+ }
345
+ // Extract project name
346
+ const nameMatch = content.match(/\[project\]\s*\n(?:[\s\S]*?)name\s*=\s*"([^"]+)"/);
347
+ if (nameMatch) {
348
+ for (const part of this.splitIdentifier(nameMatch[1])) {
349
+ keywords.push(part.toLowerCase());
350
+ }
351
+ }
352
+ }
353
+ catch { /* ignore read errors */ }
354
+ }
355
+ // README.md — first 500 chars for domain keywords
356
+ const readmePaths = ['README.md', 'readme.md', 'README.rst'];
357
+ for (const readmeName of readmePaths) {
358
+ const readmePath = join(projectPath, readmeName);
359
+ if (existsSync(readmePath)) {
360
+ try {
361
+ const content = readFileSync(readmePath, 'utf-8').slice(0, 1500);
362
+ // Extract heading and first paragraph
363
+ const lines = content.split('\n').filter(l => l.trim().length > 0).slice(0, 10);
364
+ for (const line of lines) {
365
+ const words = line.replace(/[#*_`\[\]()]/g, '').toLowerCase().split(/\s+/);
366
+ for (const w of words) {
367
+ if (w.length > 3)
368
+ keywords.push(w.replace(/[^a-z0-9]/g, ''));
369
+ }
370
+ }
371
+ }
372
+ catch { /* ignore */ }
373
+ break;
374
+ }
375
+ }
376
+ // package.json — description and keywords
377
+ const pkgPath = join(projectPath, 'package.json');
378
+ if (existsSync(pkgPath)) {
379
+ try {
380
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
381
+ if (pkg.description) {
382
+ const words = pkg.description.toLowerCase().split(/\s+/);
383
+ for (const w of words) {
384
+ if (w.length > 3)
385
+ keywords.push(w.replace(/[^a-z0-9]/g, ''));
386
+ }
387
+ }
388
+ if (Array.isArray(pkg.keywords)) {
389
+ for (const kw of pkg.keywords) {
390
+ keywords.push(kw.toLowerCase());
391
+ }
392
+ }
393
+ }
394
+ catch { /* ignore */ }
395
+ }
396
+ return keywords.filter(k => k.length > 0);
397
+ }
398
+ splitIdentifier(name) {
399
+ return name
400
+ .replace(/([a-z])([A-Z])/g, '$1 $2')
401
+ .replace(/[-_./\\]/g, ' ')
402
+ .split(/\s+/)
403
+ .filter(p => p.length > 0);
404
+ }
405
+ }
406
+ // Domain keyword mappings - patterns that indicate specific domains
407
+ DomainInferrer.DOMAIN_PATTERNS = {
408
+ fintech: {
409
+ keywords: ['payment', 'transaction', 'invoice', 'billing', 'ledger', 'account', 'transfer', 'wallet', 'bank', 'loan', 'credit', 'debit', 'finance', 'fiscal', 'tax', 'irpf', 'imposto', 'receita', 'declaracao', 'contribuinte', 'pix', 'boleto', 'nfe', 'nota-fiscal'],
410
+ subDomains: {
411
+ 'tax-processing': ['irpf', 'tax', 'imposto', 'fiscal', 'receita', 'declaracao', 'contribuinte', 'deducao', 'rendimento'],
412
+ 'payment-gateway': ['payment', 'pix', 'boleto', 'stripe', 'checkout', 'charge'],
413
+ 'banking': ['bank', 'account', 'transfer', 'balance', 'statement', 'ledger'],
414
+ 'invoicing': ['invoice', 'billing', 'nfe', 'nota-fiscal', 'fatura'],
415
+ 'lending': ['loan', 'credit', 'installment', 'interest', 'amortization'],
416
+ },
417
+ },
418
+ healthtech: {
419
+ keywords: ['patient', 'medical', 'health', 'diagnosis', 'prescription', 'clinical', 'hospital', 'doctor', 'appointment', 'ehr', 'fhir', 'dicom', 'sus', 'prontuario', 'consulta', 'exame'],
420
+ subDomains: {
421
+ 'ehr': ['patient', 'record', 'prontuario', 'clinical', 'ehr'],
422
+ 'telemedicine': ['appointment', 'consulta', 'video', 'teleconsulta'],
423
+ 'diagnostics': ['diagnosis', 'exame', 'lab', 'result'],
424
+ },
425
+ },
426
+ 'e-commerce': {
427
+ keywords: ['product', 'cart', 'order', 'catalog', 'shipping', 'checkout', 'inventory', 'price', 'discount', 'coupon', 'store', 'shop', 'marketplace', 'seller', 'buyer', 'carrinho', 'pedido', 'estoque', 'frete'],
428
+ subDomains: {
429
+ 'marketplace': ['seller', 'buyer', 'marketplace', 'commission'],
430
+ 'retail': ['product', 'catalog', 'inventory', 'store', 'shop'],
431
+ 'logistics': ['shipping', 'delivery', 'frete', 'tracking', 'warehouse'],
432
+ },
433
+ },
434
+ edtech: {
435
+ keywords: ['student', 'course', 'lesson', 'quiz', 'grade', 'enrollment', 'teacher', 'classroom', 'curriculum', 'lms', 'aluno', 'aula', 'nota', 'matricula', 'professor'],
436
+ subDomains: {
437
+ 'lms': ['course', 'lesson', 'enrollment', 'lms', 'aula'],
438
+ 'assessment': ['quiz', 'grade', 'exam', 'prova', 'nota'],
439
+ },
440
+ },
441
+ saas: {
442
+ keywords: ['tenant', 'subscription', 'plan', 'workspace', 'organization', 'team', 'member', 'role', 'permission', 'billing', 'api-key', 'webhook', 'dashboard'],
443
+ subDomains: {
444
+ 'multi-tenant': ['tenant', 'workspace', 'organization'],
445
+ 'subscription': ['subscription', 'plan', 'billing', 'trial'],
446
+ },
447
+ },
448
+ iot: {
449
+ keywords: ['device', 'sensor', 'telemetry', 'mqtt', 'gateway', 'firmware', 'signal', 'measurement', 'monitoring', 'alert', 'threshold'],
450
+ subDomains: {
451
+ 'monitoring': ['sensor', 'telemetry', 'monitoring', 'measurement'],
452
+ 'device-management': ['device', 'firmware', 'gateway', 'provision'],
453
+ },
454
+ },
455
+ 'content-management': {
456
+ keywords: ['article', 'post', 'blog', 'page', 'cms', 'content', 'media', 'publish', 'author', 'category', 'tag', 'comment'],
457
+ subDomains: {
458
+ 'cms': ['article', 'post', 'publish', 'cms', 'content'],
459
+ 'media': ['media', 'image', 'video', 'upload', 'gallery'],
460
+ },
461
+ },
462
+ 'real-estate': {
463
+ keywords: ['property', 'listing', 'tenant', 'landlord', 'rent', 'lease', 'imovel', 'aluguel', 'inquilino', 'condominio'],
464
+ subDomains: {
465
+ 'property-management': ['property', 'tenant', 'rent', 'lease', 'condominio'],
466
+ 'listings': ['listing', 'search', 'filter', 'imovel'],
467
+ },
468
+ },
469
+ logistics: {
470
+ keywords: ['shipment', 'route', 'delivery', 'warehouse', 'fleet', 'driver', 'tracking', 'dispatch', 'load', 'cargo', 'entrega', 'rastreamento', 'frota', 'motorista'],
471
+ subDomains: {
472
+ 'fleet-management': ['fleet', 'driver', 'vehicle', 'frota', 'motorista'],
473
+ 'delivery': ['delivery', 'shipment', 'tracking', 'entrega', 'rastreamento'],
474
+ 'warehouse': ['warehouse', 'inventory', 'stock', 'storage'],
475
+ },
476
+ },
477
+ 'hr-management': {
478
+ keywords: ['employee', 'payroll', 'leave', 'attendance', 'hiring', 'candidate', 'department', 'salary', 'benefit', 'funcionario', 'folha', 'ferias', 'ponto', 'contratacao'],
479
+ subDomains: {
480
+ 'payroll': ['payroll', 'salary', 'folha', 'benefit', 'compensation'],
481
+ 'recruitment': ['hiring', 'candidate', 'interview', 'contratacao'],
482
+ 'time-tracking': ['attendance', 'leave', 'ponto', 'ferias'],
483
+ },
484
+ },
485
+ };
486
+ // Compliance mappings based on domain and geography
487
+ DomainInferrer.COMPLIANCE_MAP = {
488
+ fintech: [
489
+ {
490
+ name: 'PCI-DSS',
491
+ reason: 'Handles financial/payment data',
492
+ mandatoryChecks: [
493
+ 'Credit card data never stored in plaintext',
494
+ 'Payment tokens used instead of raw card numbers',
495
+ 'Audit trail for all financial transactions',
496
+ 'Encryption at rest for financial data',
497
+ 'Access controls with principle of least privilege',
498
+ ],
499
+ },
500
+ ],
501
+ 'tax-processing': [
502
+ {
503
+ name: 'LGPD',
504
+ reason: 'Processes Brazilian taxpayer personal data (CPF, income, assets)',
505
+ mandatoryChecks: [
506
+ 'CPF/CNPJ data encrypted at rest and in transit',
507
+ 'Consent management for data processing',
508
+ 'Right to deletion (direito ao esquecimento)',
509
+ 'Data minimization — only collect necessary fields',
510
+ 'Data breach notification procedures',
511
+ 'DPO (Data Protection Officer) contact documented',
512
+ 'Cross-border data transfer restrictions',
513
+ ],
514
+ },
515
+ {
516
+ name: 'RFB-Compliance',
517
+ reason: 'Integrates with Receita Federal do Brasil systems',
518
+ mandatoryChecks: [
519
+ 'Digital certificate (e-CPF/e-CNPJ) handling',
520
+ 'XML schema validation against RFB specifications',
521
+ 'Audit log for all tax calculation modifications',
522
+ 'Retention period compliance (5 years minimum)',
523
+ 'Hash validation for submitted declarations',
524
+ ],
525
+ },
526
+ ],
527
+ healthtech: [
528
+ {
529
+ name: 'HIPAA',
530
+ reason: 'Handles protected health information (PHI)',
531
+ mandatoryChecks: [
532
+ 'PHI encryption at rest and in transit',
533
+ 'Access audit logging for all PHI access',
534
+ 'Minimum necessary access principle',
535
+ 'Business Associate Agreements (BAA) tracking',
536
+ 'Breach notification within 60 days',
537
+ ],
538
+ },
539
+ {
540
+ name: 'LGPD-Health',
541
+ reason: 'Processes sensitive health data under Brazilian law',
542
+ mandatoryChecks: [
543
+ 'Explicit consent for health data processing',
544
+ 'Data anonymization where possible',
545
+ 'Restricted access to health records',
546
+ 'CFM/CRM compliance for medical data',
547
+ ],
548
+ },
549
+ ],
550
+ 'e-commerce': [
551
+ {
552
+ name: 'CDC',
553
+ reason: 'Consumer Defense Code (Código de Defesa do Consumidor)',
554
+ mandatoryChecks: [
555
+ 'Clear pricing display (no hidden fees)',
556
+ 'Right of withdrawal (7 days for online purchases)',
557
+ 'Order tracking transparency',
558
+ 'Invoice generation for all transactions',
559
+ ],
560
+ },
561
+ ],
562
+ 'hr-management': [
563
+ {
564
+ name: 'LGPD-Employment',
565
+ reason: 'Processes employee personal and financial data',
566
+ mandatoryChecks: [
567
+ 'Employee data encrypted at rest',
568
+ 'Salary data access restricted to HR and payroll',
569
+ 'Data retention aligned with labor law (5 years after termination)',
570
+ 'Consent for data processing beyond employment',
571
+ ],
572
+ },
573
+ ],
574
+ };
575
+ //# sourceMappingURL=domain-inferrer.js.map