Compare commits
4 Commits
v2.1.0-sta
...
a4287a122e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4287a122e | ||
|
|
6db211b9aa | ||
|
|
d50c31f8f4 | ||
|
|
d6be2b5c6b |
@@ -77,11 +77,15 @@ Principios estructurales (de ADR-001):
|
|||||||
- **Umbral de k-anonimato** obligatorio en toda visualización compartida (nunca mostrar celda con
|
- **Umbral de k-anonimato** obligatorio en toda visualización compartida (nunca mostrar celda con
|
||||||
n < umbral).
|
n < umbral).
|
||||||
|
|
||||||
## 6. ADRs iniciales
|
## 6. ADRs
|
||||||
|
|
||||||
|
Ver `docs/adr/` para los archivos completos.
|
||||||
|
|
||||||
- **ADR-001** — Modelo de privacidad y gobierno de datos *(el corazón del producto)*.
|
- **ADR-001** — Modelo de privacidad y gobierno de datos *(el corazón del producto)*.
|
||||||
- **ADR-002** — Stack tecnológico y residencia de datos.
|
- **ADR-002** — Stack tecnológico y residencia de datos.
|
||||||
- **ADR-003** — Consentimiento granular versionado e inmutable.
|
- **ADR-003** — Consentimiento granular versionado e inmutable.
|
||||||
|
- **ADR-004** — Capa de identidad y autenticación (SSO Keycloak para staff; sin login para respondentes).
|
||||||
|
- **ADR-005** — Esquema declarativo de formularios y estrategia de dos fases (Sprint 4). La lógica del flujo vive en datos (JSONB), interpretada por un motor backend; el frontend wizard es un renderer sin reglas de negocio. Motor genérico diferido a Fase 2.
|
||||||
|
|
||||||
## 7. Riesgos
|
## 7. Riesgos
|
||||||
|
|
||||||
|
|||||||
24
BACKLOG.md
24
BACKLOG.md
@@ -7,6 +7,19 @@
|
|||||||
|
|
||||||
## Seguridad
|
## Seguridad
|
||||||
|
|
||||||
|
### [SEC-002] Sprint de compliance & seguridad
|
||||||
|
- **Estado:** Diferido — pendiente de priorizar tras Sprint 4
|
||||||
|
- **Contexto:** COMPLIANCE.md documenta el estado actual de seguridad (v2.1.0) y el roadmap
|
||||||
|
de hardening. Antes de escalar a más empresas o datos reales, se requiere un sprint dedicado.
|
||||||
|
- **Ítems principales (ver COMPLIANCE.md secciones 5 y 6):**
|
||||||
|
- Registro de auditoría append-only (log inmutable de operaciones sensibles)
|
||||||
|
- Hashing SHA-256 de integridad de respuestas (detección de tampering sin blockchain)
|
||||||
|
- Cifrado en reposo a nivel de volumen/disco de la base de datos
|
||||||
|
- Roadmap de hardening por capas: aplicación, autenticación, datos, infraestructura,
|
||||||
|
observabilidad y proceso (revisión periódica de CVEs, pen testing)
|
||||||
|
- **Dependencia:** no bloquea Sprint 4; sí bloquea escalar a producción masiva.
|
||||||
|
- **Ver:** `COMPLIANCE.md` secciones 5 y 6.
|
||||||
|
|
||||||
### [SEC-001] Actualizar Next.js — CVE pendiente en 15.3.3
|
### [SEC-001] Actualizar Next.js — CVE pendiente en 15.3.3
|
||||||
- **Estado:** Pendiente
|
- **Estado:** Pendiente
|
||||||
- **Prioridad:** Alta
|
- **Prioridad:** Alta
|
||||||
@@ -58,6 +71,17 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### [BACKLOG-002] Fase 2 — Motor genérico de formularios
|
||||||
|
- **Estado:** Diferido post-deadline
|
||||||
|
- **Contexto:** En Sprint 4 se construye un intérprete del esquema declarativo específico
|
||||||
|
para el formulario de cuidadores (ADR-005, Fase 1). Una vez entregado ese caso, el
|
||||||
|
intérprete se extrae a un motor universal que interprete cualquier esquema definido en
|
||||||
|
`questions.conditional_rules` + campos de instanciación, sin hardcodear ningún formulario.
|
||||||
|
El formulario de cuidadores se vuelve el primer caso de prueba del motor sin reescribir
|
||||||
|
el contrato de datos.
|
||||||
|
- **Dependencia:** Fase 1 completada (Sprint 4 — wizard funcional).
|
||||||
|
- **Ver:** ADR-005 (`docs/adr/ADR-005-esquema-declarativo-formularios.md`).
|
||||||
|
|
||||||
- Dashboard / reportes (Sprint 3)
|
- Dashboard / reportes (Sprint 3)
|
||||||
- Formulario de consentimiento + persistencia de respuestas (Etapa 2B)
|
- Formulario de consentimiento + persistencia de respuestas (Etapa 2B)
|
||||||
- Builder visual de encuestas (post-validación del caso fijo)
|
- Builder visual de encuestas (post-validación del caso fijo)
|
||||||
|
|||||||
58
CHANGELOG.md
Normal file
58
CHANGELOG.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Changelog — Datos País sobre el Cuidado
|
||||||
|
|
||||||
|
Todas las versiones notables de este proyecto se documentan en este archivo.
|
||||||
|
|
||||||
|
El formato sigue [Keep a Changelog](https://keepachangelog.com/es/1.1.0/)
|
||||||
|
y el proyecto adhiere a [Versionado Semántico](https://semver.org/lang/es/).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [No publicado] — Sprint 4: Formulario Wizard v3
|
||||||
|
|
||||||
|
En desarrollo en `main`. Cambio mayor: reescritura del formulario a wizard
|
||||||
|
pregunta-por-pantalla con instancias de vínculo familiar.
|
||||||
|
|
||||||
|
### Por agregar
|
||||||
|
- Wizard pregunta-por-pantalla para todo el formulario
|
||||||
|
- Instrumento v3: 10 secciones, mini-wizard anidado para vínculos familiares
|
||||||
|
- Columna `instance_id` en `answers` para datos multi-instancia
|
||||||
|
- Autocomplete de barrios desde dataset INE/DGEEC
|
||||||
|
- Subtítulos explicativos del "porqué" por sección
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [2.1.0] — 2026-06-16
|
||||||
|
|
||||||
|
Versión estable preservada en la rama `v2.1.0-stable`. Última versión del
|
||||||
|
formulario lineal antes del rediseño a wizard.
|
||||||
|
|
||||||
|
### Agregado
|
||||||
|
- Dashboard multitenante con selector de empresa (Todos / InQuality / Fundación / Demo)
|
||||||
|
- Flag `p_all` (UUID cero) para vista agregada de todos los surveys
|
||||||
|
- Vista de control `/admin/responses` con tabla plana, filtro por empresa,
|
||||||
|
colapsar/expandir por submission
|
||||||
|
- Dos encuestas piloto: InQuality y Fundación Solidaridad (organizaciones separadas)
|
||||||
|
- Método formalizado: `method/PATTERNS.md` y `method/ANTI_PATTERNS.md`
|
||||||
|
(patrones C.8, AP.10, AP.11)
|
||||||
|
|
||||||
|
### Cambiado
|
||||||
|
- Instrumento actualizado a v2.1 (feedback equipo médico): salto triple,
|
||||||
|
nueva pregunta 6.6, eliminación de "Prefiero no decir", 2.4 eliminada,
|
||||||
|
2.1 a multiple_choice
|
||||||
|
- Next.js actualizado a 15.3.8 (pin exacto)
|
||||||
|
|
||||||
|
### Seguridad
|
||||||
|
- Resuelto CVE-2025-66478 (+ advisory posterior CVE-2025-55183/55184/67779)
|
||||||
|
|
||||||
|
### Infraestructura
|
||||||
|
- Migración completa a Supabase self-hosted en Dokploy
|
||||||
|
- Backups GFS locales con retención de 3 días + domingos 14 días
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [2.0.0] — 2026-06 (anterior)
|
||||||
|
|
||||||
|
Primera versión en producción con Supabase self-hosted.
|
||||||
|
- Formulario lineal de 44 preguntas
|
||||||
|
- Dashboard con 11 widgets y k-anonimato (k≥5)
|
||||||
|
- Instrumento v2 (44 preguntas, 8 secciones)
|
||||||
141
COMPLIANCE.md
Normal file
141
COMPLIANCE.md
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# COMPLIANCE.md — Cumplimiento, seguridad y auditabilidad
|
||||||
|
|
||||||
|
> Documento vivo. Área: Compliance & Seguridad del producto "Datos País sobre el Cuidado".
|
||||||
|
> Audiencia: dirección técnica, auditores externos, equipo legal, clientes (resumen).
|
||||||
|
> Última actualización: 2026-06-20 · Versión del producto: 2.1.0 (prod) / 3.0.0 (desarrollo)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Principio rector de seguridad
|
||||||
|
|
||||||
|
**No existe un sistema "imposible de hackear". El objetivo es defensa en profundidad:**
|
||||||
|
encarecer progresivamente el ataque, minimizar la superficie expuesta, contener el daño
|
||||||
|
si una capa cae, y garantizar trazabilidad para detectar, auditar y reconstruir cualquier
|
||||||
|
incidente. Toda afirmación de inviolabilidad absoluta se considera, en sí misma, una
|
||||||
|
señal de inmadurez en seguridad.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Naturaleza de los datos y marco normativo
|
||||||
|
|
||||||
|
### 2.1 Clasificación de datos
|
||||||
|
- **Datos sensibles** (salud, discapacidad): preguntas marcadas `is_sensitive=true`
|
||||||
|
(Sección de prevalencia, condición propia y de familiares).
|
||||||
|
- **Cuasi-identificadores**: departamento, ciudad, sector, rango etario, género.
|
||||||
|
- **Dato confidencial restringido**: franja salarial (analyst-only, nunca en vistas de empresa).
|
||||||
|
- **NO se recogen identificadores directos**: sin nombre, documento, email ni teléfono
|
||||||
|
en la encuesta anónima. La encuesta es anónima por diseño.
|
||||||
|
|
||||||
|
### 2.2 Marco normativo aplicable (Paraguay)
|
||||||
|
- Ley N° 6534/2020 de Protección de Datos Personales Crediticios y normativa de datos
|
||||||
|
personales aplicable en Paraguay.
|
||||||
|
- Principios alineados a estándares internacionales (minimización, finalidad, consentimiento).
|
||||||
|
- **Pendiente de revisión legal formal** con el equipo de Fundación Solidaridad / asesoría legal.
|
||||||
|
|
||||||
|
### 2.3 Consentimiento
|
||||||
|
- Registrado en tablas `consent_records` + `consent_versions` con versión y timestamp.
|
||||||
|
- Doble propósito separado y autorizable independientemente: diagnóstico interno de empresa
|
||||||
|
(requerido) y estudio país (opcional).
|
||||||
|
- Por ser anónima, la encuesta no permite revocación post-envío (no hay forma de localizar
|
||||||
|
una respuesta individual) — comunicado explícitamente al participante en el consentimiento.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Anonimato y protección contra reidentificación
|
||||||
|
|
||||||
|
### 3.1 k-anonimato (k ≥ 5)
|
||||||
|
- Regla no negociable del sistema: ningún corte de datos con menos de 5 respuestas se muestra.
|
||||||
|
- Implementado en las RPCs del dashboard (`SECURITY DEFINER`), no en el frontend.
|
||||||
|
- Estados de supresión: `suppressed` con `n` real solo a nivel agregado.
|
||||||
|
|
||||||
|
### 3.2 Separación de datos sensibles
|
||||||
|
- Franja salarial (3.4 / 8.4 según versión): nunca expuesta en vistas de empresa
|
||||||
|
ni en `/admin/responses`.
|
||||||
|
- Política RLS `deny_sensitive` a nivel de base de datos.
|
||||||
|
- Vista de control `/admin/responses` excluye `is_sensitive=true` y `text_long` a nivel
|
||||||
|
de query, no de presentación (los valores no llegan al servidor).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Seguridad — estado actual (v2.1.0)
|
||||||
|
|
||||||
|
### 4.1 Implementado
|
||||||
|
- **Cifrado en tránsito**: TLS/SSL vía Kong + Traefik (Let's Encrypt) en `db.inqualityhq.com`
|
||||||
|
y `economia-cuidado.inqualityhq.com`.
|
||||||
|
- **Soberanía del dato**: Supabase self-hosted en infraestructura propia (VPS controlado),
|
||||||
|
no en nube de terceros. Decisión arquitectónica fundacional.
|
||||||
|
- **RLS (Row Level Security)**: políticas activas en tablas sensibles; el rol `anon` solo
|
||||||
|
puede insertar respuestas, no leer datos de otros.
|
||||||
|
- **Service role aislado**: la clave de servicio nunca llega al bundle del cliente
|
||||||
|
(verificado: vistas server-side, no Client Components con la key).
|
||||||
|
- **Gestión de vulnerabilidades**: CVE-2025-66478 resuelto (Next.js 15.3.8, pin exacto).
|
||||||
|
- **Backups**: GFS local (3 días diarios + domingos 14 días), restore probado.
|
||||||
|
- **Aislamiento de red**: Studio de administración solo accesible vía SSH tunnel, no expuesto.
|
||||||
|
|
||||||
|
### 4.2 Deuda de seguridad registrada (ver TECH_DEBT.md)
|
||||||
|
- **TECH-DEBT-006**: backup remoto S3 — sin réplica off-site, riesgo ante pérdida del VPS.
|
||||||
|
Bloqueante antes del primer dato real de empresa.
|
||||||
|
- **TECH-DEBT-008**: `/admin/responses` sin autenticación — mitigado por URL no publicada,
|
||||||
|
pero requiere gate de auth antes de exponer.
|
||||||
|
- **TECH-DEBT-009**: rotación de secrets Supabase post-CVE — pendiente.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Auditabilidad y trazabilidad (roadmap)
|
||||||
|
|
||||||
|
> Objetivo: ante una auditoría o un incidente, poder responder "quién accedió a qué,
|
||||||
|
> cuándo, y demostrar que un registro no fue alterado".
|
||||||
|
|
||||||
|
### 5.1 Pendiente de diseño e implementación (BACKLOG — sprint de compliance)
|
||||||
|
- **Registro de auditoría append-only**: log inmutable de operaciones sensibles
|
||||||
|
(accesos a datos sensibles, cambios de configuración, ejecución de migraciones).
|
||||||
|
- **Hashing de integridad (SHA-256)**: hash de los registros de respuesta para demostrar
|
||||||
|
no-alteración, encadenable para detección de tampering. Provee el beneficio probatorio
|
||||||
|
de inmutabilidad SIN los costos de blockchain.
|
||||||
|
- **Cifrado en reposo**: cifrado a nivel de volumen/disco de la base de datos.
|
||||||
|
- **Trazabilidad de cambios de datos**: tablas de historial con triggers, o aprovechamiento
|
||||||
|
del WAL de PostgreSQL para reconstrucción temporal.
|
||||||
|
|
||||||
|
### 5.2 Por qué NO blockchain (decisión registrada)
|
||||||
|
Blockchain aporta valor cuando se requiere registro inmutable verificable entre partes
|
||||||
|
que NO confían entre sí, sin autoridad central legítima. En este sistema la confianza
|
||||||
|
está legítimamente centralizada (InQuality es responsable y operador soberano del dato),
|
||||||
|
por lo que blockchain no resuelve ningún problema real que no esté mejor resuelto por
|
||||||
|
audit logs + hashing. Además, su inmutabilidad absoluta entra en CONFLICTO con el derecho
|
||||||
|
de rectificación y supresión exigido por la normativa de protección de datos. Se descarta
|
||||||
|
por inadecuación técnica y normativa, no por desconocimiento.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Roadmap de hardening de seguridad (a evaluar en sprint de compliance)
|
||||||
|
|
||||||
|
> Defensa en profundidad — capas a evaluar e implementar gradualmente.
|
||||||
|
|
||||||
|
- **Capa de aplicación**: validación y sanitización de inputs, protección contra inyección
|
||||||
|
(parametrización ya usada vía PostgREST/Supabase), rate limiting en endpoints públicos,
|
||||||
|
headers de seguridad (CSP, HSTS, X-Frame-Options).
|
||||||
|
- **Capa de autenticación**: gate de auth para vistas administrativas, rotación de secretos,
|
||||||
|
gestión de sesiones robusta cuando se introduzcan roles autenticados.
|
||||||
|
- **Capa de datos**: cifrado en reposo, RLS exhaustivo, principio de mínimo privilegio en roles.
|
||||||
|
- **Capa de infraestructura**: firewall, fail2ban, actualizaciones de SO, monitoreo de
|
||||||
|
intrusiones, segmentación de red.
|
||||||
|
- **Capa de observabilidad**: logs centralizados, alertas ante patrones anómalos,
|
||||||
|
registro de auditoría (sección 5).
|
||||||
|
- **Proceso**: revisión periódica de dependencias (`npm audit`), gestión de CVEs,
|
||||||
|
pruebas de penetración antes de escalar a producción masiva.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Responsabilidades
|
||||||
|
|
||||||
|
- **Responsable del dato**: InQuality (operador de infraestructura y autoridad del dato).
|
||||||
|
- **Aliado institucional**: Fundación Solidaridad.
|
||||||
|
- **Revisión legal**: pendiente de formalizar con asesoría legal especializada en
|
||||||
|
protección de datos en Paraguay.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Historial de revisiones de este documento
|
||||||
|
| Fecha | Versión producto | Cambio |
|
||||||
|
|---|---|---|
|
||||||
|
| 2026-06-20 | 2.1.0 / 3.0.0-dev | Creación inicial. Estado de seguridad v2.1.0, roadmap de auditabilidad, decisión sobre blockchain. |
|
||||||
@@ -106,9 +106,20 @@ id uuid pk
|
|||||||
response_id uuid fk -> responses(id)
|
response_id uuid fk -> responses(id)
|
||||||
question_id uuid fk -> questions(id)
|
question_id uuid fk -> questions(id)
|
||||||
value jsonb not null -- texto: "x" | matriz: {"rows":{...}} | ranking: [3,1,2] | etc.
|
value jsonb not null -- texto: "x" | matriz: {"rows":{...}} | ranking: [3,1,2] | etc.
|
||||||
|
instance_id text not null default 'default'
|
||||||
|
-- 'default' → preguntas normales (la gran mayoría)
|
||||||
|
-- 'familiar_1', 'familiar_2', ... → instancias del mini-wizard de vínculos (4A, Sprint 4)
|
||||||
|
UNIQUE (response_id, question_id, instance_id) -- constraint: answers_response_question_instance_key
|
||||||
```
|
```
|
||||||
> El texto libre (`text_long`) **no** se expone al store analítico crudo: la capa de reportes lee
|
> El texto libre (`text_long`) **no** se expone al store analítico crudo: la capa de reportes lee
|
||||||
> categorías derivadas, no `value` crudo de preguntas abiertas (regla no negociable #4).
|
> categorías derivadas, no `value` crudo de preguntas abiertas (regla no negociable #4).
|
||||||
|
>
|
||||||
|
> **Patrón `instance_id` (v3.0.0):** la pregunta 4.1 ("¿Tenés familiar con discapacidad/adulto
|
||||||
|
> mayor a cargo?") dispara el mini-wizard. Por cada familiar declarado se genera un conjunto de
|
||||||
|
> respuestas para las preguntas 4.2, 4.3, etc., cada una con su propio `instance_id`. Las RPCs
|
||||||
|
> de dashboard que agregan datos de vínculo operan sobre filas donde `instance_id != 'default'`.
|
||||||
|
> Las RPCs existentes de v2 no se modifican: siguen usando `instance_id = 'default'` implícitamente
|
||||||
|
> (las preguntas de vínculo no estaban en el instrumento v2).
|
||||||
|
|
||||||
### `consent_versions` — textos de consentimiento versionados
|
### `consent_versions` — textos de consentimiento versionados
|
||||||
```sql
|
```sql
|
||||||
|
|||||||
Binary file not shown.
102
docs/adr/ADR-005-esquema-declarativo-formularios.md
Normal file
102
docs/adr/ADR-005-esquema-declarativo-formularios.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# 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`.
|
||||||
22
supabase/migrations/20260620000001_add_instance_id.sql
Normal file
22
supabase/migrations/20260620000001_add_instance_id.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
-- Sprint 4 (v3.0.0) — instance_id para respuestas multi-instancia
|
||||||
|
-- Habilita el mini-wizard de vínculos familiares (una respuesta por familiar)
|
||||||
|
-- Nombre original de constraint verificado: answers_response_id_question_id_key
|
||||||
|
-- (inline UNIQUE en CREATE TABLE, migración 20260531000001_create_tables.sql, sin renombrado posterior)
|
||||||
|
|
||||||
|
-- 1. Agregar la columna con default para filas existentes
|
||||||
|
ALTER TABLE public.answers
|
||||||
|
ADD COLUMN IF NOT EXISTS instance_id text NOT NULL DEFAULT 'default';
|
||||||
|
|
||||||
|
-- 2. Eliminar la constraint única vieja
|
||||||
|
ALTER TABLE public.answers
|
||||||
|
DROP CONSTRAINT IF EXISTS answers_response_id_question_id_key;
|
||||||
|
|
||||||
|
-- 3. Crear la nueva constraint que incluye instance_id
|
||||||
|
ALTER TABLE public.answers
|
||||||
|
ADD CONSTRAINT answers_response_question_instance_key
|
||||||
|
UNIQUE (response_id, question_id, instance_id);
|
||||||
|
|
||||||
|
-- 4. Índice para consultas por instancia (análisis de vínculos)
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_answers_instance
|
||||||
|
ON public.answers (question_id, instance_id)
|
||||||
|
WHERE instance_id != 'default';
|
||||||
Reference in New Issue
Block a user