@omnizap-system/omnizap 2.5.12

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 (425) hide show
  1. package/.clusterfuzzlite/Dockerfile +10 -0
  2. package/.env.example +907 -0
  3. package/.github/codeql/codeql-config.yml +10 -0
  4. package/.github/dependabot.yml +35 -0
  5. package/.github/workflows/ci.yml +73 -0
  6. package/.github/workflows/codeql.yml +106 -0
  7. package/.github/workflows/db-migration-check.yml +98 -0
  8. package/.github/workflows/dependency-review.yml +22 -0
  9. package/.github/workflows/deploy.yml +95 -0
  10. package/.github/workflows/release.yml +106 -0
  11. package/.github/workflows/security-attest-provenance.yml +51 -0
  12. package/.github/workflows/security-gitleaks.yml +34 -0
  13. package/.github/workflows/security-runner-hardening.yml +31 -0
  14. package/.github/workflows/security-scorecard.yml +44 -0
  15. package/.github/workflows/security-zap-baseline.yml +44 -0
  16. package/.github/workflows/security-zap-full-scan.yml +43 -0
  17. package/.github/workflows/security-zizmor.yml +36 -0
  18. package/.github/workflows/wiki-sync.yml +44 -0
  19. package/.gitleaks.toml +15 -0
  20. package/.prettierrc +34 -0
  21. package/CODE_OF_CONDUCT.md +114 -0
  22. package/LICENSE +56 -0
  23. package/README.md +110 -0
  24. package/SECURITY.md +110 -0
  25. package/app/config/index.js +4 -0
  26. package/app/configParts/adminIdentity.js +92 -0
  27. package/app/configParts/baileysConfig.js +1818 -0
  28. package/app/configParts/groupUtils.js +692 -0
  29. package/app/configParts/loggerConfig.js +394 -0
  30. package/app/configParts/messagePersistenceService.js +305 -0
  31. package/app/connection/baileysCompatibility.test.js +40 -0
  32. package/app/connection/baileysDbAuthState.js +344 -0
  33. package/app/connection/socketController.js +2243 -0
  34. package/app/controllers/messageController.js +7 -0
  35. package/app/controllers/messagePipeline/commandMiddleware.js +146 -0
  36. package/app/controllers/messagePipeline/conversationMiddleware.js +183 -0
  37. package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +522 -0
  38. package/app/controllers/messagePipeline/postProcessingMiddleware.js +41 -0
  39. package/app/controllers/messagePipeline/preProcessingMiddlewares.js +166 -0
  40. package/app/controllers/messageProcessingPipeline.js +699 -0
  41. package/app/modules/adminModule/AGENT.md +4056 -0
  42. package/app/modules/adminModule/adminAiHelpService.js +56 -0
  43. package/app/modules/adminModule/adminConfigRuntime.js +177 -0
  44. package/app/modules/adminModule/commandConfig.json +7122 -0
  45. package/app/modules/adminModule/groupCommandHandlers.js +1823 -0
  46. package/app/modules/adminModule/groupCommandHandlers.test.js +350 -0
  47. package/app/modules/adminModule/groupEventHandlers.js +399 -0
  48. package/app/modules/aiModule/AGENT.md +547 -0
  49. package/app/modules/aiModule/aiAiHelpService.js +14 -0
  50. package/app/modules/aiModule/aiConfigRuntime.js +135 -0
  51. package/app/modules/aiModule/catCommand.js +967 -0
  52. package/app/modules/aiModule/commandConfig.json +981 -0
  53. package/app/modules/analyticsModule/messageAnalysisEventRepository.js +83 -0
  54. package/app/modules/gameModule/AGENT.md +196 -0
  55. package/app/modules/gameModule/commandConfig.json +366 -0
  56. package/app/modules/gameModule/diceCommand.js +42 -0
  57. package/app/modules/gameModule/gameAiHelpService.js +14 -0
  58. package/app/modules/gameModule/gameConfigRuntime.js +68 -0
  59. package/app/modules/menuModule/AGENT.md +205 -0
  60. package/app/modules/menuModule/commandConfig.json +366 -0
  61. package/app/modules/menuModule/common.js +316 -0
  62. package/app/modules/menuModule/menuAiHelpService.js +14 -0
  63. package/app/modules/menuModule/menuConfigRuntime.js +68 -0
  64. package/app/modules/menuModule/menus.js +66 -0
  65. package/app/modules/playModule/AGENT.md +321 -0
  66. package/app/modules/playModule/commandConfig.json +584 -0
  67. package/app/modules/playModule/playAiHelpService.js +14 -0
  68. package/app/modules/playModule/playCommand.js +1417 -0
  69. package/app/modules/playModule/playConfigRuntime.js +68 -0
  70. package/app/modules/quoteModule/AGENT.md +199 -0
  71. package/app/modules/quoteModule/commandConfig.json +366 -0
  72. package/app/modules/quoteModule/quoteAiHelpService.js +14 -0
  73. package/app/modules/quoteModule/quoteCommand.js +842 -0
  74. package/app/modules/quoteModule/quoteConfigRuntime.js +68 -0
  75. package/app/modules/rpgPokemonModule/AGENT.md +229 -0
  76. package/app/modules/rpgPokemonModule/commandConfig.json +386 -0
  77. package/app/modules/rpgPokemonModule/rpgBattleCanvasRenderer.js +795 -0
  78. package/app/modules/rpgPokemonModule/rpgBattleService.js +2110 -0
  79. package/app/modules/rpgPokemonModule/rpgBattleService.test.js +770 -0
  80. package/app/modules/rpgPokemonModule/rpgEvolutionUtils.js +22 -0
  81. package/app/modules/rpgPokemonModule/rpgPokemonAiHelpService.js +14 -0
  82. package/app/modules/rpgPokemonModule/rpgPokemonCommand.js +174 -0
  83. package/app/modules/rpgPokemonModule/rpgPokemonConfigRuntime.js +68 -0
  84. package/app/modules/rpgPokemonModule/rpgPokemonDomain.js +192 -0
  85. package/app/modules/rpgPokemonModule/rpgPokemonDomain.test.js +93 -0
  86. package/app/modules/rpgPokemonModule/rpgPokemonEvolution.test.js +46 -0
  87. package/app/modules/rpgPokemonModule/rpgPokemonMessages.js +746 -0
  88. package/app/modules/rpgPokemonModule/rpgPokemonRepository.js +1847 -0
  89. package/app/modules/rpgPokemonModule/rpgPokemonService.js +6839 -0
  90. package/app/modules/rpgPokemonModule/rpgProfileCanvasRenderer.js +354 -0
  91. package/app/modules/statsModule/AGENT.md +320 -0
  92. package/app/modules/statsModule/commandConfig.json +540 -0
  93. package/app/modules/statsModule/globalRankingCommand.js +64 -0
  94. package/app/modules/statsModule/rankingCommand.js +41 -0
  95. package/app/modules/statsModule/rankingCommon.js +1305 -0
  96. package/app/modules/statsModule/statsAiHelpService.js +14 -0
  97. package/app/modules/statsModule/statsConfigRuntime.js +68 -0
  98. package/app/modules/stickerModule/AGENT.md +692 -0
  99. package/app/modules/stickerModule/addStickerMetadata.js +239 -0
  100. package/app/modules/stickerModule/commandConfig.json +1216 -0
  101. package/app/modules/stickerModule/convertToWebp.js +367 -0
  102. package/app/modules/stickerModule/stickerAiHelpService.js +14 -0
  103. package/app/modules/stickerModule/stickerCommand.js +446 -0
  104. package/app/modules/stickerModule/stickerConfigRuntime.js +68 -0
  105. package/app/modules/stickerModule/stickerConvertCommand.js +159 -0
  106. package/app/modules/stickerModule/stickerTextCommand.js +653 -0
  107. package/app/modules/stickerPackModule/AGENT.md +215 -0
  108. package/app/modules/stickerPackModule/autoPackCollectorRuntime.js +20 -0
  109. package/app/modules/stickerPackModule/autoPackCollectorService.js +357 -0
  110. package/app/modules/stickerPackModule/commandConfig.json +387 -0
  111. package/app/modules/stickerPackModule/domainEventOutboxRepository.js +227 -0
  112. package/app/modules/stickerPackModule/domainEvents.js +52 -0
  113. package/app/modules/stickerPackModule/semanticReclassificationEngine.js +429 -0
  114. package/app/modules/stickerPackModule/semanticReclassificationEngine.test.js +75 -0
  115. package/app/modules/stickerPackModule/semanticThemeClusterService.js +544 -0
  116. package/app/modules/stickerPackModule/stickerAssetClassificationRepository.js +400 -0
  117. package/app/modules/stickerPackModule/stickerAssetRepository.js +400 -0
  118. package/app/modules/stickerPackModule/stickerAssetReprocessQueueRepository.js +175 -0
  119. package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +3702 -0
  120. package/app/modules/stickerPackModule/stickerClassificationBackgroundRuntime.js +559 -0
  121. package/app/modules/stickerPackModule/stickerClassificationService.js +557 -0
  122. package/app/modules/stickerPackModule/stickerDedicatedTaskWorkerRuntime.js +249 -0
  123. package/app/modules/stickerPackModule/stickerDomainEventBus.js +65 -0
  124. package/app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js +208 -0
  125. package/app/modules/stickerPackModule/stickerMarketplaceDriftService.js +99 -0
  126. package/app/modules/stickerPackModule/stickerObjectStorageService.js +285 -0
  127. package/app/modules/stickerPackModule/stickerPackAiHelpService.js +14 -0
  128. package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +1148 -0
  129. package/app/modules/stickerPackModule/stickerPackConfigRuntime.js +68 -0
  130. package/app/modules/stickerPackModule/stickerPackEngagementRepository.js +152 -0
  131. package/app/modules/stickerPackModule/stickerPackErrors.js +30 -0
  132. package/app/modules/stickerPackModule/stickerPackInteractionEventRepository.js +101 -0
  133. package/app/modules/stickerPackModule/stickerPackItemRepository.js +432 -0
  134. package/app/modules/stickerPackModule/stickerPackMarketplaceService.js +313 -0
  135. package/app/modules/stickerPackModule/stickerPackMessageService.js +268 -0
  136. package/app/modules/stickerPackModule/stickerPackRepository.js +450 -0
  137. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRepository.js +179 -0
  138. package/app/modules/stickerPackModule/stickerPackScoreSnapshotRuntime.js +271 -0
  139. package/app/modules/stickerPackModule/stickerPackService.js +733 -0
  140. package/app/modules/stickerPackModule/stickerPackServiceRuntime.js +32 -0
  141. package/app/modules/stickerPackModule/stickerPackUtils.js +107 -0
  142. package/app/modules/stickerPackModule/stickerStorageService.js +559 -0
  143. package/app/modules/stickerPackModule/stickerWorkerPipelineRuntime.js +242 -0
  144. package/app/modules/stickerPackModule/stickerWorkerTaskQueueRepository.js +242 -0
  145. package/app/modules/systemMetricsModule/AGENT.md +193 -0
  146. package/app/modules/systemMetricsModule/commandConfig.json +344 -0
  147. package/app/modules/systemMetricsModule/pingCommand.js +399 -0
  148. package/app/modules/systemMetricsModule/systemMetricsAiHelpService.js +14 -0
  149. package/app/modules/systemMetricsModule/systemMetricsConfigRuntime.js +68 -0
  150. package/app/modules/tiktokModule/AGENT.md +196 -0
  151. package/app/modules/tiktokModule/commandConfig.json +366 -0
  152. package/app/modules/tiktokModule/tiktokAiHelpService.js +14 -0
  153. package/app/modules/tiktokModule/tiktokCommand.js +716 -0
  154. package/app/modules/tiktokModule/tiktokConfigRuntime.js +68 -0
  155. package/app/modules/userModule/AGENT.md +200 -0
  156. package/app/modules/userModule/commandConfig.json +386 -0
  157. package/app/modules/userModule/userAiHelpService.js +14 -0
  158. package/app/modules/userModule/userCommand.js +1155 -0
  159. package/app/modules/userModule/userConfigRuntime.js +68 -0
  160. package/app/modules/waifuPicsModule/AGENT.md +431 -0
  161. package/app/modules/waifuPicsModule/commandConfig.json +780 -0
  162. package/app/modules/waifuPicsModule/waifuPicsAiHelpService.js +14 -0
  163. package/app/modules/waifuPicsModule/waifuPicsCommand.js +586 -0
  164. package/app/modules/waifuPicsModule/waifuPicsConfigRuntime.js +68 -0
  165. package/app/observability/metrics.js +766 -0
  166. package/app/services/ai/aiHelpResponseCacheRepository.js +280 -0
  167. package/app/services/ai/aiLearningRepository.js +400 -0
  168. package/app/services/ai/commandConfigEnrichmentRepository.js +769 -0
  169. package/app/services/ai/commandConfigEnrichmentService.js +452 -0
  170. package/app/services/ai/commandConfigValidationService.js +443 -0
  171. package/app/services/ai/commandToolBuilderService.js +192 -0
  172. package/app/services/ai/conversationRouterService.js +516 -0
  173. package/app/services/ai/geminiService.js +115 -0
  174. package/app/services/ai/geminiService.test.js +87 -0
  175. package/app/services/ai/globalModuleAiHelpService.js +1412 -0
  176. package/app/services/ai/globalToolCallingService.js +203 -0
  177. package/app/services/ai/messageCommandExecutionService.js +391 -0
  178. package/app/services/ai/moduleAiHelpCoreService.js +1099 -0
  179. package/app/services/ai/moduleAiHelpWrapperFactory.js +65 -0
  180. package/app/services/ai/moduleCommandConfigRuntimeService.js +113 -0
  181. package/app/services/ai/moduleToolExecutorService.js +464 -0
  182. package/app/services/ai/moduleToolRegistryService.js +178 -0
  183. package/app/services/ai/toolCandidateSelectorService.js +781 -0
  184. package/app/services/auth/googleWebLinkService.js +80 -0
  185. package/app/services/auth/whatsappLoginLinkService.js +230 -0
  186. package/app/services/external/pokeApiService.js +398 -0
  187. package/app/services/group/groupMetadataService.js +311 -0
  188. package/app/services/infra/dbWriteQueue.js +874 -0
  189. package/app/services/infra/featureFlagService.js +131 -0
  190. package/app/services/infra/queueUtils.js +55 -0
  191. package/app/services/messaging/captchaService.js +491 -0
  192. package/app/services/messaging/messagePersistenceService.js +1 -0
  193. package/app/services/messaging/newsBroadcastService.js +347 -0
  194. package/app/services/sticker/stickerFocusService.js +347 -0
  195. package/app/services/sticker/stickerFocusService.test.js +43 -0
  196. package/app/store/aiPromptStore.js +38 -0
  197. package/app/store/conversationSessionStore.js +131 -0
  198. package/app/store/groupConfigStore.js +58 -0
  199. package/app/store/premiumUserStore.js +54 -0
  200. package/app/utils/antiLink/antiLinkModule.js +700 -0
  201. package/app/utils/http/getImageBufferModule.js +18 -0
  202. package/app/utils/json/jsonSanitizer.js +113 -0
  203. package/app/utils/json/jsonSanitizer.test.js +40 -0
  204. package/app/utils/systemMetrics/systemMetricsModule.js +88 -0
  205. package/app/workers/aiLearningWorker.js +605 -0
  206. package/app/workers/commandConfigEnrichmentWorker.js +242 -0
  207. package/database/index.js +2075 -0
  208. package/database/init.js +151 -0
  209. package/database/migrations/.gitkeep +0 -0
  210. package/database/migrations/20260307_d0_hardening_down.sql +64 -0
  211. package/database/migrations/20260307_d0_hardening_up.sql +79 -0
  212. package/database/migrations/20260307_d1_terms_acceptance_down.sql +11 -0
  213. package/database/migrations/20260307_d1_terms_acceptance_up.sql +37 -0
  214. package/database/migrations/20260307_d2_auth_hardening_down.sql +75 -0
  215. package/database/migrations/20260307_d2_auth_hardening_up.sql +100 -0
  216. package/database/migrations/20260314_d7_canonical_sender_down.sql +53 -0
  217. package/database/migrations/20260314_d7_canonical_sender_up.sql +114 -0
  218. package/database/migrations/20260406_d30_security_analytics_down.sql +95 -0
  219. package/database/migrations/20260406_d30_security_analytics_up.sql +292 -0
  220. package/database/migrations/20260407_d31_web_google_session_token_hardening_down.sql +2 -0
  221. package/database/migrations/20260407_d31_web_google_session_token_hardening_up.sql +17 -0
  222. package/database/migrations/20260408_d32_ai_help_response_cache_down.sql +1 -0
  223. package/database/migrations/20260408_d32_ai_help_response_cache_up.sql +22 -0
  224. package/database/migrations/20260409_d33_ai_learning_tables_down.sql +4 -0
  225. package/database/migrations/20260409_d33_ai_learning_tables_up.sql +52 -0
  226. package/database/migrations/20260410_d34_command_config_enrichment_down.sql +3 -0
  227. package/database/migrations/20260410_d34_command_config_enrichment_up.sql +48 -0
  228. package/database/schema.sql +1186 -0
  229. package/docker-compose.yml +104 -0
  230. package/docs/audits/stickerCatalogController-out-of-scope.md +103 -0
  231. package/docs/audits/stickerCatalogController-symbols.md +58 -0
  232. package/docs/compliance/acceptable-use-policy-2026-03-07.md +35 -0
  233. package/docs/compliance/dpa-b2b-standard-2026-03-07.md +80 -0
  234. package/docs/compliance/monthly-compliance-checklist-2026-03-07.md +88 -0
  235. package/docs/compliance/notice-and-takedown-policy-2026-03-07.md +34 -0
  236. package/docs/compliance/privacy-policy-2026-03-07.md +75 -0
  237. package/docs/compliance/subprocessors-inventory-2026-03-07.md +16 -0
  238. package/docs/database/production-db-evolution-runbook-2026q1.md +365 -0
  239. package/docs/security/dsar-lgpd-runbook-2026-03-07.md +86 -0
  240. package/docs/security/incident-response-lgpd-anpd-runbook-2026-03-07.md +77 -0
  241. package/docs/security/network-hardening-runbook-2026-03-07.md +137 -0
  242. package/docs/seo/omnizap-seo-playbook-br-2026-02-28.md +238 -0
  243. package/docs/seo/satellite-page-template.md +116 -0
  244. package/docs/seo/satellite-pages-phase1.json +364 -0
  245. package/docs/wiki/Home.md +120 -0
  246. package/docs/wiki/pair-extraordinaire-2026-03-08.md +3 -0
  247. package/docs/wiki/recent-changes-2026-03-08.md +47 -0
  248. package/ecosystem.prod.config.cjs +135 -0
  249. package/eslint.config.js +89 -0
  250. package/index.js +488 -0
  251. package/ml/clip_classifier/Dockerfile +18 -0
  252. package/ml/clip_classifier/README.md +118 -0
  253. package/ml/clip_classifier/adaptive_scoring.py +40 -0
  254. package/ml/clip_classifier/classifier.py +654 -0
  255. package/ml/clip_classifier/embedding_store.py +481 -0
  256. package/ml/clip_classifier/env_loader.py +15 -0
  257. package/ml/clip_classifier/llm_label_expander.py +144 -0
  258. package/ml/clip_classifier/main.py +213 -0
  259. package/ml/clip_classifier/requirements.txt +10 -0
  260. package/ml/clip_classifier/similarity_engine.py +74 -0
  261. package/new-logo.png +0 -0
  262. package/observability/alert-rules.yml +60 -0
  263. package/observability/grafana/dashboards/omnizap-mysql.json +136 -0
  264. package/observability/grafana/dashboards/omnizap-overview.json +170 -0
  265. package/observability/grafana/provisioning/dashboards/dashboards.yml +11 -0
  266. package/observability/grafana/provisioning/datasources/datasources.yml +15 -0
  267. package/observability/loki-config.yml +38 -0
  268. package/observability/mysql-setup.sql +46 -0
  269. package/observability/prometheus.yml +35 -0
  270. package/observability/promtail-config.yml +84 -0
  271. package/observability/sticker-catalog-slo.md +83 -0
  272. package/observability/sticker-scale-hardening-rollout.md +128 -0
  273. package/package.json +144 -0
  274. package/public/apple-touch-icon.png +0 -0
  275. package/public/assets/css/commands-react.input.css +71 -0
  276. package/public/assets/css/create-pack-react.input.css +31 -0
  277. package/public/assets/css/home-react.input.css +106 -0
  278. package/public/assets/css/login-react.input.css +58 -0
  279. package/public/assets/css/stickers-react.input.css +18 -0
  280. package/public/assets/css/terms-react.input.css +115 -0
  281. package/public/assets/css/user-react.input.css +57 -0
  282. package/public/assets/images/brand-icon-192.png +0 -0
  283. package/public/assets/images/brand-logo-128.webp +0 -0
  284. package/public/assets/images/hero-banner-1280.jpg +0 -0
  285. package/public/comandos/commands-catalog.json +4517 -0
  286. package/public/css/api-docs.css +161 -0
  287. package/public/css/stickers-admin.css +1288 -0
  288. package/public/css/styles.css +679 -0
  289. package/public/css/systemadm/admin.css +474 -0
  290. package/public/css/systemadm/base.css +73 -0
  291. package/public/css/systemadm/components.css +662 -0
  292. package/public/css/systemadm/layout.css +229 -0
  293. package/public/css/systemadm/tokens.css +56 -0
  294. package/public/favicon-16x16.png +0 -0
  295. package/public/favicon-32x32.png +0 -0
  296. package/public/favicon.ico +0 -0
  297. package/public/js/apps/apiDocsApp.js +235 -0
  298. package/public/js/apps/commandsReactApp.js +528 -0
  299. package/public/js/apps/createPackApp.js +1646 -0
  300. package/public/js/apps/homeReactApp.js +942 -0
  301. package/public/js/apps/loginReactApp.js +496 -0
  302. package/public/js/apps/stickersAdminApp.js +1753 -0
  303. package/public/js/apps/stickersApp.js +3797 -0
  304. package/public/js/apps/termsReactApp.js +528 -0
  305. package/public/js/apps/userApp.js +2540 -0
  306. package/public/js/apps/userProfile/actions.js +66 -0
  307. package/public/js/apps/userReactApp.js +547 -0
  308. package/public/js/catalog.js +950 -0
  309. package/public/pages/api-docs.html +40 -0
  310. package/public/pages/aup.html +158 -0
  311. package/public/pages/comandos.html +41 -0
  312. package/public/pages/dpa.html +227 -0
  313. package/public/pages/home.html +45 -0
  314. package/public/pages/licenca.html +182 -0
  315. package/public/pages/login.html +40 -0
  316. package/public/pages/notice-and-takedown.html +234 -0
  317. package/public/pages/politica-de-privacidade.html +251 -0
  318. package/public/pages/seo-bot-whatsapp-para-grupo.html +350 -0
  319. package/public/pages/seo-bot-whatsapp-sem-programar.html +350 -0
  320. package/public/pages/seo-como-automatizar-avisos-no-whatsapp.html +350 -0
  321. package/public/pages/seo-como-criar-comandos-whatsapp.html +350 -0
  322. package/public/pages/seo-como-evitar-spam-no-whatsapp.html +350 -0
  323. package/public/pages/seo-como-moderar-grupo-whatsapp.html +350 -0
  324. package/public/pages/seo-como-organizar-comunidade-whatsapp.html +350 -0
  325. package/public/pages/seo-melhor-bot-whatsapp-para-grupos.html +350 -0
  326. package/public/pages/stickers-admin.html +31 -0
  327. package/public/pages/stickers-create.html +41 -0
  328. package/public/pages/stickers.html +45 -0
  329. package/public/pages/suboperadores.html +237 -0
  330. package/public/pages/termos-de-uso-texto-integral.html +241 -0
  331. package/public/pages/termos-de-uso.html +41 -0
  332. package/public/pages/user-password-reset.html +32 -0
  333. package/public/pages/user-systemadm.html +508 -0
  334. package/public/pages/user.html +39 -0
  335. package/public/robots.txt +9 -0
  336. package/public/site.webmanifest +24 -0
  337. package/public/sitemap.xml +98 -0
  338. package/schemas/command-config.schema.json +582 -0
  339. package/scripts/baileys-compat-smoke.mjs +12 -0
  340. package/scripts/cache-bust.mjs +142 -0
  341. package/scripts/deploy.sh +916 -0
  342. package/scripts/email-broadcast-terms-update.mjs +170 -0
  343. package/scripts/enrich-command-discovery-fields.mjs +286 -0
  344. package/scripts/generate-command-config-schema.mjs +273 -0
  345. package/scripts/generate-commands-catalog.mjs +308 -0
  346. package/scripts/generate-module-agents.mjs +631 -0
  347. package/scripts/generate-seo-satellite-pages.mjs +400 -0
  348. package/scripts/github-deploy-notify.mjs +174 -0
  349. package/scripts/github-release-notify.mjs +219 -0
  350. package/scripts/release.sh +599 -0
  351. package/scripts/run-codeql-local.sh +116 -0
  352. package/scripts/run-prettier-all.mjs +25 -0
  353. package/scripts/security-smoketest.mjs +581 -0
  354. package/scripts/sticker-catalog-loadtest.mjs +210 -0
  355. package/scripts/sticker-worker-task.mjs +119 -0
  356. package/scripts/sync-readme-snapshot.mjs +133 -0
  357. package/scripts/validate-command-config-schema.mjs +130 -0
  358. package/scripts/validate-command-configs.mjs +15 -0
  359. package/scripts/wiki-sync.sh +191 -0
  360. package/server/auth/googleWebAuth/googleWebAuthRuntime.js +62 -0
  361. package/server/auth/googleWebAuth/googleWebAuthService.js +807 -0
  362. package/server/auth/jwt/webJwtService.js +147 -0
  363. package/server/auth/stickerCatalogAuthContext.js +165 -0
  364. package/server/auth/termsAcceptance/termsAcceptanceHandler.js +189 -0
  365. package/server/auth/userPassword/index.js +14 -0
  366. package/server/auth/userPassword/userPasswordAuthService.js +422 -0
  367. package/server/auth/userPassword/userPasswordCrypto.js +199 -0
  368. package/server/auth/userPassword/userPasswordCrypto.test.js +76 -0
  369. package/server/auth/userPassword/userPasswordRecoveryService.js +728 -0
  370. package/server/auth/validation/authSchemas.js +236 -0
  371. package/server/auth/webAccount/webAccountHandlers.js +1434 -0
  372. package/server/controllers/admin/adminBanService.js +138 -0
  373. package/server/controllers/admin/adminPanelHandlers.js +2083 -0
  374. package/server/controllers/admin/stickerCatalogAdminContext.js +17 -0
  375. package/server/controllers/admin/systemAdminController.js +201 -0
  376. package/server/controllers/email/emailAutomationController.js +239 -0
  377. package/server/controllers/metricsController.js +21 -0
  378. package/server/controllers/seo/stickerCatalogSeoContext.js +514 -0
  379. package/server/controllers/sticker/nonCatalogHandlers.js +303 -0
  380. package/server/controllers/sticker/stickerCatalogController.js +4700 -0
  381. package/server/controllers/system/contactController.js +115 -0
  382. package/server/controllers/system/githubController.js +137 -0
  383. package/server/controllers/system/stickerCatalogSystemContext.js +758 -0
  384. package/server/controllers/system/storageController.js +154 -0
  385. package/server/controllers/system/systemController.js +135 -0
  386. package/server/controllers/system/systemMetricsController.js +156 -0
  387. package/server/controllers/system/visitController.js +90 -0
  388. package/server/controllers/userController.js +145 -0
  389. package/server/email/emailAutomationRuntime.js +225 -0
  390. package/server/email/emailAutomationService.js +125 -0
  391. package/server/email/emailOutboxRepository.js +282 -0
  392. package/server/email/emailTemplateService.js +480 -0
  393. package/server/email/emailTransportService.js +156 -0
  394. package/server/http/clientIp.js +95 -0
  395. package/server/http/httpRequestUtils.js +262 -0
  396. package/server/http/httpRequestUtils.test.js +80 -0
  397. package/server/http/httpServer.js +180 -0
  398. package/server/http/requestContext.js +20 -0
  399. package/server/http/siteRoutingUtils.js +87 -0
  400. package/server/index.js +1 -0
  401. package/server/middleware/cachePolicy.js +26 -0
  402. package/server/middleware/cachePolicyHelpers.js +1 -0
  403. package/server/middleware/endpointRateLimit.js +181 -0
  404. package/server/middleware/rateLimit.js +70 -0
  405. package/server/middleware/requireAdminAuth.js +48 -0
  406. package/server/middleware/securityHeaders.js +97 -0
  407. package/server/routes/admin/systemAdminRouter.js +64 -0
  408. package/server/routes/email/emailAutomationRouter.js +46 -0
  409. package/server/routes/health/healthRouter.js +41 -0
  410. package/server/routes/indexRouter.js +234 -0
  411. package/server/routes/metrics/metricsRouter.js +58 -0
  412. package/server/routes/static/staticPageRouter.js +134 -0
  413. package/server/routes/sticker/catalogHandlers/catalogAdminHttp.js +105 -0
  414. package/server/routes/sticker/catalogHandlers/catalogAuthHttp.js +77 -0
  415. package/server/routes/sticker/catalogHandlers/catalogPublicHttp.js +120 -0
  416. package/server/routes/sticker/catalogHandlers/catalogUploadHttp.js +83 -0
  417. package/server/routes/sticker/catalogRouter.js +77 -0
  418. package/server/routes/sticker/stickerApiRouter.js +84 -0
  419. package/server/routes/sticker/stickerDataRouter.js +145 -0
  420. package/server/routes/sticker/stickerSiteRouter.js +43 -0
  421. package/server/routes/user/userApiPaths.js +66 -0
  422. package/server/routes/user/userRouter.js +65 -0
  423. package/server/utils/safePath.js +26 -0
  424. package/utils/logger/loggerModule.js +35 -0
  425. package/vite.config.mjs +38 -0
