# Reformix — Specifications & Requirements

**Fecha:** 24-may-2026
**Fuente:** Blueprint v2 (sync con Google Doc del 22-may) + sesiones de planificación 21-may → 24-may
**Estado:** ☐ Pendiente aprobación del equipo
**Versión:** 1.0

---

## Contexto

Reformix es un SaaS B2B para reformistas en España que entrega al cliente final del reformista, en menos de 5 minutos desde una landing, un **render IA antes/después** de su cocina o baño + un **presupuesto orientativo desglosado**, mediante un agente de voz IA que llama al cliente desde un número fijo provincial y la entrega final por WhatsApp. Este documento formaliza los Requisitos Funcionales (RF) y No Funcionales (RNF) usando **notación EARS** (Easy Approach to Requirements Syntax), con criterios de aceptación binarios y trazabilidad a plan → código → tests.

### Notación EARS (recordatorio)

| Patrón | Forma | Ejemplo |
|---|---|---|
| Ubicuo | *El sistema deberá [acción]* | El sistema deberá registrar timestamp de consentimiento. |
| Evento | *Cuando [trigger], el sistema deberá [acción]* | Cuando el usuario envía el formulario, el sistema deberá persistir el lead en <2 s. |
| Estado | *Mientras [estado], el sistema deberá [acción]* | Mientras una llamada esté activa, el sistema deberá grabar el audio. |
| Opcional | *Donde [feature esté disponible], el sistema deberá [acción]* | Donde el cliente incluya un DIN-A4 en la foto, el sistema deberá estimar medidas reales. |
| No deseado | *Si [condición no deseada], entonces el sistema deberá [acción]* | Si el teléfono está en Lista Robinson, entonces el sistema deberá cancelar la llamada y registrar el motivo. |

### Convención de IDs

- `RF-<superficie>-NN` — Requisitos Funcionales por superficie.
  - **A** = Landing B2B (ventas a reformistas)
  - **B** = Landing B2C (cliente final del reformista)
  - **C** = Funnel B2C (los 5 pasos del flujo de presupuesto)
  - **D** = Panel del reformista
- `RNF-<categoría>-NN` — Requisitos No Funcionales transversales.

### Fases

| Fase | Fecha | Alcance |
|---|---|---|
| **F1 — Landings** | 28-may-2026 | Landings B2B + B2C live, tracking activo, ads activos |
| **F2 — MVP** | 11-jun-2026 | Funnel B2C completo end-to-end (form → llamada → render → entrega WhatsApp) + Panel del reformista mínimo |
| F1.5 | post-hackathon | Configurador multi-tenant, ~~validación pre-envío~~ (adelantada a F2, ver nota), NL refinement, 3 versiones B/M/P, m² automático |
| F2 (Producto) | mes 9+ | Marketplace B2C + valorador "Precio Justo" + sello certificado |

---

## Functional Requirements (RF)

### Superficie A — Landing B2B (ventas al reformista)

Objetivo: convertir tráfico de ads / outreach en pruebas gratuitas de 14 días y captar waitlist de features futuras.

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-A-01 | El sistema deberá mostrar un hero con headline *"Tus clientes verán su reforma antes de llamarte"* y CTA primario *"Empieza gratis 14 días"*. | Inspección DOM muestra `<h1>` con el texto y un `<button>`/`<a>` apuntando a `/signup`. | Alta | F1 |
| RF-A-02 | El sistema deberá embeber una demo jugable del widget (con datos de "Reformas Ejemplo") accesible desde un CTA *"Pruébalo ahora"*. | Al hacer click se abre un iframe del widget B2C completo y se puede recorrer el flujo entero hasta recibir un render generado. | Alta | F1 |
| RF-A-03 | El sistema deberá mostrar 3 tarjetas de pricing con tier Starter (29 €), Pro (79 €, destacado) y Business (199 €), con leads incluidos y overage por tier. | Las 3 tarjetas son visibles a 1280px y 375px, Pro tiene marcador visual de "recomendado", y los precios coinciden con el blueprint. | Alta | F1 |
| RF-A-04 | El sistema deberá mostrar un bloque *"Próximamente — Doble nomenclatura"* con formulario de waitlist (solo email). | Submit del email persiste en tabla `waitlist_features` con tag `doble-nomenclatura` y muestra mensaje de confirmación. | Media | F1 |
| RF-A-05 | El sistema deberá mostrar un formulario de signup trial (email + nombre + nombre de empresa + provincia + opt-in marketing). | Submit válido crea cuenta en `accounts` con status `trial`, redirige a `/onboarding` y envía email de bienvenida en <30 s. | Alta | F1 |
| RF-A-06 | El sistema deberá disparar eventos de analítica (`landing_b2b_view`, `demo_widget_started`, `demo_widget_completed`, `pricing_view`, `signup_completed`, `waitlist_doble_nomenclatura`) a PostHog + Meta Pixel + GA. | Inspección de Network muestra los 6 eventos disparándose en el flujo correspondiente. | Alta | F1 |
| RF-A-07 | El sistema deberá mostrar enlaces a Política de Privacidad, Política de Cookies, Aviso Legal y Términos y Condiciones en el footer. | Los 4 enlaces existen, devuelven HTTP 200 y contienen los textos legales mínimos del proyecto. | Alta | F1 |
| RF-A-08 | El sistema deberá mostrar una FAQ con al menos 5 preguntas (calidad del render, precios "reales", personalización tabla precios, integración web, fin del trial). | DOM contiene `<details>` o componente FAQ con ≥ 5 entradas. | Media | F1 |
| RF-A-09 | El sistema deberá mostrar un banner de consentimiento de cookies al primer acceso, con opciones granulares (técnicas / analíticas / marketing). | Antes de aceptar, no se cargan scripts de Meta Pixel ni GA. Tras aceptar, sí. | Alta | F1 |
| RF-A-10 | Donde el visitante interactúe con la demo del widget, el sistema deberá mostrar un CTA contextual *"Quiero esto en mi web"* que pre-rellena el formulario de signup con la provincia detectada. | Tras completar la demo, aparece el CTA con cookie de tracking y al hacer click `/signup?provincia=X` se pre-rellena. | Media | F1 |

