Files
motor-de-encuestas/docs/adr/ADR-005-esquema-declarativo-formularios.md

5.0 KiB

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.