← back to Norma

app/api/audit/route.ts

61 lines

import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';

/**
 * GET /api/audit
 * List audit events with optional filters.
 * Query params: ?event_type=, ?entity_type=, ?entity_id=, ?limit= (default 50)
 * Ordered by created_at DESC.
 */
export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const { searchParams } = new URL(request.url);
    const eventType = searchParams.get('event_type');
    const entityType = searchParams.get('entity_type');
    const entityId = searchParams.get('entity_id');
    const limitParam = searchParams.get('limit');
    const limit = Math.min(Math.max(parseInt(limitParam || '50', 10) || 50, 1), 500);

    const conditions: string[] = [];
    const values: unknown[] = [];
    let paramIndex = 1;

    if (eventType) {
      conditions.push(`event_type = $${paramIndex}`);
      values.push(eventType);
      paramIndex++;
    }

    if (entityType) {
      conditions.push(`entity_type = $${paramIndex}`);
      values.push(entityType);
      paramIndex++;
    }

    if (entityId) {
      conditions.push(`entity_id = $${paramIndex}`);
      values.push(entityId);
      paramIndex++;
    }

    const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

    values.push(limit);
    const result = await query(
      `SELECT * FROM audit_events ${whereClause}
       ORDER BY created_at DESC
       LIMIT $${paramIndex}`,
      values
    );

    return NextResponse.json({ events: result.rows });
  } catch (err) {
    console.error('[api/audit] GET error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to fetch audit events' }, { status: 500 });
  }
}