### Superficie B — Landing B2C (cliente final del reformista)

Objetivo: capturar inmediatamente el lead (teléfono) y sus fotos para disparar la llamada en <2 minutos.

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-B-01 | El sistema deberá mostrar un hero con headline *"Recibe tu presupuesto de reforma en 5 minutos. Te llamamos en menos de 2."* y un CTA primario *"Llámame en 2 minutos"*. | DOM muestra el `<h1>` con el texto y el CTA hace scroll/abre al paso 1 del formulario. | Alta | F1 |
| RF-B-02 | El sistema deberá mostrar una imagen antes/después con copy *"Envíanos tu foto y ve cómo quedará tu reforma en 5 minutos"*. | DOM muestra un componente con dos imágenes (original + renderizada) y el texto. | Alta | F1 |
| RF-B-03 | El sistema deberá mostrar branding del reformista (logo + nombre + provincia) en el header del widget. | DOM muestra `<img>` del logo cargado y nombre de empresa. En MVP, el branding es "Reformas Ejemplo" hardcoded. | Alta | F1 |
| RF-B-04 | El sistema deberá mostrar un formulario de paso 1 con campos: nombre, teléfono (España), email, opt-in LSSI-CE (separado), opt-in RGPD, opt-in grabación. | Los 3 opt-ins son checkboxes independientes, no pre-marcados; el submit está deshabilitado si falta cualquiera. | Alta | F1 |
| RF-B-05 | Cuando el formulario del paso 1 se envíe con datos válidos, el sistema deberá persistir el lead en estado `pending_photos` y avanzar al paso 2 en <2 s. | Inspección de DB: nuevo registro `leads` con status correcto. UI cambia a paso 2 antes de 2 s. | Alta | F1 |
| RF-B-06 | El sistema deberá mostrar un componente de subida de fotos (paso 2) que acepte entre 2 y 4 imágenes JPG/PNG/HEIC. | UI rechaza con error inline si <2 o >4 fotos, o si el tipo MIME no es válido. | Alta | F1 |
| RF-B-07 | Donde el cliente incluya un DIN-A4 visible en una foto, el sistema deberá detectarlo automáticamente e indicarlo como input al pipeline de medidas. | Test con foto que contiene DIN-A4: detección flag `has_din_a4 = true` en metadata del lead. Sin DIN-A4: `false`. | Media | F2 |
| RF-B-08 | Cuando se complete el paso 2 (fotos subidas), el sistema deberá mostrar una pantalla de confirmación con cuenta atrás *"Te llamamos en <X> minutos desde <número provincial>"*. | UI muestra el número provincial real (no placeholder) y un timer visible. | Alta | F1 |
| RF-B-09 | El sistema deberá mostrar un disclaimer claro *"El presupuesto que recibirás es orientativo. El presupuesto definitivo lo confirma tu reformista en visita gratuita"* en el paso 2 antes del envío. | Texto literal presente en DOM, visible sin scroll en el viewport del paso 2. | Alta | F1 |
| RF-B-10 | Si el navegador del cliente bloquea cookies de tracking, entonces el sistema deberá seguir funcionando para captura de lead y envío de llamada (degradación). | Test con cookies bloqueadas: form + subida de fotos + disparo de llamada funcionan, solo se pierde la analítica. | Alta | F1 |

### Superficie C — Funnel B2C (los 5 pasos del flujo de presupuesto)

Objetivo: ejecutar el flujo punta a punta desde que el cliente sube fotos hasta que recibe el render + presupuesto por WhatsApp.

