Initial commit: LeadFlow lead generation platform
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>
This commit is contained in:
51
app/api/credentials/route.ts
Normal file
51
app/api/credentials/route.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { encrypt, decrypt } from "@/lib/utils/encryption";
|
||||
|
||||
const SERVICES = ["anymailfinder", "apify", "vayne", "airscale"] as const;
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const creds = await prisma.apiCredential.findMany();
|
||||
const result: Record<string, boolean> = {};
|
||||
for (const svc of SERVICES) {
|
||||
result[svc] = creds.some(c => c.service === svc && c.value);
|
||||
}
|
||||
return NextResponse.json(result);
|
||||
} catch (err) {
|
||||
console.error("GET /api/credentials error:", err);
|
||||
return NextResponse.json({ anymailfinder: false, apify: false, vayne: false, airscale: false });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const body = await req.json() as Record<string, string>;
|
||||
for (const [service, value] of Object.entries(body)) {
|
||||
if (!SERVICES.includes(service as typeof SERVICES[number])) continue;
|
||||
if (value === null || value === undefined) continue;
|
||||
await prisma.apiCredential.upsert({
|
||||
where: { service },
|
||||
create: { service, value: value ? encrypt(value) : "" },
|
||||
update: { value: value ? encrypt(value) : "" },
|
||||
});
|
||||
}
|
||||
return NextResponse.json({ ok: true });
|
||||
} catch (err) {
|
||||
console.error("POST /api/credentials error:", err);
|
||||
return NextResponse.json({ error: "Failed to save credentials" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// GET a specific decrypted value (for internal API use only)
|
||||
export async function PUT(req: NextRequest) {
|
||||
try {
|
||||
const { service } = await req.json() as { service: string };
|
||||
const cred = await prisma.apiCredential.findUnique({ where: { service } });
|
||||
if (!cred) return NextResponse.json({ value: null });
|
||||
return NextResponse.json({ value: decrypt(cred.value) });
|
||||
} catch (err) {
|
||||
console.error("PUT /api/credentials error:", err);
|
||||
return NextResponse.json({ error: "Failed" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user