feat: adiciona fluxo de redefinição de senha e melhora página de configurações

- Adiciona página /recuperar para solicitar redefinição de senha
- Adiciona página /redefinir-senha para definir nova senha com token
- Cria APIs /api/auth/forgot-password e /api/auth/reset-password
- Adiciona notificação por e-mail quando ticket é criado
- Repagina página de configurações removendo informações técnicas
- Adiciona script de teste para todos os tipos de e-mail
- Corrige acentuações em templates de e-mail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-15 10:42:08 -03:00
parent 300179279a
commit 1bc08d3a5f
10 changed files with 1258 additions and 166 deletions

View file

@ -281,6 +281,43 @@ async function sendSmtpMail(cfg: SmtpConfig, to: string, subject: string, html:
}
}
export const sendTicketCreatedEmail = action({
args: {
to: v.string(),
ticketId: v.string(),
reference: v.number(),
subject: v.string(),
priority: v.string(),
},
handler: async (_ctx, { to, ticketId, reference, subject, priority }) => {
const smtp = buildSmtpConfig()
if (!smtp) {
console.warn("SMTP not configured; skipping ticket created email")
return { skipped: true }
}
const baseUrl = buildBaseUrl()
const url = `${baseUrl}/portal/tickets/${ticketId}`
const priorityLabels: Record<string, string> = {
LOW: "Baixa",
MEDIUM: "Média",
HIGH: "Alta",
URGENT: "Urgente",
}
const priorityLabel = priorityLabels[priority] ?? priority
const mailSubject = `Novo chamado #${reference} aberto`
const html = await renderSimpleNotificationEmailHtml({
title: `Novo chamado #${reference} aberto`,
message: `Seu chamado foi registrado com sucesso. Nossa equipe irá analisá-lo em breve.\n\nAssunto: ${subject}\nPrioridade: ${priorityLabel}\nStatus: Pendente`,
ctaLabel: "Ver chamado",
ctaUrl: url,
})
await sendSmtpMail(smtp, to, mailSubject, html)
return { ok: true }
},
})
export const sendPublicCommentEmail = action({
args: {
to: v.string(),

View file

@ -2456,6 +2456,25 @@ export const create = mutation({
createdAt: now,
});
// Notificação por e-mail: ticket criado para o solicitante
try {
const requesterEmail = requester?.email
if (requesterEmail) {
const schedulerRunAfter = ctx.scheduler?.runAfter
if (typeof schedulerRunAfter === "function") {
await schedulerRunAfter(0, api.ticketNotifications.sendTicketCreatedEmail, {
to: requesterEmail,
ticketId: String(id),
reference: nextRef,
subject,
priority: args.priority,
})
}
}
} catch (e) {
console.warn("[tickets] Falha ao agendar e-mail de ticket criado", e)
}
if (initialAssigneeId && initialAssignee) {
await ctx.db.insert("ticketEvents", {
ticketId: id,