From c70b30a0005a456b9aeae2029d4dae5dce7dccd9 Mon Sep 17 00:00:00 2001 From: lorentz Date: Thu, 16 Jul 2026 14:43:43 -0400 Subject: [PATCH] feat(22-02): add firstReportTicketId to campaigns list route - Alias campaigns table as c, add correlated subquery for the earliest linked report's ticket_id so the list page can navigate a row click straight to /phishing/tickets/{firstReportTicketId} - Additive only: count query, limit/offset, requirePermission gate, and the { items, total, limit, offset } envelope all unchanged --- app/api/phishing/campaigns/route.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/api/phishing/campaigns/route.ts b/app/api/phishing/campaigns/route.ts index cbe895b..da9db17 100644 --- a/app/api/phishing/campaigns/route.ts +++ b/app/api/phishing/campaigns/route.ts @@ -20,6 +20,7 @@ interface CampaignRow { report_count: number; status: string; created_at: string; + first_report_ticket_id: string | null; } export async function GET(request: NextRequest) { @@ -37,15 +38,16 @@ export async function GET(request: NextRequest) { let statusFilter = ''; if (status) { params.push(status); - statusFilter = `WHERE status = $${params.length}`; + statusFilter = `WHERE c.status = $${params.length}`; } const campaigns = await postgresClient.query( - `SELECT id::text, campaign_key, group_method, first_seen_at::text, last_seen_at::text, - report_count, status, created_at::text - FROM campaigns + `SELECT c.id::text, c.campaign_key, c.group_method, c.first_seen_at::text, c.last_seen_at::text, + c.report_count, c.status, c.created_at::text, + (SELECT r.ticket_id::text FROM reports r WHERE r.campaign_id = c.id ORDER BY r.created_at ASC LIMIT 1) AS first_report_ticket_id + FROM campaigns c ${statusFilter} - ORDER BY last_seen_at DESC NULLS LAST + ORDER BY c.last_seen_at DESC NULLS LAST LIMIT $1 OFFSET $2`, params ); @@ -72,6 +74,7 @@ export async function GET(request: NextRequest) { reportCount: c.report_count, status: c.status, createdAt: c.created_at, + firstReportTicketId: c.first_report_ticket_id, })); return NextResponse.json({ items, total, limit, offset });