#### C.1 — Captura del lead

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-C-01 | El sistema deberá validar el formato del teléfono español (E.164 o nacional) antes de aceptar el lead. | Submit con `+34666...` o `666...` válido pasa; con `123` o vacío muestra error inline. | Alta | F1 |
| RF-C-02 | El sistema deberá almacenar timestamp, IP y user-agent del consentimiento LSSI-CE y RGPD al crear el lead. | Inspección DB: registro `consents` con los 3 campos rellenos por lead. | Alta | F1 |
| RF-C-03 | Si el teléfono del lead aparece en la Lista Robinson, entonces el sistema deberá cancelar la llamada saliente, registrar `robinson_blocked = true` y enviar email al cliente con un formulario asíncrono para que solicite la llamada explícitamente. | Test con número simulado en Robinson: no se dispara llamada, registro DB tiene flag, email enviado. | Alta | F2 |

#### C.2 — Subida y procesamiento de fotos

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-C-04 | El sistema deberá subir las fotos a S3 con cifrado at-rest y guardar las URLs en el registro del lead. | Inspección S3: objetos con `ServerSideEncryption=AES256` y bucket privado. DB: array `photo_urls` con N entradas. | Alta | F2 |
| RF-C-05 | El sistema deberá ejecutar GPT-4o Vision sobre las fotos para extraer: tipo de espacio, materiales actuales detectados, condición de iluminación, dimensiones aproximadas. | Llamada API devuelve JSON con esos 4 campos en <8 s p95. | Alta | F2 |
| RF-C-06 | El sistema deberá rechazar fotos > 10 MB y reescalar a un máximo de 2048 px en el lado mayor antes del procesamiento. | Test con foto 15 MB: rechazada con mensaje claro. Test con 4000 px: reescalada antes de enviar a Vision. | Alta | F2 |

#### C.3 — Pre-llamada (SMS + WhatsApp)

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-C-07 | Cuando el lead complete el paso 2, el sistema deberá enviar un SMS al cliente con el texto *"En 2 minutos te llama [Reformista] desde [número provincial] para tu presupuesto"* vía Zadarma. | Test E2E: SMS recibido en <30 s con el texto correcto y el número real. | Alta | F2 |
| RF-C-08 | Cuando el lead complete el paso 2, el sistema deberá enviar un mensaje WhatsApp equivalente al SMS, vía Evolution API o WhatsApp Business API. | Test E2E: WhatsApp recibido en <30 s con el texto y desde un número Business. | Alta | F2 |
| RF-C-09 | Si la hora local del cliente está fuera del horario permitido (lun-vie 9-21, sáb 9-14), entonces el sistema deberá programar la llamada para el siguiente slot válido y avisar por SMS/WhatsApp con la hora estimada. | Test E2E: form completado a las 23:00 → llamada programada al día siguiente 9:00 y avisos enviados. | Alta | F2 |

#### C.4 — Llamada del agente de voz

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-C-10 | Cuando se complete el paso 2 dentro del horario permitido, el sistema deberá disparar una llamada saliente del agente Retell desde un número fijo provincial Zadarma en ≤ 2 minutos. | Test E2E: tiempo entre submit y ringing del móvil < 120 s p95. | Alta | F2 |
| RF-C-11 | Mientras la llamada esté activa, el sistema deberá grabar el audio en S3 con cifrado at-rest y retención máxima 12 meses. | Inspección S3: archivo de audio por llamada, cifrado, con metadata de retención. | Alta | F2 |
| RF-C-12 | El sistema deberá iniciar la llamada con el aviso *"Hola, soy el asistente virtual de [Reformista]. Esta llamada va a ser grabada y transcrita para generar tu presupuesto. ¿Te parece bien que sigamos?"*. | Transcripción del primer turno del agente contiene literalmente esos componentes. | Alta | F2 |
| RF-C-13 | Si el cliente responde "no" al aviso de grabación, entonces el sistema deberá colgar educadamente, borrar la grabación parcial y marcar el lead como `consent_revoked`. | Test E2E: respuesta "no" → llamada termina en <15 s, audio borrado, flag en DB. | Alta | F2 |
| RF-C-14 | El sistema deberá generar el script del agente desde la configuración del reformista (tipos de reforma, opciones disponibles, tabla de precios, branding). | Cambiar configuración del reformista de "baño" a "cocina" cambia el primer prompt del agente sin redeploy. | Alta | F2 |
| RF-C-15 | El agente deberá recopilar obligatoriamente: tipo de reforma, m² aproximados, calidad (B/M/P), presupuesto target, urgencia, cambios estructurales (sanitarios / muros / distribución), preferencias estéticas. | JSON de salida tras la llamada contiene los 7 campos no nulos en > 80 % de llamadas completadas. | Alta | F2 |
| RF-C-16 | Si la duración de la llamada supera los 8 minutos, entonces el sistema deberá cerrar la conversación educadamente y proceder al pipeline con la info parcial. | Test E2E con timeout simulado: llamada cierra en ≤ 8:30 y pipeline arranca. | Alta | F2 |
| RF-C-17 | Si el cliente no descuelga, entonces el sistema deberá reintentar la llamada a los 30 minutos y a las 4 horas (máximo 3 intentos en total). | Test E2E con simulación de no-answer: registros de 3 intentos con timestamps correctos. | Alta | F2 |
| RF-C-18 | Cuando la llamada termine, el sistema deberá transcribir el audio y extraer las entidades estructuradas en JSON usando GPT-4o en <10 s p95. | Test con audio de 4 min: JSON estructurado disponible en DB en <10 s tras colgar. | Alta | F2 |

