/** * Audit Log API * GET /api/transparency/audit - Query audit entries * POST /api/transparency/audit - Log a custom audit entry * * Provides access to the immutable audit trail. */ import type { NextApiRequest, NextApiResponse } from 'next'; import { getAuditLog, AuditQuery, AuditAction, AuditCategory, AuditSeverity } from '../../../lib/transparency'; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const auditLog = getAuditLog(); if (req.method === 'GET') { try { const { startDate, endDate, actions, categories, severities, actorId, actorType, resourceType, resourceId, correlationId, search, limit = '100', offset = '0', format = 'json' } = req.query; const query: AuditQuery = { startDate: startDate as string, endDate: endDate as string, actions: actions ? (actions as string).split(',') as AuditAction[] : undefined, categories: categories ? (categories as string).split(',') as AuditCategory[] : undefined, severities: severities ? (severities as string).split(',') as AuditSeverity[] : undefined, actorId: actorId as string, actorType: actorType as any, resourceType: resourceType as string, resourceId: resourceId as string, correlationId: correlationId as string, searchTerm: search as string, limit: parseInt(limit as string, 10), offset: parseInt(offset as string, 10) }; // Handle different formats if (format === 'csv') { const csv = auditLog.export('csv', query); res.setHeader('Content-Type', 'text/csv'); res.setHeader('Content-Disposition', 'attachment; filename=audit-log.csv'); return res.status(200).send(csv); } if (format === 'summary') { const summary = auditLog.export('summary', query); res.setHeader('Content-Type', 'text/plain'); return res.status(200).send(summary); } const result = auditLog.query(query); return res.status(200).json({ success: true, data: { entries: result.entries, total: result.total, limit: query.limit, offset: query.offset } }); } catch (error) { console.error('[API] Audit query error:', error); return res.status(500).json({ success: false, error: 'Failed to query audit log' }); } } if (req.method === 'POST') { try { const { action, category, description, severity, actor, resource, metadata } = req.body; if (!action || !category || !description) { return res.status(400).json({ success: false, error: 'Missing required fields: action, category, description' }); } const entry = auditLog.log( action as AuditAction, category as AuditCategory, description, { severity: severity as AuditSeverity, actor: { ...actor, ip: req.headers['x-forwarded-for'] as string || req.socket.remoteAddress, userAgent: req.headers['user-agent'] }, resource, metadata } ); return res.status(201).json({ success: true, data: entry }); } catch (error) { console.error('[API] Audit log error:', error); return res.status(500).json({ success: false, error: 'Failed to create audit entry' }); } } return res.status(405).json({ error: 'Method not allowed' }); }