diff --git a/src/app/api/notifications/digest/route.ts b/src/app/api/notifications/digest/route.ts index 0140ac0..a320442 100644 --- a/src/app/api/notifications/digest/route.ts +++ b/src/app/api/notifications/digest/route.ts @@ -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 + * + * 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, diff --git a/src/core/notifications/notification-service.ts b/src/core/notifications/notification-service.ts index 8d6420e..998041b 100644 --- a/src/core/notifications/notification-service.ts +++ b/src/core/notifications/notification-service.ts @@ -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 { return result; } + +// ── Test digest — sends sample email to all subscribers ── + +export async function sendTestDigest(): Promise { + 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; +}