← back to Norma

app/api/intelligence/activity/route.ts

78 lines

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

/**
 * GET /api/intelligence/activity
 * Query params:
 *   ?limit= — rows to return (default 50, max 200)
 *   ?type=  — comma-separated activity_type values
 *             e.g. "news_trigger,journalist_mention"
 * Headers:
 *   x-org-id — scope results to a specific org
 * Returns: { activities: [...] }
 * 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 orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;
    const typeParam = searchParams.get('type');

    let limit = parseInt(searchParams.get('limit') || '50', 10);
    if (isNaN(limit) || limit < 1) limit = 50;
    if (limit > 200) limit = 200;

    // Parse comma-separated activity types; discard empties
    const activityTypes = typeParam
      ? typeParam.split(',').map((t) => t.trim()).filter(Boolean)
      : [];

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

    if (orgId) {
      conditions.push(`org_id = $${paramIndex}`);
      values.push(orgId);
      paramIndex++;
    }

    if (activityTypes.length > 0) {
      // Use ANY($N::text[]) so a single parameterised binding handles N types
      conditions.push(`activity_type = ANY($${paramIndex}::text[])`);
      values.push(activityTypes);
      paramIndex++;
    }

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

    const result = await query(
      `SELECT
         org_id,
         activity_type,
         entity_type,
         entity_id,
         entity_name,
         summary,
         delta,
         relevance_score,
         created_at
       FROM org_activity
       ${whereClause}
       ORDER BY created_at DESC
       LIMIT $${paramIndex}`,
      [...values, limit],
    );

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