Merge remote-tracking branch 'origin' into feat-pedidos

This commit is contained in:
2025-12-11 10:08:12 -03:00
194 changed files with 30374 additions and 10247 deletions

View File

@@ -1,8 +1,8 @@
import { v } from 'convex/values';
import type { Doc } from './_generated/dataModel';
import { mutation, query } from './_generated/server';
import { registrarAtividade } from './logsAtividades';
import { textToHTML, wrapEmailHTML } from './utils/emailTemplateWrapper';
import { Doc } from './_generated/dataModel';
import { wrapEmailHTML, textToHTML } from './utils/emailTemplateWrapper';
/**
* Listar todos os templates
@@ -61,10 +61,7 @@ export const criarTemplate = mutation({
criadoPorId: v.id('usuarios')
},
returns: v.union(
v.object({
sucesso: v.literal(true),
templateId: v.id('templatesMensagens')
}),
v.object({ sucesso: v.literal(true), templateId: v.id('templatesMensagens') }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args) => {
@@ -146,10 +143,7 @@ export const editarTemplate = mutation({
// Não permite editar templates do sistema
if (template.tipo === 'sistema') {
return {
sucesso: false as const,
erro: 'Templates do sistema não podem ser editados'
};
return { sucesso: false as const, erro: 'Templates do sistema não podem ser editados' };
}
// Atualizar template
@@ -209,10 +203,7 @@ export const excluirTemplate = mutation({
// Não permite excluir templates do sistema
if (template.tipo === 'sistema') {
return {
sucesso: false as const,
erro: 'Templates do sistema não podem ser excluídos'
};
return { sucesso: false as const, erro: 'Templates do sistema não podem ser excluídos' };
}
// Excluir template
@@ -361,8 +352,27 @@ export const criarTemplatesPadrao = mutation({
nome: 'Boas-vindas',
titulo: 'Bem-vindo ao SGSE',
corpo:
'Olá {{nome}},\n\nSeja bem-vindo ao SGSE - Sistema de Gerenciamento de Secretaria!\n\nSuas credenciais de acesso:\nMatrícula: {{matricula}}\nSenha temporária: {{senha}}\n\nPor favor, altere sua senha no primeiro acesso.\n\nEquipe de TI',
variaveis: ['nome', 'matricula', 'senha']
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #2563EB;'>Bem-vindo ao SGSE</h2>" +
'<p>Olá <strong>{{nome}}</strong>,</p>' +
'<p>Seja bem-vindo ao <strong>SGSE - Sistema de Gerenciamento de Secretaria</strong>!</p>' +
'<p>Seu cadastro foi realizado com sucesso.</p>' +
"<div style='background-color: #F3F4F6; border-left: 4px solid #2563EB; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0 0 10px 0;'><strong>Suas credenciais de acesso:</strong></p>" +
"<ul style='margin: 0; padding-left: 20px;'>" +
'<li><strong>E-mail:</strong> {{email}}</li>' +
'{{credenciaisAdicionais}}' +
'<li><strong>Senha temporária:</strong> {{senha}}</li>' +
'</ul>' +
'</div>' +
'<p><strong>⚠️ Importante:</strong> Por favor, altere sua senha no primeiro acesso ao sistema.</p>' +
"<p>Acesse o sistema através do link: <a href='{{urlSistema}}' style='color: #2563EB;'>{{urlSistema}}</a></p>" +
"<p style='margin-top: 30px; color: #6B7280; font-size: 14px;'>Equipe de TI - Secretaria de Esportes</p>" +
'</div></body></html>',
variaveis: ['nome', 'email', 'credenciaisAdicionais', 'senha', 'urlSistema'],
categoria: 'email' as const,
tags: ['boas_vindas', 'cadastro', 'credenciais']
},
{
codigo: 'chat_mensagem',
@@ -554,10 +564,138 @@ export const criarTemplatesPadrao = mutation({
'Recomenda-se verificar o painel de monitoramento do SGSE para detalhes adicionais e, se necessário, ' +
'executar ações corretivas.\n\n' +
'Esta é uma notificação automática do sistema de monitoramento SGSE.',
htmlCorpo:
'<div style="max-width: 600px; margin: 0 auto; padding: 20px;">' +
'<div style="background: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%); border-radius: 8px; padding: 20px; margin-bottom: 25px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">' +
'<h2 style="color: #FFFFFF; margin: 0 0 10px 0; font-size: 24px; font-weight: bold;">⚠️ Alerta de Sistema</h2>' +
'<p style="color: #FFFFFF; margin: 0; font-size: 16px; font-weight: 500;">Métrica: <strong>{{metricName}}</strong></p>' +
'</div>' +
'<p style="color: #333333; font-size: 16px; line-height: 1.6; margin: 0 0 20px 0;">Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<div style="background-color: #FFF3CD; border-left: 4px solid #FFC107; padding: 15px; border-radius: 4px; margin: 20px 0;">' +
'<p style="margin: 0 0 10px 0; color: #856404; font-weight: bold; font-size: 14px;">📊 Detalhes do Alerta:</p>' +
'<ul style="margin: 0; padding-left: 20px; color: #856404; font-size: 14px; line-height: 1.8;">' +
'<li><strong>Métrica:</strong> {{metricName}}</li>' +
'<li><strong>Valor Atual:</strong> <span style="color: #DC3545; font-weight: bold;">{{metricValue}}</span></li>' +
'<li><strong>Limite Configurado:</strong> {{threshold}}</li>' +
'</ul>' +
'</div>' +
'<p style="color: #333333; font-size: 14px; line-height: 1.6; margin: 20px 0;">' +
'Recomenda-se verificar o <strong>painel de monitoramento do SGSE</strong> para detalhes adicionais e, se necessário, executar ações corretivas.' +
'</p>' +
'<div style="background-color: #E7F3FF; border-left: 4px solid #0052A5; padding: 15px; border-radius: 4px; margin: 20px 0;">' +
'<p style="margin: 0; color: #004085; font-size: 14px; line-height: 1.6;">' +
'<strong>💡 Dica:</strong> Acesse o painel de monitoramento para visualizar gráficos e histórico detalhado desta métrica.' +
'</p>' +
'</div>' +
'<p style="color: #666666; font-size: 12px; margin-top: 30px; padding-top: 20px; border-top: 1px solid #E0E0E0;">' +
'Esta é uma notificação automática do sistema de monitoramento SGSE.' +
'</p>' +
'</div>',
variaveis: ['destinatarioNome', 'metricName', 'metricValue', 'threshold'],
categoria: 'email' as const,
tags: ['monitoramento', 'alerta', 'sistema', 'ti']
},
// ===================== LGPD =====================
{
codigo: 'lgpd_solicitacao_criada',
nome: 'LGPD - Solicitação Criada',
titulo: 'Recebemos sua solicitação LGPD ({{tipoSolicitacaoLabel}})',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Recebemos sua solicitação LGPD do tipo "{{tipoSolicitacaoLabel}}".\n\n' +
'Prazo estimado para resposta: até {{prazoResposta}}.\n\n' +
'Você pode acompanhar o andamento acessando: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'tipoSolicitacaoLabel', 'prazoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'solicitacao', 'dados_pessoais']
},
{
codigo: 'lgpd_resposta_acesso',
nome: 'LGPD - Resposta Acesso',
titulo: 'Resposta à sua solicitação LGPD - Acesso aos Dados',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Sua solicitação LGPD de Acesso aos Dados foi marcada como {{statusLabel}}.\n\n' +
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'acesso', 'dados_pessoais']
},
{
codigo: 'lgpd_resposta_correcao',
nome: 'LGPD - Resposta Correção',
titulo: 'Resposta à sua solicitação LGPD - Correção de Dados',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Sua solicitação LGPD de Correção de Dados foi marcada como {{statusLabel}}.\n\n' +
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'correcao', 'dados_pessoais']
},
{
codigo: 'lgpd_resposta_exclusao',
nome: 'LGPD - Resposta Exclusão',
titulo: 'Resposta à sua solicitação LGPD - Exclusão de Dados',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Sua solicitação LGPD de Exclusão de Dados foi marcada como {{statusLabel}}.\n\n' +
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'exclusao', 'dados_pessoais']
},
{
codigo: 'lgpd_resposta_portabilidade',
nome: 'LGPD - Resposta Portabilidade',
titulo: 'Resposta à sua solicitação LGPD - Portabilidade dos Dados',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Sua solicitação LGPD de Portabilidade dos Dados foi marcada como {{statusLabel}}.\n\n' +
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
'Caso tenha recebido um arquivo anexo, ele contém os dados em formato portável.\n\n' +
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'portabilidade', 'dados_pessoais']
},
{
codigo: 'lgpd_resposta_revogacao_consentimento',
nome: 'LGPD - Resposta Revogação de Consentimento',
titulo: 'Confirmação de Revogação de Consentimento',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Sua solicitação LGPD de Revogação de Consentimento foi marcada como {{statusLabel}}.\n\n' +
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
'Todos os consentimentos ativos associados à sua conta foram marcados como revogados a partir desta data.\n\n' +
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'revogacao_consentimento', 'dados_pessoais']
},
{
codigo: 'lgpd_resposta_informacao_compartilhamento',
nome: 'LGPD - Resposta Informação sobre Compartilhamento',
titulo: 'Resposta à sua solicitação LGPD - Informação sobre Compartilhamento',
corpo:
'Olá {{nomeTitular}},\n\n' +
'Sua solicitação LGPD de Informação sobre Compartilhamento foi marcada como {{statusLabel}}.\n\n' +
'Resumo da resposta:\n{{resumoResposta}}\n\n' +
'Para mais detalhes, acesse: {{urlPortalLGPD}}.\n\n' +
'Equipe de Proteção de Dados / TI.',
variaveis: ['nomeTitular', 'statusLabel', 'resumoResposta', 'urlPortalLGPD'],
categoria: 'email' as const,
tags: ['lgpd', 'informacao_compartilhamento', 'dados_pessoais']
},
{
codigo: 'ausencia_solicitada',
nome: 'Ausência Solicitada',
@@ -609,6 +747,264 @@ export const criarTemplatesPadrao = mutation({
],
categoria: 'email' as const,
tags: ['ausencia', 'reprovacao', 'gestao']
},
{
codigo: 'ferias_aprovada',
nome: 'Férias Aprovada',
titulo: 'Solicitação de Férias Aprovada',
corpo:
'Olá {{funcionarioNome}},\n\nSua solicitação de férias foi <strong>aprovada</strong> pelo gestor {{gestorNome}}:\n\n<ul><li><strong>Período:</strong> {{dataInicio}} até {{dataFim}}</li><li><strong>Dias:</strong> {{diasFerias}} dias</li></ul>',
variaveis: [
'funcionarioNome',
'gestorNome',
'dataInicio',
'dataFim',
'diasFerias',
'urlSistema'
],
categoria: 'email' as const,
tags: ['ferias', 'aprovacao', 'gestao']
},
{
codigo: 'ferias_cancelada_rh',
nome: 'Férias Cancelada pelo RH',
titulo: 'Solicitação de Férias Cancelada',
corpo:
'Olá {{funcionarioNome}},\n\nSua solicitação de férias foi <strong>cancelada</strong> pelo setor de Recursos Humanos:\n\n<ul><li><strong>Período:</strong> {{dataInicio}} até {{dataFim}}</li><li><strong>Dias:</strong> {{diasFerias}} dias</li></ul>\n\nPara mais informações, entre em contato com o setor de Recursos Humanos.',
variaveis: ['funcionarioNome', 'dataInicio', 'dataFim', 'diasFerias', 'urlSistema'],
categoria: 'email' as const,
tags: ['ferias', 'cancelamento', 'recursos_humanos']
},
// ===================== ALERTAS DE SEGURANÇA CIBERNÉTICA =====================
{
codigo: 'incidente_critico',
nome: 'Incidente Crítico - Ação Imediata',
titulo: '🚨 ALERTA CRÍTICO: {{tipoAtaque}}',
corpo:
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #DC2626;'>🚨 ALERTA CRÍTICO DE SEGURANÇA</h2>" +
'<p>Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<p>Um <strong>incidente crítico de segurança</strong> foi detectado no sistema:</p>' +
"<div style='background-color: #FEF2F2; border-left: 4px solid #DC2626; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0;'><strong>Tipo de Ataque:</strong> {{tipoAtaque}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Severidade:</strong> <span style='color: #DC2626; font-weight: bold;'>{{severidade}}</span></p>" +
"<p style='margin: 5px 0 0 0;'><strong>Descrição:</strong> {{descricao}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>IP de Origem:</strong> {{origemIp}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Data/Hora:</strong> {{dataHora}}</p>" +
'</div>' +
"<p style='color: #DC2626; font-weight: bold;'>⚠️ AÇÃO IMEDIATA NECESSÁRIA</p>" +
"<p style='margin-top: 30px;'>" +
"<a href='{{urlSistema}}/ti/cybersecurity' " +
"style='background-color: #DC2626; color: white; padding: 12px 24px; " +
"text-decoration: none; border-radius: 6px; display: inline-block;'>" +
'Ver Detalhes do Incidente' +
'</a>' +
'</p>' +
"<p style='color: #6B7280; font-size: 12px; margin-top: 30px;'>" +
'SGSE - Sistema de Gerenciamento de Secretaria - Equipe de Segurança' +
'</p>' +
'</div></body></html>',
variaveis: [
'destinatarioNome',
'tipoAtaque',
'severidade',
'descricao',
'origemIp',
'dataHora',
'urlSistema'
],
categoria: 'email' as const,
tags: ['seguranca', 'alerta', 'critico', 'cybersecurity']
},
{
codigo: 'bloqueio_automatico',
nome: 'Bloqueio Automático',
titulo: '🔒 Bloqueio Automático: {{tipoAtaque}}',
corpo:
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #F59E0B;'>🔒 Bloqueio Automático Aplicado</h2>" +
'<p>Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<p>O sistema aplicou um <strong>bloqueio automático</strong> devido a uma tentativa de ataque detectada:</p>' +
"<div style='background-color: #FFFBEB; border-left: 4px solid #F59E0B; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0;'><strong>Tipo de Ataque:</strong> {{tipoAtaque}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>IP Bloqueado:</strong> {{origemIp}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Descrição:</strong> {{descricao}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Data/Hora:</strong> {{dataHora}}</p>" +
'</div>' +
"<p style='margin-top: 30px;'>" +
"<a href='{{urlSistema}}/ti/cybersecurity' " +
"style='background-color: #F59E0B; color: white; padding: 12px 24px; " +
"text-decoration: none; border-radius: 6px; display: inline-block;'>" +
'Ver Detalhes do Bloqueio' +
'</a>' +
'</p>' +
"<p style='color: #6B7280; font-size: 12px; margin-top: 30px;'>" +
'SGSE - Sistema de Gerenciamento de Secretaria - Equipe de Segurança' +
'</p>' +
'</div></body></html>',
variaveis: [
'destinatarioNome',
'tipoAtaque',
'origemIp',
'descricao',
'dataHora',
'urlSistema'
],
categoria: 'email' as const,
tags: ['seguranca', 'bloqueio', 'automatico', 'cybersecurity']
},
{
codigo: 'sumario_30min',
nome: 'Sumário 30 Min',
titulo: '📊 Sumário de Segurança - Últimos 30 minutos',
corpo:
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #2563EB;'>📊 Sumário de Segurança</h2>" +
'<p>Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<p>Resumo dos eventos de segurança dos últimos 30 minutos:</p>' +
"<div style='background-color: #EFF6FF; border-left: 4px solid #2563EB; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0;'><strong>Total de Eventos:</strong> {{totalEventos}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Eventos Críticos:</strong> {{eventosCriticos}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Eventos Altos:</strong> {{eventosAltos}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>IPs Bloqueados:</strong> {{ipsBloqueados}}</p>" +
'</div>' +
"<p style='margin-top: 30px;'>" +
"<a href='{{urlSistema}}/ti/cybersecurity' " +
"style='background-color: #2563EB; color: white; padding: 12px 24px; " +
"text-decoration: none; border-radius: 6px; display: inline-block;'>" +
'Ver Relatório Completo' +
'</a>' +
'</p>' +
"<p style='color: #6B7280; font-size: 12px; margin-top: 30px;'>" +
'SGSE - Sistema de Gerenciamento de Secretaria - Equipe de Segurança' +
'</p>' +
'</div></body></html>',
variaveis: [
'destinatarioNome',
'totalEventos',
'eventosCriticos',
'eventosAltos',
'ipsBloqueados',
'urlSistema'
],
categoria: 'email' as const,
tags: ['seguranca', 'sumario', 'relatorio', 'cybersecurity']
},
{
codigo: 'anormalidade',
nome: 'Anomalia Detectada',
titulo: '⚠️ Anomalia Detectada: {{tipoAtaque}}',
corpo:
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #F59E0B;'>⚠️ Anomalia Detectada</h2>" +
'<p>Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<p>O sistema detectou uma <strong>anomalia de segurança</strong> que requer atenção:</p>' +
"<div style='background-color: #FFFBEB; border-left: 4px solid #F59E0B; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0;'><strong>Tipo de Ataque:</strong> {{tipoAtaque}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Severidade:</strong> {{severidade}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Descrição:</strong> {{descricao}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>IP de Origem:</strong> {{origemIp}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Data/Hora:</strong> {{dataHora}}</p>" +
'</div>' +
"<p style='margin-top: 30px;'>" +
"<a href='{{urlSistema}}/ti/cybersecurity' " +
"style='background-color: #F59E0B; color: white; padding: 12px 24px; " +
"text-decoration: none; border-radius: 6px; display: inline-block;'>" +
'Ver Detalhes da Anomalia' +
'</a>' +
'</p>' +
"<p style='color: #6B7280; font-size: 12px; margin-top: 30px;'>" +
'SGSE - Sistema de Gerenciamento de Secretaria - Equipe de Segurança' +
'</p>' +
'</div></body></html>',
variaveis: [
'destinatarioNome',
'tipoAtaque',
'severidade',
'descricao',
'origemIp',
'dataHora',
'urlSistema'
],
categoria: 'email' as const,
tags: ['seguranca', 'anomalia', 'alerta', 'cybersecurity']
},
// ===================== NOTIFICAÇÕES DE ERROS DO SERVIDOR =====================
{
codigo: 'ERRO_SERVIDOR_404',
nome: 'Erro 404 - Página Não Encontrada',
titulo: '⚠️ Erro 404 - Página não encontrada',
corpo:
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #F59E0B;'>⚠️ Erro 404 - Página Não Encontrada</h2>" +
'<p>Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<p>O sistema detectou uma tentativa de acesso a uma página que não existe:</p>' +
"<div style='background-color: #FFFBEB; border-left: 4px solid #F59E0B; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0;'><strong>URL:</strong> {{url}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Método HTTP:</strong> {{method}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Mensagem:</strong> {{mensagem}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Data/Hora:</strong> {{timestamp}}</p>" +
'</div>' +
"<p style='color: #6B7280; font-size: 14px; margin-top: 20px;'>" +
'<strong>Possíveis causas:</strong><br>' +
'• Link quebrado ou desatualizado<br>' +
'• URL digitada incorretamente<br>' +
'• Página movida ou removida<br>' +
'• Tentativa de acesso a recurso inexistente' +
'</p>' +
"<p style='color: #6B7280; font-size: 12px; margin-top: 30px;'>" +
'SGSE - Sistema de Gerenciamento de Secretaria - Equipe de TI' +
'</p>' +
'</div></body></html>',
variaveis: ['destinatarioNome', 'url', 'method', 'mensagem', 'timestamp'],
categoria: 'email' as const,
tags: ['erro', '404', 'servidor', 'notificacao', 'ti']
},
{
codigo: 'ERRO_SERVIDOR_500',
nome: 'Erro 500 - Erro Interno do Servidor',
titulo: '🚨 Erro 500 - Erro Interno do Servidor',
corpo:
"<html><body style='font-family: Arial, sans-serif; line-height: 1.6; color: #333;'>" +
"<div style='max-width: 600px; margin: 0 auto; padding: 20px;'>" +
"<h2 style='color: #DC2626;'>🚨 Erro 500 - Erro Interno do Servidor</h2>" +
'<p>Olá <strong>{{destinatarioNome}}</strong>,</p>' +
'<p>O sistema detectou um <strong>erro interno do servidor</strong> que requer atenção imediata:</p>' +
"<div style='background-color: #FEF2F2; border-left: 4px solid #DC2626; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0;'><strong>Código HTTP:</strong> {{statusCode}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>URL:</strong> {{url}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Método HTTP:</strong> {{method}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Mensagem:</strong> {{mensagem}}</p>" +
"<p style='margin: 5px 0 0 0;'><strong>Data/Hora:</strong> {{timestamp}}</p>" +
'</div>' +
"<div style='background-color: #F9FAFB; border: 1px solid #E5E7EB; padding: 15px; border-radius: 8px; margin: 20px 0;'>" +
"<p style='margin: 0; font-size: 12px; color: #6B7280;'><strong>Stack Trace:</strong></p>" +
"<pre style='margin: 10px 0 0 0; padding: 10px; background-color: #FFFFFF; border: 1px solid #E5E7EB; border-radius: 4px; font-size: 11px; white-space: pre-wrap; word-wrap: break-word; overflow-x: auto;'>{{stack}}</pre>" +
'</div>' +
"<p style='color: #DC2626; font-weight: bold; margin-top: 20px;'>" +
'⚠️ AÇÃO IMEDIATA NECESSÁRIA' +
'</p>' +
"<p style='color: #6B7280; font-size: 12px; margin-top: 30px;'>" +
'SGSE - Sistema de Gerenciamento de Secretaria - Equipe de TI<br>' +
'Este é um alerta automático do sistema de monitoramento de erros.' +
'</p>' +
'</div></body></html>',
variaveis: [
'destinatarioNome',
'statusCode',
'url',
'method',
'mensagem',
'stack',
'timestamp'
],
categoria: 'email' as const,
tags: ['erro', '500', 'servidor', 'critico', 'notificacao', 'ti']
}
];
@@ -653,10 +1049,7 @@ export const atualizarTemplateHTML = mutation({
// Não permite editar templates do sistema
if (template.tipo === 'sistema') {
return {
sucesso: false as const,
erro: 'Templates do sistema não podem ser editados'
};
return { sucesso: false as const, erro: 'Templates do sistema não podem ser editados' };
}
await ctx.db.patch(args.templateId, {
@@ -746,7 +1139,7 @@ export const previewTemplate = query({
* Função auxiliar para obter URL base
*/
function getBaseUrl(): string {
const url = process.env.FRONTEND_URL || 'http://localhost:5173';
const url = process.env.SITE_URL || 'http://localhost:5173';
if (!url.match(/^https?:\/\//i)) {
return `http://${url}`;
}
@@ -907,10 +1300,7 @@ export const duplicarTemplate = mutation({
criadoPorId: v.id('usuarios')
},
returns: v.union(
v.object({
sucesso: v.literal(true),
templateId: v.id('templatesMensagens')
}),
v.object({ sucesso: v.literal(true), templateId: v.id('templatesMensagens') }),
v.object({ sucesso: v.literal(false), erro: v.string() })
),
handler: async (ctx, args) => {
@@ -948,11 +1338,7 @@ export const duplicarTemplate = mutation({
args.criadoPorId,
'duplicar',
'templates',
JSON.stringify({
templateId,
codigo: args.novoCodigo,
originalId: args.templateId
}),
JSON.stringify({ templateId, codigo: args.novoCodigo, originalId: args.templateId }),
templateId
);