From b3166173dfec43573082a626593c4e0980c5f36e Mon Sep 17 00:00:00 2001 From: Jonas Pacheco Date: Wed, 8 Apr 2026 11:00:14 -0300 Subject: [PATCH] feat(kernel): implementa XOS Discovery Provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cria XOSDiscovery.ts para descobrir serviços XOS - Descobre filas de atendimento ativas - Descobre integrações (WhatsApp, Email) - Descobre automações ativas - Integra ao Kernel como provider de discovery O XOS Discovery consulta o banco de dados para encontrar serviços configurados no XOS (CRM/Atendimento/Marketing). Refs: xos, discovery, kernel-semana-5 --- server/kernel/discovery/XOSDiscovery.ts | 323 ++++++++++++++++++++++++ server/kernel/index.ts | 2 + 2 files changed, 325 insertions(+) create mode 100644 server/kernel/discovery/XOSDiscovery.ts diff --git a/server/kernel/discovery/XOSDiscovery.ts b/server/kernel/discovery/XOSDiscovery.ts new file mode 100644 index 0000000..72dde72 --- /dev/null +++ b/server/kernel/discovery/XOSDiscovery.ts @@ -0,0 +1,323 @@ +/** + * XOS Discovery Provider + * Descobre serviços e integrações do XOS (Experience Operating System) + * + * O XOS é o sistema operacional de experiência do cliente, unificando: + * - CRM (Pipeline, Contatos, Empresas) + * - Atendimento (Inbox, Tickets, Filas) + * - Marketing (Campanhas, Automações) + * - Integrações (WhatsApp, Email, SMS) + * + * Este provider consulta o banco de dados para descobrir: + * 1. Filas de atendimento ativas + * 2. Integrações de comunicação configuradas + * 3. Automações ativas + * 4. Canais de entrada (WhatsApp, Email, Chat) + */ + +import { DiscoveryProvider, RegisteredService, ServiceCategory, ServiceCapability } from '../registry/types'; +import { HealthStatus } from '../types'; +import { db } from '../../../db'; +import { sql } from 'drizzle-orm'; + +export interface XOSDiscoveryOptions { + // Opções futuras: filtros por tenant, etc +} + +// Tipos de serviços XOS que podem ser descobertos +interface XOSQueue { + id: number; + name: string; + is_active: boolean; + users_count?: number; + open_conversations?: number; +} + +interface XOSIntegration { + id: number; + type: string; // 'whatsapp', 'email', 'sms', 'chat' + name: string; + status: string; + config?: any; +} + +interface XOSAutomation { + id: number; + name: string; + trigger_type: string; + is_active: boolean; +} + +export class XOSDiscovery implements DiscoveryProvider { + public readonly name = 'XOSDiscovery'; + private options: XOSDiscoveryOptions; + + constructor(options: XOSDiscoveryOptions = {}) { + this.options = options; + } + + /** + * Verifica se o XOS está disponível (se as tabelas existem) + */ + async isAvailable(): Promise { + try { + // Verifica se a tabela xos_queues existe + const result = await db.execute(sql` + SELECT EXISTS ( + SELECT FROM information.tables + WHERE table_schema = 'public' + AND table_name = 'xos_queues' + ) as exists + `); + return result.rows[0]?.exists === true; + } catch { + // Se der erro, assume que não está disponível + return false; + } + } + + /** + * Descobre todos os serviços XOS + */ + async discover(): Promise { + const services: RegisteredService[] = []; + + try { + // 1. Descobrir filas de atendimento ativas + const queues = await this.discoverQueues(); + services.push(...queues); + + // 2. Descobrir integrações de comunicação + const integrations = await this.discoverIntegrations(); + services.push(...integrations); + + // 3. Descobrir automações ativas + const automations = await this.discoverAutomations(); + services.push(...automations); + + console.log(`[XOSDiscovery] Descobertos ${services.length} serviços XOS`); + return services; + } catch (error) { + console.error('[XOSDiscovery] Erro ao descobrir serviços:', error); + return []; + } + } + + /** + * Descobre filas de atendimento + */ + private async discoverQueues(): Promise { + try { + const result = await db.execute(sql` + SELECT + q.id, + q.name, + q.is_active, + (SELECT COUNT(*) FROM xos_queue_users qu WHERE qu.queue_id = q.id AND qu.is_active = true) as users_count, + (SELECT COUNT(*) FROM xos_conversations c WHERE c.queue_id = q.id AND c.status = 'open') as open_conversations + FROM xos_queues q + WHERE q.is_active = true + `); + + const queues = result.rows as XOSQueue[]; + + return queues.map((queue): RegisteredService => ({ + id: `xos-queue-${queue.id}`, + name: `Fila: ${queue.name}`, + displayName: queue.name, + type: 'node', + category: 'intelligence', + description: `Fila de atendimento XOS - ${queue.open_conversations || 0} conversas abertas, ${queue.users_count || 0} atendentes`, + host: 'localhost', + port: 5000, // Porta principal da aplicação + endpoint: 'http://localhost:5000', + healthCheckPath: '/api/xos/health', + healthStatus: queue.is_active ? 'healthy' : 'unhealthy', + lastHealthCheck: new Date(), + capabilities: [ + { name: 'queue_management', version: '1.0', endpoints: ['/api/xos/queues'] }, + { name: 'conversation_routing', version: '1.0', endpoints: ['/api/xos/conversations'] }, + { name: 'sla_monitoring', version: '1.0', endpoints: ['/api/xos/sla'] }, + ], + requiresIA: false, + metadata: { + source: 'manual', // XOS é configurado manualmente no banco + discoveredAt: new Date(), + lastUpdated: new Date(), + labels: { + 'xos.type': 'queue', + 'xos.queue_id': String(queue.id), + 'xos.open_conversations': String(queue.open_conversations || 0), + 'xos.active_users': String(queue.users_count || 0), + }, + }, + enabled: queue.is_active, + version: '1.0.0', + })); + } catch (error) { + console.error('[XOSDiscovery] Erro ao descobrir filas:', error); + return []; + } + } + + /** + * Descobre integrações de comunicação + */ + private async discoverIntegrations(): Promise { + const services: RegisteredService[] = []; + + try { + // WhatsApp Business (Miroflow) + const whatsappResult = await db.execute(sql` + SELECT COUNT(*) as count + FROM whatsapp_sessions + WHERE status = 'connected' + `); + const whatsappCount = parseInt(whatsappResult.rows[0]?.count || '0', 10); + + if (whatsappCount > 0) { + services.push({ + id: 'xos-whatsapp', + name: 'WhatsApp Business', + displayName: 'WhatsApp Business (Miroflow)', + type: 'node', + category: 'communication', + description: `Integração WhatsApp Business - ${whatsappCount} sessão(ões) conectada(s)`, + host: process.env.MIROFLOW_HOST || 'miroflow', + port: parseInt(process.env.MIROFLOW_PORT || '8006', 10), + endpoint: `http://${process.env.MIROFLOW_HOST || 'miroflow'}:${process.env.MIROFLOW_PORT || '8006'}`, + healthCheckPath: '/health', + healthStatus: 'unknown', // Será verificado pelo health check + lastHealthCheck: new Date(), + capabilities: [ + { name: 'whatsapp_messaging', version: '1.0', endpoints: ['/api/whatsapp/send'] }, + { name: 'whatsapp_webhook', version: '1.0', endpoints: ['/api/whatsapp/webhook'] }, + { name: 'template_messages', version: '1.0', endpoints: ['/api/whatsapp/templates'] }, + ], + requiresIA: true, + iaPolicies: ['communication', 'lgpd'], + metadata: { + source: 'manual', + discoveredAt: new Date(), + lastUpdated: new Date(), + labels: { + 'xos.type': 'integration', + 'xos.integration_type': 'whatsapp', + 'xos.sessions_count': String(whatsappCount), + }, + }, + enabled: true, + version: '1.0.0', + }); + } + + // Email (se houver configuração) + const emailResult = await db.execute(sql` + SELECT COUNT(*) as count + FROM settings + WHERE key LIKE 'smtp_%' OR key LIKE 'email_%' + `); + const hasEmail = parseInt(emailResult.rows[0]?.count || '0', 10) > 0; + + if (hasEmail) { + services.push({ + id: 'xos-email', + name: 'Email Service', + displayName: 'Serviço de Email', + type: 'node', + category: 'communication', + description: 'Integração SMTP para envio de emails', + host: 'localhost', + port: 5000, + endpoint: 'http://localhost:5000', + healthCheckPath: '/api/health', + healthStatus: 'unknown', + lastHealthCheck: new Date(), + capabilities: [ + { name: 'email_sending', version: '1.0', endpoints: ['/api/email/send'] }, + { name: 'email_templates', version: '1.0', endpoints: ['/api/email/templates'] }, + ], + requiresIA: false, + metadata: { + source: 'manual', + discoveredAt: new Date(), + lastUpdated: new Date(), + labels: { + 'xos.type': 'integration', + 'xos.integration_type': 'email', + }, + }, + enabled: true, + version: '1.0.0', + }); + } + + return services; + } catch (error) { + console.error('[XOSDiscovery] Erro ao descobrir integrações:', error); + return []; + } + } + + /** + * Descobre automações ativas + */ + private async discoverAutomations(): Promise { + try { + const result = await db.execute(sql` + SELECT + id, + name, + trigger_type, + is_active + FROM xos_automations + WHERE is_active = true + LIMIT 10 + `); + + const automations = result.rows as XOSAutomation[]; + + if (automations.length === 0) { + return []; + } + + // Cria um serviço único para o motor de automações XOS + return [{ + id: 'xos-automations', + name: 'XOS Automation Engine', + displayName: 'Motor de Automações XOS', + type: 'node', + category: 'automation', + description: `Motor de automações XOS - ${automations.length} automação(ões) ativa(s)`, + host: 'localhost', + port: 5000, + endpoint: 'http://localhost:5000', + healthCheckPath: '/api/xos/automations/health', + healthStatus: 'healthy', + lastHealthCheck: new Date(), + capabilities: [ + { name: 'workflow_automation', version: '1.0', endpoints: ['/api/xos/automations'] }, + { name: 'trigger_management', version: '1.0', endpoints: ['/api/xos/automations/triggers'] }, + { name: 'action_execution', version: '1.0', endpoints: ['/api/xos/automations/execute'] }, + ], + requiresIA: true, + iaPolicies: ['automation', 'lgpd'], + metadata: { + source: 'manual', + discoveredAt: new Date(), + lastUpdated: new Date(), + labels: { + 'xos.type': 'automation_engine', + 'xos.automations_count': String(automations.length), + 'xos.triggers': automations.map(a => a.trigger_type).join(','), + }, + }, + enabled: true, + version: '1.0.0', + }]; + } catch (error) { + console.error('[XOSDiscovery] Erro ao descobrir automações:', error); + return []; + } + } +} diff --git a/server/kernel/index.ts b/server/kernel/index.ts index 8c09df4..bc58f78 100644 --- a/server/kernel/index.ts +++ b/server/kernel/index.ts @@ -19,6 +19,7 @@ import { ServiceRegistry } from './registry/ServiceRegistry'; import { DockerDiscovery } from './discovery/DockerDiscovery'; import { StaticDiscovery } from './discovery/StaticDiscovery'; import { CoolifyDiscovery } from './discovery/CoolifyDiscovery'; +import { XOSDiscovery } from './discovery/XOSDiscovery'; import { RegistryConfig, RegisteredService } from './registry/types'; // Suporte a ESM e CommonJS (build do Docker) @@ -110,6 +111,7 @@ export class ArcadiaKernel { baseUrl: 'https://coolify.onboardbi.com.br', token: process.env.COOLIFY_API_TOKEN || '', }), + new XOSDiscovery(), // Descoberta de serviços XOS (filas, integrações) new DockerDiscovery({ networkName: 'arcadia' }), // Fallback ], });