# ADR-005 — Esquema declarativo de formularios y estrategia de dos fases > Para agregar a `ARCHITECTURE.md` (o `docs/adr/`). Estado: **Aceptada**. > Fecha: 2026-06-20 · Sprint 4 · Versión objetivo 3.0.0 --- ## Contexto El producto es un **motor de formularios/flujos de encuesta**. La aplicación actual (encuesta "Mapeo de Cuidadores") es su primer caso de uso real, pero la arquitectura debe servir al producto, no solo a este formulario. El rediseño a wizard v3 introduce lógica de flujo significativamente más compleja que v2: recorridos ramificados (cuidador completo / solo niño / sin vínculo), mini-wizard de instancias de vínculo familiar (preguntas que se repiten N veces, una por familiar), y saltos condicionales de sección. Existe una restricción de negocio: dos clientes inminentes en 10-20 días requieren la encuesta funcionando para validación. El esquema actual de `questions` ya posee una base declarativa: - `conditional_rules` JSONB con operadores `eq` / `eq_any` y acción `show` - Auto-target implícito (la regla afecta a la pregunta que la porta) - Tipos de pregunta extensibles vía CHECK constraint ## Problema ¿Dónde reside la lógica del flujo del formulario? Tres anti-patrones a evitar: 1. **Lógica en el presentador** (frontend con reglas hardcodeadas) — impide reutilización, genera bugs de sincronización de estado, no escala al producto. 2. **Lógica dispersa en columnas sueltas** de la base — deuda técnica; no soporta evolución a flujos más complejos sin migrar el esquema entero. 3. **Sobre-ingeniería prematura** — construir un motor genérico universal para casos hipotéticos antes de conocerlos, retrasando el deadline real. ## Decisión **La lógica del flujo vive en una capa de definición declarativa (datos), interpretada por un motor en el backend, y renderizada por un frontend sin reglas de negocio.** Se adopta una **estrategia de dos fases**: ### Fase 1 (Sprint 4 — para el deadline) - El formulario de cuidadores se define como **esquema declarativo persistido**, extendiendo el `conditional_rules` JSONB existente y agregando campos declarativos de instanciación a `questions`. - Se construye un motor de resolución de flujo **para este formulario** (interpreta el esquema; calcula qué pantalla sigue desde esquema + estado). - El frontend wizard es un **renderer** del esquema, sin reglas de negocio. - NO se construye el intérprete genérico universal todavía. ### Fase 2 (sprints posteriores — post-deadline, registrada en BACKLOG) - Se extrae el intérprete a un **motor genérico de formularios**. - El formulario de cuidadores, ya definido como esquema, se vuelve el primer caso de prueba del motor — sin reescribir el contrato. ### Diseño técnico del esquema (Fase 1) Se extiende `questions` en lugar de crear una tabla de definición separada: - `conditional_rules` extendido con nuevos operadores (`not_in`, acción `hide`) para expresar saltos como "Ninguno → salta a sección final". - Nuevos campos declarativos para instanciación: - `instance_generator` — marca la pregunta que genera instancias (ej. 4.1) - `instance_of` — código del generador del que depende una pregunta (ej. 4.2 → "4.1") - Representación de secciones con nombre y descripción (el "porqué"). ## Alternativas consideradas 1. **Lógica en el frontend (rechazada):** rápida para este formulario, pero viola el principio de producto, no escala, y reproduce los bugs de sincronización ya vistos en el mockup. 2. **Columnas sueltas tipo `is_instanced` (rechazada):** resuelve hoy, genera deuda; no soporta flujos más complejos sin migración de esquema. 3. **Motor genérico universal ahora (rechazada):** arquitectónicamente deseable como fin, pero sobre-ingeniería antes del deadline y con un solo caso de uso conocido (diseñar en el vacío). Se difiere a Fase 2 cuando haya más casos que informen el diseño abstracto. 4. **Tabla de definición de flujo separada (diferida):** posible mejor forma para el motor genérico, pero para un solo formulario es sobre-ingeniería. Se reevalúa en Fase 2. ## Consecuencias **Positivas:** - Entrega la encuesta en plazo sin generar retrabajo estructural. - La lógica en datos habilita guardado parcial, reanudación, validación consistente y progreso preciso — mejor UX, fuente única de verdad del estado. - La Fase 2 es generalización del intérprete, no reescritura del contrato. - El esquema declarativo es versionable y auditable. **Negativas / deuda intencional:** - Fase 1 es más trabajo que parchear el formulario actual. - El motor de Fase 1 es específico a este formulario (no genérico) — deuda registrada en BACKLOG, asumida conscientemente, no oculta. - Extender `conditional_rules` puede requerir reevaluación cuando lleguen flujos con lógica que el vocabulario actual de operadores no exprese. ## Cumplimiento (cómo se verifica) - Revisión de código: el frontend wizard NO contiene reglas de flujo del negocio. - El flujo es reproducible desde el esquema persistido. - La deuda de Fase 2 figura en `BACKLOG.md`.