import { defineTable } from 'convex/server'; import { v } from 'convex/values'; import { ataqueCiberneticoTipo, severidadeSeguranca } from './security'; export const systemTables = { // Logs de Atividades do Sistema logsAtividades: defineTable({ usuarioId: v.id('usuarios'), acao: v.string(), recurso: v.string(), recursoId: v.optional(v.string()), detalhes: v.optional(v.string()), timestamp: v.number() }) .index('by_usuario', ['usuarioId']) .index('by_acao', ['acao']) .index('by_recurso', ['recurso']) .index('by_timestamp', ['timestamp']) .index('by_recurso_id', ['recurso', 'recursoId']), // Configuração de Email/SMTP configuracaoEmail: defineTable({ servidor: v.string(), // smtp.gmail.com porta: v.number(), // 587, 465, etc. usuario: v.string(), senhaHash: v.string(), // senha criptografada reversível (AES-GCM) - necessário para descriptografar e usar no SMTP emailRemetente: v.string(), nomeRemetente: v.string(), usarSSL: v.boolean(), usarTLS: v.boolean(), ativo: v.boolean(), testadoEm: v.optional(v.number()), configuradoPor: v.id('usuarios'), atualizadoEm: v.number() }).index('by_ativo', ['ativo']), // Fila de Emails notificacoesEmail: defineTable({ destinatario: v.string(), // email destinatarioId: v.optional(v.id('usuarios')), assunto: v.string(), corpo: v.string(), // HTML ou texto templateId: v.optional(v.id('templatesMensagens')), status: v.union( v.literal('pendente'), v.literal('enviando'), v.literal('enviado'), v.literal('falha') ), tentativas: v.number(), ultimaTentativa: v.optional(v.number()), erroDetalhes: v.optional(v.string()), enviadoPor: v.id('usuarios'), criadoEm: v.number(), enviadoEm: v.optional(v.number()), agendadaPara: v.optional(v.number()) // timestamp para agendamento }) .index('by_status', ['status']) .index('by_destinatario', ['destinatarioId']) .index('by_enviado_por', ['enviadoPor']) .index('by_criado_em', ['criadoEm']) .index('by_agendamento', ['agendadaPara']), // Rate Limiting de Emails rateLimitEmails: defineTable({ remetenteId: v.id('usuarios'), timestamp: v.number(), contador: v.number(), // quantidade de emails enviados neste período periodo: v.union( v.literal('minuto'), // último minuto v.literal('hora') // última hora ) }) .index('by_remetente_periodo', ['remetenteId', 'periodo', 'timestamp']) .index('by_timestamp', ['timestamp']), // Tabelas de Monitoramento do Sistema systemMetrics: defineTable({ timestamp: v.number(), // Métricas de Sistema cpuUsage: v.optional(v.number()), memoryUsage: v.optional(v.number()), networkLatency: v.optional(v.number()), storageUsed: v.optional(v.number()), // Métricas de Aplicação usuariosOnline: v.optional(v.number()), mensagensPorMinuto: v.optional(v.number()), tempoRespostaMedio: v.optional(v.number()), errosCount: v.optional(v.number()) }).index('by_timestamp', ['timestamp']), alertConfigurations: defineTable({ metricName: v.string(), threshold: v.number(), operator: v.union( v.literal('>'), v.literal('<'), v.literal('>='), v.literal('<='), v.literal('==') ), enabled: v.boolean(), notifyByEmail: v.boolean(), notifyByChat: v.boolean(), createdBy: v.id('usuarios'), lastModified: v.number() }).index('by_enabled', ['enabled']), alertHistory: defineTable({ configId: v.id('alertConfigurations'), metricName: v.string(), metricValue: v.number(), threshold: v.number(), timestamp: v.number(), status: v.union(v.literal('triggered'), v.literal('resolved')), notificationsSent: v.object({ email: v.boolean(), chat: v.boolean() }) }) .index('by_timestamp', ['timestamp']) .index('by_status', ['status']) .index('by_config', ['configId', 'timestamp']), rateLimitConfig: defineTable({ nome: v.string(), tipo: v.union( v.literal('ip'), v.literal('usuario'), v.literal('endpoint'), v.literal('global') ), identificador: v.optional(v.string()), limite: v.number(), janelaSegundos: v.number(), estrategia: v.union( v.literal('fixed_window'), v.literal('sliding_window'), v.literal('token_bucket') ), acaoExcedido: v.union(v.literal('bloquear'), v.literal('throttle'), v.literal('alertar')), bloqueioTemporarioSegundos: v.optional(v.number()), ativo: v.boolean(), prioridade: v.number(), criadoPor: v.id('usuarios'), atualizadoPor: v.optional(v.id('usuarios')), criadoEm: v.number(), atualizadoEm: v.number(), notas: v.optional(v.string()), tags: v.optional(v.array(v.string())) }) .index('by_tipo_identificador', ['tipo', 'identificador']) .index('by_ativo', ['ativo']) .index('by_prioridade', ['prioridade']), alertConfigs: defineTable({ nome: v.string(), canais: v.object({ email: v.boolean(), chat: v.boolean() }), emails: v.array(v.string()), chatUsers: v.array(v.string()), severidadeMin: severidadeSeguranca, tiposAtaque: v.optional(v.array(ataqueCiberneticoTipo)), reenvioMin: v.number(), criadoPor: v.id('usuarios'), criadoEm: v.number(), atualizadoEm: v.number() }).index('by_criadoEm', ['criadoEm']), // Configurações Gerais config: defineTable({ comprasSetorId: v.optional(v.id('setores')), financeiroSetorId: v.optional(v.id('setores')), juridicoSetorId: v.optional(v.id('setores')), convenioSetorId: v.optional(v.id('setores')), programasEsportivosSetorId: v.optional(v.id('setores')), comunicacaoSetorId: v.optional(v.id('setores')), tiSetorId: v.optional(v.id('setores')), criadoPor: v.id('usuarios'), atualizadoEm: v.number() }), // Templates de Mensagens templatesMensagens: defineTable({ codigo: v.string(), // "USUARIO_BLOQUEADO", "SENHA_RESETADA", etc. nome: v.string(), tipo: v.union( v.literal('sistema'), // predefinido, não editável v.literal('customizado') // criado por TI_MASTER ), titulo: v.string(), corpo: v.string(), // pode ter variáveis {{variavel}} htmlCorpo: v.optional(v.string()), // versão HTML do corpo (com wrapper) variaveis: v.optional(v.array(v.string())), // ["motivo", "senha", etc.] categoria: v.optional(v.union(v.literal('email'), v.literal('chat'), v.literal('ambos'))), // categoria do template tags: v.optional(v.array(v.string())), // tags para organização criadoPor: v.optional(v.id('usuarios')), criadoEm: v.number() }) .index('by_codigo', ['codigo']) .index('by_tipo', ['tipo']) .index('by_criado_por', ['criadoPor']) .index('by_categoria', ['categoria']), // Configuração de Jitsi Meet configuracaoJitsi: defineTable({ domain: v.string(), // Domínio do servidor Jitsi (ex: "localhost:8443" ou "meet.example.com") appId: v.string(), // ID da aplicação Jitsi roomPrefix: v.string(), // Prefixo para nomes de salas useHttps: v.boolean(), // Usar HTTPS acceptSelfSignedCert: v.optional(v.boolean()), // Aceitar certificados autoassinados (útil para desenvolvimento) ativo: v.boolean(), // Configuração ativa testadoEm: v.optional(v.number()), // Timestamp do último teste de conexão configuradoEm: v.optional(v.number()), // Timestamp da última configuração do servidor Docker configuradoNoServidor: v.optional(v.boolean()), // Indica se a configuração foi aplicada no servidor configuradoNoServidorEm: v.optional(v.number()), // Timestamp de quando foi configurado no servidor configuradoPor: v.id('usuarios'), // Usuário que configurou atualizadoEm: v.number(), // Timestamp de atualização jitsiConfigPath: v.optional(v.string()), // Caminho da configuração do Jitsi no servidor (ex: "~/.jitsi-meet-cfg") sshUsername: v.optional(v.string()), // Usuário SSH para acesso ao servidor sshPasswordHash: v.optional(v.string()), // Hash da senha SSH (criptografada) sshPort: v.optional(v.number()) // Porta SSH (padrão: 22) }).index('by_ativo', ['ativo']) };