import { NextRequest, NextResponse } from 'next/server'; import { sessionManager, AnalyticsData, PerformanceData, ErrorData } from '@/lib/session-management'; /** * Analytics API Endpoints * * POST /api/analytics - Track analytics event * POST /api/analytics/performance - Track performance metrics * POST /api/analytics/error - Track error events * GET /api/analytics/report - Generate analytics report * * Security Features: * - Input validation and sanitization * - Rate limiting protection * - Privacy-compliant data collection * - Error handling without exposing sensitive information */ export async function POST(request: NextRequest) { try { const { eventType, sessionId, metrics } = await request.json(); // Input validation if (!eventType || typeof eventType !== 'string') { return NextResponse.json( { error: 'Valid event type is required' }, { status: 400 } ); } if (!sessionId || typeof sessionId !== 'string') { return NextResponse.json( { error: 'Valid session ID is required' }, { status: 400 } ); } if (!metrics || typeof metrics !== 'object') { return NextResponse.json( { error: 'Valid metrics object is required' }, { status: 400 } ); } // Validate event type const validEventTypes = [ 'document_upload', 'ai_question', 'session_created', 'violation_found', 'user_login', 'user_logout' ]; if (!validEventTypes.includes(eventType)) { return NextResponse.json( { error: 'Invalid event type' }, { status: 400 } ); } // Sanitize metrics const sanitizedMetrics = sanitizeMetrics(metrics); const analyticsData: AnalyticsData = { eventType, sessionId, timestamp: new Date().toISOString(), metrics: sanitizedMetrics }; // Track analytics await sessionManager.trackAnalytics(analyticsData); return NextResponse.json({ success: true, message: 'Analytics tracked successfully' }); } catch (error) { console.error('Analytics tracking error:', error); return NextResponse.json( { error: 'Failed to track analytics' }, { status: 500 } ); } } export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const startDate = searchParams.get('startDate'); const endDate = searchParams.get('endDate'); // Input validation if (!startDate || !endDate) { return NextResponse.json( { error: 'Start date and end date are required' }, { status: 400 } ); } // Validate date format const startDateObj = new Date(startDate); const endDateObj = new Date(endDate); if (isNaN(startDateObj.getTime()) || isNaN(endDateObj.getTime())) { return NextResponse.json( { error: 'Invalid date format' }, { status: 400 } ); } if (startDateObj >= endDateObj) { return NextResponse.json( { error: 'Start date must be before end date' }, { status: 400 } ); } // Generate analytics report const report = await sessionManager.generateAnalyticsReport(startDate, endDate); if (!report) { return NextResponse.json( { error: 'Failed to generate report' }, { status: 500 } ); } return NextResponse.json({ success: true, report }); } catch (error) { console.error('Analytics report error:', error); return NextResponse.json( { error: 'Failed to generate analytics report' }, { status: 500 } ); } } /** * Sanitize metrics to prevent injection attacks * @param metrics - Raw metrics object * @returns Sanitized metrics object */ function sanitizeMetrics(metrics: any): any { const sanitized: any = {}; // Only allow specific metric fields const allowedFields = [ 'userId', 'ipAddress', 'fileType', 'fileSize', 'processingTime', 'questionLength', 'responseTime', 'tokensUsed', 'violationsCount', 'language', 'timezone', 'deviceType' ]; for (const [key, value] of Object.entries(metrics)) { if (allowedFields.includes(key)) { // Validate and sanitize values if (typeof value === 'string' && value.length <= 1000) { sanitized[key] = value.replace(/[<>]/g, ''); // Remove potential HTML tags } else if (typeof value === 'number' && isFinite(value)) { sanitized[key] = value; } else if (typeof value === 'boolean') { sanitized[key] = value; } else if (value === null) { sanitized[key] = null; } } } return sanitized; }