← back to Norma
app/api/pulse/articles/route.ts
74 lines
/**
* GET /api/pulse/articles
* Returns news articles for the Pulse feed.
* Reads directly from news_items table (no external agent needed).
*/
import { NextRequest, NextResponse } from 'next/server';
import { requireRole } from '@/lib/require-role';
import { query } from '@/lib/db';
export async function GET(request: NextRequest) {
const auth = requireRole(request, 'admin', 'staff', 'pulse');
if (auth instanceof NextResponse) return auth;
try {
const url = new URL(request.url);
const limit = parseInt(url.searchParams.get('limit') || '50', 10);
const category = url.searchParams.get('category');
const offset = parseInt(url.searchParams.get('offset') || '0', 10);
let whereClause = 'WHERE 1=1';
const params: (string | number)[] = [];
let paramIdx = 1;
if (category && category !== 'all') {
whereClause += ` AND source_type = $${paramIdx}`;
params.push(category);
paramIdx++;
}
params.push(limit, offset);
const result = await query(
`SELECT
id,
headline AS title,
url,
author_name AS author,
summary,
published_at,
sentiment,
COALESCE(sentiment_score, relevance_score) AS sentiment_score,
petition_potential,
petition_angle,
tags AS topics,
geo_state,
outlet AS feed_name,
COALESCE(source_type, 'news') AS feed_category,
NULL AS feed_station
FROM news_items
${whereClause}
ORDER BY published_at DESC NULLS LAST
LIMIT $${paramIdx} OFFSET $${paramIdx + 1}`,
params
);
// Get total count
const countResult = await query(
`SELECT COUNT(*) AS total FROM news_items ${whereClause}`,
params.slice(0, paramIdx - 1)
);
return NextResponse.json({
articles: result.rows,
total: parseInt(countResult.rows[0]?.total || '0', 10),
limit,
offset,
});
} catch (err) {
console.error('[api/pulse/articles] error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to fetch articles' }, { status: 500 });
}
}