import { NextRequest, NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; import { requireSessionAuth } from '@/lib/auth'; export async function GET(request: NextRequest) { try { // Admin-only endpoint const isAdminRequest = request.headers.get('x-admin-request') === 'true'; if (!isAdminRequest) return NextResponse.json({ error: 'Admin access required' }, { status: 403 }); const authError = requireSessionAuth(request); if (authError) return authError; // Get performance data from database const pageViews = await prisma.pageView.findMany({ orderBy: { timestamp: 'desc' }, take: 1000 // Last 1000 page views }); const userInteractions = await prisma.userInteraction.findMany({ orderBy: { timestamp: 'desc' }, take: 1000 // Last 1000 interactions }); // Get all projects for performance data const projects = await prisma.project.findMany(); // Calculate real performance metrics from projects const projectsWithPerformance = projects.map(p => ({ id: p.id, title: p.title, lighthouse: ((p.performance as Record)?.lighthouse as number) || 0, loadTime: ((p.performance as Record)?.loadTime as number) || 0, fcp: ((p.performance as Record)?.firstContentfulPaint as number) || 0, lcp: ((p.performance as Record)?.coreWebVitals as Record)?.lcp as number || 0, cls: ((p.performance as Record)?.coreWebVitals as Record)?.cls as number || 0 })); // Calculate average lighthouse score (currently unused but kept for future use) const _avgLighthouse = projectsWithPerformance.length > 0 ? Math.round(projectsWithPerformance.reduce((sum, p) => sum + p.lighthouse, 0) / projectsWithPerformance.length) : 0; // Calculate bounce rate from page views const pageViewsByIP = pageViews.reduce((acc, pv) => { const ip = pv.ip || 'unknown'; if (!acc[ip]) acc[ip] = []; acc[ip].push(pv); return acc; }, {} as Record); const totalSessions = Object.keys(pageViewsByIP).length; const bouncedSessions = Object.values(pageViewsByIP).filter(session => session.length === 1).length; const bounceRate = totalSessions > 0 ? Math.round((bouncedSessions / totalSessions) * 100) : 0; // Calculate average session duration const sessionDurations = Object.values(pageViewsByIP) .map(session => { if (session.length < 2) return 0; const sorted = session.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()); return sorted[sorted.length - 1].timestamp.getTime() - sorted[0].timestamp.getTime(); }) .filter(d => d > 0); const avgSessionDuration = sessionDurations.length > 0 ? Math.round(sessionDurations.reduce((a, b) => a + b, 0) / sessionDurations.length / 1000) // in seconds : 0; // Calculate pages per session const pagesPerSession = totalSessions > 0 ? (pageViews.length / totalSessions).toFixed(1) : '0'; // Calculate performance metrics const performance = { avgLighthouse: (() => { const projectsWithPerf = projects.filter(p => { const perf = (p.performance as Record) || {}; return (perf.lighthouse as number || 0) > 0; }); return projectsWithPerf.length > 0 ? Math.round(projectsWithPerf.reduce((sum, p) => { const perf = (p.performance as Record) || {}; return sum + (perf.lighthouse as number || 0); }, 0) / projectsWithPerf.length) : 0; })(), totalViews: pageViews.length, metrics: { bounceRate, avgSessionDuration: avgSessionDuration, pagesPerSession: parseFloat(pagesPerSession), newUsers: new Set(pageViews.map(pv => pv.ip).filter(Boolean)).size }, pageViews: { total: pageViews.length, last24h: pageViews.filter(pv => { const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); return new Date(pv.timestamp) > dayAgo; }).length, last7d: pageViews.filter(pv => { const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); return new Date(pv.timestamp) > weekAgo; }).length, last30d: pageViews.filter(pv => { const monthAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); return new Date(pv.timestamp) > monthAgo; }).length }, interactions: { total: userInteractions.length, last24h: userInteractions.filter(ui => { const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000); return new Date(ui.timestamp) > dayAgo; }).length, last7d: userInteractions.filter(ui => { const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); return new Date(ui.timestamp) > weekAgo; }).length, last30d: userInteractions.filter(ui => { const monthAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); return new Date(ui.timestamp) > monthAgo; }).length }, topPages: pageViews.reduce((acc, pv) => { acc[pv.page] = (acc[pv.page] || 0) + 1; return acc; }, {} as Record), topInteractions: userInteractions.reduce((acc, ui) => { acc[ui.type] = (acc[ui.type] || 0) + 1; return acc; }, {} as Record) }; return NextResponse.json(performance); } catch (error) { console.error('Performance analytics error:', error); return NextResponse.json( { error: 'Failed to fetch performance data' }, { status: 500 } ); } }