import { prisma } from "@/lib/prisma"; import { Prisma } from "@/app/generated/prisma/client"; import type { EmailJobStatus } from "@/app/generated/prisma/enums"; /** Filter untuk halaman admin email log. Keduanya opsional, match `contains`. */ export interface EmailLogFilters { to?: string; template?: string; } const LIST_LIMIT = 100; function buildWhere( filters: EmailLogFilters ): T { const where = {} as T; if (filters.to) { (where as { to?: unknown }).to = { contains: filters.to, mode: "insensitive", }; } if (filters.template) { (where as { template?: unknown }).template = { contains: filters.template, mode: "insensitive", }; } return where; } export const emailRepo = { /** EmailJob (retry queue) per status — terbaru dulu. */ async listJobs(statuses: EmailJobStatus[], filters: EmailLogFilters) { const where = buildWhere(filters); where.status = { in: statuses }; return prisma.emailJob.findMany({ where, orderBy: { updatedAt: "desc" }, take: LIST_LIMIT, }); }, /** EmailSent (log email berhasil terkirim) — terbaru dulu. */ async listSent(filters: EmailLogFilters) { const where = buildWhere(filters); return prisma.emailSent.findMany({ where, orderBy: { sentAt: "desc" }, take: LIST_LIMIT, }); }, /** * Statistik kesehatan pengiriman email — dipakai kartu ringkasan * `/admin/emails` dan `/admin/system`. * - `queued` : job menunggu dikirim (PENDING/PROCESSING). * - `failed24h` : job gagal dalam 24 jam terakhir. * - `deadLetter` : job gagal yang sudah habis 5 attempt — cron berhenti * retry, butuh aksi manual admin. */ async stats() { const since24h = new Date(Date.now() - 24 * 60 * 60 * 1000); const [queued, failed24h, deadLetter] = await Promise.all([ prisma.emailJob.count({ where: { status: { in: ["PENDING", "PROCESSING"] } }, }), prisma.emailJob.count({ where: { status: "FAILED", updatedAt: { gte: since24h } }, }), prisma.emailJob.count({ where: { status: "FAILED", attempts: { gte: 5 } }, }), ]); return { queued, failed24h, deadLetter }; }, };