Files
motor-de-encuestas/migrate-claude/ESTADO_PROYECTO_JUNIO_2026.md
markosbenitez 157e108322 Los triggers 1.1, 1.6, 1.13 muestran solo Sí · No (sin "Prefiero no decir")
Al responder "No" en las tres, el formulario salta a 6.4 (no muestra secciones 2-5 ni 6.1-6.3)
La pregunta 6.6 aparece antes del cierre
Las preguntas multiple_choice muestran el hint "Podés marcar más de una opción"
2026-06-10 15:49:05 -03:00

179 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ESTADO DEL PROYECTO — Datos País sobre el Cuidado
## Documento de continuidad — junio 2026
> Generado al cierre de una sesión extendida de dirección técnica.
> Propósito: minimizar pérdida de contexto al abrir una nueva conversación.
> Director: Marcos (Roy) · Metodología: Maria Mersan · Contacto Fundación: Valeria Arce
---
## 1. Qué es el proyecto
Plataforma soberana de encuestas sobre economía del cuidado en Paraguay.
- **Producto:** formulario anónimo + dashboard analítico con k-anonimato.
- **Marca:** RE (Responsabilidad y Empatía Empresarial) · Fundación Solidaridad · InQuality.
- **URL producción:** https://economia-cuidado.inqualityhq.com
- **Survey demo:** https://economia-cuidado.inqualityhq.com/?s=30000000-0000-0000-0000-000000000001
---
## 2. Infraestructura actual — OPERATIVA ✅
### Stack
- **App:** Next.js 15.3.3 + TypeScript + Tailwind CSS
- **DB:** Supabase self-hosted en Dokploy (stack oficial clonado)
- **Deploy:** Dokploy v0.29.4 en VPS inq-mart-2 (IP VPN: 172.20.5.11)
- **Repos:**
- App: `git.inquality.com.py/marcos/motor-de-encuestas` (migrado desde GitHub InqGit)
- Supabase stack: `git.inquality.com.py/marcos/supabase-motor-fomularios`
- **Dominio API Supabase:** `db.inqualityhq.com` (Kong expuesto con SSL via Traefik/Let's Encrypt)
### Supabase self-hosted — detalles técnicos
- Stack corriendo desde repo Gitea (modo Git, NO docker raw — docker raw no tiene ./volumes/db/)
- Kong conectado a `dokploy-network` (persistente en docker-compose.yml del repo)
- Fix aplicado: `LUA_AUTH_EXPR` en `kong-entrypoint.sh` con prefijo `Bearer ` para PostgREST JWT propagation
- Variables de entorno en Dokploy: ANON_KEY, SERVICE_ROLE_KEY, SUPABASE_ANON_KEY, SUPABASE_SERVICE_KEY (nombres que usa kong.yml)
- SMTP_PORT=587 requerido aunque SMTP esté desactivado (GoTrue lo exige como int)
- GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=false (GoTrue lo exige como bool explícito)
- Backups: script GFS en /usr/local/bin/supabase-backup.sh, cron 3AM root, retención 3 días diarios + domingos 14 días
- Studio: solo accesible via SSH tunnel `ssh -L 3001:localhost:3001 administrator@172.20.5.11`
### Variables de entorno de la app Next.js (Build Arguments en Dokploy)
- NEXT_PUBLIC_SUPABASE_URL=https://db.inqualityhq.com
- NEXT_PUBLIC_SUPABASE_ANON_KEY=<JWT anon>
- SUPABASE_SERVICE_ROLE_KEY=<JWT service_role> (Environment Setting, no Build Arg)
---
## 3. Estado del código — Sprint 2 COMPLETADO, Sprint 3 COMPLETADO
### Migraciones aplicadas (12 en total, en orden)
1. 20260531000001_create_tables.sql — 7 tablas
2. 20260531000002_enable_rls.sql
3. 20260531000003_rls_policies.sql — PARCIAL (ver TECH-DEBT-007)
4. 20260531000004_constraints_triggers.sql
5. 20260531000005_agg_segment.sql
6. 20260531000006_grants.sql
7. 20260602111851_revoke_consent_select.sql
8. 20260604200932_fix_answers_insert_policy.sql
9. 20260605093948_dashboard_rpc.sql
10. 20260605093949_rls_deny_sensitive.sql
11. 20260605140000_011_truncate_testing_data.sql
12. 20260605140001_012_dashboard_rpc_v2.sql — 11 RPCs v2 del dashboard
### Políticas RLS activas (7)
- answers_insert, deny_sensitive_answers
- consent_records_insert, consent_versions_select_all
- questions_select_live, responses_insert
- surveys_select_live_anon
### Políticas RLS que fallaron (TECH-DEBT-007)
- org_select_own, surveys_select_auth, questions_select_auth
- Causa: auth.jwt() deprecado en GoTrue v2.189+ — no es bloqueante para el piloto
### Dashboard — widgets y códigos reales del instrumento
| Widget | Códigos reales | Subtítulo |
|---|---|---|
| K1 Cuidadores activos | 1.6 + 1.13 | % plantilla con responsabilidades de cuidado |
| K2 Frecuencia ausentismo | 5.2 | % con 4+ ausencias al año |
| K3 Bienestar | 4.3 (rating 1-5) | autorreporte bienestar general |
| W1 Prevalencia por depto | A1 (Departamento) | % cuidadores activos por departamento |
| W2 Perfil población | 1.1+1.6+1.13 | composición no excluyente |
| W3 Madurez organizacional | 6.1(×0.7)+6.5(×0.3) | score 0-100 |
| W4 Horas×Ausentismo | 2.2×5.2 | correlación intensidad/ausentismo |
| W5 Pirámide demográfica | A5×A6 | etario por género (k≥5) |
| W6 Apoyos demandados | 6.2 | top 8 multi-select |
| W7 Intensidad vs Bienestar | 2.2×4.3 | bins k≥5 |
| W8 Saturación cuidador | 4.3+5.1+5.2 | indicador compuesto |
---
## 4. Deuda técnica registrada
| ID | Descripción | Bloqueante |
|---|---|---|
| TECH-DEBT-006 | Backup remoto S3 (Backblaze B2 o Wasabi ~$5/mes) | **SÍ — antes del primer dato real** |
| TECH-DEBT-007 | auth.jwt() deprecado en GoTrue v2.189+ — current_app_role() y current_org_id() no funcionales | No (service_role bypasa RLS) |
| CVE-2025-66478 | Next.js 15.3.3 con vulnerabilidad de seguridad crítica | **SÍ — antes del primer dato real** |
---
## 5. Prompts pendientes de ejecutar en Claude Code
### ETAPA 2G — Cierre Sprint 2 (método)
**Archivo:** `sprints/sprint-2/ETAPA_2G_PROMPT.md`
**Qué hace:** promueve Patrón C.8 a estable + documenta AP.10 y AP.11 en method/ANTI_PATTERNS.md con casos reales del proyecto.
### ETAPA 3V — Vista de control /admin/responses
**Archivo:** `sprints/sprint-3-infra/ETAPA_3V_PROMPT.md`
**Qué hace:** crea ruta Next.js /admin/responses que muestra tabla de todas las respuestas ordenadas por fecha descendente, sin auth, usando service_role.
---
## 6. Contexto comercial
- **2 empresas comprometidas** para piloto (no en producción aún)
- **Cronograma deck:** JUN 2026 inicio · JUL-AGO relevamiento · SEP análisis · OCT primer informe + evento
- **Meta:** 20 empresas pioneras
- **Precios:** Gs. 4.5M (≤50) · 7.5M (≤200) · 12M (≤400)
- **GAPs deck vs. producto:**
- RE Index no implementado (fórmula: Bienestar×0.35 + Concentración×0.25 + Descanso×0.25 + Apoyo×0.15)
- Informe descargable prometido en el deck, no existe todavía
- **Contacto Fundación:** Valeria Arce — ddff@fundacionsolidaridad.org.py · +595 991 854333
---
## 7. Documentos producidos en estas sesiones
| Archivo | Descripción |
|---|---|
| INSTALL_SUPABASE.md | Guía instalación self-hosted (384 líneas) — con tabla de errores conocidos |
| BACKUP_STRATEGY.md | Estrategia backup GFS (335 líneas) — con procedimiento de restore |
| DOCUMENTACION_PLATAFORMA.md | Doc conceptual con 3 diagramas Mermaid |
| DatoPais_DocumentacionConceptual.docx | Word con 3 PNGs de diagramas embebidos |
| DatoPais_DimensionamientoEconomico.docx | Word con 5 charts económicos |
| DatoPais_ValidacionInstrumento.xlsx | Planilla colaborativa 4 hojas |
| sprints/sprint-2/ETAPA_2G_PROMPT.md | Cierre Sprint 2 — PENDIENTE ejecución |
| sprints/sprint-3-infra/ETAPA_3V_PROMPT.md | Vista /admin/responses — PENDIENTE ejecución |
---
## 8. Decisiones clave tomadas (no reabrir)
1. **docker raw de Dokploy es incompatible con Supabase** — usar siempre modo Git; el compose oficial necesita ./volumes/db/ que docker raw no tiene.
2. **POSTGRES_PASSWORD siempre con openssl rand -hex** — base64 tiene caracteres especiales que rompen el escaping de Docker Compose.
3. **kong.yml: una sola entrada por bloque keyauth_credentials** — dos entradas con el mismo valor JWT causa uniqueness violation.
4. **SMTP_PORT=587 siempre explícito** aunque SMTP esté desactivado — GoTrue lo parsea como int y falla si está vacío.
5. **GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=false siempre explícito** — GoTrue lo parsea como bool y falla si está vacío.
6. **LUA_AUTH_EXPR con prefijo "Bearer "** en kong-entrypoint.sh rama legacy — sin el prefijo PostgREST recibe JWT vacío.
7. **kong.yml usa $ANON_KEY y $SERVICE_ROLE_KEY** — alineado con los nombres de variables en Dokploy; SUPABASE_ANON_KEY y SUPABASE_SERVICE_KEY son aliases adicionales.
8. **App Next.js conecta a Supabase por URL pública** (https://db.inqualityhq.com) — las variables NEXT_PUBLIC_* se embeben en el bundle en build time y el navegador no puede resolver nombres Docker internos.
9. **NEXT_PUBLIC_SUPABASE_URL va como Build Argument** en Dokploy, no como Environment Setting — se embebe en el bundle de JavaScript durante el build.
10. **Repos en Gitea** (migrado desde GitHub InqGit) — VS Code configurado apuntando a git.inquality.com.py.
---
## 9. Patrones y anti-patrones del método (pendiente formalización en 2G)
### C.8 — Verificación de códigos contra fuente única (PROMOVER A ESTABLE)
Todos los widget subtitles y RPC mappings deben verificarse contra el instrumento real (SEED_SPEC.md). El drift silencioso entre instrumento e implementación es un failure mode de alto costo.
### AP.10 — Propagación silenciosa de inconsistencia entre fuentes
Caso real: Etapa 2D tenía subtítulos con códigos incorrectos que no se detectaron hasta auditoría explícita. Los errores de mapeo de códigos no generan errores en tiempo de compilación.
### AP.11 — Contrato desactualizado por código
Caso real: Etapa 1D dejó SEED_SPEC.md desactualizado respecto al seed.sql. El documento de referencia divergió del código sin señal visible.
---
## 10. Próximos pasos en orden de prioridad
1. **TECH-DEBT-006** — Backup remoto S3 (bloqueante antes del primer dato real)
2. **CVE-2025-66478** — Actualizar Next.js antes del primer dato real
3. **ETAPA 2G** — Ejecutar en Claude Code (método, no infraestructura)
4. **ETAPA 3V** — Ejecutar en Claude Code (vista /admin/responses)
5. **RE Index** — Implementar como widget real (confirmar mapeo G1/G2/G4/G5 → códigos seed con Marcos primero)
6. **Informe descargable** — Prometido en deck comercial, no existe
7. **Onboarding 2 empresas comprometidas** — cuando validación esté lista
8. **Validación instrumento** — Respuestas equipo de salud en DatoPais_ValidacionInstrumento.xlsx (12 preguntas metodológicas abiertas)