#### C.5 — Pipeline post-llamada y entrega

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-C-19 | Cuando se cierre la llamada y exista transcripción + fotos, el sistema deberá generar un render IA antes/después con Nano Banana 2 / Image 2. | Test E2E: archivo de imagen generado en S3, URL accesible en DB, en <30 s tras transcripción. | Alta | F2 |
| RF-C-20 | Si la generación de render falla (timeout o error), entonces el sistema deberá reintentar con un proveedor alternativo (Replicate SDXL + ControlNet) y, si también falla, entregar un placeholder con disclaimer. | Test con Nano Banana caído: fallback ejecutado, render generado o placeholder visible. | Alta | F2 |
| RF-C-21 | El sistema deberá calcular el presupuesto desglosado por partidas (demolición, alicatado, fontanería, electricidad, carpintería, mano de obra, extras, licencia si aplica) aplicando la tabla de precios del reformista y el factor multiplicador por zona. | Test con inputs conocidos: el desglose coincide con el cálculo manual ±1 €. | Alta | F2 |
| RF-C-22 | Donde el agente haya detectado cambios estructurales (movimiento de sanitarios principales, derribo de muros, cambio de distribución), el sistema deberá sumar al presupuesto un rango estimado de licencia urbanística + proyecto técnico (300-1.500 €) e incluir mensaje informativo. | Test E2E con flag `structural_change=true`: presupuesto incluye partida `Licencia + Proyecto técnico` con rango. | Alta | F2 |
| RF-C-23 | El sistema deberá generar un PDF del presupuesto con branding del reformista (logo, nombre, contacto, disclaimer orientativo) usando react-pdf o Puppeteer. | Test: PDF generado, abre sin errores, contiene los elementos visuales esperados. | Alta | F2 |
| RF-C-24 | Cuando el render + PDF estén listos, el sistema deberá entregar al cliente por WhatsApp el render + PDF + CTA *"Quiero visita gratuita"* en <60 s tras finalizar la llamada. | Test E2E: tiempo entre colgar y recibir WhatsApp con los 3 elementos < 60 s p95. | Alta | F2 |
| RF-C-25 | Cuando el lead esté procesado, el sistema deberá enviar un email vía SMTP al reformista con todos los artefactos (datos del cliente + transcripción + entidades + URL render + PDF) y crear el registro en su panel. | Test E2E: email recibido en <2 min y nuevo lead visible en panel del reformista. | Alta | F2 |
| RF-C-26 | El sistema deberá tracear en PostHog los eventos del funnel (`b2c_landing_view`, `form_step1_completed`, `form_step2_completed`, `precall_sms_sent`, `precall_whatsapp_sent`, `call_started`, `call_completed`, `call_no_answer`, `render_generated`, `budget_generated`, `whatsapp_delivered`, `client_requested_visit`). | Inspección PostHog: los 12 eventos disparan en el flujo correspondiente con sus propiedades. | Alta | F2 |

#### C.6 — Upsell (path alternativo)

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-C-27 | Donde el cliente solicite *"callback inmediato"* desde la landing, el sistema deberá omitir la subida de fotos, disparar la llamada del agente y permitirle peticiones libres que se canalizan directamente al sistema de presupuestos. | Test E2E con callback inmediato: llamada disparada sin fotos, presupuesto generado solo a partir de la conversación. | Media | F2 |

### Superficie D — Panel del reformista

Objetivo: dar al reformista visibilidad de leads, capacidad de marcarlos y de cerrar el bucle de precisión introduciendo el precio final firmado.

