@omnizap-system/omnizap 2.6.1 → 2.6.2
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.
- package/.env.example +54 -9
- package/.github/workflows/ci.yml +3 -3
- package/.github/workflows/security-runner-hardening.yml +1 -1
- package/.github/workflows/security-zap-full-scan.yml +1 -0
- package/app/config/index.js +2 -0
- package/app/configParts/adminIdentity.js +5 -5
- package/app/configParts/baileysConfig.js +226 -55
- package/app/configParts/groupUtils.js +5 -0
- package/app/configParts/messagePersistenceService.js +143 -3
- package/app/configParts/sessionConfig.js +157 -0
- package/app/connection/baileysCompatibility.test.js +1 -1
- package/app/connection/groupOwnerWriteStateResolver.js +109 -0
- package/app/connection/socketController.js +625 -124
- package/app/connection/socketController.multiSession.test.js +108 -0
- package/app/controllers/messageController.js +1 -1
- package/app/controllers/messagePipeline/commandMiddleware.js +12 -10
- package/app/controllers/messagePipeline/conversationMiddleware.js +2 -1
- package/app/controllers/messagePipeline/messagePipelineMiddlewares.test.js +104 -0
- package/app/controllers/messagePipeline/preProcessingMiddlewares.js +80 -2
- package/app/controllers/messageProcessingPipeline.js +88 -9
- package/app/controllers/messageProcessingPipeline.test.js +200 -0
- package/app/modules/adminModule/AGENT.md +1 -1
- package/app/modules/adminModule/commandConfig.json +3318 -1347
- package/app/modules/adminModule/groupCommandHandlers.js +856 -14
- package/app/modules/adminModule/groupCommandHandlers.test.js +375 -9
- package/app/modules/adminModule/groupWarningRepository.js +152 -0
- package/app/modules/aiModule/AGENT.md +47 -30
- package/app/modules/aiModule/aiConfigRuntime.js +1 -0
- package/app/modules/aiModule/catCommand.js +132 -25
- package/app/modules/aiModule/commandConfig.json +114 -28
- package/app/modules/analyticsModule/messageAnalysisEventRepository.js +54 -6
- package/app/modules/gameModule/AGENT.md +1 -1
- package/app/modules/gameModule/commandConfig.json +29 -0
- package/app/modules/menuModule/AGENT.md +1 -1
- package/app/modules/menuModule/commandConfig.json +45 -10
- package/app/modules/menuModule/menuCatalogService.js +190 -0
- package/app/modules/menuModule/menuCommandUsageRepository.js +109 -0
- package/app/modules/menuModule/menuDynamicService.js +511 -0
- package/app/modules/menuModule/menuDynamicService.test.js +141 -0
- package/app/modules/menuModule/menus.js +36 -5
- package/app/modules/playModule/AGENT.md +10 -5
- package/app/modules/playModule/commandConfig.json +74 -16
- package/app/modules/playModule/playCommandConstants.js +13 -7
- package/app/modules/playModule/playCommandCore.js +4 -6
- package/app/modules/playModule/{playCommandYtDlpClient.js → playCommandMediaClient.js} +684 -332
- package/app/modules/playModule/playConfigRuntime.js +5 -6
- package/app/modules/playModule/playModuleCriticalFlows.test.js +44 -59
- package/app/modules/quoteModule/AGENT.md +1 -1
- package/app/modules/quoteModule/commandConfig.json +29 -0
- package/app/modules/rpgPokemonModule/AGENT.md +1 -1
- package/app/modules/rpgPokemonModule/commandConfig.json +29 -0
- package/app/modules/statsModule/AGENT.md +1 -1
- package/app/modules/statsModule/commandConfig.json +58 -0
- package/app/modules/stickerModule/AGENT.md +1 -1
- package/app/modules/stickerModule/commandConfig.json +145 -0
- package/app/modules/stickerPackModule/AGENT.md +1 -1
- package/app/modules/stickerPackModule/autoPackCollectorService.js +5 -1
- package/app/modules/stickerPackModule/commandConfig.json +29 -0
- package/app/modules/stickerPackModule/stickerAutoPackByTagsRuntime.js +1 -1
- package/app/modules/stickerPackModule/stickerPackCommandHandlers.js +78 -57
- package/app/modules/stickerPackModule/stickerPackService.js +13 -6
- package/app/modules/systemMetricsModule/AGENT.md +1 -1
- package/app/modules/systemMetricsModule/commandConfig.json +29 -0
- package/app/modules/tiktokModule/AGENT.md +1 -1
- package/app/modules/tiktokModule/commandConfig.json +29 -0
- package/app/modules/userModule/AGENT.md +1 -1
- package/app/modules/userModule/commandConfig.json +29 -0
- package/app/modules/waifuPicsModule/AGENT.md +57 -27
- package/app/modules/waifuPicsModule/commandConfig.json +87 -0
- package/app/observability/metrics.js +136 -0
- package/app/services/ai/commandConfigEnrichmentService.js +229 -47
- package/app/services/ai/geminiService.js +131 -7
- package/app/services/ai/geminiService.test.js +59 -2
- package/app/services/ai/moduleAiHelpCoreService.js +33 -4
- package/app/services/group/groupMetadataService.js +24 -1
- package/app/services/infra/dbWriteQueue.js +51 -21
- package/app/services/messaging/newsBroadcastService.js +843 -27
- package/app/services/multiSession/assignmentBalancerService.js +457 -0
- package/app/services/multiSession/groupOwnershipRepository.js +381 -0
- package/app/services/multiSession/groupOwnershipService.js +890 -0
- package/app/services/multiSession/groupOwnershipService.test.js +309 -0
- package/app/services/multiSession/sessionRegistryService.js +293 -0
- package/app/store/aiPromptStore.js +36 -19
- package/app/store/groupConfigStore.js +41 -5
- package/app/store/premiumUserStore.js +21 -7
- package/app/utils/antiLink/antiLinkModule.js +352 -16
- package/app/workers/aiHelperContinuousLearningWorker.js +512 -0
- package/database/index.js +6 -0
- package/database/migrations/20260307_d0_hardening_down.sql +1 -1
- package/database/migrations/20260314_d7_canonical_sender_down.sql +1 -1
- package/database/migrations/20260406_d30_security_analytics_down.sql +1 -1
- package/database/migrations/20260411_d35_group_community_metadata_down.sql +59 -0
- package/database/migrations/20260411_d35_group_community_metadata_up.sql +62 -0
- package/database/migrations/20260412_d36_system_config_tables_down.sql +32 -0
- package/database/migrations/20260412_d36_system_config_tables_up.sql +66 -0
- package/database/migrations/20260413_d37_group_user_warnings_down.sql +11 -0
- package/database/migrations/20260413_d37_group_user_warnings_up.sql +24 -0
- package/database/migrations/20260414_d38_multi_session_foundation_down.sql +72 -0
- package/database/migrations/20260414_d38_multi_session_foundation_up.sql +125 -0
- package/database/migrations/20260414_d39_multi_session_cutover_down.sql +103 -0
- package/database/migrations/20260414_d39_multi_session_cutover_up.sql +83 -0
- package/database/schema.sql +102 -1
- package/docker-compose.yml +4 -1
- package/docs/compliance/acceptable-use-policy-2026-03-07.md +1 -1
- package/docs/compliance/privacy-policy-2026-03-07.md +2 -2
- package/docs/security/dsar-lgpd-runbook-2026-03-07.md +1 -1
- package/docs/security/network-hardening-runbook-2026-03-07.md +53 -0
- package/docs/security/omnizap-static-security-headers.conf +25 -0
- package/ecosystem.prod.config.cjs +31 -11
- package/index.js +52 -18
- package/observability/alert-rules.yml +20 -0
- package/observability/grafana/dashboards/omnizap-system-admin.json +229 -0
- package/observability/mysql-setup.sql +4 -4
- package/observability/system-admin-observability.md +26 -0
- package/package.json +12 -5
- package/public/comandos/commands-catalog.json +2253 -78
- package/public/js/apps/commandsReactApp.js +267 -87
- package/public/js/apps/createPackApp.js +3 -3
- package/public/js/apps/stickersApp.js +255 -103
- package/public/js/apps/termsReactApp.js +57 -8
- package/public/js/apps/userPasswordResetReactApp.js +406 -0
- package/public/js/apps/userReactApp.js +96 -47
- package/public/js/apps/userSystemAdmReactApp.js +1506 -0
- package/public/pages/politica-de-privacidade.html +1 -1
- package/public/pages/stickers.html +5 -5
- package/public/pages/termos-de-uso-texto-integral.html +1 -1
- package/public/pages/termos-de-uso.html +1 -1
- package/public/pages/user-password-reset.html +3 -4
- package/public/pages/user-systemadm.html +8 -462
- package/public/pages/user.html +1 -1
- package/scripts/clear-whatsapp-session.sh +123 -0
- package/scripts/core-ai-mode.mjs +163 -0
- package/scripts/deploy.sh +10 -0
- package/scripts/enrich-command-config-ux-openai.mjs +492 -0
- package/scripts/generate-commands-catalog.mjs +155 -0
- package/scripts/new-whatsapp-session.sh +317 -0
- package/scripts/security-web-surface-check.mjs +218 -0
- package/server/controllers/admin/adminPanelHandlers.js +253 -3
- package/server/controllers/admin/systemAdminController.js +267 -0
- package/server/controllers/sticker/stickerCatalogController.js +9 -23
- package/server/controllers/system/contactController.js +9 -17
- package/server/controllers/system/stickerCatalogSystemContext.js +27 -6
- package/server/controllers/system/systemController.js +254 -1
- package/server/controllers/userController.js +6 -0
- package/server/email/emailTemplateService.js +3 -2
- package/server/http/httpServer.js +8 -4
- package/server/middleware/securityHeaders.js +20 -1
- package/server/routes/admin/systemAdminRouter.js +6 -0
- package/server/routes/indexRouter.js +30 -6
- package/server/routes/observability/grafanaProxyRouter.js +254 -0
- package/server/routes/static/staticPageRouter.js +27 -1
- package/server/utils/publicContact.js +31 -0
- package/utils/whatsapp/contactEnv.js +39 -0
- package/vite.config.mjs +2 -1
- package/app/modules/playModule/local/installYtDlp.js +0 -25
- package/app/modules/playModule/local/ytDlpInstaller.js +0 -28
package/database/schema.sql
CHANGED
|
@@ -138,15 +138,50 @@ CREATE TABLE IF NOT EXISTS `group_configs` (
|
|
|
138
138
|
PRIMARY KEY (`id`)
|
|
139
139
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
140
140
|
|
|
141
|
+
CREATE TABLE IF NOT EXISTS `group_user_warnings` (
|
|
142
|
+
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
143
|
+
`group_id` varchar(255) NOT NULL,
|
|
144
|
+
`participant_jid` varchar(255) NOT NULL,
|
|
145
|
+
`warned_by_jid` varchar(255) DEFAULT NULL,
|
|
146
|
+
`reason` text DEFAULT NULL,
|
|
147
|
+
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
|
148
|
+
PRIMARY KEY (`id`),
|
|
149
|
+
KEY `idx_group_user_warnings_lookup` (`group_id`,`participant_jid`,`created_at`),
|
|
150
|
+
KEY `idx_group_user_warnings_prune` (`group_id`,`participant_jid`,`id`)
|
|
151
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
152
|
+
|
|
153
|
+
CREATE TABLE IF NOT EXISTS `system_premium_users` (
|
|
154
|
+
`id` varchar(255) NOT NULL,
|
|
155
|
+
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
|
156
|
+
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
|
157
|
+
PRIMARY KEY (`id`)
|
|
158
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
159
|
+
|
|
160
|
+
CREATE TABLE IF NOT EXISTS `system_ai_prompts` (
|
|
161
|
+
`id` varchar(255) NOT NULL,
|
|
162
|
+
`prompt` longtext NOT NULL,
|
|
163
|
+
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
|
164
|
+
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
|
165
|
+
PRIMARY KEY (`id`)
|
|
166
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
167
|
+
|
|
141
168
|
CREATE TABLE IF NOT EXISTS `groups_metadata` (
|
|
142
169
|
`id` varchar(255) NOT NULL,
|
|
143
170
|
`subject` varchar(255) DEFAULT NULL,
|
|
144
171
|
`description` text DEFAULT NULL,
|
|
145
172
|
`owner_jid` varchar(255) DEFAULT NULL,
|
|
146
173
|
`creation` bigint(20) DEFAULT NULL,
|
|
174
|
+
`linked_parent_jid` varchar(255) DEFAULT NULL,
|
|
175
|
+
`is_community` tinyint(1) DEFAULT NULL,
|
|
176
|
+
`is_community_announce` tinyint(1) DEFAULT NULL,
|
|
177
|
+
`member_add_mode` tinyint(1) DEFAULT NULL,
|
|
178
|
+
`join_approval_mode` tinyint(1) DEFAULT NULL,
|
|
179
|
+
`addressing_mode` varchar(8) DEFAULT NULL,
|
|
147
180
|
`participants` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`participants`)),
|
|
148
181
|
`updated_at` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
|
149
|
-
PRIMARY KEY (`id`)
|
|
182
|
+
PRIMARY KEY (`id`),
|
|
183
|
+
KEY `idx_groups_metadata_linked_parent_jid` (`linked_parent_jid`),
|
|
184
|
+
KEY `idx_groups_metadata_is_community_parent` (`is_community`,`linked_parent_jid`)
|
|
150
185
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
151
186
|
|
|
152
187
|
CREATE TABLE IF NOT EXISTS `lid_map` (
|
|
@@ -162,6 +197,7 @@ CREATE TABLE IF NOT EXISTS `lid_map` (
|
|
|
162
197
|
|
|
163
198
|
CREATE TABLE IF NOT EXISTS `message_analysis_event` (
|
|
164
199
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
200
|
+
`session_id` varchar(64) NOT NULL DEFAULT 'default',
|
|
165
201
|
`message_id` varchar(255) DEFAULT NULL,
|
|
166
202
|
`chat_id` varchar(255) DEFAULT NULL,
|
|
167
203
|
`sender_id` varchar(255) DEFAULT NULL,
|
|
@@ -185,6 +221,10 @@ CREATE TABLE IF NOT EXISTS `message_analysis_event` (
|
|
|
185
221
|
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
|
186
222
|
PRIMARY KEY (`id`),
|
|
187
223
|
KEY `idx_message_analysis_created` (`created_at`),
|
|
224
|
+
KEY `idx_message_analysis_session_created` (`session_id`,`created_at`),
|
|
225
|
+
KEY `idx_message_analysis_session_chat_created` (`session_id`,`chat_id`,`created_at`),
|
|
226
|
+
KEY `idx_message_analysis_session_sender_created` (`session_id`,`sender_id`,`created_at`),
|
|
227
|
+
KEY `idx_message_analysis_session_command_created` (`session_id`,`command_name`,`created_at`),
|
|
188
228
|
KEY `idx_message_analysis_chat_created` (`chat_id`,`created_at`),
|
|
189
229
|
KEY `idx_message_analysis_sender_created` (`sender_id`,`created_at`),
|
|
190
230
|
KEY `idx_message_analysis_command_created` (`command_name`,`created_at`),
|
|
@@ -195,6 +235,7 @@ CREATE TABLE IF NOT EXISTS `message_analysis_event` (
|
|
|
195
235
|
|
|
196
236
|
CREATE TABLE IF NOT EXISTS `baileys_event_journal` (
|
|
197
237
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
238
|
+
`session_id` varchar(64) NOT NULL DEFAULT 'default',
|
|
198
239
|
`event_name` varchar(64) NOT NULL,
|
|
199
240
|
`socket_generation` int(10) unsigned DEFAULT NULL,
|
|
200
241
|
`chat_id` varchar(255) DEFAULT NULL,
|
|
@@ -205,6 +246,10 @@ CREATE TABLE IF NOT EXISTS `baileys_event_journal` (
|
|
|
205
246
|
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
|
206
247
|
PRIMARY KEY (`id`),
|
|
207
248
|
KEY `idx_baileys_event_created` (`created_at`),
|
|
249
|
+
KEY `idx_baileys_event_session_created` (`session_id`,`created_at`),
|
|
250
|
+
KEY `idx_baileys_event_session_name_created` (`session_id`,`event_name`,`created_at`),
|
|
251
|
+
KEY `idx_baileys_event_session_chat_created` (`session_id`,`chat_id`,`created_at`),
|
|
252
|
+
KEY `idx_baileys_event_session_message_created` (`session_id`,`message_id`,`created_at`),
|
|
208
253
|
KEY `idx_baileys_event_name_created` (`event_name`,`created_at`),
|
|
209
254
|
KEY `idx_baileys_event_chat_created` (`chat_id`,`created_at`),
|
|
210
255
|
KEY `idx_baileys_event_message_created` (`message_id`,`created_at`),
|
|
@@ -222,9 +267,61 @@ CREATE TABLE IF NOT EXISTS `baileys_auth_state` (
|
|
|
222
267
|
KEY `idx_baileys_auth_state_category_updated` (`category`,`updated_at`)
|
|
223
268
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
224
269
|
|
|
270
|
+
CREATE TABLE IF NOT EXISTS `wa_session_registry` (
|
|
271
|
+
`session_id` varchar(64) NOT NULL,
|
|
272
|
+
`bot_jid` varchar(255) DEFAULT NULL,
|
|
273
|
+
`status` varchar(24) NOT NULL DEFAULT 'offline',
|
|
274
|
+
`capacity_weight` int(10) unsigned NOT NULL DEFAULT 1,
|
|
275
|
+
`current_score` decimal(12,4) NOT NULL DEFAULT 0.0000,
|
|
276
|
+
`last_heartbeat_at` datetime DEFAULT NULL,
|
|
277
|
+
`last_connected_at` datetime DEFAULT NULL,
|
|
278
|
+
`last_disconnected_at` datetime DEFAULT NULL,
|
|
279
|
+
`metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
|
|
280
|
+
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
|
281
|
+
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
|
282
|
+
PRIMARY KEY (`session_id`),
|
|
283
|
+
KEY `idx_wa_session_registry_status_updated` (`status`,`updated_at`),
|
|
284
|
+
KEY `idx_wa_session_registry_heartbeat` (`last_heartbeat_at`)
|
|
285
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
286
|
+
|
|
287
|
+
CREATE TABLE IF NOT EXISTS `group_assignment` (
|
|
288
|
+
`group_jid` varchar(255) NOT NULL,
|
|
289
|
+
`owner_session_id` varchar(64) NOT NULL,
|
|
290
|
+
`lease_expires_at` datetime NOT NULL,
|
|
291
|
+
`cooldown_until` datetime DEFAULT NULL,
|
|
292
|
+
`assignment_version` bigint(20) unsigned NOT NULL DEFAULT 1,
|
|
293
|
+
`pinned` tinyint(1) NOT NULL DEFAULT 0,
|
|
294
|
+
`last_reason` varchar(64) DEFAULT NULL,
|
|
295
|
+
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
|
296
|
+
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
|
297
|
+
PRIMARY KEY (`group_jid`),
|
|
298
|
+
KEY `idx_group_assignment_owner_lease` (`owner_session_id`,`lease_expires_at`),
|
|
299
|
+
KEY `idx_group_assignment_lease` (`lease_expires_at`),
|
|
300
|
+
KEY `idx_group_assignment_cooldown` (`cooldown_until`),
|
|
301
|
+
KEY `idx_group_assignment_pinned_updated` (`pinned`,`updated_at`),
|
|
302
|
+
CONSTRAINT `fk_group_assignment_owner_session` FOREIGN KEY (`owner_session_id`) REFERENCES `wa_session_registry` (`session_id`) ON UPDATE CASCADE
|
|
303
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
304
|
+
|
|
305
|
+
CREATE TABLE IF NOT EXISTS `group_assignment_history` (
|
|
306
|
+
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
307
|
+
`group_jid` varchar(255) NOT NULL,
|
|
308
|
+
`previous_session_id` varchar(64) DEFAULT NULL,
|
|
309
|
+
`new_session_id` varchar(64) NOT NULL,
|
|
310
|
+
`change_reason` varchar(64) DEFAULT NULL,
|
|
311
|
+
`changed_by` varchar(64) NOT NULL DEFAULT 'system',
|
|
312
|
+
`assignment_version` bigint(20) unsigned NOT NULL,
|
|
313
|
+
`metadata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`metadata`)),
|
|
314
|
+
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
|
315
|
+
PRIMARY KEY (`id`),
|
|
316
|
+
KEY `idx_group_assignment_history_group_created` (`group_jid`,`created_at`),
|
|
317
|
+
KEY `idx_group_assignment_history_new_session_created` (`new_session_id`,`created_at`),
|
|
318
|
+
KEY `idx_group_assignment_history_prev_session_created` (`previous_session_id`,`created_at`)
|
|
319
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
320
|
+
|
|
225
321
|
CREATE TABLE IF NOT EXISTS `messages` (
|
|
226
322
|
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
227
323
|
`message_id` varchar(255) NOT NULL,
|
|
324
|
+
`session_id` varchar(64) NOT NULL DEFAULT 'default',
|
|
228
325
|
`chat_id` varchar(255) NOT NULL,
|
|
229
326
|
`sender_id` varchar(255) DEFAULT NULL,
|
|
230
327
|
`canonical_sender_id` varchar(255) DEFAULT NULL,
|
|
@@ -234,6 +331,10 @@ CREATE TABLE IF NOT EXISTS `messages` (
|
|
|
234
331
|
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
|
235
332
|
PRIMARY KEY (`id`),
|
|
236
333
|
UNIQUE KEY `message_id` (`message_id`),
|
|
334
|
+
KEY `idx_messages_session_message_id` (`session_id`,`message_id`),
|
|
335
|
+
KEY `idx_messages_session_chat_timestamp` (`session_id`,`chat_id`,`timestamp`),
|
|
336
|
+
KEY `idx_messages_session_sender_timestamp` (`session_id`,`sender_id`,`timestamp`),
|
|
337
|
+
KEY `idx_messages_session_canonical_sender_timestamp` (`session_id`,`canonical_sender_id`,`timestamp`),
|
|
237
338
|
KEY `idx_chat_timestamp` (`chat_id`,`timestamp`),
|
|
238
339
|
KEY `idx_sender` (`sender_id`),
|
|
239
340
|
KEY `idx_timestamp` (`timestamp`),
|
package/docker-compose.yml
CHANGED
|
@@ -22,8 +22,10 @@ services:
|
|
|
22
22
|
environment:
|
|
23
23
|
- GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER:-admin}
|
|
24
24
|
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin}
|
|
25
|
+
- GF_SECURITY_ALLOW_EMBEDDING=${GRAFANA_ALLOW_EMBEDDING:-true}
|
|
25
26
|
- GF_USERS_ALLOW_SIGN_UP=false
|
|
26
27
|
- GF_SERVER_ROOT_URL=${GRAFANA_ROOT_URL:-%(protocol)s://%(domain)s:%(http_port)s/}
|
|
28
|
+
- GF_SERVER_SERVE_FROM_SUB_PATH=${GRAFANA_SERVE_FROM_SUB_PATH:-true}
|
|
27
29
|
# Opcional: se quiser setar timezone do Grafana
|
|
28
30
|
- GF_DATE_FORMATS_DEFAULT_TIMEZONE=${GRAFANA_TIMEZONE:-America/Boa_Vista}
|
|
29
31
|
volumes:
|
|
@@ -65,7 +67,7 @@ services:
|
|
|
65
67
|
image: prom/mysqld-exporter:${MYSQL_EXPORTER_IMAGE_TAG:-v0.15.1}
|
|
66
68
|
restart: unless-stopped
|
|
67
69
|
environment:
|
|
68
|
-
- DATA_SOURCE_NAME=${MYSQL_EXPORTER_DSN:-exporter:exporter@(
|
|
70
|
+
- DATA_SOURCE_NAME=${MYSQL_EXPORTER_DSN:-exporter:exporter@unix(/run/mysqld/mysqld.sock)/}
|
|
69
71
|
command:
|
|
70
72
|
- "--config.my-cnf=/etc/mysql-exporter/my.cnf"
|
|
71
73
|
- "--collect.global_status"
|
|
@@ -79,6 +81,7 @@ services:
|
|
|
79
81
|
- "--collect.perf_schema.tablelocks"
|
|
80
82
|
volumes:
|
|
81
83
|
- ${MYSQL_EXPORTER_CNF_PATH:-./observability/mysql-exporter.cnf}:/etc/mysql-exporter/my.cnf:ro
|
|
84
|
+
- /run/mysqld:/run/mysqld
|
|
82
85
|
ports:
|
|
83
86
|
- "${MYSQL_EXPORTER_BIND_HOST:-127.0.0.1}:${MYSQL_EXPORTER_PORT:-9104}:9104"
|
|
84
87
|
extra_hosts:
|
|
@@ -32,4 +32,4 @@ Definir usos permitidos e proibidos na plataforma OmniZap para reduzir risco jur
|
|
|
32
32
|
## 5) Canal de denúncia
|
|
33
33
|
|
|
34
34
|
- Página formal: `/notice-and-takedown/`.
|
|
35
|
-
- Contato oficial: https://wa.me
|
|
35
|
+
- Contato oficial: `https://wa.me/<WHATSAPP_SUPPORT_NUMBER>`.
|
|
@@ -12,14 +12,14 @@ Escopo: site, login web, painel, API e operação de automação do Omnizap.
|
|
|
12
12
|
## 1) Controlador e contato
|
|
13
13
|
|
|
14
14
|
- Controlador: 59.034.123 KAIKY BRITO RIBEIRO (CNPJ 59.034.123/0001-96).
|
|
15
|
-
- Contato de privacidade: https://wa.me
|
|
15
|
+
- Contato de privacidade: `https://wa.me/<WHATSAPP_SUPPORT_NUMBER>`
|
|
16
16
|
- Canal para titulares (LGPD): mensagem com assunto "DSAR LGPD" no contato oficial.
|
|
17
17
|
- Para serviços de terceiros baseados em fork/self-host, o contato de privacidade deve ser solicitado diretamente ao operador da respectiva instância.
|
|
18
18
|
|
|
19
19
|
## 1.1) Encarregado pelo tratamento (LGPD art. 41)
|
|
20
20
|
|
|
21
21
|
- Encarregado (DPO): Kaiky Brito Ribeiro (59.034.123 KAIKY BRITO RIBEIRO, CNPJ 59.034.123/0001-96).
|
|
22
|
-
- Contato do encarregado: https://wa.me
|
|
22
|
+
- Contato do encarregado: `https://wa.me/<WHATSAPP_SUPPORT_NUMBER>` (assunto recomendado: "ENCARREGADO LGPD").
|
|
23
23
|
- Divulgação pública mantida para transparência regulatória.
|
|
24
24
|
|
|
25
25
|
## 2) Tabela de tratamento de dados
|
|
@@ -8,7 +8,7 @@ Padronizar resposta para direitos do titular: acesso, correção, exclusão, opo
|
|
|
8
8
|
|
|
9
9
|
## 2) Canais de entrada
|
|
10
10
|
|
|
11
|
-
- WhatsApp oficial: https://wa.me
|
|
11
|
+
- WhatsApp oficial: `https://wa.me/<WHATSAPP_SUPPORT_NUMBER>`
|
|
12
12
|
- Canal interno de compliance (registro em ticket obrigatório)
|
|
13
13
|
|
|
14
14
|
## 3) Papéis e responsáveis
|
|
@@ -129,6 +129,59 @@ Resultado esperado:
|
|
|
129
129
|
- `22`, `80`, `443` abertos;
|
|
130
130
|
- `3001` e `8007` filtrados/fechados externamente.
|
|
131
131
|
|
|
132
|
+
## 8) Hardening da superficie web estatica (ZAP issue #103)
|
|
133
|
+
|
|
134
|
+
Objetivo: eliminar soft-404 e alinhar headers de seguranca em rotas estaticas servidas direto pelo Nginx (`/`, `/comandos/`, `/login/`, etc.).
|
|
135
|
+
|
|
136
|
+
1. Publicar snippet de headers estaticos:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
sudo install -D -m 0644 docs/security/omnizap-static-security-headers.conf /etc/nginx/snippets/omnizap-static-security-headers.conf
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
2. No `server { ... }` de producao, garantir que rotas proxy (`/api/`, `/stickers/`, `/data/`) venham antes do fallback estatico e aplicar:
|
|
143
|
+
|
|
144
|
+
```nginx
|
|
145
|
+
# Nao permitir dotfiles sensiveis
|
|
146
|
+
location ~* (^|/)\.(?!well-known/) {
|
|
147
|
+
return 404;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Fallback estatico sem soft-404 (nao retorna home para caminho inexistente)
|
|
151
|
+
location / {
|
|
152
|
+
try_files $uri $uri/ =404;
|
|
153
|
+
include /etc/nginx/snippets/omnizap-static-security-headers.conf;
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
3. Validar e recarregar:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
sudo nginx -t
|
|
161
|
+
sudo systemctl reload nginx
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
4. Validacao rapida manual:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
curl -I https://omnizap.shop/
|
|
168
|
+
curl -I https://omnizap.shop/notice-and-takedown/
|
|
169
|
+
curl -I https://omnizap.shop/.env
|
|
170
|
+
curl -I https://omnizap.shop/__security_probe_nonexistent_omnizap__.txt
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
5. Validacao automatizada (repositorio):
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
npm run security:web-surface
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Resultado esperado:
|
|
180
|
+
|
|
181
|
+
- rotas estaticas com `Content-Security-Policy`, `X-Frame-Options`, `Strict-Transport-Security`, `X-Content-Type-Options`, `Permissions-Policy`;
|
|
182
|
+
- `/.env` sem `200`;
|
|
183
|
+
- caminho inexistente sem fallback `200` para a home.
|
|
184
|
+
|
|
132
185
|
## Referências
|
|
133
186
|
|
|
134
187
|
- Nginx admin guide: https://nginx.org/en/docs/
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# OmniZap static web hardening snippet (Nginx)
|
|
2
|
+
#
|
|
3
|
+
# Uso recomendado:
|
|
4
|
+
# 1) Salvar em /etc/nginx/snippets/omnizap-static-security-headers.conf
|
|
5
|
+
# 2) Incluir SOMENTE em blocos de location que servem conteudo estatico.
|
|
6
|
+
# 3) Nao incluir em locations proxy de API/catalogo que ja recebem headers do backend.
|
|
7
|
+
#
|
|
8
|
+
# Exemplo:
|
|
9
|
+
# location / {
|
|
10
|
+
# try_files $uri $uri/ =404;
|
|
11
|
+
# include /etc/nginx/snippets/omnizap-static-security-headers.conf;
|
|
12
|
+
# }
|
|
13
|
+
|
|
14
|
+
add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self'; script-src 'self' 'unsafe-inline' https://accounts.google.com https://cdn.tailwindcss.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; img-src 'self' data: blob: https:; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; connect-src 'self' https://accounts.google.com https://oauth2.googleapis.com https://api.github.com; frame-src 'self' https://accounts.google.com https://omnizap.shop; worker-src 'self' blob:; manifest-src 'self'" always;
|
|
15
|
+
add_header Cross-Origin-Opener-Policy "same-origin" always;
|
|
16
|
+
add_header Cross-Origin-Resource-Policy "same-origin" always;
|
|
17
|
+
add_header Referrer-Policy "no-referrer" always;
|
|
18
|
+
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
19
|
+
add_header X-Content-Type-Options "nosniff" always;
|
|
20
|
+
add_header X-DNS-Prefetch-Control "off" always;
|
|
21
|
+
add_header X-Download-Options "noopen" always;
|
|
22
|
+
add_header X-Frame-Options "SAMEORIGIN" always;
|
|
23
|
+
add_header X-Permitted-Cross-Domain-Policies "none" always;
|
|
24
|
+
add_header X-XSS-Protection "0" always;
|
|
25
|
+
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
|
|
@@ -29,15 +29,31 @@ const baseEnv = {
|
|
|
29
29
|
STICKER_WORKER_CURATION_CADENCE_MS: '21600000',
|
|
30
30
|
STICKER_WORKER_REBUILD_CADENCE_MS: '43200000',
|
|
31
31
|
STICKER_DEDICATED_WORKERS_ENABLED: 'false',
|
|
32
|
-
STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS: '
|
|
33
|
-
STICKER_DEDICATED_WORKER_IDLE_BACKOFF_MULTIPLIER: '
|
|
34
|
-
STICKER_DEDICATED_WORKER_IDLE_MAX_POLL_INTERVAL_MS: '
|
|
35
|
-
STICKER_DEDICATED_WORKER_IDLE_JITTER_PERCENT: '
|
|
32
|
+
STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS: '45000',
|
|
33
|
+
STICKER_DEDICATED_WORKER_IDLE_BACKOFF_MULTIPLIER: '3',
|
|
34
|
+
STICKER_DEDICATED_WORKER_IDLE_MAX_POLL_INTERVAL_MS: '300000',
|
|
35
|
+
STICKER_DEDICATED_WORKER_IDLE_JITTER_PERCENT: '12',
|
|
36
36
|
STICKER_DOMAIN_EVENT_CONSUMER_ENABLED: 'false',
|
|
37
37
|
STICKER_DOMAIN_EVENT_CONSUMER_POLLER_INTERVAL_MS: '15000',
|
|
38
38
|
STICKER_SCORE_SNAPSHOT_ENABLED: 'false',
|
|
39
39
|
STICKER_SCORE_SNAPSHOT_REFRESH_INTERVAL_MS: '1500000',
|
|
40
40
|
STICKER_SCORE_SNAPSHOT_BATCH_SIZE: '20',
|
|
41
|
+
// Core IA defaults locked in PM2 env to avoid drift between restarts.
|
|
42
|
+
AI_HELP_LLM_PROVIDER: process.env.AI_HELP_LLM_PROVIDER || 'gemini',
|
|
43
|
+
GEMINI_AUTH_MODE: process.env.GEMINI_AUTH_MODE || 'cli',
|
|
44
|
+
GEMINI_MODEL: process.env.GEMINI_MODEL || 'gemini-2.5-flash',
|
|
45
|
+
GEMINI_CLI_COMMAND: process.env.GEMINI_CLI_COMMAND || 'gemini',
|
|
46
|
+
COMMAND_CONFIG_ENRICHMENT_WORKER_PROVIDER: process.env.COMMAND_CONFIG_ENRICHMENT_WORKER_PROVIDER || 'gemini',
|
|
47
|
+
COMMAND_CONFIG_ENRICHMENT_WORKER_MODEL: process.env.COMMAND_CONFIG_ENRICHMENT_WORKER_MODEL || 'gemini-2.5-flash',
|
|
48
|
+
COMMAND_CONFIG_ENRICHMENT_WORKER_GEMINI_AUTH_MODE: process.env.COMMAND_CONFIG_ENRICHMENT_WORKER_GEMINI_AUTH_MODE || 'cli',
|
|
49
|
+
COMMAND_CONFIG_ENRICHMENT_WORKER_TIMEOUT_MS: process.env.COMMAND_CONFIG_ENRICHMENT_WORKER_TIMEOUT_MS || '90000',
|
|
50
|
+
COMMAND_CONFIG_ENRICHMENT_PROVIDER_FAILURE_COOLDOWN_MS: process.env.COMMAND_CONFIG_ENRICHMENT_PROVIDER_FAILURE_COOLDOWN_MS || '900000',
|
|
51
|
+
AI_HELP_CONTINUOUS_LEARNING_ENABLED: process.env.AI_HELP_CONTINUOUS_LEARNING_ENABLED || 'true',
|
|
52
|
+
AI_HELP_CONTINUOUS_LEARNING_INTERVAL_MS: process.env.AI_HELP_CONTINUOUS_LEARNING_INTERVAL_MS || '120000',
|
|
53
|
+
AI_HELP_CONTINUOUS_LEARNING_BATCH_SIZE: process.env.AI_HELP_CONTINUOUS_LEARNING_BATCH_SIZE || '18',
|
|
54
|
+
AI_HELP_CONTINUOUS_LEARNING_MIN_AUTO_APPLY_CONFIDENCE: process.env.AI_HELP_CONTINUOUS_LEARNING_MIN_AUTO_APPLY_CONFIDENCE || '0.72',
|
|
55
|
+
AI_HELP_CONTINUOUS_LEARNING_MAX_HELP_QUESTIONS_PER_COMMAND: process.env.AI_HELP_CONTINUOUS_LEARNING_MAX_HELP_QUESTIONS_PER_COMMAND || '4',
|
|
56
|
+
AI_HELP_CONTINUOUS_LEARNING_MAX_HELP_CALLS_PER_CYCLE: process.env.AI_HELP_CONTINUOUS_LEARNING_MAX_HELP_CALLS_PER_CYCLE || '90',
|
|
41
57
|
METRICS_HOST: process.env.METRICS_HOST || '127.0.0.1',
|
|
42
58
|
};
|
|
43
59
|
|
|
@@ -78,9 +94,9 @@ module.exports = {
|
|
|
78
94
|
env: {
|
|
79
95
|
...baseEnv,
|
|
80
96
|
STICKER_DEDICATED_WORKERS_ENABLED: 'true',
|
|
81
|
-
STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS: '
|
|
82
|
-
STICKER_DEDICATED_WORKER_IDLE_BACKOFF_MULTIPLIER: '
|
|
83
|
-
STICKER_DEDICATED_WORKER_IDLE_MAX_POLL_INTERVAL_MS: '
|
|
97
|
+
STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS: '45000',
|
|
98
|
+
STICKER_DEDICATED_WORKER_IDLE_BACKOFF_MULTIPLIER: '3',
|
|
99
|
+
STICKER_DEDICATED_WORKER_IDLE_MAX_POLL_INTERVAL_MS: '300000',
|
|
84
100
|
STICKER_CLASSIFICATION_BACKGROUND_BATCH_SIZE: '3',
|
|
85
101
|
STICKER_CLASSIFICATION_BACKGROUND_CONCURRENCY: '1',
|
|
86
102
|
STICKER_REPROCESS_QUEUE_ENABLED: 'false',
|
|
@@ -104,9 +120,11 @@ module.exports = {
|
|
|
104
120
|
error_file: `logs/${appName}-worker-curation-error.log`,
|
|
105
121
|
env: {
|
|
106
122
|
...baseEnv,
|
|
107
|
-
STICKER_DEDICATED_WORKERS_ENABLED: '
|
|
123
|
+
STICKER_DEDICATED_WORKERS_ENABLED: 'true',
|
|
108
124
|
STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS: '60000',
|
|
109
|
-
STICKER_AUTO_PACK_BY_TAGS_ENABLED: '
|
|
125
|
+
STICKER_AUTO_PACK_BY_TAGS_ENABLED: 'true',
|
|
126
|
+
STICKER_AUTO_PACK_BY_TAGS_MAX_SCAN_ASSETS: '1200',
|
|
127
|
+
STICKER_AUTO_PACK_BY_TAGS_SCAN_PASSES: '1',
|
|
110
128
|
},
|
|
111
129
|
kill_timeout: 5000,
|
|
112
130
|
},
|
|
@@ -125,9 +143,11 @@ module.exports = {
|
|
|
125
143
|
error_file: `logs/${appName}-worker-rebuild-error.log`,
|
|
126
144
|
env: {
|
|
127
145
|
...baseEnv,
|
|
128
|
-
STICKER_DEDICATED_WORKERS_ENABLED: '
|
|
146
|
+
STICKER_DEDICATED_WORKERS_ENABLED: 'true',
|
|
129
147
|
STICKER_DEDICATED_WORKER_POLL_INTERVAL_MS: '60000',
|
|
130
|
-
STICKER_AUTO_PACK_BY_TAGS_ENABLED: '
|
|
148
|
+
STICKER_AUTO_PACK_BY_TAGS_ENABLED: 'true',
|
|
149
|
+
STICKER_AUTO_PACK_BY_TAGS_MAX_SCAN_ASSETS: '1200',
|
|
150
|
+
STICKER_AUTO_PACK_BY_TAGS_SCAN_PASSES: '1',
|
|
131
151
|
},
|
|
132
152
|
kill_timeout: 5000,
|
|
133
153
|
},
|
package/index.js
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
import 'dotenv/config';
|
|
19
19
|
|
|
20
20
|
import logger from '#logger';
|
|
21
|
-
import {
|
|
22
|
-
import { backfillLidMapFromMessagesOnce } from './app/config/index.js';
|
|
21
|
+
import { connectAllWhatsAppSessions, disconnectAllWhatsAppSessions } from './app/connection/socketController.js';
|
|
22
|
+
import { backfillLidMapFromMessagesOnce, getMultiSessionRuntimeConfig } from './app/config/index.js';
|
|
23
23
|
import { initializeNewsBroadcastService, stopNewsBroadcastService } from './app/services/messaging/newsBroadcastService.js';
|
|
24
24
|
import initializeDatabase from './database/init.js';
|
|
25
25
|
import { startHttpServer, stopHttpServer } from './server/index.js';
|
|
@@ -31,7 +31,9 @@ import { startStickerPackScoreSnapshotRuntime, stopStickerPackScoreSnapshotRunti
|
|
|
31
31
|
import { startStickerDomainEventConsumer, stopStickerDomainEventConsumer } from './app/modules/stickerPackModule/stickerDomainEventConsumerRuntime.js';
|
|
32
32
|
import { startAiLearningWorker, stopAiLearningWorker } from './app/workers/aiLearningWorker.js';
|
|
33
33
|
import { startCommandConfigEnrichmentWorker, stopCommandConfigEnrichmentWorker } from './app/workers/commandConfigEnrichmentWorker.js';
|
|
34
|
+
import { startAiHelperContinuousLearningWorker, stopAiHelperContinuousLearningWorker } from './app/workers/aiHelperContinuousLearningWorker.js';
|
|
34
35
|
import { formatCommandConfigValidationReport, validateAllCommandConfigs } from './app/services/ai/commandConfigValidationService.js';
|
|
36
|
+
import { startGroupAssignmentBalancer, stopGroupAssignmentBalancer } from './app/services/multiSession/assignmentBalancerService.js';
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
39
|
* Timeout máximo para inicialização do banco (criar/verificar DB + tabelas).
|
|
@@ -187,6 +189,21 @@ async function closeDatabasePool() {
|
|
|
187
189
|
async function startApp() {
|
|
188
190
|
try {
|
|
189
191
|
logger.info('Iniciando Omnizap...');
|
|
192
|
+
const multiSessionConfig = getMultiSessionRuntimeConfig();
|
|
193
|
+
logger.info('Configuracao de sessoes WhatsApp carregada.', {
|
|
194
|
+
sessionIds: multiSessionConfig.sessionIds,
|
|
195
|
+
primarySessionId: multiSessionConfig.primarySessionId,
|
|
196
|
+
sessionWeights: multiSessionConfig.sessionWeights,
|
|
197
|
+
ownerEnforcementMode: multiSessionConfig.ownerEnforcementMode,
|
|
198
|
+
ownerLeaseMs: multiSessionConfig.ownerLeaseMs,
|
|
199
|
+
ownerHeartbeatMs: multiSessionConfig.ownerHeartbeatMs,
|
|
200
|
+
balancerEnabled: multiSessionConfig.balancerEnabled,
|
|
201
|
+
});
|
|
202
|
+
if (multiSessionConfig.warnings.length > 0) {
|
|
203
|
+
logger.warn('Ajustes aplicados na configuracao multi-sessao do WhatsApp.', {
|
|
204
|
+
warnings: multiSessionConfig.warnings,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
190
207
|
|
|
191
208
|
const shouldValidateCommandConfigs = process.env.COMMAND_CONFIG_VALIDATE_ON_BOOT !== 'false';
|
|
192
209
|
if (shouldValidateCommandConfigs) {
|
|
@@ -224,6 +241,7 @@ async function startApp() {
|
|
|
224
241
|
startStickerDomainEventConsumer();
|
|
225
242
|
startAiLearningWorker();
|
|
226
243
|
startCommandConfigEnrichmentWorker();
|
|
244
|
+
startAiHelperContinuousLearningWorker();
|
|
227
245
|
|
|
228
246
|
// Backfill é opcional, rodando em background.
|
|
229
247
|
const shouldBackfill = process.env.LID_BACKFILL_ON_START !== 'false';
|
|
@@ -242,9 +260,12 @@ async function startApp() {
|
|
|
242
260
|
});
|
|
243
261
|
}
|
|
244
262
|
|
|
245
|
-
logger.info('Conectando
|
|
246
|
-
|
|
247
|
-
|
|
263
|
+
logger.info('Conectando sessoes do WhatsApp...');
|
|
264
|
+
const sessionConnectTimeoutMs = Math.max(WHATSAPP_CONNECT_TIMEOUT_MS, multiSessionConfig.sessionIds.length * WHATSAPP_CONNECT_TIMEOUT_MS);
|
|
265
|
+
await withTimeout(connectAllWhatsAppSessions(), sessionConnectTimeoutMs, 'Conexao WhatsApp (multi-session)');
|
|
266
|
+
logger.info('Sessoes do WhatsApp conectadas.');
|
|
267
|
+
|
|
268
|
+
startGroupAssignmentBalancer();
|
|
248
269
|
|
|
249
270
|
logger.info('Inicializando servico de noticias...');
|
|
250
271
|
await initializeNewsBroadcastService();
|
|
@@ -309,6 +330,14 @@ async function shutdown(signal, error) {
|
|
|
309
330
|
logger.warn('Falha ao encerrar servico de noticias.', { error: stopError.message });
|
|
310
331
|
}
|
|
311
332
|
|
|
333
|
+
try {
|
|
334
|
+
stopGroupAssignmentBalancer();
|
|
335
|
+
} catch (balancerStopError) {
|
|
336
|
+
logger.warn('Falha ao encerrar balanceador de grupos.', {
|
|
337
|
+
error: balancerStopError?.message,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
312
341
|
// 2) Esperar backfill (best-effort) com timeout
|
|
313
342
|
if (backfillPromise) {
|
|
314
343
|
try {
|
|
@@ -322,19 +351,16 @@ async function shutdown(signal, error) {
|
|
|
322
351
|
}
|
|
323
352
|
}
|
|
324
353
|
|
|
325
|
-
// 3) Encerrar
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
stack: sockError.stack,
|
|
336
|
-
});
|
|
337
|
-
}
|
|
354
|
+
// 3) Encerrar conexões WhatsApp
|
|
355
|
+
try {
|
|
356
|
+
logger.info('Encerrando sessoes do WhatsApp...');
|
|
357
|
+
await withTimeout(disconnectAllWhatsAppSessions(), 12000, 'Encerramento WhatsApp multi-session');
|
|
358
|
+
logger.info('Sessoes do WhatsApp encerradas.');
|
|
359
|
+
} catch (sockError) {
|
|
360
|
+
logger.error('Erro ao encerrar conexões do WhatsApp:', {
|
|
361
|
+
error: sockError.message,
|
|
362
|
+
stack: sockError.stack,
|
|
363
|
+
});
|
|
338
364
|
}
|
|
339
365
|
|
|
340
366
|
// 4) Encerrar servidor HTTP
|
|
@@ -403,6 +429,14 @@ async function shutdown(signal, error) {
|
|
|
403
429
|
});
|
|
404
430
|
}
|
|
405
431
|
|
|
432
|
+
try {
|
|
433
|
+
stopAiHelperContinuousLearningWorker();
|
|
434
|
+
} catch (continuousLearningWorkerError) {
|
|
435
|
+
logger.warn('Falha ao encerrar worker de aprendizado contínuo de IA.', {
|
|
436
|
+
error: continuousLearningWorkerError?.message,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
|
|
406
440
|
try {
|
|
407
441
|
stopEmailAutomationRuntime();
|
|
408
442
|
} catch (emailRuntimeError) {
|
|
@@ -58,3 +58,23 @@ groups:
|
|
|
58
58
|
annotations:
|
|
59
59
|
summary: "Memória acima de 80%"
|
|
60
60
|
description: "Uso de memória acima de 80% por 10 minutos."
|
|
61
|
+
|
|
62
|
+
- name: omnizap-admin
|
|
63
|
+
rules:
|
|
64
|
+
- alert: OmniZapAdminSnapshotStale
|
|
65
|
+
expr: (time() - omnizap_admin_overview_updated_at_seconds) > 300
|
|
66
|
+
for: 15m
|
|
67
|
+
labels:
|
|
68
|
+
severity: warning
|
|
69
|
+
annotations:
|
|
70
|
+
summary: "Snapshot admin sem atualizacao recente"
|
|
71
|
+
description: "As métricas do painel admin estão sem atualização há mais de 5 minutos."
|
|
72
|
+
|
|
73
|
+
- alert: OmniZapAdminCriticalAlerts
|
|
74
|
+
expr: omnizap_admin_alerts_total{severity="critical"} > 0
|
|
75
|
+
for: 2m
|
|
76
|
+
labels:
|
|
77
|
+
severity: critical
|
|
78
|
+
annotations:
|
|
79
|
+
summary: "Alertas críticos ativos no painel admin"
|
|
80
|
+
description: "Existe ao menos um alerta crítico no snapshot de observabilidade do System Admin."
|