import { NextRequest, NextResponse } from 'next/server'; import { sendBriefToClient, sendLeadNotification } from '@/lib/email'; import { analyzeSite, type SiteAnalysis } from '@/lib/site-analysis'; // ─── Types ──────────────────────────────────────────────────────────────────── interface ConfigureRequestBody { services: string[]; aiEnabled: boolean; aiTypes: string[]; industry: string | null; scope: string; timeline: string | null; name: string; company: string; email: string; phone: string; contactPreference: string; currentSiteUrl?: string; currentSiteThoughts?: string; locale?: string; } // ─── Formatting helpers ────────────────────────────────────────────────────── const SERVICE_NAMES: Record = { web: 'Web Design & Development', systems: 'Custom Software', infrastructure: 'Private Infrastructure', }; const INDUSTRY_NAMES: Record = { maritime: 'Maritime & Yachting', hospitality: 'Hospitality', technology: 'Technology', realestate: 'Real Estate', finance: 'Finance', ngo: 'NGO & Nonprofit', other: 'Other', }; const TIMELINE_NAMES: Record = { asap: 'As soon as possible', '1-3months': '1–3 months', '3-6months': '3–6 months', exploring: 'Just exploring', }; const AI_TYPE_NAMES: Record = { teammate: 'Internal AI Teammate', 'customer-facing': 'Customer-Facing AI', 'data-intelligence': 'Data Intelligence', notsure: 'AI Integration (approach TBD)', }; function buildContext(body: ConfigureRequestBody, siteAnalysis: SiteAnalysis | null = null): string { const services = body.services.map((s) => SERVICE_NAMES[s] ?? s).join(', '); const industry = body.industry ? INDUSTRY_NAMES[body.industry] ?? body.industry : 'Not specified'; const timeline = body.timeline ? TIMELINE_NAMES[body.timeline] ?? body.timeline : 'Not specified'; const company = body.company.trim() || 'Not specified'; const aiTypeNames = body.aiEnabled && body.aiTypes.length > 0 ? body.aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', ') : null; let context = `Client Name: ${body.name} Company: ${company} Services Requested: ${services} Industry: ${industry} Timeline: ${timeline}`; if (body.aiEnabled) { context += `\nAI Integration: Yes — ${aiTypeNames ?? 'type to be determined'}`; } if (body.phone?.trim()) { context += `\nPhone: ${body.phone.trim()}`; } if (body.contactPreference?.trim()) { context += `\nPreferred Contact Method: ${body.contactPreference.trim()}`; } if (body.scope.trim()) { context += `\nClient's Goals: "${body.scope.trim()}"`; } if (body.currentSiteUrl?.trim()) { context += `\nCurrent Website: ${body.currentSiteUrl.trim()}`; } if (body.currentSiteThoughts?.trim()) { context += `\nClient's Thoughts on Current Site: "${body.currentSiteThoughts.trim()}"`; } if (siteAnalysis && !siteAnalysis.fetchError) { context += '\n\n--- Current Website Analysis ---'; if (siteAnalysis.techStack) { const { cms, framework, ecommerce, analytics, hosting } = siteAnalysis.techStack; if (cms) context += `\nCMS: ${cms}`; if (framework) context += `\nFront-End Framework: ${framework}`; if (ecommerce) context += `\nE-Commerce: ${ecommerce}`; if (analytics.length > 0) context += `\nAnalytics: ${analytics.join(', ')}`; if (hosting) context += `\nHosting: ${hosting}`; } if (siteAnalysis.performance) { const p = siteAnalysis.performance; context += `\nPerformance Score (mobile): ${p.score}/100`; context += `\nCore Web Vitals — FCP: ${Math.round(p.fcp)}ms, LCP: ${Math.round(p.lcp)}ms, CLS: ${p.cls.toFixed(2)}, TBT: ${Math.round(p.tbt)}ms`; } if (siteAnalysis.title) context += `\nSite Title: ${siteAnalysis.title}`; if (siteAnalysis.description) context += `\nMeta Description: ${siteAnalysis.description}`; if (siteAnalysis.primaryColors.length > 0) context += `\nBrand Colors: ${siteAnalysis.primaryColors.join(', ')}`; if (siteAnalysis.hasForms) context += '\nHas Contact/Lead Forms: Yes'; } else if (siteAnalysis?.fetchError) { context += `\nNote: Attempted to analyze ${body.currentSiteUrl} but it was unreachable.`; } return context; } // ─── AI Brief Generation ───────────────────────────────────────────────────── async function generateBriefWithAI(body: ConfigureRequestBody, siteAnalysis: SiteAnalysis | null = null): Promise { const apiKey = process.env.OPENROUTER_API_KEY; if (!apiKey) { console.log('[configure] OPENROUTER_API_KEY not set, using fallback brief template'); return generateFallbackBrief(body); } console.log('[configure] Generating AI brief via OpenRouter (deepseek/deepseek-v3.2)...'); const context = buildContext(body, siteAnalysis); console.log('[configure] AI context:\n', context); const displayName = body.name.split(' ')[0] || body.name; const systemPrompt = `You are writing a project brief on behalf of LetsBe Solutions, a digital studio that builds custom websites, custom software, and private digital infrastructure. The company is American-founded and serves clients internationally. Key facts about LetsBe: - Every project is designed and coded from scratch — no templates, no page builders - They build custom software (CRMs, management platforms, association systems, etc.) - They deploy private infrastructure on dedicated servers that the client fully owns and controls - They can layer AI integration into any system they build - Small, experienced team with decades of combined experience in design and engineering - They emphasize data ownership, privacy, and digital sovereignty Write in a professional but warm tone. Be specific and practical — no empty buzzwords. The brief should feel like it was written by someone who understood the client's needs, not a generic template. Structure the brief for easy scanning — use short paragraphs, bullet points where appropriate, and clear section headings. Avoid walls of text. Always reference a 30-minute introductory call (not 60 minutes or 1 hour) when mentioning next steps. When site analysis data is provided in the context, you MUST include a dedicated **Current Website Analysis** section near the top of the brief (after the introduction, before the proposed solution). This section should: - State what technology the site currently runs on (CMS, framework, hosting) - If performance data is available, cite the exact score and what it means practically - Note any strengths or weaknesses observable from the data (e.g., has forms, missing meta description, no analytics) - If the client shared thoughts about their current site, acknowledge those specifically - Explain how the proposed solution addresses each issue found This section demonstrates that LetsBe has already begun analyzing the client's situation before the first call. Never invent data not present in the context — only reference what the analysis actually returned.`; const langInstructions: Record = { fr: '\n\nIMPORTANT: Write the entire brief in French. All headings, body text, and next steps must be in French.', it: '\n\nIMPORTANT: Write the entire brief in Italian. All headings, body text, and next steps must be in Italian.', es: '\n\nIMPORTANT: Write the entire brief in Spanish. All headings, body text, and next steps must be in Spanish.', }; const langInstruction = langInstructions[body.locale ?? ''] ?? ''; const userPrompt = `Generate a personalized project brief for the following prospect. The brief should: 1. Address the client by first name (${displayName}) 2. Acknowledge their specific industry and goals 3. For each service they selected, describe concretely what LetsBe would build. Include 2-3 specific, practical benefits the client would gain (e.g., reduced costs, time saved, better guest experience, competitive advantage). 4. Weave in deep industry context — demonstrate understanding of the client's sector, its challenges, and how the proposed solution addresses real pain points in that industry. 5. If AI integration is requested, explain practically what that would look like 6. Propose a clear engagement approach (discovery → strategy → build → launch). Keep each phase to 1-2 sentences maximum. 7. Include a timeline note based on their preference 8. End with a clear next step: book a free 30-minute introductory call to discuss the brief. Format the brief using **bold** for section headings and --- for separators. Keep it concise but substantive — around 350-500 words. Client details: ${context}`; try { const response = await fetch('https://openrouter.ai/api/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}`, 'HTTP-Referer': process.env.NEXT_PUBLIC_SITE_URL || 'https://letsbe.biz', 'X-Title': 'LetsBe Project Configurator', }, body: JSON.stringify({ model: 'deepseek/deepseek-v3.2', messages: [ { role: 'system', content: systemPrompt + langInstruction }, { role: 'user', content: userPrompt }, ], max_tokens: 1500, temperature: 0.7, }), }); if (!response.ok) { console.error(`[configure] OpenRouter API error: ${response.status} ${response.statusText}`); return generateFallbackBrief(body); } console.log('[configure] AI brief generated successfully'); const data = await response.json(); const content = data.choices?.[0]?.message?.content; if (!content) { return generateFallbackBrief(body); } return content; } catch (error) { console.error('[configure] AI brief generation failed:', error); return generateFallbackBrief(body); } } // ─── Fallback Brief (no API key or API failure) ────────────────────────────── function generateFallbackBrief(body: ConfigureRequestBody): string { const { services, aiEnabled, aiTypes, industry, scope, timeline, name, company } = body; const locale = body.locale ?? 'en'; const SERVICE_NAMES_FR: Record = { web: 'Design & Développement Web', systems: 'Logiciels Sur Mesure', infrastructure: 'Infrastructure Privée', }; const INDUSTRY_NAMES_FR: Record = { maritime: 'Maritime & Yachting', hospitality: 'Hôtellerie', technology: 'Technologie', realestate: 'Immobilier', finance: 'Finance', ngo: 'ONG & Associatif', other: 'Autre', }; const TIMELINE_NAMES_FR: Record = { asap: 'dès que possible', '1-3months': '1–3 mois', '3-6months': '3–6 mois', exploring: 'en phase d\'exploration', }; const SERVICE_NAMES_IT: Record = { web: 'Web Design & Sviluppo', systems: 'Software Su Misura', infrastructure: 'Infrastruttura Privata', }; const INDUSTRY_NAMES_IT: Record = { maritime: 'Marittimo & Nautica', hospitality: 'Ospitalità', technology: 'Tecnologia', realestate: 'Immobiliare', finance: 'Finanza', ngo: 'ONG & No-Profit', other: 'Altro', }; const TIMELINE_NAMES_IT: Record = { asap: 'il prima possibile', '1-3months': '1–3 mesi', '3-6months': '3–6 mesi', exploring: 'in fase di esplorazione', }; const SERVICE_NAMES_ES: Record = { web: 'Diseño & Desarrollo Web', systems: 'Software a Medida', infrastructure: 'Infraestructura Privada', }; const INDUSTRY_NAMES_ES: Record = { maritime: 'Marítimo & Náutico', hospitality: 'Hostelería', technology: 'Tecnología', realestate: 'Inmobiliario', finance: 'Finanzas', ngo: 'ONG & Sin Ánimo de Lucro', other: 'Otro', }; const TIMELINE_NAMES_ES: Record = { asap: 'lo antes posible', '1-3months': '1–3 meses', '3-6months': '3–6 meses', exploring: 'en fase de exploración', }; const svcMap: Record> = { fr: SERVICE_NAMES_FR, it: SERVICE_NAMES_IT, es: SERVICE_NAMES_ES }; const indMap: Record> = { fr: INDUSTRY_NAMES_FR, it: INDUSTRY_NAMES_IT, es: INDUSTRY_NAMES_ES }; const tlMap: Record> = { fr: TIMELINE_NAMES_FR, it: TIMELINE_NAMES_IT, es: TIMELINE_NAMES_ES }; const svcNames = svcMap[locale] ?? SERVICE_NAMES; const indNames = indMap[locale] ?? INDUSTRY_NAMES; const tlNames = tlMap[locale] ?? TIMELINE_NAMES; const serviceNames = services.map((s) => svcNames[s] ?? s); const joiners: Record = { fr: { and: ' et ', commaAnd: ' et ' }, it: { and: ' e ', commaAnd: ' e ' }, es: { and: ' y ', commaAnd: ' y ' }, }; const j = joiners[locale] ?? { and: ' and ', commaAnd: ', and ' }; const servicesList = serviceNames.length <= 2 ? serviceNames.join(j.and) : `${serviceNames.slice(0, -1).join(', ')}${j.commaAnd}${serviceNames[serviceNames.length - 1]}`; const industryFallbacks: Record = { fr: 'votre secteur', it: 'il tuo settore', es: 'tu sector' }; const companyFallbacks: Record = { fr: 'votre organisation', it: 'la tua organizzazione', es: 'tu organización' }; const nameFallbacks: Record = { fr: 'bonjour', it: 'ciao', es: 'hola' }; const industryLabel = industry ? indNames[industry] ?? industry : (industryFallbacks[locale] ?? 'your industry'); const displayCompany = company.trim() || (companyFallbacks[locale] ?? 'your organization'); const displayName = name.split(' ')[0] || (nameFallbacks[locale] ?? 'there'); const timelineFallbacks: Record = { fr: 'un calendrier à convenir', it: 'un calendario da definire', es: 'un calendario a convenir', }; const timelineStr = timeline ? tlNames[timeline]?.toLowerCase() ?? (timelineFallbacks[locale] ?? 'a timeline to be agreed upon') : (timelineFallbacks[locale] ?? 'a timeline to be agreed upon'); const hasWeb = services.includes('web'); const hasSystems = services.includes('systems'); const hasInfra = services.includes('infrastructure'); // Build sections per locale const sectionTemplates: Record string> = { fr: () => { let s = ''; if (hasWeb) { s += `\n**Design & Développement Web**\nNous concevrons et développerons un site web sur mesure pour ${displayCompany} — sans templates, sans constructeurs de pages. Moderne, responsive, rapide et optimisé pour le référencement dès le premier jour.\n`; } if (hasSystems) { s += `\n**Logiciels Sur Mesure**\nNous développerons un système conçu pour correspondre exactement au fonctionnement de ${displayCompany} — modèle de données personnalisé, accès par rôles et intégrations avec vos outils existants.\n`; } if (hasInfra) { s += `\n**Infrastructure Privée**\nNous mettrons en place un environnement serveur dédié pour ${displayCompany} avec email, stockage cloud et outils métier que vous possédez et contrôlez entièrement.\n`; } if (aiEnabled && aiTypes.length > 0) { const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', '); s += `\n**Intégration IA**\nNous intégrerons ${aiLabels.toLowerCase()} dans vos systèmes — en profondeur, pas en surface. L'approche exacte sera définie lors de la phase de découverte.\n`; } else if (aiEnabled) { s += `\n**Intégration IA**\nNous intégrerons l'IA dans vos systèmes — en profondeur, pas en surface. L'approche exacte sera définie lors de la phase de découverte.\n`; } if (scope?.trim()) { s += `\n**Vos Objectifs**\nVous avez partagé : "${scope.trim()}" — nous orienterons nos sessions de découverte autour de ces priorités.\n`; } return s; }, it: () => { let s = ''; if (hasWeb) { s += `\n**Web Design & Sviluppo**\nProgetteremo e svilupperemo un sito web su misura per ${displayCompany} da zero — nessun template, nessun page builder. Moderno, responsive, veloce e ottimizzato per i motori di ricerca fin dal primo giorno.\n`; } if (hasSystems) { s += `\n**Software Su Misura**\nRealizzaremo un sistema progettato su misura per come opera ${displayCompany} — modello dati personalizzato, accesso basato sui ruoli e integrazioni con i tuoi strumenti esistenti.\n`; } if (hasInfra) { s += `\n**Infrastruttura Privata**\nConfigureremo un ambiente server dedicato per ${displayCompany} con email, cloud storage e strumenti aziendali che possiedi e controlli interamente.\n`; } if (aiEnabled && aiTypes.length > 0) { const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', '); s += `\n**Integrazione IA**\nIntegreremo ${aiLabels.toLowerCase()} nei tuoi sistemi — in profondità, non in superficie. L'approccio esatto sarà definito durante la fase di scoperta.\n`; } else if (aiEnabled) { s += `\n**Integrazione IA**\nIntegreremo l'IA nei tuoi sistemi — in profondità, non in superficie. L'approccio esatto sarà definito durante la fase di scoperta.\n`; } if (scope?.trim()) { s += `\n**I Tuoi Obiettivi**\nHai condiviso: "${scope.trim()}" — struttureremo le nostre sessioni di scoperta attorno a queste priorità.\n`; } return s; }, es: () => { let s = ''; if (hasWeb) { s += `\n**Diseño & Desarrollo Web**\nDiseñaremos y desarrollaremos un sitio web a medida para ${displayCompany} desde cero — sin plantillas, sin constructores de páginas. Moderno, responsive, rápido y optimizado para motores de búsqueda desde el primer día.\n`; } if (hasSystems) { s += `\n**Software a Medida**\nDesarrollaremos un sistema diseñado específicamente para cómo opera ${displayCompany} — modelo de datos personalizado, acceso basado en roles e integraciones con tus herramientas existentes.\n`; } if (hasInfra) { s += `\n**Infraestructura Privada**\nConfiguraremos un entorno de servidor dedicado para ${displayCompany} con correo electrónico, almacenamiento en la nube y herramientas empresariales que posees y controlas completamente.\n`; } if (aiEnabled && aiTypes.length > 0) { const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', '); s += `\n**Integración IA**\nIntegraremos ${aiLabels.toLowerCase()} en tus sistemas — de forma profunda, no superficial. El enfoque exacto se definirá durante la fase de descubrimiento.\n`; } else if (aiEnabled) { s += `\n**Integración IA**\nIntegraremos la IA en tus sistemas — de forma profunda, no superficial. El enfoque exacto se definirá durante la fase de descubrimiento.\n`; } if (scope?.trim()) { s += `\n**Tus Objetivos**\nCompartiste: "${scope.trim()}" — orientaremos nuestras sesiones de descubrimiento en torno a estas prioridades.\n`; } return s; }, en: () => { let s = ''; if (hasWeb) { s += `\n**Web Design & Development**\nWe'll design and build a custom website for ${displayCompany} from scratch — no templates, no page builders. Modern, responsive, fast, and optimized for search engines from day one.\n`; } if (hasSystems) { s += `\n**Custom Software**\nWe'll build a purpose-made system tailored to how ${displayCompany} actually operates — custom data model, role-based access, and integrations with your existing tools.\n`; } if (hasInfra) { s += `\n**Private Infrastructure**\nWe'll set up a dedicated server environment for ${displayCompany} with email, cloud storage, and business tools that you fully own and control.\n`; } if (aiEnabled && aiTypes.length > 0) { const aiLabels = aiTypes.map((t) => AI_TYPE_NAMES[t] ?? t).join(', '); s += `\n**AI Integration**\nWe'll layer ${aiLabels.toLowerCase()} into your systems — deeply integrated, not bolted on. The exact approach will be scoped during discovery.\n`; } else if (aiEnabled) { s += `\n**AI Integration**\nWe'll layer AI integration into your systems — deeply integrated, not bolted on. The exact approach will be scoped during discovery.\n`; } if (scope?.trim()) { s += `\n**Your Goals**\nYou shared: "${scope.trim()}" — we'll frame our discovery sessions around these priorities.\n`; } return s; }, }; const sections = (sectionTemplates[locale] ?? sectionTemplates['en'])(); if (locale === 'fr') { return `**Brief Projet pour ${displayCompany}** Préparé pour : ${name} Date : ${new Date().toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' })} --- **Aperçu** Bonjour ${displayName}, suite à votre intérêt pour ${servicesList} dans le secteur ${industryLabel}, voici un brief préliminaire pour guider notre première conversation. Nous aborderons ceci comme un projet unifié — chaque composant fonctionnant ensemble, entièrement détenu et contrôlé par vous. ${sections} **Notre Approche** Nous commençons par une phase de Découverte (2–3 sessions) pour comprendre vos besoins avant d'écrire la moindre ligne de code. **Calendrier** Livraison cible : ${timelineStr}. Une feuille de route détaillée suivra la phase de Découverte. **Prochaines Étapes** 1. Réservez un appel de présentation de 30 minutes 2. Nous vous enverrons un document de cadrage détaillé sous 48 heures 3. La Découverte commence — sans engagement Au plaisir de construire quelque chose de formidable ensemble. — L'équipe LetsBe`; } if (locale === 'it') { return `**Brief Progetto per ${displayCompany}** Preparato per: ${name} Data: ${new Date().toLocaleDateString('it-IT', { year: 'numeric', month: 'long', day: 'numeric' })} --- **Panoramica** Ciao ${displayName}, in base al tuo interesse per ${servicesList} nel settore ${industryLabel}, ecco un brief preliminare per guidare la nostra prima conversazione. Affronteremo questo come un progetto unificato — ogni componente che lavora insieme, interamente di tua proprietà e sotto il tuo controllo. ${sections} **Il Nostro Approccio** Iniziamo con una fase di Scoperta (2–3 sessioni) per comprendere le tue esigenze prima di scrivere una sola riga di codice. **Tempistiche** Consegna prevista: ${timelineStr}. Una roadmap dettagliata seguirà la fase di Scoperta. **Prossimi Passi** 1. Prenota una chiamata introduttiva gratuita di 30 minuti 2. Ti invieremo un documento di scoping dettagliato entro 48 ore 3. La Scoperta inizia — senza impegno Non vediamo l'ora di costruire qualcosa di straordinario insieme. — Il Team LetsBe`; } if (locale === 'es') { return `**Brief de Proyecto para ${displayCompany}** Preparado para: ${name} Fecha: ${new Date().toLocaleDateString('es-ES', { year: 'numeric', month: 'long', day: 'numeric' })} --- **Resumen** Hola ${displayName}, basándonos en tu interés en ${servicesList} para el sector ${industryLabel}, aquí tienes un brief preliminar para guiar nuestra primera conversación. Abordaremos esto como un proyecto unificado — cada componente trabajando en conjunto, totalmente de tu propiedad y bajo tu control. ${sections} **Nuestro Enfoque** Comenzamos con una fase de Descubrimiento (2–3 sesiones) para comprender tus requisitos antes de escribir cualquier línea de código. **Plazo** Entrega objetivo: ${timelineStr}. Una hoja de ruta detallada seguirá a la fase de Descubrimiento. **Próximos Pasos** 1. Reserva una llamada introductoria gratuita de 30 minutos 2. Te enviaremos un documento de alcance detallado en 48 horas 3. El Descubrimiento comienza — sin compromiso Con ganas de construir algo extraordinario juntos. — El Equipo LetsBe`; } return `**Project Brief for ${displayCompany}** Prepared for: ${name} Date: ${new Date().toLocaleDateString('en-GB', { year: 'numeric', month: 'long', day: 'numeric' })} --- **Overview** Hi ${displayName}, based on your interest in ${servicesList} for the ${industryLabel} sector, here's a preliminary brief to guide our first conversation. We'll approach this as a unified project — every component working together, fully owned and controlled by you. ${sections} **Our Approach** We start with a Discovery phase (2–3 sessions) to understand your requirements before writing any code. This ensures we build exactly what you need. **Timeline** Target delivery: ${timelineStr}. A detailed roadmap will follow the Discovery phase. **Next Steps** 1. Book a 30-minute introductory call 2. We'll share a detailed scope document within 48 hours 3. Discovery begins — no obligation Looking forward to building something great together. — The LetsBe Team`; } // ─── Route Handler ──────────────────────────────────────────────────────────── export async function POST(request: NextRequest) { try { const body = (await request.json()) as ConfigureRequestBody; // Validate required fields if (!body.services || body.services.length === 0) { return NextResponse.json( { success: false, error: 'At least one service must be selected.' }, { status: 400 }, ); } if (!body.name || body.name.trim().length < 2) { return NextResponse.json( { success: false, error: 'A valid name is required.' }, { status: 400 }, ); } if (!body.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(body.email)) { return NextResponse.json( { success: false, error: 'A valid email address is required.' }, { status: 400 }, ); } // Analyze current website if URL provided let siteAnalysis: SiteAnalysis | null = null; if (body.currentSiteUrl?.trim()) { console.log(`[configure] Analyzing site: ${body.currentSiteUrl.trim()}...`); siteAnalysis = await analyzeSite(body.currentSiteUrl.trim()); console.log(`[configure] Site analysis complete (fetchError: ${siteAnalysis.fetchError ?? 'none'})`); console.log(`[configure] Tech stack:`, JSON.stringify(siteAnalysis.techStack)); console.log(`[configure] Performance:`, JSON.stringify(siteAnalysis.performance)); console.log(`[configure] Colors:`, siteAnalysis.primaryColors); console.log(`[configure] Title:`, siteAnalysis.title); } // Generate the brief (AI if available, fallback otherwise) const brief = await generateBriefWithAI(body, siteAnalysis); // Send emails (non-blocking — don't fail the response if email fails) const smtpHost = process.env.SMTP_HOST; const smtpPass = process.env.SMTP_PASS; if (smtpHost && smtpPass) { console.log(`[configure] SMTP configured (host: ${smtpHost}), sending emails to ${body.email} and ${process.env.ADMIN_EMAIL || 'hello@letsbe.biz'}...`); Promise.allSettled([ sendBriefToClient({ to: body.email, name: body.name, company: body.company, brief, }), sendLeadNotification({ to: process.env.ADMIN_EMAIL || 'hello@letsbe.biz', name: body.name, company: body.company, brief, services: body.services, email: body.email, phone: body.phone || undefined, contactPreference: body.contactPreference || undefined, }), ]).then((results) => { results.forEach((result, i) => { const target = i === 0 ? 'client brief' : 'admin notification'; if (result.status === 'fulfilled') { console.log(`[configure] Email sent successfully: ${target}`); } else { console.error(`[configure] Email failed: ${target}`, result.reason); } }); }); } else { console.log(`[configure] SMTP not configured (SMTP_HOST: ${smtpHost ? 'set' : 'missing'}, SMTP_PASS: ${smtpPass ? 'set' : 'missing'}), skipping emails`); } return NextResponse.json({ success: true, brief }); } catch { return NextResponse.json( { success: false, error: 'An unexpected error occurred. Please try again.' }, { status: 500 }, ); } }