| ID | Requisito (EARS) | Criterio de aceptación (binario) | Prioridad | Fase |
|---|---|---|---|---|
| RF-D-01 | El sistema deberá mostrar al reformista una lista de sus leads con columnas: fecha/hora, nombre cliente, teléfono, estado actual, presupuesto estimado, miniatura del render. | UI muestra tabla/cards con esas 6 columnas, ordenadas por fecha descendente por defecto. | Alta | F2 |
| RF-D-02 | Cuando el reformista abra un lead, el sistema deberá mostrar todos los artefactos: datos personales, transcripción de la llamada, JSON de entidades extraídas, render generado, PDF descargable, audio reproducible. | UI de detalle muestra todos los 6 artefactos y todos son interactivos (descargar/reproducir). | Alta | F2 |
| RF-D-03 | El sistema deberá permitir al reformista marcar el estado del lead entre: `Nuevo`, `Contactado`, `Visita agendada`, `Presupuesto enviado`, `Ganado`, `Perdido`. | Cambio de estado se persiste en DB y se refleja en la lista sin recargar página. | Alta | F2 |
| RF-D-04 | Cuando el reformista marque un lead como `Ganado`, el sistema deberá pedirle el **precio final firmado** y calcular la delta vs estimado, almacenándolo en la tabla `precision_history`. | Test E2E: marcar `Ganado` abre modal de precio final; al guardar, registro creado con `estimated`, `final`, `delta_pct`. | Alta | F2 |
| RF-D-05 | El sistema deberá proteger el panel mediante token único firmado (JWT) enviado por email tras la creación del lead o cuenta, con expiración 7 días renovable. | Test: acceso sin token devuelve 401; con token válido devuelve panel; con token expirado pide renovación por email. | Alta | F2 |
| RF-D-06 | El sistema deberá notificar al reformista por email (SMTP) cada vez que se cree un nuevo lead, en <2 min desde la finalización de la llamada. | Test E2E: tiempo entre `whatsapp_delivered` y recepción de email < 2 min p95. | Alta | F2 |
| RF-D-07 | El sistema deberá ofrecer al reformista un configurador de perfil con: nombre de empresa, logo, provincia/zona, tipos de reforma ofrecidos, opciones disponibles por tipo, tabla de precios editable, número WhatsApp Business propio (opcional). | UI con formulario completo; submit persiste en DB y regenera el script del agente. | Alta | F2 |
| RF-D-08 | Cuando el reformista modifique la configuración, el sistema deberá regenerar el script del agente en <5 s y ofrecer una demo de prueba de la llamada con su nuevo script. | Test E2E: cambio de tipo de reforma de "baño" a "cocina" → primer prompt del agente cambia en <5 s; botón "Probar llamada" hace ringing al móvil del reformista. | Media | F2 |

---

## Non-Functional Requirements (RNF)

### Performance

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-PERF-01 | El sistema deberá servir las landings con First Contentful Paint < 2 s. | FCP p95 < 2 s en red 3G throttled (Lighthouse mobile). |
| RNF-PERF-02 | El sistema deberá obtener score Lighthouse Performance ≥ 85 en las dos landings. | Lighthouse Performance score ≥ 85 (mobile y desktop). |
| RNF-PERF-03 | Cuando el cliente complete el formulario y subida de fotos, el sistema deberá disparar la llamada en ≤ 2 minutos. | Tiempo `form_step2_completed` → `call_started` < 120 s p95. |
| RNF-PERF-04 | Mientras se ejecute el pipeline post-llamada, el sistema deberá entregar render + presupuesto + PDF al WhatsApp del cliente en < 60 s tras colgar. | Tiempo `call_completed` → `whatsapp_delivered` < 60 s p95. |
| RNF-PERF-05 | El sistema deberá completar el flujo end-to-end del cliente (landing → recibir WhatsApp con render) en < 7 minutos. | Tiempo `b2c_landing_view` → `whatsapp_delivered` < 7 min p95. |

### Security

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-SEC-01 | El sistema deberá forzar HTTPS en todas las rutas (HSTS activado). | Inspección de headers: `Strict-Transport-Security: max-age=31536000`. |
| RNF-SEC-02 | El sistema deberá rate-limitar el formulario público de la landing B2C a 5 envíos/minuto por IP. | Test: 6 envíos en 60 s desde misma IP → 6º devuelve HTTP 429. |
| RNF-SEC-03 | El sistema deberá almacenar todas las grabaciones de audio y fotos del cliente en S3 con cifrado at-rest AES-256. | Inspección S3: `ServerSideEncryption=AES256` en todos los objetos. |
| RNF-SEC-04 | El sistema deberá almacenar secretos (API keys de Retell, ElevenLabs, OpenAI, etc.) en un secret manager, nunca en código ni env vars compartidas. | Audit del repo: 0 secretos hardcoded; variables vienen de Vercel env vars / vault. |
| RNF-SEC-05 | Si se detecta intento de SQL injection o XSS en el formulario, entonces el sistema deberá rechazar el input y registrar el intento. | Test con payload conocido: rechazado con HTTP 400 y log de seguridad. |
| RNF-SEC-06 | El sistema deberá proteger el panel del reformista con JWT con expiración 7 días renovable y rotación de secret cada 90 días. | Token expira a los 7 días reales; rotación de secret invalida tokens antiguos. |

