diff --git a/app/backend/src/lib/error-digest.ts b/app/backend/src/lib/error-digest.ts new file mode 100644 index 0000000..a3efc51 --- /dev/null +++ b/app/backend/src/lib/error-digest.ts @@ -0,0 +1,48 @@ +import { prisma } from '../db.js'; +import { sendEmail } from './email.js'; + +const ALERT_THRESHOLD = 50; +const ALERT_RECIPIENT = process.env.ADMIN_ALERT_EMAIL || ''; + +export async function sendErrorDigest(): Promise<{ sent: boolean; count: number }> { + const since = new Date(); + since.setHours(0, 0, 0, 0); + + const errors = await prisma.clientError.findMany({ + where: { createdAt: { gte: since } }, + orderBy: { createdAt: 'desc' }, + take: 100, + }); + + const count = await prisma.clientError.count({ + where: { createdAt: { gte: since } }, + }); + + if (count < ALERT_THRESHOLD || !ALERT_RECIPIENT) { + return { sent: false, count }; + } + + const topMessages = Object.entries( + errors.reduce>((acc, e) => { + acc[e.message] = (acc[e.message] || 0) + 1; + return acc; + }, {}), + ) + .sort(([, a], [, b]) => b - a) + .slice(0, 10); + + const html = ` +
+

گزارش خطاهای روزانه تکناو

+

تعداد خطاها در ۲۴ ساعت گذشته: ${count}

+

بیشترین تکرار:

+ +

این گزارش از پنل خطاهای تکناو ارسال شده است.

+
+ `; + + await sendEmail({ to: ALERT_RECIPIENT, subject: `گزارش خطاهای تکناو — ${count} خطا`, html }); + return { sent: true, count }; +}