import { NextResponse } from 'next/server' import { db } from '@/lib/db' import { getCurrentUser } from '@/lib/auth/current' export const runtime = 'nodejs' export const dynamic = 'force-dynamic' const METRIKEN = new Set(['LCP', 'INP', 'CLS', 'TTFB', 'FCP']) const BEWERTUNGEN = new Set(['good', 'needs-improvement', 'poor']) /** * Nimmt Ladewerte aus dem Browser entgegen. * * **Was hier ankommt, wird geprüft und beschnitten**, bevor es in die * Datenbank geht: nur bekannte Metriken, nur plausible Zahlen, und die Route * als Muster statt als konkreter Pfad. Ein Endpunkt, der ungeprüft * Zeichenketten aus dem Browser speichert, ist ein Ablagefach für Fremde. * * Der Nutzer wird **nicht** mitgeschrieben. Wer wann welche Akte geöffnet hat, * steht im Zugriffsprotokoll - dort gehört es hin, dort ist es geregelt, und * eine zweite Spur daneben wäre eine Überwachungsfunktion ohne Auftrag. */ export async function POST(request: Request): Promise { // Angemeldet sein muss man trotzdem: sonst ist es ein offener Schreibzugang. const user = await getCurrentUser() if (!user) return new NextResponse(null, { status: 404 }) let daten: unknown try { daten = await request.json() } catch { return new NextResponse(null, { status: 400 }) } const eintrag = daten as Record const metric = String(eintrag.metric ?? '') const rating = String(eintrag.rating ?? '') const value = Number(eintrag.value) const route = String(eintrag.route ?? '').slice(0, 120) if (!METRIKEN.has(metric) || !BEWERTUNGEN.has(rating)) { return new NextResponse(null, { status: 400 }) } // CLS liegt bei 0..1, die Zeiten in Millisekunden. Alles darüber ist Unfug // oder ein Messfehler und würde nur den Durchschnitt verderben. if (!Number.isFinite(value) || value < 0 || value > 600_000) { return new NextResponse(null, { status: 400 }) } try { await db.webVital.create({ data: { metric, value, route, rating } }) } catch (error) { console.error('[vitals] nicht gespeichert', error) } // Der Browser sendet das per `sendBeacon` und interessiert sich nicht für // die Antwort. return new NextResponse(null, { status: 204 }) }