feat(email): phase 6 — replace Resend with Brevo transactional email

Removes resend npm dependency. Adds lib/notifications/mailer.ts with a
raw-HTTP Brevo wrapper (sendEmail + sendPasswordResetEmail). All three
notification files updated to use the new wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-23 22:20:12 +08:00
co-authored by Claude Sonnet 4.6
parent 186c732ac0
commit d785d86636
6 changed files with 48 additions and 83 deletions
+2 -8
View File
@@ -1,5 +1,5 @@
import 'server-only'
import { Resend } from 'resend'
import { sendEmail } from '@/lib/notifications/mailer'
import { asAdmin } from '@/lib/db/with-user'
import { capaActions, incidents, users, notificationsLog } from '@/lib/db/schema'
import { and, eq, inArray, not } from 'drizzle-orm'
@@ -52,8 +52,6 @@ export async function escalateOverdueCapa(): Promise<{ notified: number }> {
if (!capas || capas.length === 0) return { notified: 0 }
const resend = new Resend(process.env.RESEND_API_KEY)
const from = process.env.RESEND_FROM_EMAIL ?? 'onboarding@resend.dev'
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL ?? 'http://localhost:3000'
let notified = 0
@@ -105,11 +103,7 @@ export async function escalateOverdueCapa(): Promise<{ notified: number }> {
to.push(...hseUsers.map(u => u.email).filter(Boolean) as string[])
}
const { error } = await resend.emails.send({ from, to: [...new Set(to)], subject, html, text })
if (error) {
console.error('Escalation email error:', error)
continue
}
await sendEmail({ to: [...new Set(to)], subject, html, text })
// WhatsApp for urgent thresholds only (owner must have a phone number)
if (['overdue_3d', 'overdue_7d'].includes(threshold)) {