feat: add test digest mode (?test=true) + group company sees all entries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-11 08:47:17 +02:00
parent 479afb1039
commit 9d58f1b705
2 changed files with 117 additions and 2 deletions
+8 -1
View File
@@ -1,11 +1,15 @@
import { NextResponse } from "next/server";
import { runDigest } from "@/core/notifications";
import { sendTestDigest } from "@/core/notifications/notification-service";
/**
* POST /api/notifications/digest
*
* Server-to-server endpoint called by N8N cron.
* Auth via Authorization: Bearer <NOTIFICATION_CRON_SECRET>
*
* Query params:
* ?test=true — send a test email with sample data to all subscribers
*/
export async function POST(request: Request) {
const secret = process.env.NOTIFICATION_CRON_SECRET;
@@ -24,7 +28,10 @@ export async function POST(request: Request) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
const result = await runDigest();
const url = new URL(request.url);
const isTest = url.searchParams.get("test") === "true";
const result = isTest ? await sendTestDigest() : await runDigest();
return NextResponse.json(result, {
status: result.success ? 200 : 500,
+109 -1
View File
@@ -74,7 +74,11 @@ function buildCompanyDigest(
entries: RegistryEntry[],
company: CompanyId,
): DigestSection[] {
const companyEntries = entries.filter((e) => e.company === company);
// "group" users see ALL entries across all companies
const companyEntries =
company === "group"
? entries
: entries.filter((e) => e.company === company);
const sections: DigestSection[] = [];
const now = new Date();
@@ -385,3 +389,107 @@ export async function runDigest(): Promise<DigestResult> {
return result;
}
// ── Test digest — sends sample email to all subscribers ──
export async function sendTestDigest(): Promise<DigestResult> {
const result: DigestResult = {
success: true,
totalEmails: 0,
errors: [],
companySummary: {},
};
try {
const preferences = await getAllPreferences();
if (preferences.length === 0) {
return { ...result, errors: ["Nu exista preferinte de notificare configurate"] };
}
const today = new Date().toISOString().slice(0, 10);
// Sample data for testing
const testSections: DigestSection[] = [
{
type: "deadline-urgent",
title: "Termene urgente (5 zile sau mai putin)",
items: [
{
entryNumber: "BTG-0001/2026",
subject: "[TEST] Certificat de urbanism - str. Exemplu nr. 10",
label: "Emitere CU (30 zile lucratoare)",
dueDate: today,
daysRemaining: 2,
color: "yellow",
},
{
entryNumber: "BTG-0005/2026",
subject: "[TEST] Aviz ISU - Proiect rezidential",
label: "Raspuns aviz ISU (15 zile)",
dueDate: today,
daysRemaining: 5,
color: "yellow",
},
],
},
{
type: "deadline-overdue",
title: "Termene depasite",
items: [
{
entryNumber: "BTG-0003/2026",
subject: "[TEST] Autorizatie construire - bloc P+4",
label: "Emitere AC (30 zile lucratoare)",
dueDate: "2026-03-01",
daysRemaining: -10,
color: "red",
},
],
},
{
type: "document-expiry",
title: "Documente care expira",
items: [
{
entryNumber: "BTG-0010/2025",
subject: "[TEST] CU nr. 123/2025 - proiect mixt",
label: "Expira curand",
dueDate: "2026-03-25",
daysRemaining: 14,
color: "yellow",
},
],
},
];
for (const pref of preferences) {
if (pref.globalOptOut) continue;
const companyName = COMPANY_LABELS[pref.company] ?? pref.company;
const html = renderDigestHtml(testSections, companyName, today);
const subject = `[ArchiTools TEST] 4 alerte - ${companyName} (${formatDateRo(today)})`;
try {
await sendEmail({ to: pref.email, subject, html });
result.totalEmails++;
} catch (err) {
result.errors.push(
`Eroare trimitere catre ${pref.email}: ${err instanceof Error ? err.message : String(err)}`,
);
}
}
result.companySummary["test"] = {
emails: result.totalEmails,
sections: testSections.length,
};
} catch (err) {
result.success = false;
result.errors.push(
`Eroare test digest: ${err instanceof Error ? err.message : String(err)}`,
);
}
return result;
}