From f914ab6e4794135475ddf68b9d0de4309deb9d89 Mon Sep 17 00:00:00 2001 From: Timo Uttenweiler Date: Fri, 20 Mar 2026 18:01:44 +0100 Subject: [PATCH] fix: Maps-Vault-Sync sofort nach Google Maps, nicht erst nach Anymailfinder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Google Maps Ergebnisse werden direkt nach der Suche in LeadVault gespeichert - Anymailfinder-Fehler führen nicht mehr zum Datenverlust - Bessere Fehlermeldungen: echter Fehlertext statt hardcoded Message - Anymailfinder-Fehlermeldung auf Deutsch Co-Authored-By: Claude Sonnet 4.6 --- app/api/jobs/maps-enrich/route.ts | 58 ++++++++++++++++++------------- app/maps/page.tsx | 13 +++---- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/app/api/jobs/maps-enrich/route.ts b/app/api/jobs/maps-enrich/route.ts index 49d4877..bb498b0 100644 --- a/app/api/jobs/maps-enrich/route.ts +++ b/app/api/jobs/maps-enrich/route.ts @@ -74,7 +74,7 @@ async function runMapsEnrich( data: { totalLeads: places.length }, }); - // 2. Store raw Google Maps results immediately + // 2. Store raw Google Maps results + immediately sink to LeadVault for (const place of places) { await prisma.leadResult.create({ data: { @@ -91,10 +91,24 @@ async function runMapsEnrich( }); } + // Sink Google Maps results to vault immediately (before enrichment) + // so they're available even if Anymailfinder fails + await sinkLeadsToVault( + places.map(p => ({ + domain: p.domain, + companyName: p.name || null, + phone: p.phone, + address: p.address, + })), + "maps", + params.queries.join(", "), + jobId, + ); + // 3. Optionally enrich with Anymailfinder if (params.enrichEmails && places.length > 0) { const anymailKey = await getApiKey("anymailfinder"); - if (!anymailKey) throw new Error("Anymailfinder key missing"); + if (!anymailKey) throw new Error("Anymailfinder API-Key fehlt — bitte in den Einstellungen eintragen"); const domains = places.filter(p => p.domain).map(p => p.domain!); // Map domain → placeId for updating results @@ -142,35 +156,29 @@ async function runMapsEnrich( where: { id: jobId }, data: { status: "complete", emailsFound, totalLeads: places.length }, }); + + // Update vault entries with enrichment results + await sinkLeadsToVault( + enrichResults + .filter(r => r.email) + .map(r => ({ + domain: r.domain, + contactName: r.person_full_name || null, + contactTitle: r.person_job_title || null, + email: r.email || null, + linkedinUrl: r.person_linkedin_url || null, + emailConfidence: r.valid_email ? 1.0 : r.email_status === "risky" ? 0.5 : 0, + })), + "maps", + params.queries.join(", "), + jobId, + ); } else { await prisma.job.update({ where: { id: jobId }, data: { status: "complete", totalLeads: places.length }, }); } - - // Sync to LeadVault - const finalResults = await prisma.leadResult.findMany({ where: { jobId } }); - await sinkLeadsToVault( - finalResults.map(r => { - let src: { phone?: string; address?: string } = {}; - try { src = JSON.parse(r.source || "{}"); } catch { /* ignore */ } - return { - domain: r.domain, - companyName: r.companyName, - contactName: r.contactName, - contactTitle: r.contactTitle, - email: r.email, - linkedinUrl: r.linkedinUrl, - emailConfidence: r.confidence, - phone: src.phone || null, - address: src.address || null, - }; - }), - "maps", - params.queries.join(", "), - jobId, - ); } catch (err) { const message = err instanceof Error ? err.message : String(err); await prisma.job.update({ diff --git a/app/maps/page.tsx b/app/maps/page.tsx index 7199742..f91f99c 100644 --- a/app/maps/page.tsx +++ b/app/maps/page.tsx @@ -121,14 +121,14 @@ export default function MapsPage() { try { const res = await fetch(`/api/jobs/${id}/status`); const data = await res.json() as { - status: string; totalLeads: number; emailsFound: number; results: ResultRow[]; + status: string; totalLeads: number; emailsFound: number; results: ResultRow[]; error?: string; }; if (data.totalLeads > 0 && data.emailsFound === 0 && enrichEmails) { - phase = "Enriching with Anymailfinder..."; + phase = "Anreicherung mit Anymailfinder..."; } if (data.emailsFound > 0) { - phase = `Found ${data.emailsFound} emails so far...`; + phase = `${data.emailsFound} E-Mails gefunden...`; } setProgress({ @@ -146,12 +146,13 @@ export default function MapsPage() { if (data.status === "complete") { setStage("done"); const msg = enrichEmails - ? `Done! ${data.totalLeads} companies found, ${data.emailsFound} emails enriched` - : `Done! ${data.totalLeads} companies found`; + ? `Fertig! ${data.totalLeads} Unternehmen gefunden, ${data.emailsFound} E-Mails angereichert` + : `Fertig! ${data.totalLeads} Unternehmen gefunden`; toast.success(msg); } else { setStage("failed"); - toast.error("Job failed. Check your Google Maps API key in Settings."); + const errMsg = data.error || "Unbekannter Fehler"; + toast.error(`Job fehlgeschlagen: ${errMsg}`); } } } catch {