### Usability

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-UX-01 | El sistema deberá ser usable a viewport 375 px (mobile) sin scroll horizontal. | Inspección visual en Chrome DevTools 375 px: ningún elemento sale del viewport. |
| RNF-UX-02 | El sistema deberá cumplir WCAG 2.1 nivel AA en las landings. | Audit con axe-core o Lighthouse Accessibility ≥ 95. |
| RNF-UX-03 | Cuando el cliente envíe el formulario con campos inválidos, el sistema deberá mostrar errores inline por campo en < 200 ms. | Test E2E: submit con email inválido → error visible bajo el campo en < 200 ms. |
| RNF-UX-04 | El sistema deberá usar voces ElevenLabs premium en español con entonación natural y manejo de interrupciones. | Auditoría subjetiva del equipo: ≥ 4/5 en escala "suena humano" sobre 10 llamadas test. |
| RNF-UX-05 | El sistema deberá soportar copia funcional de los datos del lead a portapapeles desde el panel del reformista (botón "Copiar teléfono", "Copiar email"). | UI tiene los botones; click copia el valor al portapapeles. |

### Reliability

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-REL-01 | El sistema deberá mantener uptime ≥ 99,5 % de las landings y del endpoint de captura de leads. | Status page tipo BetterStack reporta ≥ 99,5 % mensual. |
| RNF-REL-02 | Si Nano Banana 2 / Image 2 falla, entonces el sistema deberá conmutar automáticamente a Replicate (SDXL + ControlNet) sin intervención. | Test simulando fallo: pipeline completa con fallback en < 90 s. |
| RNF-REL-03 | Si Retell.ai cae, entonces el sistema deberá enviar al cliente un SMS/WhatsApp ofreciendo el formulario asíncrono y registrar el lead en estado `pending_retry`. | Test simulando fallo: cliente recibe mensaje y lead queda en cola. |
| RNF-REL-04 | El sistema deberá ejecutar backups automáticos diarios de Postgres con retención 30 días. | Cron de backup configurado; restauración test ejecutada al menos 1 vez antes del lanzamiento. |
| RNF-REL-05 | El sistema deberá usar una cola con reintentos exponenciales (1 s, 5 s, 30 s, 5 min) para todas las tareas asíncronas del pipeline. | Inspección de código: cola implementada con esta política. |

### Maintainability

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-MAINT-01 | El sistema deberá tener cobertura de tests ≥ 70 % en el motor de cálculo de presupuestos. | `vitest --coverage` sobre `src/budget/*` reporta ≥ 70 %. |
| RNF-MAINT-02 | El sistema deberá traceaer eventos en PostHog que cubran el 100 % del funnel definido en RF-C-26. | Inspección del dashboard PostHog: los 12 eventos están instrumentados y disparan en producción. |
| RNF-MAINT-03 | El sistema deberá documentar el formato del script del agente generado a partir de la configuración del reformista. | Archivo `docs/agent-script-format.md` describe el formato con ejemplo. |

### Budget

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-BUD-01 | El coste medio por lead procesado (llamada + render + presupuesto + entrega) deberá ser < 1,50 €. | Medición real sobre 100 leads test: media < 1,50 €. |
| RNF-BUD-02 | El coste fijo de infraestructura mensual en fase 0 deberá ser < 200 €/mes (excluyendo ads). | Suma facturas Vercel + Postgres + S3 + ElevenLabs base + GPT-4o base + Zadarma fijo < 200 €/mes. |
| RNF-BUD-03 | El margen bruto por tier deberá ser ≥ 70 % asumiendo uso completo de leads incluidos. | Cálculo: (Precio − COGS por leads incluidos) / Precio ≥ 0,70 para los 3 tiers. |

### Legal / Compliance

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-LEG-01 | El sistema deberá obtener consentimiento LSSI-CE explícito y separado para la llamada comercial. | Auditoría legal del formulario: opt-in en checkbox independiente, no pre-marcado. |
| RNF-LEG-02 | Cuando se inicie una llamada, el sistema deberá avisar de la grabación al inicio. | Transcripción del primer turno del agente contiene el aviso. |
| RNF-LEG-03 | El sistema deberá consultar la Lista Robinson antes de cada llamada saliente y registrar el resultado de la consulta. | Tabla `robinson_checks` con un registro por llamada intentada. |
| RNF-LEG-04 | El sistema deberá conservar las grabaciones máximo 12 meses y borrarlas automáticamente al cumplir el plazo. | Cron de borrado configurado y verificado con audit. |
| RNF-LEG-05 | Cuando el cliente hable con el agente, el sistema deberá identificarse como asistente virtual / IA (no humano), cumpliendo AI Act EU. | Auditoría del script: primera frase identifica al agente como "asistente virtual". |
| RNF-LEG-06 | El sistema deberá respetar el horario de llamadas permitido en España: lunes-viernes 9-21h, sábados 9-14h, domingos no. | Test E2E: form completado fuera de horario → llamada programada para siguiente slot válido. |
| RNF-LEG-07 | El sistema deberá publicar Política de Privacidad, Política de Cookies, Aviso Legal y T&C accesibles desde el footer de ambas landings. | URLs públicas devuelven HTTP 200 con contenido legal completo. |
| RNF-LEG-08 | El sistema deberá ofrecer al cliente y al reformista mecanismos de ejercer derechos RGPD (acceso, rectificación, supresión, portabilidad) en < 30 días. | Endpoint o email accesible que tramita la solicitud; SLA documentado. |
| RNF-LEG-09 | El sistema deberá firmar contrato de Encargado de Tratamiento con cada reformista antes de procesar leads para él. | Onboarding del reformista incluye paso de aceptación del contrato; registro en DB. |

