diff --git a/src/app/(frontend)/api/configure/route.ts b/src/app/(frontend)/api/configure/route.ts index a89a664..7f31747 100644 --- a/src/app/(frontend)/api/configure/route.ts +++ b/src/app/(frontend)/api/configure/route.ts @@ -156,9 +156,12 @@ When site analysis data is provided in the context, you MUST include a dedicated - 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 langInstruction = body.locale === 'fr' - ? '\n\nIMPORTANT: Write the entire brief in French. All headings, body text, and next steps must be in French.' - : ''; + 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}) @@ -221,7 +224,7 @@ ${context}`; function generateFallbackBrief(body: ConfigureRequestBody): string { const { services, aiEnabled, aiTypes, industry, scope, timeline, name, company } = body; - const isFr = body.locale === 'fr'; + const locale = body.locale ?? 'en'; const SERVICE_NAMES_FR: Record = { web: 'Design & Développement Web', @@ -246,70 +249,170 @@ function generateFallbackBrief(body: ConfigureRequestBody): string { exploring: 'en phase d\'exploration', }; - const svcNames = isFr ? SERVICE_NAMES_FR : SERVICE_NAMES; - const indNames = isFr ? INDUSTRY_NAMES_FR : INDUSTRY_NAMES; - const tlNames = isFr ? TIMELINE_NAMES_FR : TIMELINE_NAMES; + 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 joiner = isFr ? ' et ' : ' and '; - const servicesList = serviceNames.length <= 2 - ? serviceNames.join(joiner) - : `${serviceNames.slice(0, -1).join(', ')}${isFr ? ' et ' : ', and '}${serviceNames[serviceNames.length - 1]}`; - const industryLabel = industry ? indNames[industry] ?? industry : (isFr ? 'votre secteur' : 'your industry'); - const displayCompany = company.trim() || (isFr ? 'votre organisation' : 'your organization'); - const displayName = name.split(' ')[0] || (isFr ? 'bonjour' : 'there'); + 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() ?? (isFr ? 'un calendrier à convenir' : 'a timeline to be agreed upon') - : (isFr ? 'un calendrier à convenir' : 'a timeline to be agreed upon'); + ? 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'); - let sections = ''; + // 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; + }, + }; - if (isFr) { - if (hasWeb) { - sections += `\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) { - sections += `\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) { - sections += `\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(', '); - sections += `\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) { - sections += `\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()) { - sections += `\n**Vos Objectifs**\nVous avez partagé : "${scope.trim()}" — nous orienterons nos sessions de découverte autour de ces priorités.\n`; - } - } else { - if (hasWeb) { - sections += `\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) { - sections += `\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) { - sections += `\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(', '); - sections += `\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) { - sections += `\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()) { - sections += `\n**Your Goals**\nYou shared: "${scope.trim()}" — we'll frame our discovery sessions around these priorities.\n`; - } - } + const sections = (sectionTemplates[locale] ?? sectionTemplates['en'])(); - if (isFr) { + if (locale === 'fr') { return `**Brief Projet pour ${displayCompany}** Préparé pour : ${name} Date : ${new Date().toLocaleDateString('fr-FR', { year: 'numeric', month: 'long', day: 'numeric' })} @@ -341,6 +444,70 @@ 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' })}