Commit Graph

36 Commits

Author SHA1 Message Date
Goyo Cancio
2e3cd78216 Añade impermeabilización, extras fijos y zonas al motor de presupuesto
Acerca el cálculo a tarifas de mercado sin rehacer el modelo lineal €/m²:
- Impermeabilización como partida propia en zonas húmedas (cocina/baño/integral)
- Extras fijos que no escalan con m²: boletín (siempre), tuberías (piso anterior
  a 2000) y cambio de distribución (mover inodoro/ducha/bañera)
- Intensidad por tipo en fontanería/electricidad (baseline cocina) para que un
  integral no escale como un baño
- Factor de zona por provincia en tramos (Madrid/BCN 1.40, islas 1.30, capitales
  1.20, rural 0.85, resto 1.00)
- 2 preguntas nuevas en el formulario del cliente para disparar los extras
- Panel de precios: campo de impermeabilización + sección de extras fijos
- Seed recalibrado (mano de obra, extras, catálogo suelo/pared)
- Migración 0009 (leads.anterior_a_2000, leads.cambio_distribucion, pricing_config.extras)
- Tests del motor ampliados (impermeabilización, extras, intensidad por tipo)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 14:02:57 +02: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
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
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
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
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
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
04e74f5fb4 Add sección de preferencias detectadas en el detalle del lead 2026-05-31 16:21:28 +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
b582f3ac33 Conectar funnel B2C real sin claves: captura → fotos → presupuesto
El formulario de la landing ahora crea un lead real en BD y redirige a
/solicitud/[id]/fotos, donde el cliente sube fotos y datos de la reforma.
El orquestador simula los pasos de IA (pre-llamada, llamada, render) y
calcula el presupuesto DE VERDAD con el catálogo del reformista, dejando
el lead listo en el panel con render y desglose.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 14:29:21 +02:00
Carlos Narro
b95c588efe Permitir descargar el PDF del presupuesto desde el detalle del lead
La sección Presupuesto (PDF) usaba lead.pdfUrl, que nunca se rellena en el
MVP, así que siempre mostraba "Aún no generado". Ahora apunta a la ruta
on-demand /panel/[id]/presupuesto cuando existe desglose, con un parámetro
?download=1 que fuerza Content-Disposition: attachment.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 08:12:55 +02:00
Carlos Narro
c4cc4d20d4 Rehace la maquetación móvil de la página de precios
Las filas del catálogo, la configuración general y el formulario de alta
no estaban pensados para móvil (input de precio descolgado, etiquetas que
desalineaban la cuadrícula, campos sueltos). Ahora las filas apilan
nombre + metadatos + controles de forma limpia en móvil y mantienen la
fila única en escritorio; la cuadrícula usa etiquetas legibles y alinea
los inputs; el alta es una cuadrícula de 2 columnas en móvil.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 00:53:40 +02:00
Carlos Narro
de798b00ce Hace responsive la tabla de precios en móvil
Las filas del catálogo y la cabecera CSV se desbordaban horizontalmente
en móvil (botones Guardar/Borrar fuera de pantalla), y ese overflow
horizontal desestabilizaba la barra de navegación fija. Las filas ahora
hacen wrap y el bloque <code> rompe palabra.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 00:49:28 +02:00
Carlos Narro
2f13057e02 Corrige barra de navegación móvil que no quedaba fija al hacer scroll
El body usaba overflow-x:hidden, lo que forzaba overflow-y a auto y creaba
un contenedor de scroll ambiguo que rompía position:fixed (la barra
aparecía tarde y no se anclaba abajo, sobre todo en iOS Safari). Se cambia
a overflow-x:clip, que recorta el desbordamiento horizontal sin crear
contenedor de scroll.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 23:53:26 +02:00
Carlos Narro
27165a41eb Rediseña la navegación móvil del panel/admin con barra de pestañas inferior
Sustituye el menú hamburguesa por una barra fija inferior con iconos y
etiquetas (thumb-friendly, siempre visible), manteniendo la nav horizontal
en escritorio.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 22:56:30 +02:00
Carlos Narro
83ad82e617 Mejora la navegación móvil del panel y admin
Extrae un AppNav reutilizable con menú hamburguesa desplegable en móvil
y resaltado del enlace activo. Antes la marca y los enlaces se apretaban
en una sola fila en pantallas pequeñas; ahora el nombre de empresa se
oculta en móvil y los enlaces pasan a un desplegable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 22:42:07 +02:00
Carlos Narro
ec141cdd6e Añade revisión pre-envío del reformista y PDF de presupuesto pulido
Adelanta de F1.5 a F2 la validación pre-envío: el panel permite elegir
modo de envío (automático/revisión), editar los conceptos del
presupuesto y enviar al cliente por WhatsApp (simulado).

Añade datos de empresa y logo configurables en /panel/empresa y genera
el presupuesto como PDF real descargable con esa marca vía
@react-pdf/renderer, sustituyendo la vista HTML imprimible.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 22:27:05 +02:00
Carlos Narro
b84b2f37a2 Fijar trial a 14 días en alta de tenant y reforzar filtro por tenant en escrituras 2026-05-30 20:02:02 +02:00
Carlos Narro
7565a7bf46 Mostrar badge de plan y botón de pago deshabilitado 2026-05-30 19:58:58 +02:00
Carlos Narro
df085b6cf1 Add asignación de planes y estado de suscripción 2026-05-30 19:57:49 +02:00
Carlos Narro
07d41e1f6b Add gestión de usuarios en el admin 2026-05-30 19:57:10 +02:00
Carlos Narro
6f86334c8a Add layout y dashboard del admin 2026-05-30 19:56:31 +02:00
Carlos Narro
795d6a7a19 Add signup trial que crea tenant y owner
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 19:50:50 +02:00
Carlos Narro
6add2f93ea Proteger el panel con sesión y mostrar empresa real 2026-05-30 19:45:07 +02:00
Carlos Narro
b776646a50 Add login y logout 2026-05-30 19:43:10 +02:00
Carlos Narro
a7339b8f14 Migrar resolución de tenant del panel a la sesión 2026-05-30 19:41:04 +02:00
Carlos Narro
6be00e3eb5 fix: validate numeric pricing inputs and drop unused import
Guard euro/altura inputs in precios actions so empty or non-numeric
form values return a Spanish error instead of writing NaN and throwing
a 500. Remove the now-unused formatEuros import flagged by ESLint.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 12:46:52 +02:00
Carlos Narro
588aa4dc1c feat: wire computeBudget into recalcularPresupuesto and show desglose
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 12:41:40 +02:00
Carlos Narro
4106d58614 feat: add pricing panel with catalog CRUD and CSV import 2026-05-30 12:36:31 +02:00
Carlos Narro
f09024f753 Add B2B reformista panel with Postgres/Drizzle data layer
Modela el funnel del lead en dos dimensiones (pipeline_stage técnico
de 7 pasos + estado comercial de 6 estados) y siembra 11 leads demo,
uno por cada momento del funnel, para analizar el siguiente paso.
Incluye panel /panel (lista + detalle RF-D-01/02) y wiring de deploy
(Dockerfile multi-stage + entrypoint migrate+seed).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 15:51:10 +02:00
Carlos Narro
9020c24e68 Actualización de título y adición de favicon en landing B2B 2026-05-28 22:55:33 +02:00
Carlos Narro
a9ad2d7e31 Reordenando ficheros y subida de documentacion 2026-05-27 10:27:27 +02:00