### Scalability

| ID | Requisito (EARS) | Métrica |
|---|---|---|
| RNF-SCAL-01 | El sistema deberá soportar al menos 50 llamadas simultáneas durante el demo y la fase de validación. | Test de carga: 50 llamadas en paralelo sin degradación de latencia > 20 %. |
| RNF-SCAL-02 | El sistema deberá soportar al menos 500 envíos de formulario por hora. | Test de carga: 500 submits/h sin errores HTTP 5xx. |

---

## Constraints

- **Stack obligado** (decidido):
  - Frontend + Backend: Next.js 14 (App Router + Server Actions + API Routes)
  - UI: Tailwind + shadcn/ui
  - Agente voz: Retell.ai + ElevenLabs (voces premium ES)
  - Telefonía: Zadarma (números fijos provinciales España)
  - WhatsApp: Evolution API (primario) o WhatsApp Business API (respaldo)
  - Render IA: Nano Banana 2 / Image 2 (primario) + Replicate SDXL + ControlNet (fallback)
  - IA Texto + Vision: GPT-4o (OpenAI)
  - DB: Postgres
  - Storage: S3 (AWS / Cloudflare R2 / MinIO)
  - Email: SMTP genérico
  - Deploy: Vercel
  - Analytics: PostHog (+ Meta Pixel + GA en landings)
- **Equipo:** 4 personas (Carlos producto + voz + WhatsApp, Simon backend + IA + WhatsApp, Goyo motor presupuesto + dominio, Antonio UI/UX + creativos).
- **Tiempo:** 3 semanas (24-may → 11-jun) hasta demo MVP.
- **Geografía:** España. Idioma: castellano. Provincias prioritarias: Madrid + Barcelona + capitales > 100K hab.
- **Budget bootstrap inicial:** 2.500-5.000 € entre los 4 fundadores.
- **Demo del 11-jun:** "Reformas Ejemplo" hardcoded como reformista único. Multi-tenant real va a F1.5.

---

## Out of Scope (F1 + F2)

- **Configurador multi-tenant real** del reformista (hardcoded en MVP).
- ~~**Validación opcional del reformista** antes de que el cliente reciba el presupuesto.~~ → **Adelantada a F2 (implementada).** El panel permite elegir modo de envío (automático / revisión), editar los conceptos del presupuesto y revisar el PDF antes de enviarlo al cliente.
- **Nurturing y seguimiento del lead** por WhatsApp hasta concertar cita.
- **3 versiones simultáneas Básico/Medio/Premium** con selección granular por elemento.
- **Slider de presupuesto target** con auto-ajuste.
- **Refinamiento por lenguaje natural** ("quiero ducha en vez de bañera").
- **Cálculo automático preciso de m²** desde foto (en MVP usamos lo que indique el cliente + lo que infiera el agente).
- **Doble nomenclatura** asistida por IA (feature killer B2B, post-hackathon v2).
- **"Valora tu presupuesto justo"** (Fase 2 marketplace B2C, mes 9+).
- **Sello "Precio Justo Certificado"** (puente Fase 1 ↔ Fase 2).
- **App móvil nativa** (todo web responsive).
- **PDF con membrete custom** (MVP entrega PDF genérico con branding básico).
- **Integraciones CRM** (Holded, Stel, etc.).
- **Renders 3D fotorrealistas** de alta fidelidad.
- **Pasarela de pago activa** (en MVP solo waitlist + signup trial, sin cobro real).
- **Verifactu integration** (legal F1.5).
- **Asignación automática de leads en marketplace** (Fase 2).

---

## Traceability Matrix

> Plan, Code y Test se rellenan a medida que el proyecto avanza. Celdas vacías son señales: requirement sin Plan = olvidado en planificación; sin Test = no verificado.

### Landing B2B

