Import source: app/backend/src/lib/error-digest

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:19:19 +03:30
parent af1991aad9
commit d6ee6a9b28
+48
View File
@@ -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<Record<string, number>>((acc, e) => {
acc[e.message] = (acc[e.message] || 0) + 1;
return acc;
}, {}),
)
.sort(([, a], [, b]) => b - a)
.slice(0, 10);
const html = `
<div dir="rtl" style="font-family: Vazirmatn, sans-serif; max-width: 600px; margin: 0 auto;">
<h2 style="color: #C94C4C;">گزارش خطاهای روزانه تکناو</h2>
<p>تعداد خطاها در ۲۴ ساعت گذشته: <strong>${count}</strong></p>
<h3>بیشترین تکرار:</h3>
<ul>
${topMessages.map(([msg, cnt]) => `<li><code>${msg}</code> (${cnt} بار)</li>`).join('')}
</ul>
<p style="color: #5F6B6D; font-size: 12px;">این گزارش از پنل خطاهای تکناو ارسال شده است.</p>
</div>
`;
await sendEmail({ to: ALERT_RECIPIENT, subject: `گزارش خطاهای تکناو — ${count} خطا`, html });
return { sent: true, count };
}