@@ -0,0 +1,354 @@
1
+ import axios from 'axios';
2
+ import { createCanvas, loadImage } from 'canvas';
3
+ import logger from '#logger';
4
+
5
+ const WIDTH = 1600;
6
+ const HEIGHT = 1200;
7
+ const PANEL_RADIUS = 26;
8
+ const IMAGE_TIMEOUT_MS = Math.max(2_000, Number(process.env.RPG_PROFILE_CANVAS_TIMEOUT_MS) || 6_000);
9
+ const IMAGE_CACHE_TTL_MS = Math.max(2 * 60 * 1000, Number(process.env.RPG_PROFILE_CANVAS_CACHE_TTL_MS) || 10 * 60 * 1000);
10
+ const IMAGE_CACHE_LIMIT = Math.max(20, Number(process.env.RPG_PROFILE_CANVAS_CACHE_LIMIT) || 80);
11
+
12
+ const imageCache = globalThis.__omnizapProfileCanvasImageCache instanceof Map ? globalThis.__omnizapProfileCanvasImageCache : new Map();
13
+ globalThis.__omnizapProfileCanvasImageCache = imageCache;
14
+
15
+ const TYPE_COLORS = new Map([
16
+ ['normal', '#a8a77a'],
17
+ ['fire', '#ee8130'],
18
+ ['water', '#6390f0'],
19
+ ['electric', '#f7d02c'],
20
+ ['grass', '#7ac74c'],
21
+ ['ice', '#96d9d6'],
22
+ ['fighting', '#c22e28'],
23
+ ['poison', '#a33ea1'],
24
+ ['ground', '#e2bf65'],
25
+ ['flying', '#a98ff3'],
26
+ ['psychic', '#f95587'],
27
+ ['bug', '#a6b91a'],
28
+ ['rock', '#b6a136'],
29
+ ['ghost', '#735797'],
30
+ ['dragon', '#6f35fc'],
31
+ ['dark', '#705746'],
32
+ ['steel', '#b7b7ce'],
33
+ ['fairy', '#d685ad'],
34
+ ]);
35
+
36
+ const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
37
+
38
+ const toInt = (value, fallback = 0) => {
39
+ const numeric = Number(value);
40
+ return Number.isFinite(numeric) ? Math.trunc(numeric) : fallback;
41
+ };
42
+
43
+ const toText = (value, fallback = 'N/D') => {
44
+ if (value === null || value === undefined) return fallback;
45
+ const text = String(value).trim();
46
+ return text || fallback;
47
+ };
48
+
49
+ const trimText = (value, max = 120) => {
50
+ const text = String(value || '')
51
+ .replace(/\s+/g, ' ')
52
+ .trim();
53
+ if (!text) return '';
54
+ if (text.length <= max) return text;
55
+ return `${text.slice(0, Math.max(16, max - 1)).trimEnd()}…`;
56
+ };
57
+
58
+ const drawRoundRect = (ctx, x, y, width, height, radius, fillStyle) => {
59
+ ctx.beginPath();
60
+ ctx.moveTo(x + radius, y);
61
+ ctx.lineTo(x + width - radius, y);
62
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
63
+ ctx.lineTo(x + width, y + height - radius);
64
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
65
+ ctx.lineTo(x + radius, y + height);
66
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
67
+ ctx.lineTo(x, y + radius);
68
+ ctx.quadraticCurveTo(x, y, x + radius, y);
69
+ ctx.closePath();
70
+ if (fillStyle) {
71
+ ctx.fillStyle = fillStyle;
72
+ ctx.fill();
73
+ }
74
+ };
75
+
76
+ const cleanupImageCache = () => {
77
+ if (imageCache.size <= IMAGE_CACHE_LIMIT) return;
78
+ const now = Date.now();
79
+ for (const [key, value] of imageCache.entries()) {
80
+ if (!value || value.expiresAt <= now) imageCache.delete(key);
81
+ }
82
+ while (imageCache.size > IMAGE_CACHE_LIMIT) {
83
+ const oldest = imageCache.keys().next().value;
84
+ imageCache.delete(oldest);
85
+ }
86
+ };
87
+
88
+ const resolveImage = async (url) => {
89
+ const normalized = String(url || '').trim();
90
+ if (!normalized) return null;
91
+
92
+ const cached = imageCache.get(normalized);
93
+ if (cached && cached.expiresAt > Date.now()) return cached.image;
94
+
95
+ try {
96
+ const response = await axios.get(normalized, {
97
+ responseType: 'arraybuffer',
98
+ timeout: IMAGE_TIMEOUT_MS,
99
+ validateStatus: (status) => status >= 200 && status < 400,
100
+ });
101
+ const image = await loadImage(Buffer.from(response.data));
102
+ imageCache.set(normalized, {
103
+ image,
104
+ expiresAt: Date.now() + IMAGE_CACHE_TTL_MS,
105
+ });
106
+ cleanupImageCache();
107
+ return image;
108
+ } catch (error) {
109
+ logger.debug('Falha ao carregar imagem para perfil canvas.', {
110
+ url: normalized,
111
+ error: error.message,
112
+ });
113
+ return null;
114
+ }
115
+ };
116
+
117
+ const drawProgressBar = ({ ctx, x, y, width, height, progressPct = 0, color = '#22d3ee', background = 'rgba(15,23,42,0.75)' }) => {
118
+ drawRoundRect(ctx, x, y, width, height, Math.min(14, Math.round(height / 2)), background);
119
+ const ratio = clamp(Number(progressPct) / 100, 0, 1);
120
+ if (ratio <= 0) return;
121
+ drawRoundRect(ctx, x + 2, y + 2, Math.max(0, (width - 4) * ratio), Math.max(0, height - 4), Math.min(12, Math.round((height - 4) / 2)), color);
122
+ };
123
+
124
+ const sanitizeProfileText = (text) => {
125
+ const raw = String(text || '');
126
+ return raw
127
+ .split('\n')
128
+ .map((line) =>
129
+ String(line || '')
130
+ .replace(/\*/g, '')
131
+ .replace(/\s+$/g, ''),
132
+ )
133
+ .filter((line, index, lines) => line || (index > 0 && lines[index - 1]));
134
+ };
135
+
136
+ const wrapLine = (ctx, line, maxWidth) => {
137
+ const text = String(line || '').trim();
138
+ if (!text) return [''];
139
+
140
+ const words = text.split(' ');
141
+ const wrapped = [];
142
+ let current = '';
143
+
144
+ for (const word of words) {
145
+ const candidate = current ? `${current} ${word}` : word;
146
+ if (ctx.measureText(candidate).width <= maxWidth) {
147
+ current = candidate;
148
+ continue;
149
+ }
150
+ if (current) {
151
+ wrapped.push(current);
152
+ current = word;
153
+ continue;
154
+ }
155
+
156
+ let chunk = word;
157
+ while (chunk.length > 1 && ctx.measureText(chunk).width > maxWidth) {
158
+ const safeSize = Math.max(1, Math.floor((maxWidth / Math.max(1, ctx.measureText(chunk).width)) * chunk.length));
159
+ const part = chunk.slice(0, safeSize);
160
+ wrapped.push(`${part}…`);
161
+ chunk = chunk.slice(safeSize);
162
+ }
163
+ current = chunk;
164
+ }
165
+
166
+ if (current) wrapped.push(current);
167
+ return wrapped.length ? wrapped : [''];
168
+ };
169
+
170
+ const isHeaderLine = (line) => {
171
+ const value = String(line || '').trim();
172
+ if (!value) return false;
173
+ if (/^\d+\./.test(value)) return false;
174
+ if (value.startsWith('•')) return false;
175
+ return value.length <= 36;
176
+ };
177
+
178
+ export const renderProfileCanvasCard = async ({ trainerLabel = 'Treinador', generatedAtLabel = null, activePokemon = null, summary = {}, profileText = '' }) => {
179
+ const canvas = createCanvas(WIDTH, HEIGHT);
180
+ const ctx = canvas.getContext('2d');
181
+
182
+ const primaryType = String(activePokemon?.types?.[0] || '')
183
+ .trim()
184
+ .toLowerCase();
185
+ const accent = TYPE_COLORS.get(primaryType) || '#38bdf8';
186
+
187
+ const bgGradient = ctx.createLinearGradient(0, 0, WIDTH, HEIGHT);
188
+ bgGradient.addColorStop(0, '#0b1220');
189
+ bgGradient.addColorStop(0.55, '#111827');
190
+ bgGradient.addColorStop(1, '#1e293b');
191
+ ctx.fillStyle = bgGradient;
192
+ ctx.fillRect(0, 0, WIDTH, HEIGHT);
193
+
194
+ const glow = ctx.createRadialGradient(240, 240, 40, 240, 240, 560);
195
+ glow.addColorStop(0, `${accent}70`);
196
+ glow.addColorStop(1, 'rgba(2,6,23,0)');
197
+ ctx.fillStyle = glow;
198
+ ctx.fillRect(0, 0, WIDTH, HEIGHT);
199
+
200
+ const leftX = 40;
201
+ const leftY = 40;
202
+ const leftW = 470;
203
+ const leftH = HEIGHT - 80;
204
+ drawRoundRect(ctx, leftX, leftY, leftW, leftH, PANEL_RADIUS, 'rgba(2, 6, 23, 0.72)');
205
+
206
+ const rightX = leftX + leftW + 24;
207
+ const rightY = 40;
208
+ const rightW = WIDTH - rightX - 40;
209
+ const rightH = HEIGHT - 80;
210
+ drawRoundRect(ctx, rightX, rightY, rightW, rightH, PANEL_RADIUS, 'rgba(2, 6, 23, 0.65)');
211
+
212
+ ctx.fillStyle = '#e2e8f0';
213
+ ctx.font = '700 40px Sans';
214
+ ctx.fillText('PERFIL RPG', leftX + 30, leftY + 62);
215
+
216
+ ctx.fillStyle = '#94a3b8';
217
+ ctx.font = '500 22px Sans';
218
+ ctx.fillText(trimText(trainerLabel, 22), leftX + 30, leftY + 96);
219
+
220
+ const levelText = `Nivel ${toInt(summary?.level, 1)}`;
221
+ const goldText = `${toInt(summary?.gold, 0)} gold`;
222
+ ctx.fillStyle = '#f8fafc';
223
+ ctx.font = '700 28px Sans';
224
+ ctx.fillText(levelText, leftX + 30, leftY + 146);
225
+ ctx.fillText(goldText, leftX + 30, leftY + 184);
226
+
227
+ ctx.fillStyle = '#94a3b8';
228
+ ctx.font = '500 20px Sans';
229
+ const rankText = Number.isFinite(Number(summary?.pvpWeeklyRank)) ? `Rank PvP: #${toInt(summary?.pvpWeeklyRank, 0)}` : 'Rank PvP: sem rank';
230
+ const streakText = `Streak: ${toText(summary?.streakLabel, 'Sem historico')}`;
231
+ ctx.fillText(trimText(rankText, 34), leftX + 30, leftY + 220);
232
+ ctx.fillText(trimText(streakText, 34), leftX + 30, leftY + 248);
233
+
234
+ const xpProgressPct = clamp(toInt(summary?.xpProgressPct, 0), 0, 100);
235
+ drawProgressBar({
236
+ ctx,
237
+ x: leftX + 30,
238
+ y: leftY + 272,
239
+ width: leftW - 60,
240
+ height: 24,
241
+ progressPct: xpProgressPct,
242
+ color: accent,
243
+ });
244
+
245
+ ctx.fillStyle = '#e2e8f0';
246
+ ctx.font = '600 18px Sans';
247
+ ctx.fillText(`XP: ${toInt(summary?.xp, 0)} (${xpProgressPct}%)`, leftX + 30, leftY + 325);
248
+ if (toInt(summary?.xpToNextLevel, 0) > 0) {
249
+ ctx.fillText(`Faltam ${toInt(summary?.xpToNextLevel, 0)} XP para o nivel ${toInt(summary?.nextLevel, toInt(summary?.level, 1) + 1)}`, leftX + 30, leftY + 350);
250
+ } else {
251
+ ctx.fillText('Nivel maximo alcancado', leftX + 30, leftY + 350);
252
+ }
253
+
254
+ const spriteX = leftX + 30;
255
+ const spriteY = leftY + 380;
256
+ const spriteW = leftW - 60;
257
+ const spriteH = 330;
258
+ drawRoundRect(ctx, spriteX, spriteY, spriteW, spriteH, 22, 'rgba(15, 23, 42, 0.8)');
259
+
260
+ const image = await resolveImage(activePokemon?.imageUrl || activePokemon?.sprite || null);
261
+ if (image) {
262
+ const size = Math.min(spriteW - 36, spriteH - 36);
263
+ const drawX = spriteX + (spriteW - size) / 2;
264
+ const drawY = spriteY + (spriteH - size) / 2;
265
+ ctx.drawImage(image, drawX, drawY, size, size);
266
+ } else {
267
+ ctx.fillStyle = 'rgba(148, 163, 184, 0.2)';
268
+ drawRoundRect(ctx, spriteX + 18, spriteY + 18, spriteW - 36, spriteH - 36, 18, 'rgba(148, 163, 184, 0.14)');
269
+ ctx.fillStyle = '#94a3b8';
270
+ ctx.font = '600 22px Sans';
271
+ ctx.textAlign = 'center';
272
+ ctx.fillText('Imagem indisponivel', spriteX + spriteW / 2, spriteY + spriteH / 2 + 8);
273
+ ctx.textAlign = 'start';
274
+ }
275
+
276
+ const pokemonName = trimText(activePokemon?.displayName || activePokemon?.name || 'Sem Pokemon ativo', 28);
277
+ ctx.fillStyle = '#f8fafc';
278
+ ctx.font = '700 26px Sans';
279
+ ctx.fillText(pokemonName, leftX + 30, leftY + 748);
280
+
281
+ const hpCurrent = Math.max(0, toInt(activePokemon?.currentHp, 0));
282
+ const hpMax = Math.max(1, toInt(activePokemon?.maxHp, 1));
283
+ const typeText = Array.isArray(activePokemon?.types) && activePokemon.types.length ? activePokemon.types.join(', ') : 'tipo indefinido';
284
+ ctx.fillStyle = '#94a3b8';
285
+ ctx.font = '500 20px Sans';
286
+ ctx.fillText(`Lv.${Math.max(1, toInt(activePokemon?.level, 1))} | HP ${hpCurrent}/${hpMax}`, leftX + 30, leftY + 782);
287
+ ctx.fillText(trimText(`Tipos: ${typeText}`, 36), leftX + 30, leftY + 812);
288
+
289
+ if (generatedAtLabel) {
290
+ ctx.fillStyle = '#64748b';
291
+ ctx.font = '500 17px Sans';
292
+ ctx.fillText(`Atualizado em ${generatedAtLabel}`, leftX + 30, leftY + leftH - 24);
293
+ }
294
+
295
+ ctx.fillStyle = '#e2e8f0';
296
+ ctx.font = '700 34px Sans';
297
+ ctx.fillText('Informacoes do jogador', rightX + 28, rightY + 56);
298
+
299
+ ctx.fillStyle = '#94a3b8';
300
+ ctx.font = '500 18px Sans';
301
+ ctx.fillText('Resumo completo em duas colunas', rightX + 28, rightY + 84);
302
+
303
+ const textLines = sanitizeProfileText(profileText);
304
+ ctx.font = '500 20px Sans';
305
+
306
+ const contentTop = rightY + 122;
307
+ const contentBottom = rightY + rightH - 28;
308
+ const lineHeight = 24;
309
+ const colGap = 28;
310
+ const colWidth = Math.floor((rightW - 56 - colGap) / 2);
311
+ const colOneX = rightX + 28;
312
+ const colTwoX = colOneX + colWidth + colGap;
313
+ const maxLinesPerCol = Math.max(1, Math.floor((contentBottom - contentTop) / lineHeight));
314
+ const maxLines = maxLinesPerCol * 2;
315
+
316
+ const wrapped = [];
317
+ for (const line of textLines) {
318
+ const normalized = String(line || '');
319
+ if (!normalized.trim()) {
320
+ wrapped.push('');
321
+ continue;
322
+ }
323
+ const segments = wrapLine(ctx, normalized, colWidth - 2);
324
+ segments.forEach((segment) => wrapped.push(segment));
325
+ }
326
+
327
+ const truncated = wrapped.length > maxLines;
328
+ const visible = wrapped.slice(0, maxLines);
329
+ if (truncated && visible.length) {
330
+ visible[visible.length - 1] = '... use /rpg perfil para ver texto completo';
331
+ }
332
+
333
+ visible.forEach((line, index) => {
334
+ const colIndex = Math.floor(index / maxLinesPerCol);
335
+ const rowIndex = index % maxLinesPerCol;
336
+ const x = colIndex === 0 ? colOneX : colTwoX;
337
+ const y = contentTop + rowIndex * lineHeight;
338
+
339
+ if (!line) return;
340
+
341
+ if (isHeaderLine(line)) {
342
+ ctx.fillStyle = '#f8fafc';
343
+ ctx.font = '700 20px Sans';
344
+ ctx.fillText(trimText(line, 64), x, y);
345
+ return;
346
+ }
347
+
348
+ ctx.fillStyle = '#cbd5e1';
349
+ ctx.font = '500 19px Sans';
350
+ ctx.fillText(trimText(line, 94), x, y);
351
+ });
352
+
353
+ return canvas.toBuffer('image/png', { compressionLevel: 4 });
354
+ };
@@ -0,0 +1,320 @@
1
+ # StatsModule Agent Guide
2
+
3
+ Este arquivo e destinado a agentes de IA para gerar respostas no contexto dos comandos deste modulo.
4
+
5
+ ## Fonte de Verdade
6
+
7
+ - arquivo_base: `app/modules/statsModule/commandConfig.json`
8
+ - schema_version: `2.0.0`
9
+ - module_enabled: `true`
10
+ - generated_at: `2026-03-11T02:35:17.177Z`
11
+
12
+ ## Escopo do Modulo
13
+
14
+ - module: `statsModule`
15
+ - source_files:
16
+ - rankingCommand.js
17
+ - globalRankingCommand.js
18
+ - total_commands: `2`
19
+ - total_enabled_commands: `2`
20
+
21
+ ## Defaults Schema v2
22
+
23
+ - inheritance_mode: deep_merge_with_command_overrides
24
+ - compatibility_mode: legacy_and_v2_fields
25
+ - legacy_field_aliases:
26
+ - descricao: description
27
+ - metodos_de_uso: usage
28
+ - permissao_necessaria: permission
29
+ - local_de_uso: contexts
30
+ - informacoes_coletadas: collected_data
31
+ - pre_condicoes: requirements
32
+ - dependencias_externas: dependencies
33
+ - efeitos_colaterais: side_effects
34
+ - observabilidade: observability
35
+ - privacidade: privacy
36
+ - limite_uso_por_plano: plan_limits
37
+ - argumentos: arguments
38
+ - acesso: access
39
+ - defaults.command:
40
+ - enabled: true
41
+ - category: estatisticas
42
+ - version: 1.0.0
43
+ - stability: stable
44
+ - deprecated: false
45
+ - replaced_by: null
46
+ - risk_level: medium
47
+ - defaults.requirements (legacy view):
48
+ - requer_grupo: sim
49
+ - requer_admin: nao
50
+ - requer_admin_principal: nao
51
+ - requer_google_login: sim
52
+ - requer_nsfw: nao
53
+ - requer_midia: nao
54
+ - requer_mensagem_respondida: nao
55
+
56
+ ## Protocolo de Resposta para IA
57
+
58
+ - Passo 1: identificar comando pelo token apos o prefixo.
59
+ - Passo 2: resolver alias para nome canonico usando campo `aliases`.
60
+ - Passo 3: validar `enabled`, `pre_condicoes`, permissao e local de uso.
61
+ - Passo 4: se houver erro de uso, responder com `mensagens_uso` (quando existir) ou `metodos_de_uso`.
62
+ - Passo 5: seguir `respostas_padrao` como fallback de texto.
63
+ - Passo 6: considerar `informacoes_coletadas`, `privacidade` e `observabilidade` ao elaborar resposta.
64
+
65
+ ## Regras de Seguranca para IA
66
+
67
+ - A IA orienta, mas nao executa acao administrativa automaticamente.
68
+ - Nao inventar comandos, subcomandos ou permissao fora do JSON.
69
+ - Sempre informar onde pode usar (grupo/privado) e quem pode usar.
70
+ - Em duvida de permissao, responder com orientacao conservadora.
71
+
72
+ ## Catalogo de Comandos
73
+
74
+ ### classificacao
75
+
76
+ - id: stats.classificacao
77
+ - aliases: rank, top5, ranking
78
+ - enabled: true
79
+ - categoria: estatisticas
80
+ - descricao: Mostra top 5 mais ativos do grupo.
81
+ - permissao_necessaria: usuario comum
82
+ - version: 1.0.0
83
+ - stability: stable
84
+ - deprecated: nao
85
+ - risk_level: low
86
+ - local_de_uso:
87
+ - grupo
88
+ - metodos_de_uso:
89
+ - <prefix>classificacao
90
+ - <prefix>rank
91
+ - <prefix>top5
92
+ - mensagens_uso (variantes):
93
+ - default:
94
+ - <prefix>classificacao
95
+ - <prefix>rank
96
+ - <prefix>top5
97
+ - subcomandos:
98
+ - (nenhum)
99
+ - argumentos:
100
+ - (nenhum)
101
+ - pre_condicoes:
102
+ - requer_grupo: sim
103
+ - requer_admin: nao
104
+ - requer_admin_principal: nao
105
+ - requer_google_login: sim
106
+ - requer_nsfw: nao
107
+ - requer_midia: nao
108
+ - requer_mensagem_respondida: nao
109
+ - rate_limit:
110
+ - max: null
111
+ - janela_ms: null
112
+ - escopo: sem_rate_limit_explicito
113
+ - acesso:
114
+ - somente_premium: nao
115
+ - planos_permitidos: comum, premium
116
+ - limite_uso_por_plano:
117
+ - comum: max=25, janela_ms=60000, escopo=usuario
118
+ - premium: max=120, janela_ms=60000, escopo=usuario
119
+ - informacoes_coletadas:
120
+ - identificador do chat (remoteJid)
121
+ - identificador do remetente (senderJid)
122
+ - texto do comando e argumentos
123
+ - contexto da mensagem (citacao e mencoes, quando existir)
124
+ - escopo do grupo (group id)
125
+ - estatisticas de mensagens agregadas no banco
126
+ - nomes de exibicao para composicao do ranking
127
+ - dependencias_externas:
128
+ - banco de dados de mensagens
129
+ - efeitos_colaterais:
130
+ - consulta agregações no banco
131
+ - envia ranking
132
+ - respostas_padrao:
133
+ - success: Comando executado com sucesso.
134
+ - usage_error: Formato de uso inválido. Consulte metodos_de_uso.
135
+ - permission_error: Permissão insuficiente para executar este comando.
136
+ - sucesso: Comando executado com sucesso.
137
+ - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
138
+ - erro_permissao: Permissão insuficiente para executar este comando.
139
+ - mensagens_sistema:
140
+ - (nao informado)
141
+ - limites_operacionais:
142
+ - (nao informado)
143
+ - opcoes:
144
+ - toggle_on_off_status.type: toggle
145
+ - toggle_on_off_status.allowed_actions: on, off, status
146
+ - toggle_on_off_status.action_argument: acao
147
+ - add_remove_list.type: list_management
148
+ - add_remove_list.allowed_actions: add, remove, list
149
+ - add_remove_list.action_argument: acao
150
+ - approve_reject.type: moderation_decision
151
+ - approve_reject.allowed_actions: approve, reject
152
+ - approve_reject.action_argument: acao
153
+ - approve_reject.requires_targets: true
154
+ - set_status_reset.type: configuration_window
155
+ - set_status_reset.allowed_actions: set, status, reset
156
+ - set_status_reset.action_argument: valor
157
+ - observabilidade:
158
+ - event_name: command.executed
159
+ - analytics_event: whatsapp_command_ranking
160
+ - tags_log: whatsapp, command, statsModule, ranking
161
+ - nivel_log: info
162
+ - privacidade:
163
+ - dados_sensiveis:
164
+ - chat_identifier
165
+ - sender_identifier
166
+ - command_content
167
+ - retencao: standard_app_logs
168
+ - base_legal: service_execution_and_legitimate_interest
169
+ - docs:
170
+ - summary: Mostra top 5 mais ativos do grupo.
171
+ - usage_examples: <prefix>classificacao, <prefix>rank, <prefix>top5
172
+ - usage_variants.default: <prefix>classificacao, <prefix>rank, <prefix>top5
173
+ - behavior:
174
+ - type: simple_action
175
+ - allowed_actions: (nenhum)
176
+ - limits:
177
+ - usage_description: retorna top 5
178
+ - rate_limit.max: null
179
+ - rate_limit.janela_ms: null
180
+ - rate_limit.escopo: sem_rate_limit_explicito
181
+ - access.somente_premium: false
182
+ - access.planos_permitidos: comum, premium
183
+ - plan_limits.comum.max: 25
184
+ - plan_limits.comum.janela_ms: 60000
185
+ - plan_limits.comum.escopo: usuario
186
+ - plan_limits.premium.max: 120
187
+ - plan_limits.premium.janela_ms: 60000
188
+ - plan_limits.premium.escopo: usuario
189
+ - discovery:
190
+ - keywords: classificacao, rank, top5, estatisticas, grupo
191
+ - faq_queries: como usar classificacao, o que faz classificacao, comando classificacao
192
+ - user_phrasings: quero usar classificacao, me ajuda com classificacao, mostra top 5 mais
193
+ - suggestion_priority: 100
194
+ - handler:
195
+ - file: rankingCommand.js
196
+ - method: handleRankingCommand
197
+ - command_case: classificacao
198
+
199
+ ### classificacaoglobal
200
+
201
+ - id: stats.classificacaoglobal
202
+ - aliases: rankglobal, globalrank, globalranking, rankingglobal
203
+ - enabled: true
204
+ - categoria: estatisticas
205
+ - descricao: Mostra top 5 global de atividade.
206
+ - permissao_necessaria: usuario comum
207
+ - version: 1.0.0
208
+ - stability: stable
209
+ - deprecated: nao
210
+ - risk_level: low
211
+ - local_de_uso:
212
+ - privado
213
+ - grupo
214
+ - metodos_de_uso:
215
+ - <prefix>classificacaoglobal
216
+ - <prefix>globalrank
217
+ - mensagens_uso (variantes):
218
+ - default:
219
+ - <prefix>classificacaoglobal
220
+ - <prefix>globalrank
221
+ - subcomandos:
222
+ - (nenhum)
223
+ - argumentos:
224
+ - (nenhum)
225
+ - pre_condicoes:
226
+ - requer_grupo: nao
227
+ - requer_admin: nao
228
+ - requer_admin_principal: nao
229
+ - requer_google_login: sim
230
+ - requer_nsfw: nao
231
+ - requer_midia: nao
232
+ - requer_mensagem_respondida: nao
233
+ - rate_limit:
234
+ - max: null
235
+ - janela_ms: null
236
+ - escopo: sem_rate_limit_explicito
237
+ - acesso:
238
+ - somente_premium: nao
239
+ - planos_permitidos: comum, premium
240
+ - limite_uso_por_plano:
241
+ - comum: max=25, janela_ms=60000, escopo=usuario
242
+ - premium: max=120, janela_ms=60000, escopo=usuario
243
+ - informacoes_coletadas:
244
+ - identificador do chat (remoteJid)
245
+ - identificador do remetente (senderJid)
246
+ - texto do comando e argumentos
247
+ - contexto da mensagem (citacao e mencoes, quando existir)
248
+ - estatisticas globais de mensagens agregadas no banco
249
+ - nomes de exibicao para composicao do ranking
250
+ - dependencias_externas:
251
+ - banco de dados de mensagens
252
+ - efeitos_colaterais:
253
+ - consulta agregações no banco
254
+ - envia ranking
255
+ - respostas_padrao:
256
+ - success: Comando executado com sucesso.
257
+ - usage_error: Formato de uso inválido. Consulte metodos_de_uso.
258
+ - permission_error: Permissão insuficiente para executar este comando.
259
+ - sucesso: Comando executado com sucesso.
260
+ - erro_uso: Formato de uso inválido. Consulte metodos_de_uso.
261
+ - erro_permissao: Permissão insuficiente para executar este comando.
262
+ - mensagens_sistema:
263
+ - (nao informado)
264
+ - limites_operacionais:
265
+ - (nao informado)
266
+ - opcoes:
267
+ - toggle_on_off_status.type: toggle
268
+ - toggle_on_off_status.allowed_actions: on, off, status
269
+ - toggle_on_off_status.action_argument: acao
270
+ - add_remove_list.type: list_management
271
+ - add_remove_list.allowed_actions: add, remove, list
272
+ - add_remove_list.action_argument: acao
273
+ - approve_reject.type: moderation_decision
274
+ - approve_reject.allowed_actions: approve, reject
275
+ - approve_reject.action_argument: acao
276
+ - approve_reject.requires_targets: true
277
+ - set_status_reset.type: configuration_window
278
+ - set_status_reset.allowed_actions: set, status, reset
279
+ - set_status_reset.action_argument: valor
280
+ - observabilidade:
281
+ - event_name: command.executed
282
+ - analytics_event: whatsapp_command_rankingglobal
283
+ - tags_log: whatsapp, command, statsModule, rankingglobal
284
+ - nivel_log: info
285
+ - privacidade:
286
+ - dados_sensiveis:
287
+ - chat_identifier
288
+ - sender_identifier
289
+ - command_content
290
+ - retencao: standard_app_logs
291
+ - base_legal: service_execution_and_legitimate_interest
292
+ - docs:
293
+ - summary: Mostra top 5 global de atividade.
294
+ - usage_examples: <prefix>classificacaoglobal, <prefix>globalrank
295
+ - usage_variants.default: <prefix>classificacaoglobal, <prefix>globalrank
296
+ - behavior:
297
+ - type: simple_action
298
+ - allowed_actions: (nenhum)
299
+ - limits:
300
+ - usage_description: retorna top 5
301
+ - rate_limit.max: null
302
+ - rate_limit.janela_ms: null
303
+ - rate_limit.escopo: sem_rate_limit_explicito
304
+ - access.somente_premium: false
305
+ - access.planos_permitidos: comum, premium
306
+ - plan_limits.comum.max: 25
307
+ - plan_limits.comum.janela_ms: 60000
308
+ - plan_limits.comum.escopo: usuario
309
+ - plan_limits.premium.max: 120
310
+ - plan_limits.premium.janela_ms: 60000
311
+ - plan_limits.premium.escopo: usuario
312
+ - discovery:
313
+ - keywords: classificacaoglobal, rankglobal, globalrank, globalranking, estatisticas, privado, grupo
314
+ - faq_queries: como usar classificacaoglobal, o que faz classificacaoglobal, comando classificacaoglobal
315
+ - user_phrasings: quero usar classificacaoglobal, me ajuda com classificacaoglobal, mostra top 5 global
316
+ - suggestion_priority: 100
317
+ - handler:
318
+ - file: globalRankingCommand.js
319
+ - method: handleGlobalRankingCommand
320
+ - command_case: classificacaoglobal