/** * Email-Logs Statistics Endpoint * * GET /api/email-logs/stats * * Liefert Statistiken über Email-Logs. * Nur für Super Admins und Tenant-Admins (für ihre eigenen Tenants). * * Query-Parameter: * - tenantId: number (optional) * - period: '24h' | '7d' | '30d' (default: '7d') */ import { getPayload } from 'payload' import configPromise from '@payload-config' import { NextRequest, NextResponse } from 'next/server' interface UserWithTenants { id: number email: string isSuperAdmin?: boolean tenants?: Array<{ tenant: { id: number } | number }> } function getUserTenantIds(user: UserWithTenants): number[] { return (user.tenants || []).map((t) => (typeof t.tenant === 'object' ? t.tenant.id : t.tenant)) } function getPeriodDate(period: string): Date { const now = new Date() switch (period) { case '24h': return new Date(now.getTime() - 24 * 60 * 60 * 1000) case '30d': return new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000) case '7d': default: return new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000) } } export async function GET(req: NextRequest): Promise { try { const payload = await getPayload({ config: configPromise }) // Auth prüfen const { user } = await payload.auth({ headers: req.headers }) if (!user) { return NextResponse.json({ error: 'Nicht authentifiziert' }, { status: 401 }) } const typedUser = user as unknown as UserWithTenants // Query-Parameter parsen const searchParams = req.nextUrl.searchParams const tenantIdParam = searchParams.get('tenantId') const period = searchParams.get('period') || '7d' // Tenant-Zugriff prüfen const userTenantIds = getUserTenantIds(typedUser) let tenantFilter: number[] | undefined if (typedUser.isSuperAdmin) { if (tenantIdParam) { tenantFilter = [parseInt(tenantIdParam, 10)] } } else { if (tenantIdParam) { const requestedTenant = parseInt(tenantIdParam, 10) if (!userTenantIds.includes(requestedTenant)) { return NextResponse.json({ error: 'Kein Zugriff auf diesen Tenant' }, { status: 403 }) } tenantFilter = [requestedTenant] } else { tenantFilter = userTenantIds } } const periodDate = getPeriodDate(period) // Basis-Where für alle Queries const baseWhere: Record = { createdAt: { greater_than_equal: periodDate.toISOString() }, } if (tenantFilter) { baseWhere.tenant = { in: tenantFilter } } // Statistiken parallel abrufen - Type assertions für email-logs Collection const countFn = payload.count as Function const findFn = payload.find as Function const [totalResult, sentResult, failedResult, pendingResult, recentFailed] = await Promise.all([ // Gesamt countFn({ collection: 'email-logs', where: baseWhere, }), // Gesendet countFn({ collection: 'email-logs', where: { ...baseWhere, status: { equals: 'sent' } }, }), // Fehlgeschlagen countFn({ collection: 'email-logs', where: { ...baseWhere, status: { equals: 'failed' } }, }), // Ausstehend countFn({ collection: 'email-logs', where: { ...baseWhere, status: { equals: 'pending' } }, }), // Letzte 5 fehlgeschlagene (für Quick-View) findFn({ collection: 'email-logs', where: { ...baseWhere, status: { equals: 'failed' } }, limit: 5, sort: '-createdAt', depth: 1, }), ]) // Erfolgsrate berechnen const total = totalResult.totalDocs const sent = sentResult.totalDocs const failed = failedResult.totalDocs const pending = pendingResult.totalDocs const successRate = total > 0 ? Math.round((sent / total) * 100 * 10) / 10 : 0 // Statistiken nach Quelle const sourceStats: Record = {} const sources = ['manual', 'form', 'system', 'newsletter'] await Promise.all( sources.map(async (source) => { const result = await countFn({ collection: 'email-logs', where: { ...baseWhere, source: { equals: source } }, }) sourceStats[source] = result.totalDocs }), ) return NextResponse.json({ success: true, period, periodStart: periodDate.toISOString(), stats: { total, sent, failed, pending, successRate, }, bySource: sourceStats, recentFailures: recentFailed.docs.map((doc: Record) => ({ id: doc.id, to: doc.to, subject: doc.subject, error: doc.error, createdAt: doc.createdAt, tenantId: typeof doc.tenant === 'object' && doc.tenant ? (doc.tenant as { id?: number }).id : doc.tenant, })), }) } catch (error) { console.error('[EmailLogs:Stats] Error:', error) return NextResponse.json({ error: 'Interner Serverfehler' }, { status: 500 }) } }