Commit Graph

163 Commits

Author SHA1 Message Date
unknown
aee82267d0 Configuracion de reglas de typescript 2026-06-03 23:14:53 -04:00
unknown
f082351b43 actualizacion de readme agente Luisa 2026-06-03 23:09:37 -04:00
Carlos Narro
5df608f203 Muestra fotos y notas por zona en la ficha del lead
- agruparPorZona (lib/funnel/fotos.ts): helper puro que agrupa fotos
  (antes/después) y notas por zona, con fallback al tipo del lead. 5 tests.
- getLead trae también lead_notas.
- LeadFotosGaleria: galería por zona (Antes/Después + notas) que sustituye el
  grid plano de la ficha del panel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:22:12 +02:00
Carlos Narro
0a5f8cba2b Añade canales de llamada y WhatsApp al funnel B2C
- Llamada (/llamada): "Llamar ahora" dispara la llamada saliente de Retell;
  "Programar" registra fecha/hora. Tras pedir, ofrece enviar por email el
  enlace al formulario para subir las imágenes.
- WhatsApp (/whatsapp): arranca la conversación vía webhook al flujo externo
  (con el teléfono del lead) y pide confirmación; al confirmar, agradece y
  sigue por WhatsApp.
- actions: pedirLlamada, enviarEnlaceFormularioEmail, iniciarWhatsapp,
  confirmarWhatsapp.

Verificado en navegador: las 3 pantallas y sus transiciones.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:20:14 +02:00
Carlos Narro
9b5b0d59a6 Añade chooser de canal y formulario por zonas al funnel B2C
- Paso intermedio /solicitud/[id]: el cliente elige llamada, WhatsApp o
  formulario (crearLead ahora redirige aquí, no a /fotos).
- /formulario: FormularioZonas permite añadir varias zonas, cada una con tipo,
  m², acabado, notas y fotos; /fotos queda como redirect.
- guardarDetallesYFotos: guarda fotos (antes, por zona) y notas (por zona),
  agrega los campos del lead (m² suma, tipo único o 'integral', calidad más
  alta, tasteText concatenado) para el presupuesto orientativo inmediato, y
  señala perfilCompleto al flujo externo.
- Elimina FotosUploader (sustituido por FormularioZonas).

Verificado en navegador: 2 zonas → presupuesto al instante + notas por zona +
evento de perfil en DB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:17:11 +02:00
Carlos Narro
f87a3ecd81 Añade copy del funnel multicanal (chooser + llamada + WhatsApp)
COPY-GUIDE §3: paso 2 "Elige cómo seguir" con las 3 tarjetas, pantalla del
canal llamada (ahora/programar + nota de fotos por email/WhatsApp) y pantalla
del canal WhatsApp (contacto directo + confirmación). Texto literal para B1–B4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:11:11 +02:00
Carlos Narro
35ba2f28fe Documenta el EP de ingesta y los webhooks salientes
api-docs/README.md: método/URL, auth Bearer, esquema del cuerpo (items
foto/texto, zona, momento, flags), respuesta y errores (401/404/422), ejemplos
curl de los 5 casos, y los payloads de los 3 webhooks salientes (perfil,
entrega WhatsApp, arranque WhatsApp) con cómo el flujo externo devuelve las
"después" por el mismo EP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:09:59 +02:00
Carlos Narro
ae8984fe13 Añade el EP único de ingesta async del lead
POST /api/leads/:id/ingesta (Bearer FUNNEL_API_KEY): acepta items foto/texto
etiquetados por zona y momento, más flags perfilCompleto y finalizar.
- ingesta-schema.ts: zod del cuerpo (union discriminada foto|texto), exportado
  para test; rechaza llamadas vacías.
- route.ts: auth 401, valida lead (404), inserta fotos (orden continúa el máx)
  y notas, traza fotos_subidas; perfilCompleto→señalarPerfilCompleto,
  finalizar→finalizarYEntregar.
- 10 tests del schema. Verificado por HTTP: 401/200/422/404 y finalizar genera
  el pdf_url y avanza el lead a whatsapp_entregado.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:09:16 +02:00
Carlos Narro
195ecf6cc3 Añade webhooks salientes, señal de perfil completo y finalización
- webhooks.ts: postWebhook best-effort + señalarGeneracionPerfil,
  notificarFlujoWhatsapp (entrega) e iniciarConversacionWhatsapp (arranque).
- perfil.ts: señalarPerfilCompleto arma el JSON por zona (notas + fotos
  antes/después) y lo manda al flujo externo; deja traza render_generado.
- finalizar.ts: finalizarYEntregar construye el PDF, persiste pdf_url, envía
  el email (siempre) y la señal de WhatsApp, y avanza el lead a entregado.