| Requirement | Plan | Code | Test |
|---|---|---|---|
| RF-A-01 | — | — | — |
| RF-A-02 | — | — | — |
| RF-A-03 | — | — | — |
| RF-A-04 | — | — | — |
| RF-A-05 | — | — | — |
| RF-A-06 | — | — | — |
| RF-A-07 | — | — | — |
| RF-A-08 | — | — | — |
| RF-A-09 | — | — | — |
| RF-A-10 | — | — | — |

### Landing B2C

| Requirement | Plan | Code | Test |
|---|---|---|---|
| RF-B-01 | — | — | — |
| RF-B-02 | — | — | — |
| RF-B-03 | — | — | — |
| RF-B-04 | — | — | — |
| RF-B-05 | — | — | — |
| RF-B-06 | — | — | — |
| RF-B-07 | — | — | — |
| RF-B-08 | — | — | — |
| RF-B-09 | — | — | — |
| RF-B-10 | — | — | — |

### Funnel B2C

| Requirement | Plan | Code | Test |
|---|---|---|---|
| RF-C-01 | — | — | — |
| RF-C-02 | — | — | — |
| RF-C-03 | — | — | — |
| RF-C-04 | — | — | — |
| RF-C-05 | — | — | — |
| RF-C-06 | — | — | — |
| RF-C-07 | — | — | — |
| RF-C-08 | — | — | — |
| RF-C-09 | — | — | — |
| RF-C-10 | — | — | — |
| RF-C-11 | — | — | — |
| RF-C-12 | — | — | — |
| RF-C-13 | — | — | — |
| RF-C-14 | — | — | — |
| RF-C-15 | — | — | — |
| RF-C-16 | — | — | — |
| RF-C-17 | — | — | — |
| RF-C-18 | — | — | — |
| RF-C-19 | — | — | — |
| RF-C-20 | — | — | — |
| RF-C-21 | — | — | — |
| RF-C-22 | — | — | — |
| RF-C-23 | — | — | — |
| RF-C-24 | — | — | — |
| RF-C-25 | — | — | — |
| RF-C-26 | — | — | — |
| RF-C-27 | — | — | — |

### Panel reformista

| Requirement | Plan | Code | Test |
|---|---|---|---|
| RF-D-01 | — | — | — |
| RF-D-02 | — | — | — |
| RF-D-03 | — | — | — |
| RF-D-04 | — | — | — |
| RF-D-05 | — | — | — |
| RF-D-06 | — | — | — |
| RF-D-07 | — | — | — |
| RF-D-08 | — | — | — |

### Non-Functional

| Requirement | Plan | Code | Test |
|---|---|---|---|
| RNF-PERF-01 | — | — | Lighthouse CI |
| RNF-PERF-02 | — | — | Lighthouse CI |
| RNF-PERF-03 | — | — | — |
| RNF-PERF-04 | — | — | — |
| RNF-PERF-05 | — | — | — |
| RNF-SEC-01 | — | (config) | — |
| RNF-SEC-02 | — | — | — |
| RNF-SEC-03 | — | (config) | — |
| RNF-SEC-04 | — | (config) | audit |
| RNF-SEC-05 | — | — | — |
| RNF-SEC-06 | — | — | — |
| RNF-UX-01 | — | — | — |
| RNF-UX-02 | — | — | axe-core |
| RNF-UX-03 | — | — | — |
| RNF-UX-04 | — | — | review subjetiva |
| RNF-UX-05 | — | — | — |
| RNF-REL-01 | — | (config) | BetterStack |
| RNF-REL-02 | — | — | — |
| RNF-REL-03 | — | — | — |
| RNF-REL-04 | — | (config) | restore test |
| RNF-REL-05 | — | — | — |
| RNF-MAINT-01 | — | — | vitest coverage |
| RNF-MAINT-02 | — | — | — |
| RNF-MAINT-03 | — | — | — |
| RNF-BUD-01 | — | — | medición real |
| RNF-BUD-02 | — | — | audit facturas |
| RNF-BUD-03 | — | — | cálculo manual |
| RNF-LEG-01 | — | — | audit legal |
| RNF-LEG-02 | — | — | — |
| RNF-LEG-03 | — | — | — |
| RNF-LEG-04 | — | (config) | — |
| RNF-LEG-05 | — | — | — |
| RNF-LEG-06 | — | — | — |
| RNF-LEG-07 | — | — | — |
| RNF-LEG-08 | — | — | — |
| RNF-LEG-09 | — | — | — |
| RNF-SCAL-01 | — | — | load test |
| RNF-SCAL-02 | — | — | load test |

---

## Change Log

| Versión | Fecha | Cambio |
|---|---|---|
| 1.0 | 2026-05-24 | Versión inicial. 55 RF + 30 RNF distribuidos en 4 superficies (Landing B2B, Landing B2C, Funnel B2C, Panel reformista). Notación EARS aplicada. Fases F1 (Landings 28-may) + F2 (MVP 11-jun). |
