Full-stack Next.js 16 app with three scraping pipelines: - AirScale CSV → Anymailfinder Bulk Decision Maker search - LinkedIn Sales Navigator → Vayne → Anymailfinder email enrichment - Apify Google SERP → domain extraction → Anymailfinder bulk enrichment Includes Docker multi-stage build + docker-compose for Coolify deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/db";
|
|
|
|
export async function GET() {
|
|
try {
|
|
const jobs = await prisma.job.findMany({
|
|
orderBy: { createdAt: "desc" },
|
|
take: 100,
|
|
});
|
|
|
|
const totalLeads = jobs.reduce((s, j) => s + j.totalLeads, 0);
|
|
const totalEmails = jobs.reduce((s, j) => s + j.emailsFound, 0);
|
|
const completedJobs = jobs.filter(j => j.status === "complete" && j.totalLeads > 0);
|
|
const avgHitRate = completedJobs.length > 0
|
|
? Math.round(
|
|
completedJobs.reduce((s, j) => s + (j.emailsFound / j.totalLeads) * 100, 0) / completedJobs.length
|
|
)
|
|
: 0;
|
|
|
|
return NextResponse.json({
|
|
jobs: jobs.map(j => ({
|
|
id: j.id,
|
|
type: j.type,
|
|
status: j.status,
|
|
totalLeads: j.totalLeads,
|
|
emailsFound: j.emailsFound,
|
|
createdAt: j.createdAt,
|
|
error: j.error,
|
|
})),
|
|
stats: {
|
|
totalJobs: jobs.length,
|
|
totalLeads,
|
|
totalEmails,
|
|
avgHitRate,
|
|
},
|
|
});
|
|
} catch (err) {
|
|
console.error("GET /api/jobs error:", err);
|
|
return NextResponse.json({ jobs: [], stats: {} }, { status: 500 });
|
|
}
|
|
}
|