@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,1186 @@
1
+ -- Schema consolidado para bootstrap sem migrations.
2
+ -- Gerado a partir do estado atual do banco.
3
+ SET FOREIGN_KEY_CHECKS = 0;
4
+ CREATE TABLE IF NOT EXISTS `admin_action_audit` (
5
+ `id` char(36) NOT NULL,
6
+ `admin_role` varchar(32) NOT NULL DEFAULT 'owner',
7
+ `admin_google_sub` varchar(255) DEFAULT NULL,
8
+ `admin_email` varchar(255) DEFAULT NULL,
9
+ `admin_owner_jid` varchar(255) DEFAULT NULL,
10
+ `action` varchar(96) NOT NULL,
11
+ `target_type` varchar(64) DEFAULT NULL,
12
+ `target_id` varchar(255) DEFAULT NULL,
13
+ `status` varchar(32) NOT NULL DEFAULT 'success',
14
+ `details` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`details`)),
15
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
16
+ PRIMARY KEY (`id`),
17
+ KEY `idx_admin_action_audit_created` (`created_at`),
18
+ KEY `idx_admin_action_audit_action_created` (`action`,`created_at`),
19
+ KEY `idx_admin_action_audit_admin_created` (`admin_google_sub`,`admin_email`,`created_at`)
20
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
21
+
22
+ CREATE TABLE IF NOT EXISTS `chats` (
23
+ `id` varchar(255) NOT NULL,
24
+ `name` varchar(255) DEFAULT NULL,
25
+ `raw_chat` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`raw_chat`)),
26
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
27
+ PRIMARY KEY (`id`)
28
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
29
+
30
+ CREATE TABLE IF NOT EXISTS `schema_change_log` (
31
+ `migration_key` varchar(128) NOT NULL,
32
+ `phase` varchar(32) NOT NULL,
33
+ `status` enum('applied','rolled_back') NOT NULL DEFAULT 'applied',
34
+ `notes` varchar(255) DEFAULT NULL,
35
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
36
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
37
+ PRIMARY KEY (`migration_key`),
38
+ KEY `idx_schema_change_log_phase_status` (`phase`,`status`,`updated_at`)
39
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
40
+
41
+ CREATE TABLE IF NOT EXISTS `domain_event_outbox` (
42
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
43
+ `event_type` varchar(96) NOT NULL,
44
+ `aggregate_type` varchar(96) NOT NULL,
45
+ `aggregate_id` varchar(128) NOT NULL,
46
+ `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`payload`)),
47
+ `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending',
48
+ `priority` tinyint(3) unsigned NOT NULL DEFAULT 50,
49
+ `idempotency_key` varchar(180) DEFAULT NULL,
50
+ `available_at` timestamp NOT NULL DEFAULT current_timestamp(),
51
+ `attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
52
+ `max_attempts` tinyint(3) unsigned NOT NULL DEFAULT 10,
53
+ `worker_token` char(36) DEFAULT NULL,
54
+ `last_error` varchar(255) DEFAULT NULL,
55
+ `locked_at` timestamp NULL DEFAULT NULL,
56
+ `processed_at` timestamp NULL DEFAULT NULL,
57
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
58
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
59
+ PRIMARY KEY (`id`),
60
+ UNIQUE KEY `uq_domain_event_outbox_idempotency_key` (`idempotency_key`),
61
+ KEY `idx_domain_event_outbox_status_sched` (`status`,`available_at`,`priority`),
62
+ KEY `idx_domain_event_outbox_event_type` (`event_type`,`status`,`available_at`),
63
+ KEY `idx_domain_event_outbox_aggregate` (`aggregate_type`,`aggregate_id`,`created_at`),
64
+ KEY `idx_domain_event_outbox_worker_token` (`worker_token`),
65
+ KEY `idx_domain_event_outbox_status_locked` (`status`,`locked_at`),
66
+ CONSTRAINT `chk_domain_event_outbox_attempts` CHECK (`attempts` <= `max_attempts`)
67
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
68
+
69
+ CREATE TABLE IF NOT EXISTS `domain_event_outbox_dlq` (
70
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
71
+ `outbox_event_id` bigint(20) unsigned DEFAULT NULL,
72
+ `event_type` varchar(96) NOT NULL,
73
+ `aggregate_type` varchar(96) NOT NULL,
74
+ `aggregate_id` varchar(128) NOT NULL,
75
+ `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`payload`)),
76
+ `attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
77
+ `max_attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
78
+ `last_error` varchar(255) DEFAULT NULL,
79
+ `failed_at` timestamp NOT NULL DEFAULT current_timestamp(),
80
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
81
+ PRIMARY KEY (`id`),
82
+ UNIQUE KEY `uq_domain_event_outbox_dlq_outbox_event` (`outbox_event_id`),
83
+ KEY `idx_domain_event_outbox_dlq_event` (`event_type`,`failed_at`),
84
+ KEY `idx_domain_event_outbox_dlq_aggregate` (`aggregate_type`,`aggregate_id`,`failed_at`)
85
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
86
+
87
+ CREATE TABLE IF NOT EXISTS `email_outbox` (
88
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
89
+ `recipient_email` varchar(255) NOT NULL,
90
+ `recipient_name` varchar(120) DEFAULT NULL,
91
+ `subject` varchar(180) NOT NULL,
92
+ `text_body` text DEFAULT NULL,
93
+ `html_body` mediumtext DEFAULT NULL,
94
+ `template_key` varchar(64) DEFAULT NULL,
95
+ `template_payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`template_payload`)),
96
+ `metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
97
+ `status` enum('pending','processing','sent','failed') NOT NULL DEFAULT 'pending',
98
+ `priority` tinyint(3) unsigned NOT NULL DEFAULT 50,
99
+ `idempotency_key` varchar(180) DEFAULT NULL,
100
+ `available_at` timestamp NOT NULL DEFAULT current_timestamp(),
101
+ `attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
102
+ `max_attempts` tinyint(3) unsigned NOT NULL DEFAULT 5,
103
+ `worker_token` char(36) DEFAULT NULL,
104
+ `provider_message_id` varchar(255) DEFAULT NULL,
105
+ `last_error` varchar(255) DEFAULT NULL,
106
+ `locked_at` timestamp NULL DEFAULT NULL,
107
+ `sent_at` timestamp NULL DEFAULT NULL,
108
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
109
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
110
+ PRIMARY KEY (`id`),
111
+ UNIQUE KEY `uq_email_outbox_idempotency` (`idempotency_key`),
112
+ KEY `idx_email_outbox_status_available_priority` (`status`,`available_at`,`priority`),
113
+ KEY `idx_email_outbox_recipient_created` (`recipient_email`,`created_at`),
114
+ KEY `idx_email_outbox_worker_token` (`worker_token`),
115
+ KEY `idx_email_outbox_status_locked` (`status`,`locked_at`),
116
+ CONSTRAINT `chk_email_outbox_attempts` CHECK (`attempts` <= `max_attempts`)
117
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
118
+
119
+ CREATE TABLE IF NOT EXISTS `feature_flag` (
120
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
121
+ `flag_name` varchar(120) NOT NULL,
122
+ `is_enabled` tinyint(1) NOT NULL DEFAULT 0,
123
+ `rollout_percent` tinyint(3) unsigned NOT NULL DEFAULT 100,
124
+ `description` varchar(255) DEFAULT NULL,
125
+ `updated_by` varchar(120) DEFAULT NULL,
126
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
127
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
128
+ PRIMARY KEY (`id`),
129
+ UNIQUE KEY `uq_feature_flag_name` (`flag_name`),
130
+ KEY `idx_feature_flag_enabled` (`is_enabled`,`rollout_percent`),
131
+ CONSTRAINT `chk_feature_flag_rollout_percent` CHECK (`rollout_percent` between 0 and 100)
132
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
133
+
134
+ CREATE TABLE IF NOT EXISTS `group_configs` (
135
+ `id` varchar(255) NOT NULL,
136
+ `config` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`config`)),
137
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
138
+ PRIMARY KEY (`id`)
139
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
140
+
141
+ CREATE TABLE IF NOT EXISTS `groups_metadata` (
142
+ `id` varchar(255) NOT NULL,
143
+ `subject` varchar(255) DEFAULT NULL,
144
+ `description` text DEFAULT NULL,
145
+ `owner_jid` varchar(255) DEFAULT NULL,
146
+ `creation` bigint(20) DEFAULT NULL,
147
+ `participants` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`participants`)),
148
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
149
+ PRIMARY KEY (`id`)
150
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
151
+
152
+ CREATE TABLE IF NOT EXISTS `lid_map` (
153
+ `lid` varchar(64) NOT NULL,
154
+ `jid` varchar(64) DEFAULT NULL,
155
+ `first_seen` timestamp NULL DEFAULT current_timestamp(),
156
+ `last_seen` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
157
+ `source` varchar(32) DEFAULT NULL,
158
+ PRIMARY KEY (`lid`),
159
+ KEY `idx_lid_map_jid` (`jid`),
160
+ KEY `idx_lid_map_last_seen` (`last_seen`)
161
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
162
+
163
+ CREATE TABLE IF NOT EXISTS `message_analysis_event` (
164
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
165
+ `message_id` varchar(255) DEFAULT NULL,
166
+ `chat_id` varchar(255) DEFAULT NULL,
167
+ `sender_id` varchar(255) DEFAULT NULL,
168
+ `sender_name` varchar(120) DEFAULT NULL,
169
+ `upsert_type` varchar(32) DEFAULT NULL,
170
+ `source` varchar(32) NOT NULL DEFAULT 'whatsapp',
171
+ `is_group` tinyint(1) NOT NULL DEFAULT 0,
172
+ `is_from_bot` tinyint(1) NOT NULL DEFAULT 0,
173
+ `is_command` tinyint(1) NOT NULL DEFAULT 0,
174
+ `command_name` varchar(64) DEFAULT NULL,
175
+ `command_args_count` smallint(5) unsigned NOT NULL DEFAULT 0,
176
+ `command_known` tinyint(1) DEFAULT NULL,
177
+ `command_prefix` varchar(8) DEFAULT NULL,
178
+ `message_kind` varchar(48) NOT NULL DEFAULT 'other',
179
+ `has_media` tinyint(1) NOT NULL DEFAULT 0,
180
+ `media_count` smallint(5) unsigned NOT NULL DEFAULT 0,
181
+ `text_length` int(10) unsigned NOT NULL DEFAULT 0,
182
+ `processing_result` varchar(64) NOT NULL DEFAULT 'processed',
183
+ `error_code` varchar(96) DEFAULT NULL,
184
+ `metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
185
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
186
+ PRIMARY KEY (`id`),
187
+ KEY `idx_message_analysis_created` (`created_at`),
188
+ KEY `idx_message_analysis_chat_created` (`chat_id`,`created_at`),
189
+ KEY `idx_message_analysis_sender_created` (`sender_id`,`created_at`),
190
+ KEY `idx_message_analysis_command_created` (`command_name`,`created_at`),
191
+ KEY `idx_message_analysis_kind_created` (`message_kind`,`created_at`),
192
+ KEY `idx_message_analysis_result_created` (`processing_result`,`created_at`),
193
+ KEY `idx_message_analysis_is_command_created` (`is_command`,`created_at`)
194
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
195
+
196
+ CREATE TABLE IF NOT EXISTS `baileys_event_journal` (
197
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
198
+ `event_name` varchar(64) NOT NULL,
199
+ `socket_generation` int(10) unsigned DEFAULT NULL,
200
+ `chat_id` varchar(255) DEFAULT NULL,
201
+ `message_id` varchar(255) DEFAULT NULL,
202
+ `participant_id` varchar(255) DEFAULT NULL,
203
+ `payload_summary` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`payload_summary`)),
204
+ `event_timestamp` timestamp NULL DEFAULT current_timestamp(),
205
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
206
+ PRIMARY KEY (`id`),
207
+ KEY `idx_baileys_event_created` (`created_at`),
208
+ KEY `idx_baileys_event_name_created` (`event_name`,`created_at`),
209
+ KEY `idx_baileys_event_chat_created` (`chat_id`,`created_at`),
210
+ KEY `idx_baileys_event_message_created` (`message_id`,`created_at`),
211
+ KEY `idx_baileys_event_participant_created` (`participant_id`,`created_at`)
212
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
213
+
214
+ CREATE TABLE IF NOT EXISTS `baileys_auth_state` (
215
+ `session_id` varchar(64) NOT NULL,
216
+ `category` varchar(64) NOT NULL,
217
+ `item_id` varchar(191) NOT NULL,
218
+ `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`payload`)),
219
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
220
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
221
+ PRIMARY KEY (`session_id`,`category`,`item_id`),
222
+ KEY `idx_baileys_auth_state_category_updated` (`category`,`updated_at`)
223
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
224
+
225
+ CREATE TABLE IF NOT EXISTS `messages` (
226
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
227
+ `message_id` varchar(255) NOT NULL,
228
+ `chat_id` varchar(255) NOT NULL,
229
+ `sender_id` varchar(255) DEFAULT NULL,
230
+ `canonical_sender_id` varchar(255) DEFAULT NULL,
231
+ `content` text DEFAULT NULL,
232
+ `raw_message` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`raw_message`)),
233
+ `timestamp` timestamp NULL DEFAULT NULL,
234
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
235
+ PRIMARY KEY (`id`),
236
+ UNIQUE KEY `message_id` (`message_id`),
237
+ KEY `idx_chat_timestamp` (`chat_id`,`timestamp`),
238
+ KEY `idx_sender` (`sender_id`),
239
+ KEY `idx_timestamp` (`timestamp`),
240
+ KEY `idx_messages_sender_timestamp` (`sender_id`,`timestamp`),
241
+ KEY `idx_messages_chat_sender_timestamp` (`chat_id`,`sender_id`,`timestamp`),
242
+ KEY `idx_messages_canonical_sender_timestamp` (`canonical_sender_id`,`timestamp`),
243
+ KEY `idx_messages_chat_canonical_sender_timestamp` (`chat_id`,`canonical_sender_id`,`timestamp`)
244
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
245
+
246
+ CREATE TABLE IF NOT EXISTS `message_activity_daily` (
247
+ `day_ref_date` date NOT NULL,
248
+ `chat_id` varchar(255) NOT NULL,
249
+ `canonical_sender_id` varchar(255) NOT NULL,
250
+ `total_messages` int(10) unsigned NOT NULL DEFAULT 0,
251
+ `first_message_at` datetime DEFAULT NULL,
252
+ `last_message_at` datetime DEFAULT NULL,
253
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
254
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
255
+ PRIMARY KEY (`day_ref_date`,`chat_id`,`canonical_sender_id`),
256
+ KEY `idx_message_activity_daily_sender_day` (`canonical_sender_id`,`day_ref_date`),
257
+ KEY `idx_message_activity_daily_chat_day` (`chat_id`,`day_ref_date`)
258
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
259
+
260
+ CREATE TABLE IF NOT EXISTS `rpg_battle_state` (
261
+ `chat_jid` varchar(255) NOT NULL,
262
+ `owner_jid` varchar(255) NOT NULL,
263
+ `my_pokemon_id` bigint(20) unsigned NOT NULL,
264
+ `enemy_snapshot_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`enemy_snapshot_json`)),
265
+ `turn` int(10) unsigned NOT NULL DEFAULT 1,
266
+ `expires_at` datetime NOT NULL,
267
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
268
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
269
+ PRIMARY KEY (`chat_jid`),
270
+ UNIQUE KEY `uq_rpg_battle_owner` (`owner_jid`),
271
+ KEY `idx_rpg_battle_expires_at` (`expires_at`),
272
+ KEY `fk_rpg_battle_my_pokemon` (`my_pokemon_id`),
273
+ CONSTRAINT `fk_rpg_battle_my_pokemon` FOREIGN KEY (`my_pokemon_id`) REFERENCES `rpg_player_pokemon` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
274
+ CONSTRAINT `fk_rpg_battle_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
275
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
276
+
277
+ CREATE TABLE IF NOT EXISTS `rpg_group_activity_daily` (
278
+ `day_ref_date` date NOT NULL,
279
+ `chat_jid` varchar(255) NOT NULL,
280
+ `owner_jid` varchar(255) NOT NULL,
281
+ `actions_count` int(10) unsigned NOT NULL DEFAULT 0,
282
+ `pvp_created_count` int(10) unsigned NOT NULL DEFAULT 0,
283
+ `pvp_completed_count` int(10) unsigned NOT NULL DEFAULT 0,
284
+ `coop_completed_count` int(10) unsigned NOT NULL DEFAULT 0,
285
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
286
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
287
+ PRIMARY KEY (`day_ref_date`,`chat_jid`,`owner_jid`),
288
+ KEY `idx_rpg_activity_chat_day` (`chat_jid`,`day_ref_date`),
289
+ KEY `idx_rpg_activity_owner_day` (`owner_jid`,`day_ref_date`),
290
+ CONSTRAINT `fk_rpg_activity_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
291
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
292
+
293
+ CREATE TABLE IF NOT EXISTS `rpg_group_biome` (
294
+ `group_jid` varchar(255) NOT NULL,
295
+ `biome_key` varchar(64) NOT NULL,
296
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
297
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
298
+ PRIMARY KEY (`group_jid`)
299
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
300
+
301
+ CREATE TABLE IF NOT EXISTS `rpg_group_coop_member` (
302
+ `chat_jid` varchar(255) NOT NULL,
303
+ `week_ref_date` date NOT NULL,
304
+ `owner_jid` varchar(255) NOT NULL,
305
+ `capture_contribution` int(10) unsigned NOT NULL DEFAULT 0,
306
+ `raid_contribution` int(10) unsigned NOT NULL DEFAULT 0,
307
+ `reward_claimed_at` datetime DEFAULT NULL,
308
+ `last_contribution_at` datetime DEFAULT NULL,
309
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
310
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
311
+ PRIMARY KEY (`chat_jid`,`week_ref_date`,`owner_jid`),
312
+ KEY `idx_rpg_coop_member_owner` (`owner_jid`,`week_ref_date`),
313
+ CONSTRAINT `fk_rpg_coop_member_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
314
+ CONSTRAINT `fk_rpg_coop_member_weekly` FOREIGN KEY (`chat_jid`, `week_ref_date`) REFERENCES `rpg_group_coop_weekly` (`chat_jid`, `week_ref_date`) ON DELETE CASCADE ON UPDATE CASCADE
315
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
316
+
317
+ CREATE TABLE IF NOT EXISTS `rpg_group_coop_weekly` (
318
+ `chat_jid` varchar(255) NOT NULL,
319
+ `week_ref_date` date NOT NULL,
320
+ `capture_target` int(10) unsigned NOT NULL DEFAULT 20,
321
+ `raid_target` int(10) unsigned NOT NULL DEFAULT 3,
322
+ `capture_progress` int(10) unsigned NOT NULL DEFAULT 0,
323
+ `raid_progress` int(10) unsigned NOT NULL DEFAULT 0,
324
+ `status` varchar(24) NOT NULL DEFAULT 'active',
325
+ `completed_at` datetime DEFAULT NULL,
326
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
327
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
328
+ PRIMARY KEY (`chat_jid`,`week_ref_date`),
329
+ KEY `idx_rpg_coop_weekly_status` (`status`,`week_ref_date`)
330
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
331
+
332
+ CREATE TABLE IF NOT EXISTS `rpg_group_event_member` (
333
+ `chat_jid` varchar(255) NOT NULL,
334
+ `week_ref_date` date NOT NULL,
335
+ `owner_jid` varchar(255) NOT NULL,
336
+ `contribution` bigint(20) unsigned NOT NULL DEFAULT 0,
337
+ `reward_claimed_at` datetime DEFAULT NULL,
338
+ `last_contribution_at` datetime DEFAULT NULL,
339
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
340
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
341
+ PRIMARY KEY (`chat_jid`,`week_ref_date`,`owner_jid`),
342
+ KEY `idx_rpg_event_member_owner` (`owner_jid`,`week_ref_date`),
343
+ CONSTRAINT `fk_rpg_event_member_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
344
+ CONSTRAINT `fk_rpg_event_member_weekly` FOREIGN KEY (`chat_jid`, `week_ref_date`) REFERENCES `rpg_group_event_weekly` (`chat_jid`, `week_ref_date`) ON DELETE CASCADE ON UPDATE CASCADE
345
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
346
+
347
+ CREATE TABLE IF NOT EXISTS `rpg_group_event_weekly` (
348
+ `chat_jid` varchar(255) NOT NULL,
349
+ `week_ref_date` date NOT NULL,
350
+ `event_key` varchar(64) NOT NULL,
351
+ `target_value` bigint(20) unsigned NOT NULL,
352
+ `progress_value` bigint(20) unsigned NOT NULL DEFAULT 0,
353
+ `status` varchar(24) NOT NULL DEFAULT 'active',
354
+ `expires_at` datetime NOT NULL,
355
+ `completed_at` datetime DEFAULT NULL,
356
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
357
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
358
+ PRIMARY KEY (`chat_jid`,`week_ref_date`),
359
+ KEY `idx_rpg_event_weekly_status_expires` (`status`,`expires_at`)
360
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
361
+
362
+ CREATE TABLE IF NOT EXISTS `rpg_karma_profile` (
363
+ `owner_jid` varchar(255) NOT NULL,
364
+ `karma_score` int(11) NOT NULL DEFAULT 0,
365
+ `positive_votes` int(10) unsigned NOT NULL DEFAULT 0,
366
+ `negative_votes` int(10) unsigned NOT NULL DEFAULT 0,
367
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
368
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
369
+ PRIMARY KEY (`owner_jid`),
370
+ CONSTRAINT `fk_rpg_karma_profile_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
371
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
372
+
373
+ CREATE TABLE IF NOT EXISTS `rpg_karma_vote_history` (
374
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
375
+ `week_ref_date` date NOT NULL,
376
+ `voter_jid` varchar(255) NOT NULL,
377
+ `target_jid` varchar(255) NOT NULL,
378
+ `vote_value` tinyint(4) NOT NULL,
379
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
380
+ PRIMARY KEY (`id`),
381
+ UNIQUE KEY `uq_rpg_karma_week_vote` (`week_ref_date`,`voter_jid`,`target_jid`),
382
+ KEY `idx_rpg_karma_target_week` (`target_jid`,`week_ref_date`),
383
+ KEY `fk_rpg_karma_vote_voter` (`voter_jid`),
384
+ CONSTRAINT `fk_rpg_karma_vote_target` FOREIGN KEY (`target_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
385
+ CONSTRAINT `fk_rpg_karma_vote_voter` FOREIGN KEY (`voter_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
386
+ CONSTRAINT `chk_rpg_karma_vote_value` CHECK (`vote_value` in (-1,1))
387
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
388
+
389
+ CREATE TABLE IF NOT EXISTS `rpg_player` (
390
+ `jid` varchar(255) NOT NULL,
391
+ `level` int(10) unsigned NOT NULL DEFAULT 1,
392
+ `xp` bigint(20) unsigned NOT NULL DEFAULT 0,
393
+ `xp_pool_social` bigint(20) unsigned NOT NULL DEFAULT 0,
394
+ `gold` bigint(20) unsigned NOT NULL DEFAULT 200,
395
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
396
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
397
+ PRIMARY KEY (`jid`)
398
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
399
+
400
+ CREATE TABLE IF NOT EXISTS `rpg_player_inventory` (
401
+ `owner_jid` varchar(255) NOT NULL,
402
+ `item_key` varchar(64) NOT NULL,
403
+ `quantity` int(10) unsigned NOT NULL DEFAULT 0,
404
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
405
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
406
+ PRIMARY KEY (`owner_jid`,`item_key`),
407
+ CONSTRAINT `fk_rpg_inventory_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
408
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
409
+
410
+ CREATE TABLE IF NOT EXISTS `rpg_player_mission_progress` (
411
+ `owner_jid` varchar(255) NOT NULL,
412
+ `daily_ref_date` date NOT NULL,
413
+ `daily_progress_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`daily_progress_json`)),
414
+ `daily_claimed_at` datetime DEFAULT NULL,
415
+ `weekly_ref_date` date NOT NULL,
416
+ `weekly_progress_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`weekly_progress_json`)),
417
+ `weekly_claimed_at` datetime DEFAULT NULL,
418
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
419
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
420
+ PRIMARY KEY (`owner_jid`),
421
+ CONSTRAINT `fk_rpg_mission_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
422
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
423
+
424
+ CREATE TABLE IF NOT EXISTS `rpg_player_pokedex` (
425
+ `owner_jid` varchar(255) NOT NULL,
426
+ `poke_id` int(10) unsigned NOT NULL,
427
+ `first_captured_at` timestamp NULL DEFAULT current_timestamp(),
428
+ PRIMARY KEY (`owner_jid`,`poke_id`),
429
+ KEY `idx_rpg_pokedex_owner` (`owner_jid`),
430
+ CONSTRAINT `fk_rpg_pokedex_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
431
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
432
+
433
+ CREATE TABLE IF NOT EXISTS `rpg_player_pokemon` (
434
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
435
+ `owner_jid` varchar(255) NOT NULL,
436
+ `poke_id` int(10) unsigned NOT NULL,
437
+ `nickname` varchar(120) DEFAULT NULL,
438
+ `level` int(10) unsigned NOT NULL DEFAULT 5,
439
+ `xp` bigint(20) unsigned NOT NULL DEFAULT 0,
440
+ `current_hp` int(10) unsigned NOT NULL,
441
+ `ivs_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`ivs_json`)),
442
+ `moves_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`moves_json`)),
443
+ `nature_key` varchar(64) DEFAULT NULL,
444
+ `ability_key` varchar(64) DEFAULT NULL,
445
+ `ability_name` varchar(120) DEFAULT NULL,
446
+ `is_shiny` tinyint(1) NOT NULL DEFAULT 0,
447
+ `is_active` tinyint(1) NOT NULL DEFAULT 0,
448
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
449
+ PRIMARY KEY (`id`),
450
+ KEY `idx_rpg_player_pokemon_owner` (`owner_jid`),
451
+ KEY `idx_rpg_player_pokemon_owner_active` (`owner_jid`,`is_active`),
452
+ CONSTRAINT `fk_rpg_player_pokemon_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
453
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
454
+
455
+ CREATE TABLE IF NOT EXISTS `rpg_player_travel` (
456
+ `owner_jid` varchar(255) NOT NULL,
457
+ `region_key` varchar(120) DEFAULT NULL,
458
+ `location_key` varchar(120) DEFAULT NULL,
459
+ `location_area_key` varchar(120) DEFAULT NULL,
460
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
461
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
462
+ PRIMARY KEY (`owner_jid`),
463
+ CONSTRAINT `fk_rpg_travel_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
464
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
465
+
466
+ CREATE TABLE IF NOT EXISTS `rpg_pvp_challenge` (
467
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
468
+ `chat_jid` varchar(255) DEFAULT NULL,
469
+ `challenger_jid` varchar(255) NOT NULL,
470
+ `opponent_jid` varchar(255) NOT NULL,
471
+ `status` varchar(24) NOT NULL DEFAULT 'pending',
472
+ `turn_jid` varchar(255) DEFAULT NULL,
473
+ `winner_jid` varchar(255) DEFAULT NULL,
474
+ `battle_snapshot_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`battle_snapshot_json`)),
475
+ `started_at` datetime DEFAULT NULL,
476
+ `expires_at` datetime NOT NULL,
477
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
478
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
479
+ PRIMARY KEY (`id`),
480
+ KEY `idx_rpg_pvp_status_expires` (`status`,`expires_at`),
481
+ KEY `idx_rpg_pvp_challenger` (`challenger_jid`),
482
+ KEY `idx_rpg_pvp_opponent` (`opponent_jid`),
483
+ CONSTRAINT `fk_rpg_pvp_challenger` FOREIGN KEY (`challenger_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
484
+ CONSTRAINT `fk_rpg_pvp_opponent` FOREIGN KEY (`opponent_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
485
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
486
+
487
+ CREATE TABLE IF NOT EXISTS `rpg_pvp_queue` (
488
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
489
+ `chat_jid` varchar(255) NOT NULL,
490
+ `owner_jid` varchar(255) NOT NULL,
491
+ `status` varchar(24) NOT NULL DEFAULT 'queued',
492
+ `matched_challenge_id` bigint(20) unsigned DEFAULT NULL,
493
+ `expires_at` datetime NOT NULL,
494
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
495
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
496
+ PRIMARY KEY (`id`),
497
+ UNIQUE KEY `uq_rpg_pvp_queue_chat_owner_status` (`chat_jid`,`owner_jid`,`status`),
498
+ KEY `idx_rpg_pvp_queue_chat_status_expires` (`chat_jid`,`status`,`expires_at`),
499
+ KEY `idx_rpg_pvp_queue_owner_status` (`owner_jid`,`status`),
500
+ KEY `fk_rpg_pvp_queue_challenge` (`matched_challenge_id`),
501
+ CONSTRAINT `fk_rpg_pvp_queue_challenge` FOREIGN KEY (`matched_challenge_id`) REFERENCES `rpg_pvp_challenge` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
502
+ CONSTRAINT `fk_rpg_pvp_queue_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
503
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
504
+
505
+ CREATE TABLE IF NOT EXISTS `rpg_pvp_weekly_stats` (
506
+ `week_ref_date` date NOT NULL,
507
+ `owner_jid` varchar(255) NOT NULL,
508
+ `matches_played` int(10) unsigned NOT NULL DEFAULT 0,
509
+ `wins` int(10) unsigned NOT NULL DEFAULT 0,
510
+ `losses` int(10) unsigned NOT NULL DEFAULT 0,
511
+ `points` int(10) unsigned NOT NULL DEFAULT 0,
512
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
513
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
514
+ PRIMARY KEY (`week_ref_date`,`owner_jid`),
515
+ KEY `idx_rpg_pvp_weekly_points` (`week_ref_date`,`points` DESC,`wins` DESC),
516
+ KEY `fk_rpg_pvp_weekly_owner` (`owner_jid`),
517
+ CONSTRAINT `fk_rpg_pvp_weekly_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
518
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
519
+
520
+ CREATE TABLE IF NOT EXISTS `rpg_raid_participant` (
521
+ `chat_jid` varchar(255) NOT NULL,
522
+ `owner_jid` varchar(255) NOT NULL,
523
+ `total_damage` int(10) unsigned NOT NULL DEFAULT 0,
524
+ `joined_at` timestamp NULL DEFAULT current_timestamp(),
525
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
526
+ PRIMARY KEY (`chat_jid`,`owner_jid`),
527
+ KEY `idx_rpg_raid_part_owner` (`owner_jid`),
528
+ CONSTRAINT `fk_rpg_raid_part_chat` FOREIGN KEY (`chat_jid`) REFERENCES `rpg_raid_state` (`chat_jid`) ON DELETE CASCADE ON UPDATE CASCADE,
529
+ CONSTRAINT `fk_rpg_raid_part_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
530
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
531
+
532
+ CREATE TABLE IF NOT EXISTS `rpg_raid_state` (
533
+ `chat_jid` varchar(255) NOT NULL,
534
+ `created_by_jid` varchar(255) NOT NULL,
535
+ `biome_key` varchar(64) DEFAULT NULL,
536
+ `boss_snapshot_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`boss_snapshot_json`)),
537
+ `max_hp` int(10) unsigned NOT NULL,
538
+ `current_hp` int(10) unsigned NOT NULL,
539
+ `started_at` datetime NOT NULL,
540
+ `ends_at` datetime NOT NULL,
541
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
542
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
543
+ PRIMARY KEY (`chat_jid`),
544
+ KEY `idx_rpg_raid_ends_at` (`ends_at`),
545
+ KEY `fk_rpg_raid_creator` (`created_by_jid`),
546
+ CONSTRAINT `fk_rpg_raid_creator` FOREIGN KEY (`created_by_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
547
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
548
+
549
+ CREATE TABLE IF NOT EXISTS `rpg_social_link` (
550
+ `pair_key` varchar(600) NOT NULL,
551
+ `user_a_jid` varchar(255) NOT NULL,
552
+ `user_b_jid` varchar(255) NOT NULL,
553
+ `friendship_score` int(11) NOT NULL DEFAULT 0,
554
+ `rivalry_score` int(11) NOT NULL DEFAULT 0,
555
+ `interactions_count` int(10) unsigned NOT NULL DEFAULT 0,
556
+ `last_interaction_at` datetime DEFAULT NULL,
557
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
558
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
559
+ PRIMARY KEY (`pair_key`),
560
+ UNIQUE KEY `uq_rpg_social_link_pair_users` (`user_a_jid`,`user_b_jid`),
561
+ KEY `idx_rpg_social_link_user_a` (`user_a_jid`),
562
+ KEY `idx_rpg_social_link_user_b` (`user_b_jid`),
563
+ CONSTRAINT `fk_rpg_social_link_user_a` FOREIGN KEY (`user_a_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
564
+ CONSTRAINT `fk_rpg_social_link_user_b` FOREIGN KEY (`user_b_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
565
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
566
+
567
+ CREATE TABLE IF NOT EXISTS `rpg_social_xp_daily` (
568
+ `day_ref_date` date NOT NULL,
569
+ `owner_jid` varchar(255) NOT NULL,
570
+ `chat_jid` varchar(255) NOT NULL,
571
+ `earned_xp` int(10) unsigned NOT NULL DEFAULT 0,
572
+ `converted_xp` int(10) unsigned NOT NULL DEFAULT 0,
573
+ `cap_hits` int(10) unsigned NOT NULL DEFAULT 0,
574
+ `last_message_hash` char(40) DEFAULT NULL,
575
+ `last_earned_at` datetime DEFAULT NULL,
576
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
577
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
578
+ PRIMARY KEY (`day_ref_date`,`owner_jid`,`chat_jid`),
579
+ KEY `idx_rpg_social_xp_owner_day` (`owner_jid`,`day_ref_date`),
580
+ KEY `idx_rpg_social_xp_chat_day` (`chat_jid`,`day_ref_date`),
581
+ CONSTRAINT `fk_rpg_social_xp_owner` FOREIGN KEY (`owner_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
582
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
583
+
584
+ CREATE TABLE IF NOT EXISTS `rpg_trade_offer` (
585
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
586
+ `chat_jid` varchar(255) DEFAULT NULL,
587
+ `proposer_jid` varchar(255) NOT NULL,
588
+ `receiver_jid` varchar(255) NOT NULL,
589
+ `proposer_offer_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`proposer_offer_json`)),
590
+ `receiver_offer_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`receiver_offer_json`)),
591
+ `status` varchar(24) NOT NULL DEFAULT 'pending',
592
+ `accepted_at` datetime DEFAULT NULL,
593
+ `expires_at` datetime NOT NULL,
594
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
595
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
596
+ PRIMARY KEY (`id`),
597
+ KEY `idx_rpg_trade_status_expires` (`status`,`expires_at`),
598
+ KEY `idx_rpg_trade_proposer` (`proposer_jid`),
599
+ KEY `idx_rpg_trade_receiver` (`receiver_jid`),
600
+ CONSTRAINT `fk_rpg_trade_proposer` FOREIGN KEY (`proposer_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE,
601
+ CONSTRAINT `fk_rpg_trade_receiver` FOREIGN KEY (`receiver_jid`) REFERENCES `rpg_player` (`jid`) ON DELETE CASCADE ON UPDATE CASCADE
602
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
603
+
604
+ CREATE TABLE IF NOT EXISTS `semantic_theme_clusters` (
605
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
606
+ `canonical_slug` varchar(255) NOT NULL,
607
+ `embedding_dim` smallint(5) unsigned NOT NULL,
608
+ `embedding` mediumblob NOT NULL,
609
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
610
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
611
+ PRIMARY KEY (`id`),
612
+ KEY `idx_semantic_theme_clusters_slug` (`canonical_slug`),
613
+ KEY `idx_semantic_theme_clusters_created` (`created_at`)
614
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
615
+
616
+ CREATE TABLE IF NOT EXISTS `semantic_theme_suggestion_cache` (
617
+ `suggestion_hash` char(64) NOT NULL,
618
+ `suggestion_text` varchar(512) NOT NULL,
619
+ `normalized_text` varchar(512) NOT NULL,
620
+ `semantic_cluster_id` bigint(20) unsigned NOT NULL,
621
+ `canonical_slug` varchar(255) NOT NULL,
622
+ `embedding_dim` smallint(5) unsigned NOT NULL,
623
+ `embedding` mediumblob NOT NULL,
624
+ `last_similarity` decimal(8,6) DEFAULT NULL,
625
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
626
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
627
+ PRIMARY KEY (`suggestion_hash`),
628
+ UNIQUE KEY `uq_semantic_theme_cache_normalized` (`normalized_text`),
629
+ KEY `idx_semantic_theme_cache_cluster` (`semantic_cluster_id`),
630
+ CONSTRAINT `fk_semantic_theme_cache_cluster` FOREIGN KEY (`semantic_cluster_id`) REFERENCES `semantic_theme_clusters` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
631
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
632
+
633
+ CREATE TABLE IF NOT EXISTS `sticker_asset` (
634
+ `id` char(36) NOT NULL,
635
+ `owner_jid` varchar(255) NOT NULL,
636
+ `sha256` char(64) NOT NULL,
637
+ `mimetype` varchar(64) NOT NULL,
638
+ `is_animated` tinyint(1) NOT NULL DEFAULT 0,
639
+ `width` int(10) unsigned DEFAULT NULL,
640
+ `height` int(10) unsigned DEFAULT NULL,
641
+ `size_bytes` int(10) unsigned NOT NULL,
642
+ `storage_path` varchar(1024) NOT NULL,
643
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
644
+ PRIMARY KEY (`id`),
645
+ UNIQUE KEY `uq_sticker_asset_sha256` (`sha256`),
646
+ KEY `idx_sticker_asset_owner_created` (`owner_jid`,`created_at`),
647
+ KEY `idx_sticker_asset_created_at` (`created_at`)
648
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
649
+
650
+ CREATE TABLE IF NOT EXISTS `sticker_asset_classification` (
651
+ `asset_id` char(36) NOT NULL,
652
+ `provider` varchar(64) NOT NULL DEFAULT 'clip',
653
+ `model_name` varchar(120) DEFAULT NULL,
654
+ `classification_version` varchar(32) NOT NULL DEFAULT 'v1',
655
+ `category` varchar(120) DEFAULT NULL,
656
+ `confidence` decimal(6,5) DEFAULT NULL,
657
+ `entropy` decimal(8,6) DEFAULT NULL,
658
+ `confidence_margin` decimal(8,6) DEFAULT NULL,
659
+ `nsfw_score` decimal(6,5) DEFAULT NULL,
660
+ `is_nsfw` tinyint(1) NOT NULL DEFAULT 0,
661
+ `all_scores` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`all_scores`)),
662
+ `top_labels` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`top_labels`)),
663
+ `affinity_weight` decimal(8,6) DEFAULT NULL,
664
+ `image_hash` char(64) DEFAULT NULL,
665
+ `ambiguous` tinyint(1) NOT NULL DEFAULT 0,
666
+ `llm_subtags` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`llm_subtags`)),
667
+ `llm_style_traits` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`llm_style_traits`)),
668
+ `llm_emotions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`llm_emotions`)),
669
+ `llm_pack_suggestions` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`llm_pack_suggestions`)),
670
+ `semantic_cluster_id` bigint(20) unsigned DEFAULT NULL,
671
+ `semantic_cluster_slug` varchar(255) DEFAULT NULL,
672
+ `similar_images` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`similar_images`)),
673
+ `classified_at` timestamp NULL DEFAULT current_timestamp(),
674
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
675
+ PRIMARY KEY (`asset_id`),
676
+ KEY `idx_sticker_asset_classification_category` (`category`),
677
+ KEY `idx_sticker_asset_classification_nsfw` (`is_nsfw`),
678
+ KEY `idx_sticker_asset_classification_semantic_cluster` (`semantic_cluster_id`),
679
+ KEY `idx_sticker_asset_classification_confidence` (`confidence`),
680
+ KEY `idx_sticker_asset_classification_updated_at` (`updated_at`),
681
+ KEY `idx_sticker_asset_classification_version_updated` (`classification_version`,`updated_at`),
682
+ CONSTRAINT `fk_sticker_asset_classification_asset` FOREIGN KEY (`asset_id`) REFERENCES `sticker_asset` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
683
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
684
+
685
+ CREATE TABLE IF NOT EXISTS `sticker_asset_reprocess_queue` (
686
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
687
+ `asset_id` char(36) NOT NULL,
688
+ `reason` enum('MODEL_UPGRADE','LOW_CONFIDENCE','TREND_SHIFT','NSFW_REVIEW') NOT NULL,
689
+ `priority` tinyint(3) unsigned NOT NULL DEFAULT 50,
690
+ `scheduled_at` timestamp NOT NULL DEFAULT current_timestamp(),
691
+ `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending',
692
+ `attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
693
+ `max_attempts` tinyint(3) unsigned NOT NULL DEFAULT 5,
694
+ `worker_token` char(36) DEFAULT NULL,
695
+ `last_error` varchar(255) DEFAULT NULL,
696
+ `locked_at` timestamp NULL DEFAULT NULL,
697
+ `processed_at` timestamp NULL DEFAULT NULL,
698
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
699
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
700
+ PRIMARY KEY (`id`),
701
+ KEY `idx_sticker_reprocess_status_schedule` (`status`,`scheduled_at`,`priority`),
702
+ KEY `idx_sticker_reprocess_asset_reason` (`asset_id`,`reason`),
703
+ KEY `idx_sticker_reprocess_worker_token` (`worker_token`),
704
+ KEY `idx_sticker_asset_reprocess_queue_status_locked` (`status`,`locked_at`),
705
+ CONSTRAINT `fk_sticker_reprocess_asset` FOREIGN KEY (`asset_id`) REFERENCES `sticker_asset` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
706
+ CONSTRAINT `chk_sticker_asset_reprocess_queue_attempts` CHECK (`attempts` <= `max_attempts`)
707
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
708
+
709
+ CREATE TABLE IF NOT EXISTS `sticker_pack` (
710
+ `id` char(36) NOT NULL,
711
+ `owner_jid` varchar(255) NOT NULL,
712
+ `name` varchar(120) NOT NULL,
713
+ `publisher` varchar(120) NOT NULL,
714
+ `description` text DEFAULT NULL,
715
+ `pack_key` varchar(160) NOT NULL,
716
+ `cover_sticker_id` char(36) DEFAULT NULL,
717
+ `visibility` enum('private','public','unlisted') NOT NULL DEFAULT 'private',
718
+ `status` enum('draft','uploading','processing','published','failed') NOT NULL DEFAULT 'published',
719
+ `pack_status` enum('building','ready','archived') NOT NULL DEFAULT 'ready',
720
+ `pack_theme_key` varchar(96) DEFAULT NULL,
721
+ `pack_volume` int(10) unsigned DEFAULT NULL,
722
+ `is_auto_pack` tinyint(1) NOT NULL DEFAULT 0,
723
+ `last_rebalanced_at` timestamp NULL DEFAULT NULL,
724
+ `version` int(10) unsigned NOT NULL DEFAULT 1,
725
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
726
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
727
+ `deleted_at` timestamp NULL DEFAULT NULL,
728
+ PRIMARY KEY (`id`),
729
+ UNIQUE KEY `uq_sticker_pack_pack_key` (`pack_key`),
730
+ KEY `idx_sticker_pack_owner_deleted` (`owner_jid`,`deleted_at`),
731
+ KEY `idx_sticker_pack_owner_updated` (`owner_jid`,`updated_at`),
732
+ KEY `fk_sticker_pack_cover` (`cover_sticker_id`),
733
+ KEY `idx_sticker_pack_auto_theme_status` (`is_auto_pack`,`pack_theme_key`,`pack_status`,`pack_volume`),
734
+ KEY `idx_sticker_pack_auto_owner_status` (`owner_jid`,`is_auto_pack`,`pack_status`,`updated_at`),
735
+ KEY `idx_sticker_pack_catalog_lookup` (`deleted_at`,`status`,`pack_status`,`visibility`,`updated_at`),
736
+ CONSTRAINT `fk_sticker_pack_cover` FOREIGN KEY (`cover_sticker_id`) REFERENCES `sticker_asset` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
737
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
738
+
739
+ CREATE TABLE IF NOT EXISTS `sticker_pack_engagement` (
740
+ `pack_id` char(36) NOT NULL,
741
+ `open_count` bigint(20) unsigned NOT NULL DEFAULT 0,
742
+ `like_count` bigint(20) unsigned NOT NULL DEFAULT 0,
743
+ `dislike_count` bigint(20) unsigned NOT NULL DEFAULT 0,
744
+ `last_opened_at` timestamp NULL DEFAULT NULL,
745
+ `last_interacted_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
746
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
747
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
748
+ PRIMARY KEY (`pack_id`),
749
+ KEY `idx_sticker_pack_engagement_updated` (`updated_at`),
750
+ KEY `idx_sticker_pack_engagement_like` (`like_count`),
751
+ KEY `idx_sticker_pack_engagement_open` (`open_count`),
752
+ CONSTRAINT `fk_sticker_pack_engagement_pack` FOREIGN KEY (`pack_id`) REFERENCES `sticker_pack` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
753
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
754
+
755
+ CREATE TABLE IF NOT EXISTS `sticker_pack_interaction_event` (
756
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
757
+ `pack_id` char(36) NOT NULL,
758
+ `interaction` enum('open','like','dislike') NOT NULL,
759
+ `actor_key` varchar(120) DEFAULT NULL,
760
+ `session_key` varchar(120) DEFAULT NULL,
761
+ `source` varchar(32) DEFAULT NULL,
762
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
763
+ PRIMARY KEY (`id`),
764
+ KEY `idx_sticker_pack_interaction_pack_created` (`pack_id`,`created_at`),
765
+ KEY `idx_sticker_pack_interaction_actor_created` (`actor_key`,`created_at`),
766
+ KEY `idx_sticker_pack_interaction_session_created` (`session_key`,`created_at`),
767
+ KEY `idx_sticker_pack_interaction_type_created` (`interaction`,`created_at`),
768
+ KEY `idx_sticker_pack_interaction_created_at` (`created_at`),
769
+ CONSTRAINT `fk_sticker_pack_interaction_pack` FOREIGN KEY (`pack_id`) REFERENCES `sticker_pack` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
770
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
771
+
772
+ CREATE TABLE IF NOT EXISTS `sticker_pack_item` (
773
+ `id` char(36) NOT NULL,
774
+ `pack_id` char(36) NOT NULL,
775
+ `sticker_id` char(36) NOT NULL,
776
+ `position` int(10) unsigned NOT NULL,
777
+ `emojis` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`emojis`)),
778
+ `accessibility_label` varchar(255) DEFAULT NULL,
779
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
780
+ PRIMARY KEY (`id`),
781
+ UNIQUE KEY `uq_sticker_pack_item_pack_sticker` (`pack_id`,`sticker_id`),
782
+ UNIQUE KEY `uq_sticker_pack_item_pack_position` (`pack_id`,`position`),
783
+ KEY `fk_sticker_pack_item_asset` (`sticker_id`),
784
+ KEY `idx_sticker_pack_item_sticker_id` (`sticker_id`),
785
+ CONSTRAINT `fk_sticker_pack_item_asset` FOREIGN KEY (`sticker_id`) REFERENCES `sticker_asset` (`id`) ON UPDATE CASCADE,
786
+ CONSTRAINT `fk_sticker_pack_item_pack` FOREIGN KEY (`pack_id`) REFERENCES `sticker_pack` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
787
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
788
+
789
+ CREATE TABLE IF NOT EXISTS `sticker_pack_score_snapshot` (
790
+ `pack_id` char(36) NOT NULL,
791
+ `ranking_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
792
+ `pack_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
793
+ `trend_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
794
+ `quality_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
795
+ `engagement_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
796
+ `diversity_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
797
+ `cohesion_score` decimal(10,6) NOT NULL DEFAULT 0.000000,
798
+ `sensitive_content` tinyint(1) NOT NULL DEFAULT 0,
799
+ `nsfw_level` enum('safe','suggestive','explicit') NOT NULL DEFAULT 'safe',
800
+ `sticker_count` int(10) unsigned NOT NULL DEFAULT 0,
801
+ `tags` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`tags`)),
802
+ `scores_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`scores_json`)),
803
+ `source_version` varchar(32) NOT NULL DEFAULT 'v1',
804
+ `refreshed_at` timestamp NOT NULL DEFAULT current_timestamp(),
805
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
806
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
807
+ PRIMARY KEY (`pack_id`),
808
+ KEY `idx_sticker_pack_score_snapshot_ranking` (`ranking_score`),
809
+ KEY `idx_sticker_pack_score_snapshot_trend` (`trend_score`),
810
+ KEY `idx_sticker_pack_score_snapshot_refresh` (`refreshed_at`),
811
+ CONSTRAINT `fk_sticker_pack_score_snapshot_pack` FOREIGN KEY (`pack_id`) REFERENCES `sticker_pack` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
812
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
813
+
814
+ CREATE TABLE IF NOT EXISTS `sticker_pack_web_upload` (
815
+ `id` char(36) NOT NULL,
816
+ `pack_id` char(36) NOT NULL,
817
+ `upload_id` varchar(120) NOT NULL,
818
+ `sticker_hash` char(64) NOT NULL,
819
+ `source_mimetype` varchar(64) DEFAULT NULL,
820
+ `upload_status` enum('pending','processing','done','failed') NOT NULL DEFAULT 'pending',
821
+ `sticker_id` char(36) DEFAULT NULL,
822
+ `error_code` varchar(64) DEFAULT NULL,
823
+ `error_message` varchar(255) DEFAULT NULL,
824
+ `attempt_count` int(10) unsigned NOT NULL DEFAULT 0,
825
+ `last_attempt_at` timestamp NULL DEFAULT NULL,
826
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
827
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
828
+ PRIMARY KEY (`id`),
829
+ UNIQUE KEY `uq_sticker_pack_web_upload_pack_upload_id` (`pack_id`,`upload_id`),
830
+ UNIQUE KEY `uq_sticker_pack_web_upload_pack_hash` (`pack_id`,`sticker_hash`),
831
+ KEY `idx_sticker_pack_web_upload_pack_status` (`pack_id`,`upload_status`),
832
+ KEY `idx_sticker_pack_web_upload_pack_updated` (`pack_id`,`updated_at`),
833
+ KEY `fk_sticker_pack_web_upload_sticker` (`sticker_id`),
834
+ CONSTRAINT `fk_sticker_pack_web_upload_pack` FOREIGN KEY (`pack_id`) REFERENCES `sticker_pack` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
835
+ CONSTRAINT `fk_sticker_pack_web_upload_sticker` FOREIGN KEY (`sticker_id`) REFERENCES `sticker_asset` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
836
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
837
+
838
+ CREATE TABLE IF NOT EXISTS `sticker_worker_task_dlq` (
839
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
840
+ `task_id` bigint(20) unsigned DEFAULT NULL,
841
+ `task_type` enum('classification_cycle','curation_cycle','rebuild_cycle') NOT NULL,
842
+ `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`payload`)),
843
+ `idempotency_key` varchar(180) DEFAULT NULL,
844
+ `attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
845
+ `max_attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
846
+ `priority` tinyint(3) unsigned NOT NULL DEFAULT 0,
847
+ `last_error` varchar(255) DEFAULT NULL,
848
+ `failed_at` timestamp NOT NULL DEFAULT current_timestamp(),
849
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
850
+ PRIMARY KEY (`id`),
851
+ UNIQUE KEY `uq_sticker_worker_task_dlq_task_id` (`task_id`),
852
+ KEY `idx_sticker_worker_task_dlq_type_failed_at` (`task_type`,`failed_at`),
853
+ KEY `idx_sticker_worker_task_dlq_idempotency_key` (`idempotency_key`)
854
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
855
+
856
+ CREATE TABLE IF NOT EXISTS `sticker_worker_task_queue` (
857
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
858
+ `task_type` enum('classification_cycle','curation_cycle','rebuild_cycle') NOT NULL,
859
+ `idempotency_key` varchar(180) DEFAULT NULL,
860
+ `payload` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`payload`)),
861
+ `priority` tinyint(3) unsigned NOT NULL DEFAULT 50,
862
+ `scheduled_at` timestamp NOT NULL DEFAULT current_timestamp(),
863
+ `status` enum('pending','processing','completed','failed') NOT NULL DEFAULT 'pending',
864
+ `attempts` tinyint(3) unsigned NOT NULL DEFAULT 0,
865
+ `max_attempts` tinyint(3) unsigned NOT NULL DEFAULT 5,
866
+ `worker_token` char(36) DEFAULT NULL,
867
+ `last_error` varchar(255) DEFAULT NULL,
868
+ `locked_at` timestamp NULL DEFAULT NULL,
869
+ `processed_at` timestamp NULL DEFAULT NULL,
870
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
871
+ `updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
872
+ PRIMARY KEY (`id`),
873
+ UNIQUE KEY `uq_sticker_worker_task_idempotency_key` (`idempotency_key`),
874
+ KEY `idx_sticker_worker_task_type_status_schedule` (`task_type`,`status`,`scheduled_at`,`priority`),
875
+ KEY `idx_sticker_worker_task_status_schedule` (`status`,`scheduled_at`,`priority`),
876
+ KEY `idx_sticker_worker_task_worker_token` (`worker_token`),
877
+ KEY `idx_sticker_worker_task_queue_status_locked` (`status`,`locked_at`),
878
+ CONSTRAINT `chk_sticker_worker_task_queue_attempts` CHECK (`attempts` <= `max_attempts`)
879
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
880
+
881
+ CREATE TABLE IF NOT EXISTS `web_admin_ban` (
882
+ `id` char(36) NOT NULL,
883
+ `google_sub` varchar(80) DEFAULT NULL,
884
+ `email` varchar(255) DEFAULT NULL,
885
+ `owner_jid` varchar(255) DEFAULT NULL,
886
+ `reason` varchar(255) DEFAULT NULL,
887
+ `created_by_google_sub` varchar(80) DEFAULT NULL,
888
+ `created_by_email` varchar(255) DEFAULT NULL,
889
+ `revoked_at` timestamp NULL DEFAULT NULL,
890
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
891
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
892
+ PRIMARY KEY (`id`),
893
+ KEY `idx_web_admin_ban_google_sub` (`google_sub`,`revoked_at`,`created_at`),
894
+ KEY `idx_web_admin_ban_email` (`email`,`revoked_at`,`created_at`),
895
+ KEY `idx_web_admin_ban_owner_jid` (`owner_jid`,`revoked_at`,`created_at`),
896
+ KEY `idx_web_admin_ban_revoked_created` (`revoked_at`,`created_at`),
897
+ CONSTRAINT `chk_web_admin_ban_identity` CHECK (`google_sub` is not null or `email` is not null or `owner_jid` is not null)
898
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
899
+
900
+ CREATE TABLE IF NOT EXISTS `web_admin_moderator` (
901
+ `google_sub` varchar(80) NOT NULL,
902
+ `owner_jid` varchar(255) NOT NULL,
903
+ `email` varchar(255) NOT NULL,
904
+ `name` varchar(120) DEFAULT NULL,
905
+ `password_hash` varchar(255) NOT NULL,
906
+ `created_by_google_sub` varchar(80) DEFAULT NULL,
907
+ `created_by_email` varchar(255) DEFAULT NULL,
908
+ `updated_by_google_sub` varchar(80) DEFAULT NULL,
909
+ `updated_by_email` varchar(255) DEFAULT NULL,
910
+ `last_login_at` timestamp NULL DEFAULT NULL,
911
+ `revoked_at` timestamp NULL DEFAULT NULL,
912
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
913
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
914
+ PRIMARY KEY (`google_sub`),
915
+ KEY `idx_web_admin_moderator_email` (`email`),
916
+ KEY `idx_web_admin_moderator_owner_jid` (`owner_jid`),
917
+ KEY `idx_web_admin_moderator_revoked_updated` (`revoked_at`,`updated_at`)
918
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
919
+
920
+ CREATE TABLE IF NOT EXISTS `web_google_session` (
921
+ `session_token` char(36) NOT NULL,
922
+ `session_token_hash` binary(32) NOT NULL,
923
+ `google_sub` varchar(80) NOT NULL,
924
+ `owner_jid` varchar(120) NOT NULL,
925
+ `owner_phone` varchar(20) DEFAULT NULL,
926
+ `email` varchar(255) DEFAULT NULL,
927
+ `name` varchar(120) DEFAULT NULL,
928
+ `picture_url` varchar(1024) DEFAULT NULL,
929
+ `expires_at` timestamp NOT NULL,
930
+ `revoked_at` timestamp NULL DEFAULT NULL,
931
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
932
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
933
+ `last_seen_at` timestamp NULL DEFAULT NULL,
934
+ PRIMARY KEY (`session_token`),
935
+ UNIQUE KEY `uq_web_google_session_token_hash` (`session_token_hash`),
936
+ KEY `idx_web_google_session_google_sub` (`google_sub`),
937
+ KEY `idx_web_google_session_owner_jid` (`owner_jid`),
938
+ KEY `idx_web_google_session_expires_at` (`expires_at`),
939
+ KEY `idx_web_google_session_revoked_expires` (`revoked_at`,`expires_at`),
940
+ KEY `idx_web_google_session_owner_phone` (`owner_phone`),
941
+ CONSTRAINT `fk_web_google_session_user` FOREIGN KEY (`google_sub`) REFERENCES `web_google_user` (`google_sub`) ON DELETE CASCADE ON UPDATE CASCADE
942
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
943
+
944
+ CREATE TABLE IF NOT EXISTS `web_google_user` (
945
+ `google_sub` varchar(80) NOT NULL,
946
+ `owner_jid` varchar(120) NOT NULL,
947
+ `owner_phone` varchar(20) DEFAULT NULL,
948
+ `email` varchar(255) DEFAULT NULL,
949
+ `name` varchar(120) DEFAULT NULL,
950
+ `picture_url` varchar(1024) DEFAULT NULL,
951
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
952
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
953
+ `last_login_at` timestamp NULL DEFAULT NULL,
954
+ `last_seen_at` timestamp NULL DEFAULT NULL,
955
+ PRIMARY KEY (`google_sub`),
956
+ UNIQUE KEY `uq_web_google_user_owner_jid` (`owner_jid`),
957
+ KEY `idx_web_google_user_email` (`email`),
958
+ KEY `idx_web_google_user_owner_phone` (`owner_phone`)
959
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
960
+
961
+ CREATE TABLE IF NOT EXISTS `web_user_password` (
962
+ `google_sub` varchar(80) NOT NULL,
963
+ `password_hash` varchar(255) NOT NULL,
964
+ `password_algo` varchar(24) NOT NULL DEFAULT 'argon2id',
965
+ `password_cost` tinyint(3) unsigned NOT NULL DEFAULT 3,
966
+ `failed_attempts` smallint(5) unsigned NOT NULL DEFAULT 0,
967
+ `last_failed_at` timestamp NULL DEFAULT NULL,
968
+ `last_login_at` timestamp NULL DEFAULT NULL,
969
+ `password_changed_at` timestamp NULL DEFAULT current_timestamp(),
970
+ `revoked_at` timestamp NULL DEFAULT NULL,
971
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
972
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
973
+ PRIMARY KEY (`google_sub`),
974
+ KEY `idx_web_user_password_revoked_updated` (`revoked_at`,`updated_at`),
975
+ KEY `idx_web_user_password_last_login` (`last_login_at`),
976
+ CONSTRAINT `fk_web_user_password_google_user` FOREIGN KEY (`google_sub`) REFERENCES `web_google_user` (`google_sub`) ON DELETE CASCADE ON UPDATE CASCADE
977
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
978
+
979
+ CREATE TABLE IF NOT EXISTS `web_user_password_login_throttle` (
980
+ `identity_hash` binary(32) NOT NULL,
981
+ `failed_attempts` smallint(5) unsigned NOT NULL DEFAULT 0,
982
+ `last_failed_at` timestamp NULL DEFAULT NULL,
983
+ `locked_until` timestamp NULL DEFAULT NULL,
984
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
985
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
986
+ PRIMARY KEY (`identity_hash`),
987
+ KEY `idx_web_user_password_login_throttle_locked_until` (`locked_until`),
988
+ KEY `idx_web_user_password_login_throttle_failed` (`failed_attempts`,`last_failed_at`)
989
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
990
+
991
+ CREATE TABLE IF NOT EXISTS `web_user_password_recovery_code` (
992
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
993
+ `google_sub` varchar(80) NOT NULL,
994
+ `email` varchar(255) NOT NULL,
995
+ `email_hash` binary(32) DEFAULT NULL,
996
+ `owner_jid` varchar(120) DEFAULT NULL,
997
+ `purpose` varchar(24) NOT NULL DEFAULT 'reset',
998
+ `code_hash` char(64) NOT NULL,
999
+ `attempts` smallint(5) unsigned NOT NULL DEFAULT 0,
1000
+ `max_attempts` smallint(5) unsigned NOT NULL DEFAULT 5,
1001
+ `requested_ip` varchar(64) DEFAULT NULL,
1002
+ `requested_ip_hash` binary(32) DEFAULT NULL,
1003
+ `requested_user_agent` varchar(255) DEFAULT NULL,
1004
+ `requested_user_agent_hash` binary(32) DEFAULT NULL,
1005
+ `last_attempt_at` timestamp NULL DEFAULT NULL,
1006
+ `expires_at` timestamp NOT NULL,
1007
+ `consumed_at` timestamp NULL DEFAULT NULL,
1008
+ `revoked_at` timestamp NULL DEFAULT NULL,
1009
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1010
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
1011
+ PRIMARY KEY (`id`),
1012
+ KEY `idx_web_user_password_recovery_sub_created` (`google_sub`,`created_at`),
1013
+ KEY `idx_web_user_password_recovery_email_created` (`email`,`created_at`),
1014
+ KEY `idx_web_user_password_recovery_email_hash_created` (`email_hash`,`created_at`),
1015
+ KEY `idx_web_user_password_recovery_status` (`revoked_at`,`consumed_at`,`expires_at`),
1016
+ KEY `idx_web_user_password_recovery_purpose` (`purpose`,`created_at`),
1017
+ CONSTRAINT `fk_web_user_password_recovery_google_user` FOREIGN KEY (`google_sub`) REFERENCES `web_google_user` (`google_sub`) ON DELETE CASCADE ON UPDATE CASCADE
1018
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1019
+
1020
+ CREATE TABLE IF NOT EXISTS `web_terms_acceptance_event` (
1021
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1022
+ `event_id` char(36) NOT NULL,
1023
+ `document_key` varchar(64) NOT NULL,
1024
+ `document_version` varchar(64) NOT NULL,
1025
+ `document_version_hash` char(64) NOT NULL,
1026
+ `accepted_at` timestamp NOT NULL DEFAULT current_timestamp(),
1027
+ `accepted_at_client` timestamp NULL DEFAULT NULL,
1028
+ `source` varchar(32) NOT NULL DEFAULT 'web_login',
1029
+ `google_sub` varchar(80) DEFAULT NULL,
1030
+ `email` varchar(255) DEFAULT NULL,
1031
+ `owner_jid` varchar(120) DEFAULT NULL,
1032
+ `session_key` varchar(80) DEFAULT NULL,
1033
+ `ip_address` varchar(64) DEFAULT NULL,
1034
+ `user_agent` varchar(512) DEFAULT NULL,
1035
+ `metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
1036
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
1037
+ PRIMARY KEY (`id`),
1038
+ UNIQUE KEY `uq_web_terms_acceptance_event_id` (`event_id`),
1039
+ KEY `idx_web_terms_acceptance_doc_version` (`document_key`,`document_version`,`accepted_at`),
1040
+ KEY `idx_web_terms_acceptance_identity` (`google_sub`,`email`,`owner_jid`,`accepted_at`),
1041
+ KEY `idx_web_terms_acceptance_source_created` (`source`,`created_at`),
1042
+ KEY `idx_web_terms_acceptance_session_created` (`session_key`,`created_at`)
1043
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1044
+
1045
+ CREATE TABLE IF NOT EXISTS `web_visit_event` (
1046
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1047
+ `visitor_key` varchar(80) NOT NULL,
1048
+ `session_key` varchar(80) NOT NULL,
1049
+ `page_path` varchar(255) NOT NULL,
1050
+ `referrer` varchar(1024) DEFAULT NULL,
1051
+ `user_agent` varchar(512) DEFAULT NULL,
1052
+ `source` varchar(32) NOT NULL DEFAULT 'web',
1053
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1054
+ PRIMARY KEY (`id`),
1055
+ KEY `idx_web_visit_created_at` (`created_at`),
1056
+ KEY `idx_web_visit_page_created` (`page_path`,`created_at`),
1057
+ KEY `idx_web_visit_visitor_created` (`visitor_key`,`created_at`),
1058
+ KEY `idx_web_visit_session_created` (`session_key`,`created_at`),
1059
+ KEY `idx_web_visit_source_created` (`source`,`created_at`)
1060
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1061
+
1062
+ CREATE TABLE IF NOT EXISTS `ai_help_response_cache` (
1063
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1064
+ `module_key` varchar(64) NOT NULL,
1065
+ `scope` varchar(32) NOT NULL DEFAULT 'question',
1066
+ `question_hash` char(64) NOT NULL,
1067
+ `normalized_question` varchar(512) NOT NULL,
1068
+ `original_question` varchar(512) DEFAULT NULL,
1069
+ `command_name` varchar(64) DEFAULT NULL,
1070
+ `answer_text` mediumtext NOT NULL,
1071
+ `source` varchar(32) NOT NULL DEFAULT 'deterministic',
1072
+ `model_name` varchar(80) DEFAULT NULL,
1073
+ `metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
1074
+ `hit_count` int(10) unsigned NOT NULL DEFAULT 1,
1075
+ `last_used_at` timestamp NULL DEFAULT current_timestamp(),
1076
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1077
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
1078
+ PRIMARY KEY (`id`),
1079
+ UNIQUE KEY `uq_ai_help_response_cache_lookup` (`module_key`,`scope`,`question_hash`),
1080
+ KEY `idx_ai_help_response_cache_module_command_used` (`module_key`,`command_name`,`last_used_at`),
1081
+ KEY `idx_ai_help_response_cache_used` (`last_used_at`),
1082
+ KEY `idx_ai_help_response_cache_source_used` (`source`,`last_used_at`)
1083
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1084
+
1085
+ CREATE TABLE IF NOT EXISTS `ai_learning_events` (
1086
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1087
+ `user_question` varchar(512) NOT NULL,
1088
+ `normalized_question` varchar(512) NOT NULL,
1089
+ `tool_suggested` varchar(64) NOT NULL,
1090
+ `tool_executed` varchar(64) NOT NULL,
1091
+ `success` tinyint(1) NOT NULL DEFAULT 1,
1092
+ `confidence` decimal(5,4) DEFAULT NULL,
1093
+ `processed` tinyint(1) NOT NULL DEFAULT 0,
1094
+ `processed_at` timestamp NULL DEFAULT NULL,
1095
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1096
+ PRIMARY KEY (`id`),
1097
+ KEY `idx_ai_learning_events_processed_created` (`processed`,`created_at`),
1098
+ KEY `idx_ai_learning_events_tool_created` (`tool_executed`,`created_at`),
1099
+ KEY `idx_ai_learning_events_norm_question` (`normalized_question`)
1100
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1101
+
1102
+ CREATE TABLE IF NOT EXISTS `ai_learned_patterns` (
1103
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1104
+ `pattern` varchar(512) NOT NULL,
1105
+ `tool` varchar(64) NOT NULL,
1106
+ `confidence` decimal(5,4) NOT NULL DEFAULT 0.5000,
1107
+ `source_event_id` bigint(20) unsigned NOT NULL,
1108
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1109
+ PRIMARY KEY (`id`),
1110
+ UNIQUE KEY `uq_ai_learned_patterns_event_pattern` (`source_event_id`,`tool`,`pattern`),
1111
+ KEY `idx_ai_learned_patterns_tool_created` (`tool`,`created_at`),
1112
+ KEY `idx_ai_learned_patterns_tool_confidence` (`tool`,`confidence`)
1113
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1114
+
1115
+ CREATE TABLE IF NOT EXISTS `ai_learned_keywords` (
1116
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1117
+ `keyword` varchar(128) NOT NULL,
1118
+ `tool` varchar(64) NOT NULL,
1119
+ `weight` decimal(6,4) NOT NULL DEFAULT 1.0000,
1120
+ `source_event_id` bigint(20) unsigned NOT NULL,
1121
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1122
+ PRIMARY KEY (`id`),
1123
+ UNIQUE KEY `uq_ai_learned_keywords_event_keyword` (`source_event_id`,`tool`,`keyword`),
1124
+ KEY `idx_ai_learned_keywords_tool_created` (`tool`,`created_at`),
1125
+ KEY `idx_ai_learned_keywords_tool_weight` (`tool`,`weight`)
1126
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1127
+
1128
+ CREATE TABLE IF NOT EXISTS `ai_question_embeddings` (
1129
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1130
+ `question` varchar(512) NOT NULL,
1131
+ `embedding` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`embedding`)),
1132
+ `tool` varchar(64) NOT NULL,
1133
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1134
+ PRIMARY KEY (`id`),
1135
+ KEY `idx_ai_question_embeddings_tool_created` (`tool`,`created_at`)
1136
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1137
+
1138
+ CREATE TABLE IF NOT EXISTS `ai_command_config_enrichment_cursor` (
1139
+ `id` tinyint(3) unsigned NOT NULL DEFAULT 1,
1140
+ `last_learning_event_id` bigint(20) unsigned NOT NULL DEFAULT 0,
1141
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
1142
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1143
+ PRIMARY KEY (`id`)
1144
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1145
+
1146
+ CREATE TABLE IF NOT EXISTS `ai_command_config_enrichment_suggestion` (
1147
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1148
+ `module_key` varchar(64) NOT NULL,
1149
+ `command_name` varchar(64) NOT NULL,
1150
+ `source_tool` varchar(64) DEFAULT NULL,
1151
+ `source_event_id` bigint(20) unsigned DEFAULT NULL,
1152
+ `user_question` varchar(512) DEFAULT NULL,
1153
+ `normalized_question` varchar(512) DEFAULT NULL,
1154
+ `suggestion_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`suggestion_json`)),
1155
+ `confidence` decimal(5,4) NOT NULL DEFAULT 0.5000,
1156
+ `model_name` varchar(80) DEFAULT NULL,
1157
+ `source` varchar(32) NOT NULL DEFAULT 'llm',
1158
+ `status` enum('pending','applied','rejected') NOT NULL DEFAULT 'pending',
1159
+ `suggestion_hash` char(64) NOT NULL,
1160
+ `review_notes` varchar(255) DEFAULT NULL,
1161
+ `applied_at` timestamp NULL DEFAULT NULL,
1162
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1163
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
1164
+ PRIMARY KEY (`id`),
1165
+ UNIQUE KEY `uq_ai_command_cfg_enrichment_suggestion_hash` (`suggestion_hash`),
1166
+ KEY `idx_ai_command_cfg_enrichment_module_command_status` (`module_key`,`command_name`,`status`,`updated_at`),
1167
+ KEY `idx_ai_command_cfg_enrichment_source_event` (`source_event_id`,`updated_at`),
1168
+ KEY `idx_ai_command_cfg_enrichment_status_updated` (`status`,`updated_at`)
1169
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1170
+
1171
+ CREATE TABLE IF NOT EXISTS `ai_command_config_enrichment_state` (
1172
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1173
+ `module_key` varchar(64) NOT NULL,
1174
+ `command_name` varchar(64) NOT NULL,
1175
+ `overlay_json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`overlay_json`)),
1176
+ `version` int(10) unsigned NOT NULL DEFAULT 1,
1177
+ `confidence` decimal(5,4) NOT NULL DEFAULT 0.5000,
1178
+ `last_suggestion_id` bigint(20) unsigned DEFAULT NULL,
1179
+ `created_at` timestamp NULL DEFAULT current_timestamp(),
1180
+ `updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
1181
+ PRIMARY KEY (`id`),
1182
+ UNIQUE KEY `uq_ai_command_cfg_enrichment_state_module_command` (`module_key`,`command_name`),
1183
+ KEY `idx_ai_command_cfg_enrichment_state_updated` (`updated_at`),
1184
+ KEY `idx_ai_command_cfg_enrichment_state_last_suggestion` (`last_suggestion_id`)
1185
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1186
+ SET FOREIGN_KEY_CHECKS = 1;