- orchestrator: comentario en Paso 7 apuntando a la entrega real en finalizar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:06:38 +02:00
Carlos Narro
ec09267d99 Añade envío de email SMTP del presupuesto y del enlace al formulario
- mailer.ts: transport nodemailer perezoso desde env; enviarPresupuestoEmail
  (adjunta el PDF) y enviarEnlaceFormulario. Best-effort: sin SMTP configurado
  o ante error devuelven false sin lanzar.
- COPY-GUIDE §6.b: copy literal de ambos emails al cliente final.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:05:17 +02:00
Carlos Narro
bcc882e37d Genera el PDF del presupuesto con galería antes/después por zona
- build-presupuesto.ts: construirPresupuestoPdf(leadId) agrupa fotos y notas
  por zona (fallback al tipoReforma del lead), convierte las imágenes con
  resolverImagenPdf y arma el PDF. Carga el lead por id sin scoping (uso
  interno desde el route del panel y desde la finalización pública).
- tenant-queries: getTenantPerfilById(tenantId) sin auth; getTenantPerfil lo
  reutiliza con el tenant de la sesión.
- PresupuestoDoc: prop zonas + sección "Imágenes de tu reforma" (antes/después
  lado a lado + notas por zona).
- route del panel: refactor para reutilizar construirPresupuestoPdf (DRY),
  manteniendo getLead como guardia de auth/404.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:04:02 +02:00
Carlos Narro
737496ed89 Añade env de ingesta, SMTP y webhooks + dependencia nodemailer
Variables nuevas (todas opcionales vía zod, sin romper build/demo):
- FUNNEL_API_KEY: clave Bearer del EP de ingesta.
- SMTP_* + EMAIL_FROM: envío de email del presupuesto/enlace.
- PERFIL/WHATSAPP/WHATSAPP_START webhook URLs: señales al flujo externo.
- APP_URL: base para enlaces absolutos.
Helpers emailConfigurado()/perfilWebhookConfigurado()/whatsappWebhookConfigurado()/
whatsappStartConfigurado(). nodemailer como dep directa (stack: Email SMTP).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:01:15 +02:00
Carlos Narro
b9dd90f4ef Etiqueta fotos por zona/momento y añade tabla lead_notas
Prepara el modelo de datos para la ingesta multicanal del perfil del lead:
- lead_fotos: columnas momento (foto_momento antes/despues, default antes) y
  zona (tipo_reforma, nullable con fallback al tipoReforma del lead).
