← back to Norma
app/api/intelligence/briefing/route.ts
89 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { getOrgId } from '@/lib/orgId';
const ALLOWED_STRATEGIES = new Set([
'all',
'legislative',
'media',
'coalition',
'grassroots',
]);
/**
* GET /api/intelligence/briefing
* Query params:
* ?limit= — rows to return (default 20, max 100)
* ?strategy= — all | legislative | media | coalition | grassroots
* Headers:
* x-org-id — scope results to a specific org
* LEFT JOINs power_scores to attach score_breakdown.
* Returns: { recommendations: [...] }
* Ordered by priority ASC, power_score 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 strategyParam = searchParams.get('strategy') || 'all';
const strategy = ALLOWED_STRATEGIES.has(strategyParam) ? strategyParam : 'all';
let limit = parseInt(searchParams.get('limit') || '20', 10);
if (isNaN(limit) || limit < 1) limit = 20;
if (limit > 100) limit = 100;
const conditions: string[] = [];
const values: unknown[] = [];
let paramIndex = 1;
if (orgId) {
conditions.push(`wi.org_id = $${paramIndex}`);
values.push(orgId);
paramIndex++;
}
if (strategy !== 'all') {
conditions.push(`wi.contact_strategy = $${paramIndex}`);
values.push(strategy);
paramIndex++;
}
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
const result = await query(
`SELECT
wi.org_id,
wi.week_start,
wi.entity_type,
wi.entity_id,
wi.entity_name,
wi.power_score,
wi.reasoning,
wi.trigger_news_ids,
wi.connection_chain,
wi.priority,
wi.contact_strategy,
wi.status,
wi.created_at,
ps.score_breakdown
FROM weekly_intelligence wi
LEFT JOIN power_scores ps
ON ps.entity_type = wi.entity_type
AND ps.entity_id = wi.entity_id
${whereClause}
ORDER BY wi.priority ASC, wi.power_score DESC
LIMIT $${paramIndex}`,
[...values, limit],
);
return NextResponse.json({ recommendations: result.rows });
} catch (err) {
console.error('[api/intelligence/briefing] GET error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to fetch briefing' }, { status: 500 });
}
}