- lead_notas: tabla append-only de datos de texto por zona (ej. "suelo
  premium"), con origen (ep|funnel|panel) para auditar quién los aportó.
- Migración 0008 + regenerado db-schema/schema.sql.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 19:00:08 +02:00
Carlos Narro
cd6532eb1b Añade archivos de workspace de VS Code al .gitignore
Ignora *.code-workspace para evitar que configuraciones locales de VS Code se suban al repositorio.
2026-06-03 18:09:30 +02:00
Carlos Narro
1a70ab2eaa Añade esquema SQL consolidado de la base de datos
Genera db-schema/schema.sql (DDL completo: 12 enums, 14 tablas, FKs e
índices) a partir del schema Drizzle, para que el equipo pueda consultar y
proponer cambios sobre el modelo de datos sin leer las migraciones una a una.

- db-schema/schema.sql: foto del esquema actual (drizzle-kit export)
- db-schema/README.md: qué es cada tabla, cómo cambiar el modelo y cómo
  regenerar/levantar la BD desde este SQL
- package.json: script db:export para regenerar la foto

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 18:07:46 +02:00
Carlos Narro
4aa0582f53 Merge branch 'main' of https://github.com/McGregory99/reformix-hackaton 2026-06-03 09:52:14 +02:00
Carlos Narro
d2d42ff1d4 Añade imágenes de ejemplo para galería y demostración
Incluye una imagen WebP optimizada (48caf530-fa5f-476b-8120-195cfce7a9ec.webp) y una imagen PNG de ejemplo de reformas (reformas-ejemplo.png) para usar en la galería de trabajos y demostraciones del funnel.
2026-06-03 09:52:10 +02:00
unknown
e5c8956b64 Configuracion para guardar en base de datos 2026-06-02 23:11:46 -04:00
unknown
fc6a7044b0 Configurcion de personalidad 2026-06-02 23:07:34 -04:00
unknown
7b0eb31f56 Merge branch 'main' of https://github.com/McGregory99/reformix-hackaton 2026-06-02 22:49:18 -04:00
unknown
9c5e6bc7fa Configuracion de prompt Luisa 2026-06-02 22:48:59 -04:00
Carlos Narro
372ad560bf Añade llamada saliente con Retell al funnel B2C
Integra el agente de voz de Retell (Arquitectura A para la demo): tras la
pre-llamada, el orquestador lanza una llamada saliente real con override de
agente y dynamic variables (empresa + cliente), mientras el render y el
presupuesto se siguen generando con los datos del formulario.

- src/lib/env.ts: esquema zod de RETELL_* (claves opcionales -> sin ellas el
  funnel sigue en modo simulado y el build no se rompe)
- src/lib/voice/retell.ts: cliente fino con fetch a create-phone-call
  (sin nueva dependencia), normalización E.164 y builder de variables
- orchestrator: dispara la llamada best-effort y guarda el callId
- tests del normalizador de teléfono y del builder de variables

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:55:29 +02:00
Carlos Narro
0651d964f5 Merge branch 'main' of https://github.com/McGregory99/reformix-hackaton 2026-06-02 20:05:58 +02:00
Carlos Narro
8de139f9d3 Mejora el PDF de presupuesto: disclaimer, render y conversión de imágenes
- Añade bajo el título un párrafo orientativo: el precio final se fija tras
  la visita gratuita y la estimación se basa en datos estadísticos ajustados
  para acercarse lo máximo posible al importe definitivo.
- Añade una sección con el render del resultado y una descripción generada a
  partir de los materiales (materialesRender) y el estilo de la llamada, con
  fallback elegante cuando faltan datos.
- @react-pdf solo incrusta PNG/JPEG: convierte con sharp los WebP/SVG (render
  y logo) que antes se descartaban en silencio dejando el PDF sin imagen. El
  render va a JPEG redimensionado (PDF ~360 KB en vez de ~2,7 MB) y el logo a
  PNG para conservar transparencia.
- Fija sharp como dependencia directa (ya venía como transitiva de Next).
- Copy nuevo añadido primero a COPY-GUIDE.md (sección entrega del presupuesto).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 19:48:14 +02:00
unknown
9a8f84ff37 Configuracion de prompts PENDIENTE 2026-06-02 10:24:02 -04:00
unknown
3e9d083e7d Merge branch 'main' of https://github.com/McGregory99/reformix-hackaton 2026-06-01 23:24:56 -04:00
unknown
b1b2451429 Configuracion de prueba 2026-06-01 23:24:43 -04:00
Carlos Narro
e9637f77ff Integrar recorte y optimización a WebP en las subidas de imagen del panel
Los tres uploaders del panel (logo, "quiénes somos" y galería) ahora abren
un recorte interactivo (zoom + encuadre) y reescalan en el navegador antes
de subir: logo y "quiénes somos" a máx. 500 px, galería a máx. 1200 px,
reencodando a WebP (calidad 0.82). El SVG del logo se sube tal cual para no
rasterizar el vector. Esto reduce el peso de los data URIs base64 que se
guardan en Postgres y se inlinean en el funnel.

Nueva dependencia react-easy-crop: librería de recorte ligera, sin estado
global, compatible con React 19; el reescalado y reencodado se hacen con
canvas nativo (lib/image/crop.ts), sin dependencias extra.
2026-06-01 22:36:55 +02:00
Carlos Narro
bf9e72064b Alinear panel y auth con la identidad B2B "Architectural Warmth"
Sustituye la paleta negra/azul B2C del panel del reformista por el verde
de marca, neutros cálidos y titulares en Instrument Serif de la landing B2B.
Añade tokens --color-primary-*, --color-stone-50 y --font-display al @theme.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 20:01:57 +02:00
Carlos Narro
15f2d67970 Corrige el botón Entrar de la landing B2B para que lleve al login
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 14:06:40 +02:00
Carlos Narro
1ea5d70675 Rediseña panel y auth con la identidad de la landing B2C
- Vista de leads en tarjetas + tabla con toggle (tarjetas por defecto, preferencia persistida)
- Galería de trabajos: gestión en /panel/galeria y bloque público en el funnel
- Selector de tema por reformista (presets + color de marca opcional) aplicado a la landing
- Login y registro rediseñados a pantalla partida 50/50 con foto de reforma
- Enlace "Entrar" funcional en la cabecera del funnel; elimina Navbar muerto
- Unifica tipografía y botones del panel con los tokens de la landing

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 13:51:00 +02:00
Carlos Narro
a91fe5ce2c Añade personalización SEO/Quiénes somos y testimonios gestionables por reformista
- Panel/empresa: title y meta description SEO personalizables; foto, texto y
  años de experiencia para el bloque "Quiénes somos" (toggle on/off).
- Funnel por slug: metadata SEO desde el tenant, bloque "Quiénes somos" y
  testimonios servidos desde DB (sustituye los hardcodeados).
- Flujo de opiniones: el reformista solicita la opinión desde la ficha de un
  lead ganado; el cliente la deja en un funnel dedicado /opinion/[id] con
  estrellas + texto + fotos; entra como pendiente y el reformista la modera
  (publicar/ocultar/eliminar) en /panel/opiniones antes de mostrarla.
- Schema: columnas SEO/about en tenants, testimonioSolicitadoAt en leads,
  enum testimonio_estado, tablas testimonios + testimonio_fotos (migración 0006).
- Seed: opiniones demo (2 publicadas, 1 pendiente) y contenido "Quiénes somos".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 12:26:13 +02:00
Carlos Narro
1a1caaf0df Reorganiza el routing multi-tenant: funnel por slug, B2B en raíz
- / y /b2b sirven la landing B2B estática (rewrites beforeFiles)
- /{slug} resuelve el funnel del reformista (app/[slug]/page.tsx) con
  branding propio (TenantBrand) y atribución de leads por tenant
- crearLead(slug) y páginas /solicitud usan el tenant del lead
- Panel: edición del slug del funnel + URL pública en /panel/empresa
- Helper de slugs reservados para evitar colisiones con rutas reales

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 11:09:44 +02:00
Carlos Narro
e26e6be38b Merge branch 'main' of https://github.com/McGregory99/reformix-hackaton
# Conflicts:
#	.gitignore
2026-06-01 10:18:35 +02:00
Carlos Narro
d370a725e8 Sustituir landing B2B publicada por versión animada en /b2b
Reemplaza public/b2b.html (bundle estático viejo) por la versión con
reveals al scroll, hover-lift, count-up de stats e imágenes antes/después.
Assets servidos desde /b2b-assets para evitar colisiones. Sirve en el
dominio único reformix.dv3.com.es vía el rewrite /b2b existente.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:17:47 +02:00
unknown
06c976a86e Merge branch 'main' of https://github.com/McGregory99/reformix-hackaton 2026-05-31 22:07:12 -04:00
unknown
ef78d9a14c Logia de agente de Whatsapp 2026-05-31 22:02:58 -04:00
Carlos Narro
0e7f27633b Añadir Dockerfile nginx para servir la landing B2B nueva
Sirve index.html + assets (fuentes woff2 e imágenes webp) para
desplegar la landing como app estática en Dokploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 22:43:51 +02:00
Carlos Narro
461e47cda1 Extraer landing B2B a fuente editable con animaciones e imágenes reales
Desempaqueta el bundle autocontenido a index.html + assets servidos
(17 fuentes woff2, pares antes/después webp). Añade scroll-reveal sutil
con stagger, hover-lift en tarjetas, counters animados en stats y dos
imágenes reales: render en la burbuja de WhatsApp y comparativa
antes/después en "Cómo funciona". Respeta prefers-reduced-motion.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 16:56:05 +02:00
Carlos Narro
04e74f5fb4 Add sección de preferencias detectadas en el detalle del lead 2026-05-31 16:21:28 +02:00
Carlos Narro
ba61ff4b4d Encadenar extractor de preferencias y aplicación de extras en el orquestador 2026-05-31 16:19:21 +02:00
Carlos Narro
11d78e4f69 Add captura de urgencia, target, estructural y gustos en el form de fotos 2026-05-31 16:18:39 +02:00
Carlos Narro
6e61cbe8e2 Add campos de urgencia, target, gustos y snapshot de preferencias a leads 2026-05-31 16:17:33 +02:00
Carlos Narro
ccb83a3d20 Add guion del agente de voz (preámbulo legal + slots + gustos) 2026-05-31 16:16:27 +02:00
Carlos Narro
405fdc4e32 Add merge a BudgetInputs y aplicación de extras/ajustes al presupuesto 2026-05-31 16:15:13 +02:00
Carlos Narro
a84d513c5b Add clasificador determinista de preferencias keyless 2026-05-31 16:13:38 +02:00
Carlos Narro
18e900dd52 Add léxicos en español para el clasificador de preferencias 2026-05-31 16:11:31 +02:00
Carlos Narro
c38289fcae Add tipos del contrato de preferencias del agente de voz 2026-05-31 16:11:29 +02:00
Carlos Narro
9997ce11cc Add plan de implementación del guion de voz + capa de preferencias
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 16:05:13 +02:00
Carlos Narro
a15d8c77b4 Diseño: guion del agente de voz + capa de preferencias
Spec del guion híbrido (slots fijos + bloque abierto) y de la capa que
clasifica/abstrae el texto de gustos en inputs del presupuesto, con cuatro
palancas (material, extras, render, ajustes etiquetados) y clasificador
keyless. Enfoque A: pre+post alrededor de computeBudget, motor intacto.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 15:55:33 +02:00