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"
This commit is contained in:
89
OBSERVATIONS.md
Normal file
89
OBSERVATIONS.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# OBSERVATIONS.md — Observaciones y breaking changes
|
||||
|
||||
> Registro de cambios al instrumento que rompen compatibilidad con datos existentes
|
||||
> o que requieren atención del director antes/después de re-seedear. No bloquean el
|
||||
> trabajo del agente — se documentan para que el director decida qué hacer con los
|
||||
> datos ya capturados.
|
||||
|
||||
---
|
||||
|
||||
## Etapa 3I2 — Revisión del instrumento v2.1 (feedback equipo médico)
|
||||
|
||||
### 1. Eliminación de "Prefiero no decir" (Cambio 1)
|
||||
Afecta: A5, A6, 1.1, 1.5, 1.6, 1.13, 2.5, 3.1, 3.4.
|
||||
|
||||
Si existen respuestas guardadas con el valor `"Prefiero no decir"` en alguna de estas
|
||||
preguntas, esos valores quedan **huérfanos**: ya no aparecen como opción en el
|
||||
formulario ni en `seed.sql`, pero permanecen en `responses.answers` tal cual fueron
|
||||
guardados. No se borran ni se migran automáticamente.
|
||||
|
||||
**Impacto en triggers (1.1, 1.6, 1.13):** estas preguntas ahora tienen solo 2 opciones
|
||||
(Sí/No). La lógica condicional (incluyendo el nuevo salto-triple, Cambio 4a) solo
|
||||
reacciona a `"Sí"`. Una respuesta histórica `"Prefiero no decir"` en un trigger se
|
||||
trataría como "no Sí" a efectos de la lógica condicional si se re-evaluara, pero no
|
||||
hay re-evaluación retroactiva de respuestas ya enviadas.
|
||||
|
||||
### 2. 2.1 cambia de `single_choice` a `multiple_choice` (Cambio 5)
|
||||
Respuestas existentes para 2.1 están guardadas como un string único (`"Yo soy el/la
|
||||
principal"`, etc.). El formulario nuevo espera un array de strings para preguntas
|
||||
`multiple_choice`. Las respuestas históricas de 2.1 quedan en formato de string,
|
||||
inconsistente con el nuevo esquema esperado para esa pregunta.
|
||||
|
||||
Ver `TECH_DEBT.md` → TECH-DEBT-006 (deuda de ranking pendiente sobre esta misma
|
||||
pregunta).
|
||||
|
||||
### 3. Eliminación de la pregunta 2.4 (Cambio 6)
|
||||
"¿Contás con apoyo de otras personas para el cuidado?" se elimina del seed por ser
|
||||
similar/redundante con 2.1 (feedback del equipo médico).
|
||||
|
||||
El `DELETE FROM public.questions WHERE survey_id = ...` al inicio de `seed.sql` borra
|
||||
la fila de la pregunta 2.4 (id `40000000-0000-0000-0000-000000000027`). Si existen
|
||||
filas en `responses` cuyo `answers` referencian `question_id` = 2.4 (por
|
||||
`question_id`, no por código embebido en JSON — depende del esquema de `responses`),
|
||||
esas referencias quedan apuntando a un `question_id` que ya no existe en `questions`
|
||||
tras el re-seed.
|
||||
|
||||
**No re-seedear la base de producción sin que el director confirme que no hay
|
||||
respuestas reales que dependan de 2.4**, o decidir conservar la fila de 2.4 marcada
|
||||
como `archived`/inactiva en lugar de borrarla (cambio de diseño — Nivel 3, no
|
||||
ejecutado en esta etapa).
|
||||
|
||||
### 4. Cambio de texto en opción de 3.3 (Cambio 8)
|
||||
"Es difícil sostenerlo con mis ingresos" → "No puedo sostenerlo con mis ingresos".
|
||||
|
||||
Respuestas existentes que eligieron la opción anterior quedan guardadas con el texto
|
||||
literal `"Es difícil sostenerlo con mis ingresos"`, que ya no coincide con ninguna
|
||||
opción del seed actual. Cualquier agregación por valor exacto de opción debe
|
||||
contemplar ambos strings como equivalentes para no perder esos datos en reportes.
|
||||
|
||||
### 5. División de la primera franja salarial en 3.4 (Cambio 9)
|
||||
"Sueldo mínimo – Gs. 5.000.000" se reemplaza por dos opciones nuevas: "Sueldo mínimo"
|
||||
y "Gs. 3.000.000 a 5.000.000".
|
||||
|
||||
Respuestas existentes con el valor `"Sueldo mínimo – Gs. 5.000.000"` quedan con ese
|
||||
valor, que ya no existe como opción. No hay forma automática de reasignar esas
|
||||
respuestas a una de las dos franjas nuevas (la franja exacta del respondente no se
|
||||
puede inferir del valor agregado anterior).
|
||||
|
||||
### 6. Cambio de texto en última opción de 6.1 (Cambio 10)
|
||||
"No, nunca se ha hablado del tema" → "No, no se puede hablar del tema".
|
||||
|
||||
Respuestas existentes con el valor anterior quedan con ese texto literal, que ya no
|
||||
coincide con ninguna opción del seed actual.
|
||||
|
||||
---
|
||||
|
||||
## Resumen para el director
|
||||
|
||||
- Ningún cambio de esta etapa borra datos directamente, salvo el `DELETE` estándar de
|
||||
`questions` por `survey_id` (mecanismo de idempotencia ya existente en `seed.sql`,
|
||||
no nuevo de esta etapa) — pero ese `DELETE` ahora también elimina la fila de 2.4.
|
||||
- Los cambios 1, 8, 9 y 10 dejan **valores de texto huérfanos** en respuestas
|
||||
históricas (ya no matchean ninguna opción vigente). No afecta el funcionamiento del
|
||||
formulario hacia adelante, pero sí cualquier reporte/agregación que dependa de
|
||||
matchear el string exacto de la opción.
|
||||
- El cambio 5 (2.1) deja respuestas históricas en un formato (string) distinto al que
|
||||
el formulario nuevo produce (array). Si se construye un reporte sobre 2.1, debe
|
||||
manejar ambos formatos o normalizarse en una migración de datos aparte.
|
||||
- **No se ejecutó ningún re-seed sobre la base real** — esto aplica solo cuando el
|
||||
director apruebe re-seedear con `seed.sql` v2.1.
|
||||
75
SEED_SPEC.md
75
SEED_SPEC.md
@@ -1,23 +1,31 @@
|
||||
# SEED_SPEC.md — Contrato del instrumento "Mapeo de Cuidadores" v2
|
||||
# SEED_SPEC.md — Contrato del instrumento "Mapeo de Cuidadores" v2.1
|
||||
|
||||
> Versión 2 — incorpora revisión de la colega (Jun 2026). Reemplaza la v1 (34 preguntas).
|
||||
> 44 preguntas · 8 secciones · Códigos únicos corregidos.
|
||||
> Versión 2.1 — incorpora feedback del equipo médico, Etapa 3I2 (Jun 2026). Reemplaza la v2.
|
||||
> 44 preguntas (se elimina 2.4, se agrega 6.6) · 8 secciones · Códigos únicos corregidos.
|
||||
> Claude Code reescribe `seed.sql` a partir de ESTE contrato.
|
||||
|
||||
## Convenciones
|
||||
- Tipos: radio→`single_choice`, checkbox→`multiple_choice`, escala 1-5→`rating`,
|
||||
texto libre largo→`text_long`, texto corto→`text_short`.
|
||||
- **`conditional_rules` en la pregunta DEPENDIENTE** (cada pregunta declara su propia condición).
|
||||
- Los 3 triggers (1.1, 1.6, 1.13) son `single_choice` de 3 opciones; solo **"Sí"** dispara el bloque.
|
||||
- Los 3 triggers (1.1, 1.6, 1.13) son `single_choice` de 2 opciones (Sí · No); solo **"Sí"** dispara
|
||||
el bloque correspondiente.
|
||||
- `is_sensitive=true` en preguntas de salud/discapacidad/diagnóstico (marcadas ✅).
|
||||
- `3.4` (salary) — `is_sensitive=true` + analyst-only (ADR-001 addendum): nunca en vistas org_admin.
|
||||
- RE-INDEX: las preguntas marcadas son candidatas a índice compuesto (metodología TBD Sprint 3).
|
||||
- En preguntas `multiple_choice` el formulario muestra el subtítulo "Podés marcar más de una opción".
|
||||
- "Prefiero no decir" eliminada de todas las preguntas (Cambio 1, Etapa 3I2).
|
||||
|
||||
## Estructura condicional (3 bloques)
|
||||
## Estructura condicional (4 bloques)
|
||||
- **cond-disc-propia** — 1.1='Sí' → muestra 1.2, 1.3, 1.4, 1.5
|
||||
- **cond-familiar** — 1.6='Sí' → muestra 1.7, 1.8, 1.9, 1.10, 1.11, 1.12
|
||||
- **cond-adulto-mayor** — 1.13='Sí' → muestra 1.14, 1.15, 1.16
|
||||
- Secciones A, 2, 3, 4, 5, 6, cierre: **top-level, siempre visibles.**
|
||||
- **salto-triple** — si 1.1='No' Y 1.6='No' Y 1.13='No' (es decir, ninguno de los tres dio
|
||||
'Sí'), se ocultan completas las secciones 2, 3, 4, 5 y las preguntas 6.1, 6.2, 6.3. El
|
||||
formulario salta directo a 6.4. Implementado como `conditional_rules`
|
||||
`{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}` en cada
|
||||
pregunta del bloque (equivalente: se muestra si AL MENOS uno de los tres es 'Sí').
|
||||
- Sección A, 6.4-6.6 y Sección 7 (cierre): **top-level, siempre visibles.**
|
||||
|
||||
---
|
||||
|
||||
@@ -28,49 +36,68 @@
|
||||
| A2 | single_choice | ¿En qué ciudad vivís?* | 219 ciudades (GeoSelectWidget: dependiente de A1) | qi_city — Sprint 3 |
|
||||
| A3 | text_short | ¿En qué barrio vivís? | — (texto libre, opcional) | |
|
||||
| A4 | single_choice | ¿En qué área o gerencia trabajás?* | Directorio · Gerencia · Operaciones/Producción · Comercial/Ventas · Administración/Finanzas · Recursos Humanos/Cultura · Tecnología/Sistemas · Logística/Distribución · Otra área | qi_sector |
|
||||
| A5 | single_choice | ¿Cuántos años tenés? | Menos de 25 años · 25 a 34 años · 35 a 44 años · 45 a 54 años · 55 años o más · Prefiero no decir | qi_age_bucket |
|
||||
| A6 | single_choice | ¿Con qué género te identificás? | Femenino · Masculino · No binario/Otro · Prefiero no decir | |
|
||||
| A5 | single_choice | ¿Cuántos años tenés? | Menos de 25 años · 25 a 34 años · 35 a 44 años · 45 a 54 años · 55 años o más | qi_age_bucket |
|
||||
| A6 | single_choice | ¿Con qué género te identificás? | Femenino · Masculino · No binario/Otro | |
|
||||
| A7 | single_choice | ¿Cuál es tu modalidad de trabajo actual? | Presencial · Remoto (home office) · Híbrido | |
|
||||
|
||||
## Sección 1 — Prevalencia: cuidado y discapacidad *(sensible)*
|
||||
| Code | Tipo | Cond. | Pregunta | Opciones | is_sensitive |
|
||||
|---|---|---|---|---|---|
|
||||
| 1.1 | single_choice | trigger | ¿Vos mismo/a vivís con alguna discapacidad o condición de salud que afecte tu funcionamiento cotidiano?* | Sí · No · Prefiero no decir | ✅ |
|
||||
| 1.1 | single_choice | trigger | ¿Vos mismo/a vivís con alguna discapacidad o condición de salud que afecte tu funcionamiento cotidiano?* | Sí · No | ✅ |
|
||||
| 1.2 | multiple_choice | 1.1=Sí | ¿Qué tipo de discapacidad o condición tenés? | Discapacidad física/motriz · Visual · Auditiva · Intelectual · TEA · Psicosocial/salud mental · Condición crónica que genera limitaciones · Otra | ✅ |
|
||||
| 1.3 | multiple_choice | 1.1=Sí | ¿Usás algún elemento de apoyo para la movilidad o autonomía? | Silla de ruedas · Bastón · Andador · Muletas · Prótesis · No utilizo | ✅ |
|
||||
| 1.3 | multiple_choice | 1.1=Sí | ¿Usás algún elemento de apoyo para la movilidad o autonomía? | Silla de ruedas · Bastón · Andador · Muletas · Prótesis · Tecnología asistiva · No utilizo | ✅ |
|
||||
| 1.4 | single_choice | 1.1=Sí | ¿Contás con certificado oficial de discapacidad? | Sí · No, pero estoy en trámite · No | ✅ |
|
||||
| 1.5 | single_choice | 1.1=Sí | ¿Tu condición afecta tu desempeño o comodidad en el trabajo? | Sí, de forma significativa · Sí, pero en aspectos puntuales · No, está bien gestionada · Prefiero no decir | ✅ |
|
||||
| 1.6 | single_choice | trigger | ¿Tenés algún familiar cercano (hijo/a, pareja, hermano/a, padre/madre) que viva con discapacidad?* | Sí · No · Prefiero no decir | ✅ |
|
||||
| 1.5 | single_choice | 1.1=Sí | ¿Tu condición afecta tu desempeño o comodidad en el trabajo? | Sí, de forma significativa · Sí, pero en aspectos puntuales · No, está bien gestionada | ✅ |
|
||||
| 1.6 | single_choice | trigger | ¿Tenés algún familiar cercano (hijo/a, pareja, hermano/a, padre/madre) que viva con discapacidad?* | Sí · No | ✅ |
|
||||
| 1.7 | multiple_choice | 1.6=Sí | ¿Cuál es tu vínculo con esa persona? | Hijo/a · Cónyuge/pareja · Padre o madre · Hermano/a · Otro familiar | ✅ |
|
||||
| 1.8 | multiple_choice | 1.6=Sí | ¿Qué tipo de discapacidad tiene? | Física/motriz · Visual · Auditiva · Intelectual · TEA · Psicosocial/salud mental · Condición crónica severa · Otra | ✅ |
|
||||
| 1.9 | multiple_choice | 1.6=Sí | ¿Qué tipo de apoyo o acompañamiento necesita principalmente? | Movilidad física · Comunicación · Apoyo escolar/educativo · Inclusión laboral · Terapias/rehabilitación · Apoyo emocional/psicosocial | ✅ |
|
||||
| 1.10 | multiple_choice | 1.6=Sí | ¿Usa algún elemento de apoyo para la movilidad o autonomía? | Silla de ruedas · Bastón · Andador · Muletas · Prótesis · No utiliza | ✅ |
|
||||
| 1.10 | multiple_choice | 1.6=Sí | ¿Usa algún elemento de apoyo para la movilidad o autonomía? | Silla de ruedas · Bastón · Andador · Muletas · Prótesis · Tecnología asistiva · No utiliza | ✅ |
|
||||
| 1.11 | single_choice | 1.6=Sí | Si es niño/a o adolescente en edad escolar: ¿está escolarizado/a y enfrenta barreras de aprendizaje? | Escolarizado/a, sin barreras importantes · Escolarizado/a, enfrenta barreras o faltan ajustes · No está escolarizado/a · No aplica | ✅ |
|
||||
| 1.12 | single_choice | 1.6=Sí | ¿La persona con discapacidad se encuentra trabajando actualmente? | Sí, está trabajando · No, y está buscando empleo · No, y no está buscando · No aplica | ✅ |
|
||||
| 1.13 | single_choice | trigger | ¿Tenés algún adulto mayor (60+ años) a tu cuidado o bajo tu responsabilidad?* | Sí · No · Prefiero no decir | |
|
||||
| 1.13 | single_choice | trigger | ¿Tenés algún adulto mayor (60+ años) a tu cuidado o bajo tu responsabilidad?* | Sí · No | |
|
||||
| 1.14 | single_choice | 1.13=Sí | ¿Qué nivel de dependencia tiene? (la más representativa) | Independiente, pero necesita supervisión · Dependencia leve · Dependencia moderada · Dependencia severa | ✅ |
|
||||
| 1.15 | multiple_choice | 1.13=Sí | ¿Tiene una condición de salud que genere mayor necesidad de cuidado? | Demencia/Alzheimer · ACV/Parálisis · Enfermedad crónica grave · Movilidad reducida · Deterioro cognitivo · Sin condición específica | ✅ |
|
||||
| 1.16 | single_choice | 1.13=Sí | ¿Vive con vos o en otra vivienda? | Vive en mi hogar · Vive en otra vivienda · Está en residencia/institución | |
|
||||
|
||||
## Sección 2 — Intensidad y rol del cuidado (top-level)
|
||||
> Cond.: **salto-triple** — toda la sección se oculta si 1.1='No' Y 1.6='No' Y 1.13='No'.
|
||||
|
||||
| Code | Tipo | Pregunta | Opciones |
|
||||
|---|---|---|---|
|
||||
| 2.1 | single_choice | ¿Quién es el/la responsable principal del cuidado? | Yo soy el/la principal · Comparto con otro familiar · Hay cuidador/a pagado/a · Está en institución/centro de día |
|
||||
| 2.1 | multiple_choice ⚠️ TECH-DEBT | ¿Quién es el/la responsable principal del cuidado? | Yo soy el/la principal · Comparto con otro familiar · Hay cuidador/a pagado/a · Está en institución/centro de día |
|
||||
| 2.2 | single_choice | ¿Cuántas horas por día dedicás, en promedio, al cuidado directo? | Menos de 1h · Entre 1 y 3h · Entre 3 y 6h · Más de 6h · Varía mucho |
|
||||
| 2.3 | multiple_choice | ¿En qué momentos del día cuidás principalmente? | Antes del trabajo · Durante horario laboral (llamadas/emergencias) · Al llegar del trabajo · Durante la noche · Los fines de semana · Es continuo sin horario fijo |
|
||||
| 2.4 | single_choice | ¿Contás con apoyo de otras personas para el cuidado? | Sí, apoyo familiar suficiente · Algo de apoyo, no suficiente · No, soy el/la único/a responsable · Tengo apoyo contratado |
|
||||
| 2.5 | single_choice | Como cuidador/a primario, ¿presentás signos de agotamiento o estrés crónico? | Sí, frecuentemente · A veces · No, lo llevo bien · Prefiero no decir |
|
||||
| 2.5 | single_choice | Como cuidador/a primario, ¿presentás signos de agotamiento o estrés crónico? | Sí, frecuentemente · A veces · No, lo llevo bien |
|
||||
|
||||
> ⚠️ TECH-DEBT (2.1): pasó de `single_choice` a `multiple_choice` — selección múltiple sin orden
|
||||
> de prioridad. Deuda: implementar ranking (Principal cuidador soy yo > secundario instituto >
|
||||
> principal pagado > secundario familiar). Ver `TECH_DEBT.md`.
|
||||
>
|
||||
> **2.4 eliminada** (Cambio 6, Etapa 3I2): "¿Contás con apoyo de otras personas para el cuidado?"
|
||||
> — feedback del equipo médico: pregunta similar/redundante con 2.1. Ver `OBSERVATIONS.md`.
|
||||
|
||||
## Sección 3 — Impacto económico del cuidado (top-level)
|
||||
> Cond.: **salto-triple** — toda la sección se oculta si 1.1='No' Y 1.6='No' Y 1.13='No'.
|
||||
> 3.4: is_sensitive=true + analyst-only (no exponer a org_admin).
|
||||
|
||||
| Code | Tipo | Pregunta | Opciones | Notas |
|
||||
|---|---|---|---|---|
|
||||
| 3.1 | single_choice | ¿Cuánto estimás que gastás por mes en el cuidado? | Sin gastos significativos · Menos de Gs. 500.000 · Gs. 500.000–1.500.000 · Gs. 1.500.000–3.000.000 · Gs. 3.000.000–6.000.000 · Más de Gs. 6.000.000 · Prefiero no decir | |
|
||||
| 3.1 | single_choice | ¿Cuánto estimás que gastás por mes en el cuidado? | Menos de Gs. 500.000 · Gs. 500.000–1.500.000 · Gs. 1.500.000–3.000.000 · Gs. 3.000.000–6.000.000 · Más de Gs. 6.000.000 | |
|
||||
| 3.2 | multiple_choice | ¿Qué servicios o apoyos utilizás actualmente? | Terapias especializadas · Cuidador/a particular · Centro de día/institución · Transporte adaptado · Medicación alto costo · Equipamiento médico/tecnología asistiva · No utilizo servicios formales | |
|
||||
| 3.3 | multiple_choice | ¿Cómo sostenés los gastos y responsabilidades del cuidado? | Con mi empleo de tiempo completo · Con mi empleo de tiempo parcial · Con trabajo independiente/emprendimiento · Me ayudan mis familiares · Es difícil sostenerlo con mis ingresos | |
|
||||
| 3.4 | single_choice | ¿En qué franja salarial mensual te ubicás? *(CONFIDENCIAL — analyst-only)* | Sueldo mínimo – Gs. 5.000.000 · Gs. 5.000.001–8.000.000 · Gs. 8.000.001–12.000.000 · Gs. 12.000.001–15.000.000 · Gs. 15.000.001–18.000.000 · Gs. 18.000.001–25.000.000 · Gs. 25.000.001–50.000.000 · Gs. 50.000.001 o más · Prefiero no decir | is_sensitive=true; never in org_admin views |
|
||||
| 3.3 | multiple_choice | ¿Cómo sostenés los gastos y responsabilidades del cuidado? | Con mi empleo de tiempo completo · Con mi empleo de tiempo parcial · Con trabajo independiente/emprendimiento · Me ayudan mis familiares · No puedo sostenerlo con mis ingresos | |
|
||||
| 3.4 | single_choice | ¿En qué franja salarial mensual te ubicás? *(CONFIDENCIAL — analyst-only)* | Sueldo mínimo · Gs. 3.000.000 a 5.000.000 · Gs. 5.000.001–8.000.000 · Gs. 8.000.001–12.000.000 · Gs. 12.000.001–15.000.000 · Gs. 15.000.001–18.000.000 · Gs. 18.000.001–25.000.000 · Gs. 25.000.001–50.000.000 · Gs. 50.000.001 o más | is_sensitive=true; never in org_admin views |
|
||||
| 3.5 | rating | ¿Los gastos de cuidado impactan en tu situación económica personal? | 1=Sin impacto · 2=Leve · 3=Moderado · 4=Alto · 5=Muy alto | RE-INDEX |
|
||||
|
||||
> **Cambio 7** (3.1): se elimina "Sin gastos significativos" además de "Prefiero no decir".
|
||||
> **Cambio 8** (3.3): "Es difícil sostenerlo con mis ingresos" → "No puedo sostenerlo con mis
|
||||
> ingresos". Breaking change para datos existentes — ver `OBSERVATIONS.md`.
|
||||
> **Cambio 9** (3.4): "Sueldo mínimo – Gs. 5.000.000" se divide en "Sueldo mínimo" y
|
||||
> "Gs. 3.000.000 a 5.000.000". Breaking change para datos existentes — ver `OBSERVATIONS.md`.
|
||||
|
||||
## Sección 4 — Tiempo y descanso (top-level)
|
||||
> Cond.: **salto-triple** — toda la sección se oculta si 1.1='No' Y 1.6='No' Y 1.13='No'.
|
||||
|
||||
| Code | Tipo | Pregunta | Opciones |
|
||||
|---|---|---|---|
|
||||
| 4.1 | single_choice | ¿Cómo describirías tu nivel de descanso habitual? | Descanso bien, me siento recuperado/a · Descanso de forma irregular, pero lo manejo · Me cuesta descansar, me siento cansado/a con frecuencia · Descanso muy poco, el agotamiento afecta mi día a día | RE-INDEX |
|
||||
@@ -78,19 +105,25 @@
|
||||
| 4.3 | rating | En una escala del 1 al 5, ¿cómo evaluás tu bienestar general en este momento? | 1=Muy mal · 2=Mal · 3=Regular · 4=Bien · 5=Muy bien | RE-INDEX |
|
||||
|
||||
## Sección 5 — Impacto en el trabajo (top-level)
|
||||
> Cond.: **salto-triple** — toda la sección se oculta si 1.1='No' Y 1.6='No' Y 1.13='No'.
|
||||
|
||||
| Code | Tipo | Pregunta | Opciones |
|
||||
|---|---|---|---|
|
||||
| 5.1 | single_choice | En los últimos 3 meses, ¿con qué frecuencia sentiste que el cuidado afectó tu concentración o rendimiento? | Nunca o casi nunca · Algunas veces al mes · Varias veces por semana · Casi todos los días | RE-INDEX |
|
||||
| 5.2 | single_choice | En el último año, ¿faltaste al trabajo por situaciones relacionadas al cuidado? | Nunca · Pocas veces (1–3 veces al año) · Varias veces (4–10 veces al año) · Con frecuencia (más de 10 veces al año) | |
|
||||
|
||||
## Sección 6 — Conciencia organizacional (top-level)
|
||||
> Cond. (6.1-6.3): **salto-triple** — se ocultan si 1.1='No' Y 1.6='No' Y 1.13='No'.
|
||||
> 6.4-6.6: siempre visibles (destino del salto).
|
||||
|
||||
| Code | Tipo | Pregunta | Opciones | Notas |
|
||||
|---|---|---|---|---|
|
||||
| 6.1 | single_choice | ¿Sentís que tu empresa conoce o comprende la realidad del cuidado y la discapacidad de su gente?* | Sí, me siento acompañado/a · Parcialmente, hay cierta comprensión · No, es algo bastante invisible · No, nunca se ha hablado del tema | RE-INDEX |
|
||||
| 6.1 | single_choice | ¿Sentís que tu empresa conoce o comprende la realidad del cuidado y la discapacidad de su gente?* | Sí, me siento acompañado/a · Parcialmente, hay cierta comprensión · No, es algo bastante invisible · No, no se puede hablar del tema | RE-INDEX. Cambio 10: última opción reescrita (era "No, nunca se ha hablado del tema"). Breaking change — ver `OBSERVATIONS.md`. |
|
||||
| 6.2 | multiple_choice (**max_select=3**) | ¿Qué apoyos de la empresa te ayudarían más? Elegí hasta 3 | Flexibilidad horaria o trabajo remoto · Apoyo económico o convenios/descuentos · Acceso a terapias o salud · Contención/apoyo emocional o psicológico · Capacitación y autocuidado · Redes de apoyo/grupos de pares · Información sobre recursos y servicios disponibles | ⚠️ Ranking → multiple_choice para v1. Ranking widget al backlog. |
|
||||
| 6.3 | single_choice | ¿Estarías dispuesto/a a participar en un grupo de apoyo para cuidadores dentro de la empresa? | Sí, definitivamente · Tal vez, si hay más personas en la misma situación · No por ahora · Prefiero mantenerlo en privado | |
|
||||
| 6.4 | single_choice | ¿Conocés a algún compañero/a de trabajo que esté al cuidado de una persona con discapacidad o dependiente? | Sí, conozco a varias personas · Sí, conozco a una persona · No conozco a nadie · No estoy seguro/a | Código corregido (era 6.2 duplicado) |
|
||||
| 6.5 | single_choice | ¿Considerás que la empresa debería ofrecer apoyos a quienes cuidan a una persona dependiente? | Sí, definitivamente · Tal vez, dependería del caso · No lo considero necesario · No lo sé | Código corregido (era 6.3 duplicado) |
|
||||
| 6.6 | single_choice | ¿Estarías dispuesto/a a ser voluntario/a en iniciativas y/o redes de apoyo a personas con discapacidad y/o cuidadores? | Sí · No · Tal vez | Nueva (Cambio 4b, Etapa 3I2) |
|
||||
|
||||
## Sección 7 — Para cerrar (top-level)
|
||||
| Code | Tipo | Pregunta | Notas |
|
||||
|
||||
14
TECH_DEBT.md
14
TECH_DEBT.md
@@ -58,3 +58,17 @@
|
||||
- **Para implementar:** migration futura que agregue extracción de A1/A2 en el insert
|
||||
y extienda la whitelist de `agg_segment`.
|
||||
- **Trigger:** inicio de Sprint 3 (dashboard avanzado con filtros de ciudad).
|
||||
|
||||
---
|
||||
|
||||
## [TECH-DEBT-006] Ranking widget para 2.1
|
||||
|
||||
- **Estado:** Etapa 3I2 (Cambio 5) cambió 2.1 ("¿Quién es el/la responsable principal
|
||||
del cuidado?") de `single_choice` a `multiple_choice`. Permite selección múltiple
|
||||
pero sin orden de prioridad — pierde la noción de "responsable principal" cuando
|
||||
el respondente marca más de una opción.
|
||||
- **Deuda:** implementar widget de ranking para 2.1 con el orden:
|
||||
Principal cuidador soy yo > secundario instituto > principal pagado > secundario
|
||||
familiar (mismo patrón que TECH-DEBT-001 para 6.2).
|
||||
- **Trigger:** decisión del director sobre el tipo de 2.1 en próxima versión del
|
||||
instrumento.
|
||||
|
||||
@@ -1,20 +1,44 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
// Server Component sin auth — herramienta interna de diagnóstico (Etapa 3V).
|
||||
// Server Component sin auth — herramienta interna de diagnóstico (Etapa 3V-B).
|
||||
// Usa SUPABASE_SERVICE_ROLE_KEY: vive solo acá, server-side, nunca al cliente.
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
const MAX_ROWS = 200
|
||||
const MAX_SUBMISSIONS = 500
|
||||
const PROMPT_MAX_LEN = 60
|
||||
|
||||
interface AllowedQuestion {
|
||||
id: string
|
||||
code: string
|
||||
prompt: string
|
||||
type: string
|
||||
position: number
|
||||
}
|
||||
|
||||
interface AnswerRow {
|
||||
value: unknown
|
||||
question_id: string
|
||||
}
|
||||
|
||||
interface ResponseRow {
|
||||
id: string
|
||||
submitted_at: string
|
||||
qi_zone: string | null
|
||||
qi_sector: string | null
|
||||
qi_age_bucket: string | null
|
||||
ip_hash: string | null
|
||||
surveys: { title: string } | { title: string }[] | null
|
||||
answers: { count: number }[]
|
||||
answers: AnswerRow[]
|
||||
}
|
||||
|
||||
interface FlatRow {
|
||||
key: string
|
||||
submissionNum: number
|
||||
isFirstInGroup: boolean
|
||||
submitted_at: string
|
||||
qi_zone: string | null
|
||||
qi_sector: string | null
|
||||
code: string
|
||||
prompt: string
|
||||
type: string
|
||||
value: unknown
|
||||
}
|
||||
|
||||
function getSupabaseAdmin() {
|
||||
@@ -29,45 +53,125 @@ function formatDate(iso: string): string {
|
||||
return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${d.getFullYear()} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
}
|
||||
|
||||
function dash(value: string | null): string {
|
||||
return value ?? '—'
|
||||
function truncate(text: string, max = PROMPT_MAX_LEN): string {
|
||||
return text.length > max ? `${text.slice(0, max)}...` : text
|
||||
}
|
||||
|
||||
// Spec 4.3 — null/undefined → null (renderizado como badge "sin dato")
|
||||
function renderValue(value: unknown, type: string): string | null {
|
||||
if (value === null || value === undefined) return null
|
||||
|
||||
switch (type) {
|
||||
case 'single_choice':
|
||||
case 'text_short':
|
||||
return String(value).replace(/^"|"$/g, '')
|
||||
case 'multiple_choice':
|
||||
if (Array.isArray(value)) return value.join(', ')
|
||||
return String(value)
|
||||
case 'rating':
|
||||
return String(value)
|
||||
default:
|
||||
return String(value)
|
||||
}
|
||||
}
|
||||
|
||||
export default async function AdminResponsesPage() {
|
||||
const supabase = getSupabaseAdmin()
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('responses')
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
submitted_at,
|
||||
qi_zone,
|
||||
qi_sector,
|
||||
qi_age_bucket,
|
||||
ip_hash,
|
||||
surveys ( title ),
|
||||
answers ( count )
|
||||
`
|
||||
)
|
||||
.order('submitted_at', { ascending: false })
|
||||
.limit(MAX_ROWS)
|
||||
// 1. Preguntas permitidas — text_long e is_sensitive=true se excluyen ACÁ,
|
||||
// antes de tocar la tabla answers. Sus valores nunca se consultan.
|
||||
const { data: questionsData, error: questionsError } = await supabase
|
||||
.from('questions')
|
||||
.select('id, code, prompt, type, position')
|
||||
.eq('is_sensitive', false)
|
||||
.neq('type', 'text_long')
|
||||
.order('position', { ascending: true })
|
||||
|
||||
if (error) {
|
||||
if (questionsError) {
|
||||
return (
|
||||
<div className="admin-page" role="main">
|
||||
<h1 className="admin-title">Control de respuestas</h1>
|
||||
<p className="admin-error">No fue posible conectarse a la base de datos.</p>
|
||||
<pre className="admin-error-detail">{error.message}</pre>
|
||||
<pre className="admin-error-detail">{questionsError.message}</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const { count: totalCount } = await supabase
|
||||
const allowedQuestions = (questionsData ?? []) as AllowedQuestion[]
|
||||
const allowedIds = allowedQuestions.map((q) => q.id)
|
||||
const questionMap = new Map(allowedQuestions.map((q) => [q.id, q]))
|
||||
|
||||
// 2. Submissions con sus respuestas — answers!inner + .in() filtra el ARRAY
|
||||
// embebido a solo question_id permitidos (consulta, no post-filtro).
|
||||
const { data: responsesData, error: responsesError } =
|
||||
allowedIds.length > 0
|
||||
? await supabase
|
||||
.from('responses')
|
||||
.select(
|
||||
`
|
||||
id,
|
||||
submitted_at,
|
||||
qi_zone,
|
||||
qi_sector,
|
||||
answers!inner ( value, question_id )
|
||||
`
|
||||
)
|
||||
.in('answers.question_id', allowedIds)
|
||||
.order('submitted_at', { ascending: false })
|
||||
.limit(MAX_SUBMISSIONS)
|
||||
: { data: [] as ResponseRow[], error: null }
|
||||
|
||||
if (responsesError) {
|
||||
return (
|
||||
<div className="admin-page" role="main">
|
||||
<h1 className="admin-title">Control de respuestas</h1>
|
||||
<p className="admin-error">No fue posible conectarse a la base de datos.</p>
|
||||
<pre className="admin-error-detail">{responsesError.message}</pre>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const responses = (responsesData ?? []) as unknown as ResponseRow[]
|
||||
|
||||
// 3. Contadores totales (independientes del límite de 500 submissions)
|
||||
const { count: totalSubmissions } = await supabase
|
||||
.from('responses')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
|
||||
const rows = (data ?? []) as unknown as ResponseRow[]
|
||||
const { count: totalAnswers } =
|
||||
allowedIds.length > 0
|
||||
? await supabase
|
||||
.from('answers')
|
||||
.select('*', { count: 'exact', head: true })
|
||||
.in('question_id', allowedIds)
|
||||
: { count: 0 }
|
||||
|
||||
// 4. Aplanar: una fila por answer, ordenadas por position dentro de cada submission
|
||||
const rows: FlatRow[] = []
|
||||
responses.forEach((response, idx) => {
|
||||
const answers = response.answers
|
||||
.filter((a) => questionMap.has(a.question_id))
|
||||
.sort(
|
||||
(a, b) =>
|
||||
questionMap.get(a.question_id)!.position - questionMap.get(b.question_id)!.position
|
||||
)
|
||||
|
||||
answers.forEach((a, ai) => {
|
||||
const q = questionMap.get(a.question_id)!
|
||||
rows.push({
|
||||
key: `${response.id}-${a.question_id}`,
|
||||
submissionNum: idx + 1,
|
||||
isFirstInGroup: ai === 0,
|
||||
submitted_at: response.submitted_at,
|
||||
qi_zone: response.qi_zone,
|
||||
qi_sector: response.qi_sector,
|
||||
code: q.code,
|
||||
prompt: q.prompt,
|
||||
type: q.type,
|
||||
value: a.value,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="admin-page" role="main">
|
||||
@@ -75,7 +179,7 @@ export default async function AdminResponsesPage() {
|
||||
<div>
|
||||
<h1 className="admin-title">Control de respuestas</h1>
|
||||
<p className="admin-subtitle">
|
||||
{totalCount ?? 0} respuestas en total · últimas {rows.length} ·
|
||||
{totalSubmissions ?? 0} submissions · {totalAnswers ?? 0} respuestas individuales ·
|
||||
actualizado {formatDate(new Date().toISOString())}
|
||||
</p>
|
||||
</div>
|
||||
@@ -88,29 +192,35 @@ export default async function AdminResponsesPage() {
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Fecha</th>
|
||||
<th>Encuesta</th>
|
||||
<th>Departamento</th>
|
||||
<th>Código</th>
|
||||
<th>Pregunta</th>
|
||||
<th>Tipo</th>
|
||||
<th>Valor</th>
|
||||
<th className="admin-col-optional">Departamento</th>
|
||||
<th className="admin-col-optional">Sector</th>
|
||||
<th className="admin-col-optional">Rango etario</th>
|
||||
<th>Respuestas</th>
|
||||
<th className="admin-col-optional">IP hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row, i) => {
|
||||
const survey = Array.isArray(row.surveys) ? row.surveys[0] : row.surveys
|
||||
const answerCount = row.answers?.[0]?.count ?? 0
|
||||
{rows.map((row) => {
|
||||
const groupClass =
|
||||
row.submissionNum % 2 === 0 ? 'admin-group-even' : 'admin-group-odd'
|
||||
const trClass = row.isFirstInGroup ? `${groupClass} admin-group-start` : groupClass
|
||||
const rendered = renderValue(row.value, row.type)
|
||||
return (
|
||||
<tr key={row.id}>
|
||||
<td>{i + 1}</td>
|
||||
<td>{formatDate(row.submitted_at)}</td>
|
||||
<td>{survey?.title ?? '—'}</td>
|
||||
<td>{dash(row.qi_zone)}</td>
|
||||
<td className="admin-col-optional">{dash(row.qi_sector)}</td>
|
||||
<td className="admin-col-optional">{dash(row.qi_age_bucket)}</td>
|
||||
<td>{answerCount}</td>
|
||||
<td className="admin-col-optional admin-iphash">
|
||||
{row.ip_hash ? `${row.ip_hash.slice(0, 8)}...` : '—'}
|
||||
<tr key={row.key} className={trClass}>
|
||||
<td>{row.submissionNum}</td>
|
||||
<td>{row.isFirstInGroup ? formatDate(row.submitted_at) : ''}</td>
|
||||
<td>{row.code}</td>
|
||||
<td className="admin-prompt">{truncate(row.prompt)}</td>
|
||||
<td><span className="admin-type-badge">{row.type}</span></td>
|
||||
<td>
|
||||
{rendered === null ? <span className="admin-nodata">sin dato</span> : rendered}
|
||||
</td>
|
||||
<td className="admin-col-optional">
|
||||
{row.isFirstInGroup ? (row.qi_zone ?? '—') : ''}
|
||||
</td>
|
||||
<td className="admin-col-optional">
|
||||
{row.isFirstInGroup ? (row.qi_sector ?? '—') : ''}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
||||
@@ -765,11 +765,22 @@ body {
|
||||
position: sticky; top: 0; background: var(--color-re-dark); color: #fff;
|
||||
font-weight: 600; text-align: left; padding: 10px 12px; white-space: nowrap;
|
||||
}
|
||||
.admin-table td { padding: 10px 12px; border-bottom: 1px solid var(--color-border); color: var(--color-text); }
|
||||
.admin-table tbody tr:nth-child(even) { background: var(--color-bg); }
|
||||
.admin-table tbody tr:hover { background: var(--color-primary-light); }
|
||||
.admin-table td { padding: 8px 12px; border-bottom: 1px solid var(--color-border); color: var(--color-text); vertical-align: top; }
|
||||
.admin-table tbody tr:last-child td { border-bottom: none; }
|
||||
.admin-iphash { font-family: 'Courier New', monospace; color: var(--color-text-muted); }
|
||||
.admin-table tbody tr.admin-group-even { background: var(--color-bg); }
|
||||
.admin-table tbody tr.admin-group-start td { border-top: 2px solid var(--color-re-dark); }
|
||||
.admin-table tbody tr:hover { background: var(--color-primary-light); }
|
||||
.admin-prompt { color: var(--color-text); }
|
||||
.admin-type-badge {
|
||||
display: inline-block; padding: 1px 8px; border-radius: 10px;
|
||||
background: var(--color-primary-light); color: var(--color-primary-hover);
|
||||
font-size: 0.7rem; font-weight: 600; white-space: nowrap;
|
||||
}
|
||||
.admin-nodata {
|
||||
display: inline-block; padding: 1px 8px; border-radius: 10px;
|
||||
background: var(--color-re-light); color: var(--color-re-dark);
|
||||
opacity: 0.6; font-size: 0.7rem; font-style: italic;
|
||||
}
|
||||
.admin-empty { padding: 24px; text-align: center; color: var(--color-text-muted); }
|
||||
.admin-error { color: var(--color-error); font-weight: 600; }
|
||||
.admin-error-detail {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { useCallback, useEffect, useRef, useState, useTransition } from 'react'
|
||||
import type { FormAnswers, Question, Survey } from '@/lib/types'
|
||||
import { clearDraft, loadDraft, saveDraft } from '@/lib/storage'
|
||||
import { getHiddenCodes, isQuestionVisible } from '@/lib/conditional'
|
||||
import { getHiddenCodes, isQuestionVisible, ruleQuestionCodes } from '@/lib/conditional'
|
||||
import { submitSurvey } from '@/app/actions/submit-survey'
|
||||
import { ConsentScreen } from './consent-screen'
|
||||
import { ProgressBar } from './progress-bar'
|
||||
@@ -71,7 +71,7 @@ export function SurveyForm({ survey, questions }: SurveyFormProps) {
|
||||
} else {
|
||||
const appeared = questions.some(
|
||||
(q) =>
|
||||
q.conditional_rules?.some((r) => r.if_question === code) &&
|
||||
q.conditional_rules?.some((r) => ruleQuestionCodes(r).includes(code)) &&
|
||||
isQuestionVisible(q, updated) &&
|
||||
!isQuestionVisible(q, prev)
|
||||
)
|
||||
|
||||
@@ -40,11 +40,13 @@ export function CheckboxGroup({
|
||||
{required && <span className="required-mark" aria-hidden="true"> *</span>}
|
||||
{required && <span className="sr-only"> (obligatorio)</span>}
|
||||
</legend>
|
||||
{maxSelect !== null && (
|
||||
{maxSelect !== null ? (
|
||||
<p className="max-select-hint" aria-live="polite">
|
||||
Elegí hasta {maxSelect} opciones
|
||||
{value.length > 0 && ` · ${value.length}/${maxSelect} seleccionadas`}
|
||||
</p>
|
||||
) : (
|
||||
<p className="max-select-hint">Podés marcar más de una opción</p>
|
||||
)}
|
||||
<div className="options-list" role="list">
|
||||
{options.map((opt) => {
|
||||
|
||||
@@ -11,9 +11,17 @@ export function isQuestionVisible(
|
||||
return rules.every((rule) => evaluateRule(rule, answers))
|
||||
}
|
||||
|
||||
/** Normalizes if_question to an array of codes regardless of rule shape. */
|
||||
export function ruleQuestionCodes(rule: ConditionalRule): string[] {
|
||||
return Array.isArray(rule.if_question) ? rule.if_question : [rule.if_question]
|
||||
}
|
||||
|
||||
function evaluateRule(rule: ConditionalRule, answers: FormAnswers): boolean {
|
||||
if (rule.op === 'eq') {
|
||||
return answers[rule.if_question] === rule.value
|
||||
return answers[rule.if_question as string] === rule.value
|
||||
}
|
||||
if (rule.op === 'eq_any') {
|
||||
return ruleQuestionCodes(rule).some((code) => answers[code] === rule.value)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -32,8 +40,8 @@ export function getHiddenCodes(
|
||||
return questions
|
||||
.filter((q) => {
|
||||
if (!q.conditional_rules?.length) return false
|
||||
const dependsOnTrigger = q.conditional_rules.some(
|
||||
(r) => r.if_question === triggerCode
|
||||
const dependsOnTrigger = q.conditional_rules.some((r) =>
|
||||
ruleQuestionCodes(r).includes(triggerCode)
|
||||
)
|
||||
if (!dependsOnTrigger) return false
|
||||
return !isQuestionVisible(q, projected)
|
||||
@@ -46,7 +54,7 @@ export function getTriggerCodes(questions: Question[]): Set<string> {
|
||||
const triggers = new Set<string>()
|
||||
for (const q of questions) {
|
||||
for (const rule of q.conditional_rules ?? []) {
|
||||
triggers.add(rule.if_question)
|
||||
for (const code of ruleQuestionCodes(rule)) triggers.add(code)
|
||||
}
|
||||
}
|
||||
return triggers
|
||||
|
||||
@@ -19,8 +19,8 @@ export interface RatingOptions {
|
||||
}
|
||||
|
||||
export interface ConditionalRule {
|
||||
if_question: string
|
||||
op: 'eq'
|
||||
if_question: string | string[]
|
||||
op: 'eq' | 'eq_any'
|
||||
value: string
|
||||
action: 'show'
|
||||
}
|
||||
|
||||
178
migrate-claude/ESTADO_PROYECTO_JUNIO_2026.md
Normal file
178
migrate-claude/ESTADO_PROYECTO_JUNIO_2026.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# 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)
|
||||
70
migrate-claude/PROMPT_NUEVA_SESION.md
Normal file
70
migrate-claude/PROMPT_NUEVA_SESION.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# PROMPT DE CONTINUIDAD — nueva sesión de dirección técnica
|
||||
## Datos País sobre el Cuidado
|
||||
|
||||
> Pegá este prompt al inicio de una nueva conversación con Claude.
|
||||
> Actualizado: junio 2026.
|
||||
|
||||
---
|
||||
|
||||
Sos el copiloto técnico del proyecto "Datos País sobre el Cuidado" — una plataforma soberana de encuestas sobre economía del cuidado en Paraguay. Ya tenemos múltiples sesiones de trabajo juntos. Este mensaje te pone al día antes de continuar.
|
||||
|
||||
## Contexto del proyecto
|
||||
|
||||
Plataforma de dos caras: formulario web anónimo + dashboard analítico con k-anonimato. Marca RE, Fundación Solidaridad, powered by InQuality.
|
||||
|
||||
- **Stack:** Next.js 15.3.3 + TypeScript + Tailwind CSS + Supabase self-hosted
|
||||
- **Deploy:** Dokploy v0.29.4 en VPS (IP VPN: 172.20.5.11)
|
||||
- **URL producción:** https://economia-cuidado.inqualityhq.com
|
||||
- **Repos:** app en `git.inquality.com.py/marcos/motor-de-encuestas`, Supabase stack en `git.inquality.com.py/marcos/supabase-motor-fomularios`
|
||||
- **API Supabase:** https://db.inqualityhq.com (Kong con SSL)
|
||||
|
||||
## Estado actual — Sprint 3 COMPLETADO
|
||||
|
||||
El formulario y el dashboard están operativos con Supabase self-hosted. Las 12 migraciones están aplicadas. Backups locales configurados con retención GFS. El formulario carga y permite completar la encuesta end-to-end.
|
||||
|
||||
## Deuda técnica abierta (ver TECH_DEBT.md en el repo)
|
||||
|
||||
- **TECH-DEBT-006** — Backup remoto S3 — BLOQUEANTE antes del primer dato real de empresa
|
||||
- **TECH-DEBT-007** — auth.jwt() deprecado en GoTrue v2.189+ — no bloqueante para el piloto
|
||||
- **CVE-2025-66478** — Next.js 15.3.3 con vulnerabilidad crítica — BLOQUEANTE antes del primer dato real
|
||||
|
||||
## Decisiones tomadas — no reabrir
|
||||
|
||||
1. Supabase en Dokploy siempre via modo Git (docker raw no tiene ./volumes/db/)
|
||||
2. POSTGRES_PASSWORD siempre con openssl rand -hex (evita caracteres problemáticos)
|
||||
3. kong.yml: una sola entrada por bloque keyauth_credentials
|
||||
4. SMTP_PORT=587 siempre explícito aunque SMTP esté desactivado
|
||||
5. GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=false siempre explícito
|
||||
6. LUA_AUTH_EXPR con prefijo "Bearer " en kong-entrypoint.sh rama legacy
|
||||
7. NEXT_PUBLIC_SUPABASE_URL via Build Argument en Dokploy (no Environment Setting)
|
||||
8. App Next.js conecta a Supabase por URL pública https://db.inqualityhq.com
|
||||
|
||||
## Prompts pendientes de ejecutar en Claude Code
|
||||
|
||||
1. **ETAPA 2G** — `sprints/sprint-2/ETAPA_2G_PROMPT.md` — cierre Sprint 2, formaliza patrones C.8, AP.10, AP.11 en el método
|
||||
2. **ETAPA 3V** — `sprints/sprint-3-infra/ETAPA_3V_PROMPT.md` — vista /admin/responses para control operativo
|
||||
|
||||
## Próximos pasos en orden
|
||||
|
||||
1. TECH-DEBT-006 (S3 backup) — bloqueante
|
||||
2. CVE-2025-66478 (Next.js update) — bloqueante
|
||||
3. Ejecutar ETAPA 2G en Claude Code
|
||||
4. Ejecutar ETAPA 3V en Claude Code
|
||||
5. RE Index — confirmar mapeo G1/G2/G4/G5 → códigos seed antes de implementar
|
||||
6. Informe descargable — prometido en deck comercial, no existe aún
|
||||
|
||||
## Método de trabajo
|
||||
|
||||
Usamos niveles de autonomía explícitos en los prompts (Nivel 1 = reportar antes de hacer, Nivel 3 = ejecutar con validación al final). Los prompts de Claude Code están en `sprints/`. Las decisiones arquitecturales se documentan como ADRs en `docs/adr/`. Las reglas no negociables del proyecto están en `CLAUDE.md` del repo.
|
||||
|
||||
## Preguntas frecuentes de contexto
|
||||
|
||||
**¿Por qué Supabase self-hosted y no Cloud?** Soberanía del dato — datos de cuidadores paraguayos no deben vivir en servidores de terceros fuera de control del proyecto. Decisión tomada antes de ingresar el primer dato real.
|
||||
|
||||
**¿Por qué k-anonimato k≥5?** Regla no negociable del sistema. En empresas chicas, un cruce demográfico de menos de 5 personas puede reidentificar a un individuo aunque el nombre nunca se haya guardado.
|
||||
|
||||
**¿Por qué el dashboard usa service_role?** Porque las políticas de org_admin con JWT custom claims no están implementadas (TECH-DEBT-007). Para el piloto, el dashboard es herramienta interna y service_role es aceptable. Cuando haya org_admin real, hay que resolver TECH-DEBT-007 primero.
|
||||
|
||||
---
|
||||
|
||||
¿Listo para continuar? El próximo paso es [COMPLETAR CON LO QUE VAYAS A HACER].
|
||||
48
migrate-claude/TECH_DEBT_ACTUALIZADO.md
Normal file
48
migrate-claude/TECH_DEBT_ACTUALIZADO.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# TECH_DEBT.md — actualización junio 2026
|
||||
## Para aplicar en el repo del proyecto
|
||||
|
||||
> Reemplazar el contenido existente de TECH_DEBT.md en el repo con este bloque,
|
||||
> o mergear los ítems nuevos si ya existe el archivo con otros ítems previos.
|
||||
|
||||
---
|
||||
|
||||
## Deuda técnica abierta
|
||||
|
||||
### TECH-DEBT-006 — Backup remoto S3
|
||||
**Estado:** ABIERTO — BLOQUEANTE antes del primer dato real de empresa
|
||||
**Descripción:** Los backups locales están configurados y funcionando (GFS, 3AM diario, retención 3 días + domingos 14 días). Pero los backups viven solo en el mismo VPS. Si el VPS muere, se pierden datos Y backups.
|
||||
**Solución:** rsync nocturno a S3-compatible (Backblaze B2 o Wasabi, ~USD 5/mes) usando rclone.
|
||||
**Referencia:** BACKUP_STRATEGY.md sección 5 — TECH-DEBT-006.
|
||||
|
||||
### TECH-DEBT-007 — auth.jwt() deprecado en GoTrue v2.189+
|
||||
**Estado:** ABIERTO — no bloqueante para el piloto
|
||||
**Descripción:** Las funciones helper `current_app_role()` y `current_org_id()` en migration 003 usan `auth.jwt()` que fue eliminado en GoTrue v2.189+. Las políticas que dependen de estas funciones no se crearon:
|
||||
- `org_select_own` en organizations
|
||||
- `surveys_select_auth` en surveys
|
||||
- `questions_select_auth` en questions
|
||||
**Impacto actual:** ninguno — el dashboard usa service_role que bypasa RLS. Los respondentes usan anon que tiene las políticas básicas de INSERT.
|
||||
**Impacto futuro:** org_admin no podrá autenticarse con custom claims (app_role, org_id) hasta resolver esto.
|
||||
**Solución:** migrar a auth.session() o implementar JWT claims via hook de GoTrue v2.
|
||||
**NO resolver hasta tener caso de uso real de org_admin autenticado.**
|
||||
|
||||
### CVE-2025-66478 — Next.js 15.3.3 con vulnerabilidad de seguridad
|
||||
**Estado:** ABIERTO — BLOQUEANTE antes del primer dato real de empresa
|
||||
**Descripción:** Next.js 15.3.3 tiene una vulnerabilidad de seguridad crítica. El build lo reporta explícitamente: "This version has a security vulnerability. Please upgrade to a patched version."
|
||||
**Solución:** actualizar next en package.json a la versión parcheada disponible, correr npm install, hacer redeploy.
|
||||
**Referencia:** https://nextjs.org/blog/CVE-2025-66478
|
||||
|
||||
---
|
||||
|
||||
## Deuda técnica cerrada en Sprint 3
|
||||
|
||||
### TECH-DEBT-002 — KPI NPS eliminado ✅
|
||||
KPI NPS eliminado — instrumento no tiene pregunta NPS.
|
||||
|
||||
### TECH-DEBT-003 — Brecha de políticas ✅
|
||||
Widget W6 redefinido como demanda-only (6.2), sin oferta. Documentado.
|
||||
|
||||
### TECH-DEBT-004 — Intención directa de salida no capturada
|
||||
Intención directa de salida laboral no capturada en el instrumento v2. No resuelto pero documentado como gap conocido.
|
||||
|
||||
### TECH-DEBT-005 — A1 País vs A1b ✅
|
||||
Cerrado: A1 ya es Departamento (18 opciones Paraguay) en el instrumento final.
|
||||
174
sprints/sprint-3-infra/ETAPA_3I2_PROMPT.md
Normal file
174
sprints/sprint-3-infra/ETAPA_3I2_PROMPT.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# ETAPA 3I2 — Revisión del instrumento v2.1 (feedback equipo médico)
|
||||
|
||||
## 1. Objetivo
|
||||
Aplicar 10 cambios al instrumento "Mapeo de Cuidadores" resultado del feedback del equipo
|
||||
de salud. Los cambios afectan SEED_SPEC.md, seed.sql, y el código del formulario Next.js.
|
||||
|
||||
---
|
||||
|
||||
## 2. Contexto previo
|
||||
- Instrumento actual: v2, 44 preguntas, 8 secciones, en `SEED_SPEC.md`.
|
||||
- La DB tiene al menos 1 respuesta real. Algunos cambios son breaking para datos existentes
|
||||
(opciones renombradas, tipo cambiado) — documentar en OBSERVATIONS.md, no bloquear.
|
||||
- El formulario Next.js usa un sistema de conditional_rules en el JSON de cada pregunta.
|
||||
- Los 3 triggers (1.1, 1.6, 1.13) controlan bloques condicionales enteros.
|
||||
|
||||
---
|
||||
|
||||
## 3. DECISIONES YA TOMADAS — no consultar de nuevo
|
||||
- Cambio 4: el salto a 6.4 ocurre cuando las TRES preguntas 1.1, 1.6, 1.13 dan "No"
|
||||
simultáneamente. Si al menos una da "Sí", las secciones 2-5 y 6.1-6.3 se muestran normalmente.
|
||||
- Cambio 4: las secciones 2, 3, 4, 5, 6.1, 6.2, 6.3 se saltean completamente — ir directo a 6.4.
|
||||
- Cambio 5: 2.1 pasa a multiple_choice. Es breaking para datos existentes — documentar, no bloquear.
|
||||
- Cambio 6: 2.4 se elimina del seed. Si hay respuestas con question_id de 2.4, se pierden
|
||||
al re-seedear. Documentar en OBSERVATIONS.md.
|
||||
- Cambio 4: pregunta 6.6 opciones: Sí · No · Tal vez.
|
||||
- Cambio 3: "Tecnología asistiva" va en penúltima posición (antes de "No utilizo"/"No utiliza").
|
||||
- "Prefiero no decir" se elimina de TODAS las preguntas que lo tengan.
|
||||
|
||||
---
|
||||
|
||||
## 4. Los 10 cambios — especificación exacta
|
||||
|
||||
### Cambio 1 — Eliminar "Prefiero no decir" de todo el instrumento
|
||||
Preguntas afectadas: A5, A6, 1.1, 1.5, 1.6, 1.13, 2.5, 3.1, 3.4.
|
||||
En cada una, eliminar la opción "Prefiero no decir" del array de opciones en seed.sql.
|
||||
En SEED_SPEC.md, eliminarla de la columna Opciones de cada pregunta.
|
||||
|
||||
⚠️ Los triggers 1.1, 1.6, 1.13 quedan con solo 2 opciones: Sí · No.
|
||||
La lógica condicional no cambia — solo "Sí" dispara el bloque.
|
||||
|
||||
### Cambio 2 — Subtítulo hint en todas las preguntas multiple_choice
|
||||
En el componente del formulario que renderiza preguntas de tipo `multiple_choice`,
|
||||
agregar un subtítulo/hint debajo del prompt: "Podés marcar más de una opción".
|
||||
Preguntas afectadas: 1.2, 1.3, 1.7, 1.8, 1.9, 1.10, 1.15, 2.3, 3.2, 3.3, 4.2, 6.2.
|
||||
Es un cambio de UI — no afecta seed.sql ni SEED_SPEC.md.
|
||||
|
||||
### Cambio 3 — Agregar "Tecnología asistiva" en 1.3 y 1.10
|
||||
1.3 opciones actuales: Silla de ruedas · Bastón · Andador · Muletas · Prótesis · No utilizo
|
||||
1.3 opciones nuevas: Silla de ruedas · Bastón · Andador · Muletas · Prótesis · Tecnología asistiva · No utilizo
|
||||
|
||||
1.10 opciones actuales: Silla de ruedas · Bastón · Andador · Muletas · Prótesis · No utiliza
|
||||
1.10 opciones nuevas: Silla de ruedas · Bastón · Andador · Muletas · Prótesis · Tecnología asistiva · No utiliza
|
||||
|
||||
### Cambio 4 — Salto condicional triple + nueva pregunta 6.6
|
||||
|
||||
#### 4a. Lógica de salto
|
||||
Cuando las tres responden "No": 1.1="No" AND 1.6="No" AND 1.13="No",
|
||||
las secciones 2, 3, 4, 5 completas + preguntas 6.1, 6.2, 6.3 se ocultan.
|
||||
El formulario salta directamente a 6.4.
|
||||
|
||||
Implementación sugerida: agregar una regla condicional en las preguntas de las secciones
|
||||
2-5 y 6.1-6.3 que las oculte cuando se cumple esa condición triple. La forma exacta de
|
||||
implementarlo (conditional_rules en cada pregunta vs. lógica en el componente de sección)
|
||||
la decide Claude Code según la arquitectura existente del formulario.
|
||||
|
||||
#### 4b. Nueva pregunta 6.6
|
||||
Agregar al final de la Sección 6 (después de 6.5, antes de Sección 7):
|
||||
- Code: 6.6
|
||||
- Tipo: single_choice
|
||||
- Pregunta: "¿Estarías dispuesto/a a ser voluntario/a en iniciativas y/o redes de apoyo
|
||||
a personas con discapacidad y/o cuidadores?"
|
||||
- Opciones: Sí · No · Tal vez
|
||||
- is_sensitive: false
|
||||
- top-level (siempre visible)
|
||||
|
||||
Actualizar position de 7.1 para que quede después de 6.6.
|
||||
Actualizar el conteo total de preguntas en SEED_SPEC.md (pasa de 44 a 45, o 44 si se
|
||||
compensa con la eliminación de 2.4 — verificar el conteo final).
|
||||
|
||||
### Cambio 5 — 2.1 pasa a multiple_choice
|
||||
Cambiar tipo de `single_choice` a `multiple_choice` en seed.sql y SEED_SPEC.md.
|
||||
Agregar nota en SEED_SPEC.md:
|
||||
"⚠️ TECH-DEBT: múltiple selección sin orden de prioridad. Deuda: implementar ranking
|
||||
(Principal cuidador soy yo > secundario instituto > principal pagado > secundario familiar)."
|
||||
|
||||
### Cambio 6 — Eliminar 2.4
|
||||
Eliminar la pregunta 2.4 ("¿Contás con apoyo de otras personas para el cuidado?")
|
||||
del seed.sql y SEED_SPEC.md.
|
||||
Renumerar positions de las preguntas posteriores si es necesario.
|
||||
Documentar en OBSERVATIONS.md: "2.4 eliminada por feedback equipo médico (similar a 2.1)."
|
||||
|
||||
### Cambio 7 — En 3.1 eliminar "Sin gastos significativos"
|
||||
El cambio 1 ya elimina "Prefiero no decir" de 3.1.
|
||||
Adicionalmente, eliminar "Sin gastos significativos" de las opciones de 3.1.
|
||||
3.1 opciones finales: Menos de Gs. 500.000 · Gs. 500.000–1.500.000 · Gs. 1.500.000–3.000.000
|
||||
· Gs. 3.000.000–6.000.000 · Más de Gs. 6.000.000
|
||||
|
||||
### Cambio 8 — En 3.3 cambiar texto de opción
|
||||
Cambiar: "Es difícil sostenerlo con mis ingresos"
|
||||
Por: "No puedo sostenerlo con mis ingresos"
|
||||
En seed.sql y SEED_SPEC.md.
|
||||
Documentar en OBSERVATIONS.md: "Respuestas existentes con el texto anterior quedan
|
||||
con valor 'Es difícil sostenerlo con mis ingresos' — breaking change en datos existentes."
|
||||
|
||||
### Cambio 9 — En 3.4 reestructurar primera franja salarial
|
||||
Opción actual: "Sueldo mínimo – Gs. 5.000.000"
|
||||
Reemplazar por dos opciones:
|
||||
1. "Sueldo mínimo"
|
||||
2. "Gs. 3.000.000 a 5.000.000"
|
||||
Las demás franjas no cambian.
|
||||
Documentar en OBSERVATIONS.md: "Respuestas existentes con 'Sueldo mínimo – Gs. 5.000.000'
|
||||
quedan con valor anterior — breaking change en datos existentes."
|
||||
|
||||
### Cambio 10 — En 6.1 cambiar texto de última opción
|
||||
Cambiar: "No, nunca se ha hablado del tema"
|
||||
Por: "No, no se puede hablar del tema"
|
||||
En seed.sql y SEED_SPEC.md.
|
||||
Documentar en OBSERVATIONS.md: "Breaking change en datos existentes para esta opción."
|
||||
|
||||
---
|
||||
|
||||
## 5. Archivos a modificar
|
||||
|
||||
| Archivo | Cambios |
|
||||
|---|---|
|
||||
| `SEED_SPEC.md` | Todos los cambios de opciones, tipos, preguntas nuevas/eliminadas |
|
||||
| `supabase/seed.sql` | Todos los cambios — es la fuente de verdad para re-seedear |
|
||||
| Componente formulario (multiple_choice) | Cambio 2: agregar hint |
|
||||
| Lógica condicional del formulario | Cambio 4a: salto triple |
|
||||
| `OBSERVATIONS.md` o `TECH_DEBT.md` | Documentar breaking changes y nueva deuda |
|
||||
|
||||
---
|
||||
|
||||
## 6. Entregables (DoD)
|
||||
|
||||
- [ ] SEED_SPEC.md actualizado con todos los cambios.
|
||||
- [ ] seed.sql actualizado — re-seedeable desde cero produce el instrumento v2.1.
|
||||
- [ ] Componente multiple_choice muestra hint "Podés marcar más de una opción".
|
||||
- [ ] Lógica de salto 1.1+1.6+1.13 todos "No" → salta a 6.4.
|
||||
- [ ] Pregunta 6.6 visible en el formulario.
|
||||
- [ ] "Prefiero no decir" ausente en todas las preguntas.
|
||||
- [ ] 2.4 eliminada del seed.
|
||||
- [ ] Breaking changes documentados en OBSERVATIONS.md.
|
||||
- [ ] Build exitoso.
|
||||
- [ ] `git diff --name-only HEAD` en scope.
|
||||
|
||||
## 7. Qué reportar
|
||||
```
|
||||
Verificado:
|
||||
- SEED_SPEC.md actualizado ✓
|
||||
- seed.sql actualizado ✓
|
||||
- Conteo final de preguntas: [N]
|
||||
- Hint en multiple_choice: ✓
|
||||
- Salto triple implementado: ✓ (describir cómo)
|
||||
- 6.6 agregada ✓
|
||||
- "Prefiero no decir" eliminado de: [lista de preguntas]
|
||||
- 2.4 eliminada ✓
|
||||
- Build exitoso ✓
|
||||
- Diff en scope ✓
|
||||
|
||||
Breaking changes documentados en OBSERVATIONS.md:
|
||||
- [lista]
|
||||
|
||||
Asumido:
|
||||
- [decisiones de implementación]
|
||||
```
|
||||
|
||||
## 8. Qué NO hacer
|
||||
- ❌ No re-seedear la DB de producción — solo actualizar seed.sql.
|
||||
Re-seedear producción requiere aprobación explícita del director.
|
||||
- ❌ No cambiar la estructura de tablas ni agregar columnas — solo opciones y lógica.
|
||||
- ❌ No tocar el dashboard ni las RPCs.
|
||||
- ❌ No resolver ítems de TECH_DEBT que no estén listados acá.
|
||||
- ❌ No cambiar el diseño visual del formulario más allá del hint de multiple_choice.
|
||||
175
sprints/sprint-3-infra/ETAPA_3V_B_PROMPT.md
Normal file
175
sprints/sprint-3-infra/ETAPA_3V_B_PROMPT.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# ETAPA 3V-B — Vista de control: tabla plana de respuestas individuales
|
||||
|
||||
## 1. Objetivo
|
||||
Reemplazar la vista `/admin/responses` actual (una fila por submission) por una tabla plana
|
||||
con **una fila por respuesta individual** (una fila por cada pregunta respondida), mostrando
|
||||
todos los campos explícitamente incluyendo nulos marcados visualmente.
|
||||
|
||||
---
|
||||
|
||||
## 2. Contexto previo
|
||||
- La Etapa 3V-A implementó la vista de metadatos de submissions (una fila por response).
|
||||
- El director quiere ver las respuestas individuales a las preguntas, no solo los metadatos.
|
||||
- El esquema relevante: `responses` → `answers` (via response_id) → `questions` (via question_id).
|
||||
- `answers.value` es JSONB. Los tipos de preguntas existentes en el instrumento son:
|
||||
- `single_choice` → value es string: `"Asunción (Capital)"`
|
||||
- `multiple_choice` → value es array: `["opción1","opción2"]`
|
||||
- `rating` → value es número: `3`
|
||||
- `text_short` → value es string corto
|
||||
- `text_long` → **NUNCA mostrar** — regla no negociable (RLS + privacidad)
|
||||
|
||||
---
|
||||
|
||||
## 3. DECISIONES YA TOMADAS — no consultar de nuevo
|
||||
- Ruta: `/admin/responses` — reemplaza la página anterior completamente.
|
||||
- Sin auth (herramienta interna de control).
|
||||
- Sin paginación por ahora — máximo 500 filas (limit en la query).
|
||||
- Ordenado por `responses.submitted_at DESC`, luego por `questions.position ASC` dentro de cada submission.
|
||||
- Valores nulos mostrados con badge visual "sin dato" — fondo `--color-re-light` (#E7E6E5), texto `--color-re-dark` (#494F4F) opacidad 0.6.
|
||||
- text_long excluido completamente — ni la columna ni el valor aparecen.
|
||||
- Convención CSS: `.admin-*` en `app/globals.css`, igual que la etapa anterior.
|
||||
- Cliente service-role inline en el Server Component, igual que en la versión anterior.
|
||||
|
||||
---
|
||||
|
||||
## 4. Estructura de la tabla
|
||||
|
||||
### 4.1 Encabezado de página
|
||||
- Título: "Control de respuestas"
|
||||
- Subtítulo: total de submissions + total de respuestas individuales + fecha/hora actualización.
|
||||
- Botón "Actualizar" (`<a href="/admin/responses">`).
|
||||
|
||||
### 4.2 Columnas de la tabla (una fila por answer)
|
||||
|
||||
| Columna | Fuente | Notas |
|
||||
|---|---|---|
|
||||
| # submission | índice de la submission (1, 2, 3...) | mismo número para todas las filas de esa submission |
|
||||
| Fecha | `responses.submitted_at` | DD/MM/YYYY HH:mm — solo en la primera fila de cada submission |
|
||||
| Código | `questions.code` | A1, A2, 1.1, 1.6, etc. |
|
||||
| Pregunta | `questions.prompt` | texto de la pregunta, truncado a 60 chars con "..." |
|
||||
| Tipo | `questions.type` | badge con el tipo |
|
||||
| Valor | `answers.value` | renderizado según tipo (ver 4.3) |
|
||||
| Departamento | `responses.qi_zone` | solo en primera fila de cada submission |
|
||||
| Sector | `responses.qi_sector` | solo en primera fila de cada submission |
|
||||
|
||||
### 4.3 Renderizado del valor según tipo
|
||||
|
||||
```typescript
|
||||
function renderValue(value: unknown, type: string): string {
|
||||
if (value === null || value === undefined) return null // → badge "sin dato"
|
||||
|
||||
switch(type) {
|
||||
case 'single_choice':
|
||||
case 'text_short':
|
||||
return String(value).replace(/^"|"$/g, '') // quitar comillas del JSONB string
|
||||
|
||||
case 'multiple_choice':
|
||||
if (Array.isArray(value)) return value.join(', ')
|
||||
return String(value)
|
||||
|
||||
case 'rating':
|
||||
return String(value) // número, opcionalmente con ★ repetidas
|
||||
|
||||
case 'text_long':
|
||||
return null // NUNCA mostrar — excluir de la query directamente
|
||||
|
||||
default:
|
||||
return String(value)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 Agrupación visual de submissions
|
||||
Las filas de una misma submission deben estar visualmente agrupadas:
|
||||
- Separador visual entre submissions (border-top más pronunciado o fondo alternado por submission).
|
||||
- Fecha, Departamento y Sector solo se muestran en la primera fila de cada submission.
|
||||
- Las filas siguientes de la misma submission muestran esas celdas vacías (o con colspan si es HTML puro).
|
||||
|
||||
---
|
||||
|
||||
## 5. Query recomendada
|
||||
|
||||
```typescript
|
||||
const { data } = await supabase
|
||||
.from('responses')
|
||||
.select(`
|
||||
id,
|
||||
submitted_at,
|
||||
qi_zone,
|
||||
qi_sector,
|
||||
qi_age_bucket,
|
||||
ip_hash,
|
||||
surveys ( title ),
|
||||
answers (
|
||||
value,
|
||||
questions (
|
||||
code,
|
||||
prompt,
|
||||
type,
|
||||
position,
|
||||
is_sensitive
|
||||
)
|
||||
)
|
||||
`)
|
||||
.order('submitted_at', { ascending: false })
|
||||
.limit(500)
|
||||
```
|
||||
|
||||
Después en el componente, aplanar el resultado:
|
||||
```typescript
|
||||
// Para cada response, para cada answer (excluir text_long e is_sensitive):
|
||||
// generar una fila con los datos de la response + los datos de la answer/question
|
||||
const rows = responses.flatMap((response, responseIdx) =>
|
||||
response.answers
|
||||
.filter(a => a.questions?.type !== 'text_long' && !a.questions?.is_sensitive)
|
||||
.sort((a, b) => (a.questions?.position ?? 0) - (b.questions?.position ?? 0))
|
||||
.map((answer, answerIdx) => ({
|
||||
responseIdx: responseIdx + 1,
|
||||
isFirstInGroup: answerIdx === 0,
|
||||
submitted_at: response.submitted_at,
|
||||
qi_zone: response.qi_zone,
|
||||
qi_sector: response.qi_sector,
|
||||
ip_hash: response.ip_hash,
|
||||
survey_title: response.surveys?.title,
|
||||
code: answer.questions?.code,
|
||||
prompt: answer.questions?.prompt,
|
||||
type: answer.questions?.type,
|
||||
value: answer.value,
|
||||
}))
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Entregables (DoD)
|
||||
|
||||
- [ ] Ruta `/admin/responses` renderiza con tabla plana (HTTP 200).
|
||||
- [ ] Una fila por answer, agrupadas visualmente por submission.
|
||||
- [ ] Columnas: # submission, Fecha, Código, Pregunta (truncada), Tipo, Valor, Departamento, Sector.
|
||||
- [ ] `text_long` e `is_sensitive=true` excluidos.
|
||||
- [ ] Valores nulos muestran badge "sin dato" con estilo tenue.
|
||||
- [ ] Fecha, Departamento, Sector solo en primera fila de cada grupo.
|
||||
- [ ] Build exitoso.
|
||||
- [ ] `git diff --name-only HEAD` solo en `app/admin/` y `app/globals.css`.
|
||||
|
||||
## 7. Qué reportar
|
||||
```
|
||||
Verificado:
|
||||
- Ruta /admin/responses accesible ✓
|
||||
- Total submissions: [N] · Total filas en tabla: [N]
|
||||
- Tipos de preguntas visibles: [lista]
|
||||
- text_long excluido ✓ / is_sensitive excluido ✓
|
||||
- Badge "sin dato" visible en campos nulos ✓ / no hay nulos en los datos actuales
|
||||
- Build exitoso ✓
|
||||
- Diff en scope ✓
|
||||
|
||||
Asumido:
|
||||
- [decisiones cosméticas]
|
||||
```
|
||||
|
||||
## 8. Qué NO hacer
|
||||
- ❌ No mostrar text_long ni is_sensitive bajo ningún concepto.
|
||||
- ❌ No exponer SUPABASE_SERVICE_ROLE_KEY al cliente.
|
||||
- ❌ No tocar el formulario ni el dashboard.
|
||||
- ❌ No agregar dependencias npm.
|
||||
- ❌ No paginar todavía — limit 500 es suficiente para el piloto.
|
||||
@@ -1,13 +1,15 @@
|
||||
-- ============================================================
|
||||
-- seed.sql — Instrumento "Mapeo de Cuidadores" v2 — 44 preguntas
|
||||
-- Fuente autoritativa: SEED_SPEC.md v2 (Jun 2026)
|
||||
-- seed.sql — Instrumento "Mapeo de Cuidadores" v2.1 — 44 preguntas
|
||||
-- Fuente autoritativa: SEED_SPEC.md v2.1 (Jun 2026) — Etapa 3I2
|
||||
-- Reemplaza v1 (34 preguntas con códigos A-H)
|
||||
--
|
||||
-- Estructura condicional:
|
||||
-- cond-disc-propia: 1.1='Sí' → 1.2–1.5 (4 dependientes)
|
||||
-- cond-familiar: 1.6='Sí' → 1.7–1.12 (6 dependientes)
|
||||
-- cond-adulto-mayor: 1.13='Sí' → 1.14–1.16 (3 dependientes)
|
||||
-- Resto: top-level, siempre visibles
|
||||
-- salto-triple (Cambio 4a): si 1.1, 1.6 y 1.13 son TODAS 'No', se ocultan
|
||||
-- las secciones 2-5 completas y 6.1-6.3 (eq_any 'Sí' sobre 1.1/1.6/1.13)
|
||||
-- Resto (incl. 6.4-6.6 y sección 7): top-level, siempre visibles
|
||||
--
|
||||
-- is_sensitive=true: 1.1-1.12, 1.14, 1.15, 3.4 (15 preguntas)
|
||||
-- required=false en todas (equipo decidió captura completa; obligatoriedad se define luego)
|
||||
@@ -16,7 +18,8 @@
|
||||
-- org: 10000000-0000-0000-0000-000000000001
|
||||
-- cv-v1: 20000000-0000-0000-0000-000000000001
|
||||
-- survey: 30000000-0000-0000-0000-000000000001
|
||||
-- preguntas 40000000-0000-0000-0000-00000000000{01..44}
|
||||
-- preguntas 40000000-0000-0000-0000-00000000000{01..45} excepto 027 (2.4, eliminada)
|
||||
-- → 44 preguntas activas
|
||||
-- ============================================================
|
||||
|
||||
-- ── Organización demo ─────────────────────────────────────────
|
||||
@@ -137,16 +140,14 @@ VALUES ('40000000-0000-0000-0000-000000000005','30000000-0000-0000-0000-00000000
|
||||
{"value":"25 a 34 años","label":"25 a 34 años"},
|
||||
{"value":"35 a 44 años","label":"35 a 44 años"},
|
||||
{"value":"45 a 54 años","label":"45 a 54 años"},
|
||||
{"value":"55 años o más","label":"55 años o más"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"55 años o más","label":"55 años o más"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
VALUES ('40000000-0000-0000-0000-000000000006','30000000-0000-0000-0000-000000000001',
|
||||
'A6','single_choice','¿Con qué género te identificás?',6,false,false,
|
||||
'[{"value":"Femenino","label":"Femenino"},
|
||||
{"value":"Masculino","label":"Masculino"},
|
||||
{"value":"No binario/Otro","label":"No binario/Otro"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"No binario/Otro","label":"No binario/Otro"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
VALUES ('40000000-0000-0000-0000-000000000007','30000000-0000-0000-0000-000000000001',
|
||||
@@ -168,8 +169,7 @@ VALUES ('40000000-0000-0000-0000-000000000008','30000000-0000-0000-0000-00000000
|
||||
'¿Vos mismo/a vivís con alguna discapacidad o condición de salud que afecte tu funcionamiento cotidiano?',
|
||||
8,true,false,
|
||||
'[{"value":"Sí","label":"Sí"},
|
||||
{"value":"No","label":"No"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"No","label":"No"}]'::jsonb);
|
||||
|
||||
-- cond-disc-propia: 1.2–1.5 se muestran si 1.1='Sí'
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
@@ -210,8 +210,7 @@ VALUES ('40000000-0000-0000-0000-000000000012','30000000-0000-0000-0000-00000000
|
||||
'1.5','single_choice','¿Tu condición afecta tu desempeño o comodidad en el trabajo?',12,true,false,
|
||||
'[{"value":"Sí, de forma significativa","label":"Sí, de forma significativa"},
|
||||
{"value":"Sí, pero en aspectos puntuales","label":"Sí, pero en aspectos puntuales"},
|
||||
{"value":"No, está bien gestionada","label":"No, está bien gestionada"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb,
|
||||
{"value":"No, está bien gestionada","label":"No, está bien gestionada"}]'::jsonb,
|
||||
'[{"if_question":"1.1","op":"eq","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
-- 1.6 trigger — is_sensitive=true
|
||||
@@ -221,8 +220,7 @@ VALUES ('40000000-0000-0000-0000-000000000013','30000000-0000-0000-0000-00000000
|
||||
'¿Tenés algún familiar cercano (hijo/a, pareja, hermano/a, padre/madre) que viva con discapacidad?',
|
||||
13,true,false,
|
||||
'[{"value":"Sí","label":"Sí"},
|
||||
{"value":"No","label":"No"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"No","label":"No"}]'::jsonb);
|
||||
|
||||
-- cond-familiar: 1.7–1.12 se muestran si 1.6='Sí'
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
@@ -267,6 +265,7 @@ VALUES ('40000000-0000-0000-0000-000000000017','30000000-0000-0000-0000-00000000
|
||||
{"value":"Andador","label":"Andador"},
|
||||
{"value":"Muletas","label":"Muletas"},
|
||||
{"value":"Prótesis","label":"Prótesis"},
|
||||
{"value":"Tecnología asistiva","label":"Tecnología asistiva"},
|
||||
{"value":"No utiliza","label":"No utiliza"}]'::jsonb,
|
||||
'[{"if_question":"1.6","op":"eq","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
@@ -296,8 +295,7 @@ VALUES ('40000000-0000-0000-0000-000000000020','30000000-0000-0000-0000-00000000
|
||||
'1.13','single_choice','¿Tenés algún adulto mayor (60+ años) a tu cuidado o bajo tu responsabilidad?',
|
||||
20,false,false,
|
||||
'[{"value":"Sí","label":"Sí"},
|
||||
{"value":"No","label":"No"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"No","label":"No"}]'::jsonb);
|
||||
|
||||
-- cond-adulto-mayor: 1.14–1.16 se muestran si 1.13='Sí'
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
@@ -331,26 +329,30 @@ VALUES ('40000000-0000-0000-0000-000000000023','30000000-0000-0000-0000-00000000
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- SECCIÓN 2 — Intensidad y rol del cuidado (top-level)
|
||||
-- Cambio 4a: visible si 1.1='Sí' OR 1.6='Sí' OR 1.13='Sí' (eq_any)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
-- 2.1: Cambio 5 — pasa a multiple_choice (TECH-DEBT: ranking, ver TECH_DEBT.md)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000024','30000000-0000-0000-0000-000000000001',
|
||||
'2.1','single_choice','¿Quién es el/la responsable principal del cuidado?',24,false,false,
|
||||
'2.1','multiple_choice','¿Quién es el/la responsable principal del cuidado?',24,false,false,
|
||||
'[{"value":"Yo soy el/la principal","label":"Yo soy el/la principal"},
|
||||
{"value":"Comparto con otro familiar","label":"Comparto con otro familiar"},
|
||||
{"value":"Hay cuidador/a pagado/a","label":"Hay cuidador/a pagado/a"},
|
||||
{"value":"Está en institución/centro de día","label":"Está en institución/centro de día"}]'::jsonb);
|
||||
{"value":"Está en institución/centro de día","label":"Está en institución/centro de día"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000025','30000000-0000-0000-0000-000000000001',
|
||||
'2.2','single_choice','¿Cuántas horas por día dedicás, en promedio, al cuidado directo?',25,false,false,
|
||||
'[{"value":"Menos de 1h","label":"Menos de 1h"},
|
||||
{"value":"Entre 1 y 3h","label":"Entre 1 y 3h"},
|
||||
{"value":"Entre 3 y 6h","label":"Entre 3 y 6h"},
|
||||
{"value":"Más de 6h","label":"Más de 6h"},
|
||||
{"value":"Varía mucho","label":"Varía mucho"}]'::jsonb);
|
||||
{"value":"Varía mucho","label":"Varía mucho"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000026','30000000-0000-0000-0000-000000000001',
|
||||
'2.3','multiple_choice','¿En qué momentos del día cuidás principalmente?',26,false,false,
|
||||
'[{"value":"Antes del trabajo","label":"Antes del trabajo"},
|
||||
@@ -358,98 +360,99 @@ VALUES ('40000000-0000-0000-0000-000000000026','30000000-0000-0000-0000-00000000
|
||||
{"value":"Al llegar del trabajo","label":"Al llegar del trabajo"},
|
||||
{"value":"Durante la noche","label":"Durante la noche"},
|
||||
{"value":"Los fines de semana","label":"Los fines de semana"},
|
||||
{"value":"Es continuo sin horario fijo","label":"Es continuo sin horario fijo"}]'::jsonb);
|
||||
{"value":"Es continuo sin horario fijo","label":"Es continuo sin horario fijo"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
VALUES ('40000000-0000-0000-0000-000000000027','30000000-0000-0000-0000-000000000001',
|
||||
'2.4','single_choice','¿Contás con apoyo de otras personas para el cuidado?',27,false,false,
|
||||
'[{"value":"Sí, apoyo familiar suficiente","label":"Sí, apoyo familiar suficiente"},
|
||||
{"value":"Algo de apoyo, no suficiente","label":"Algo de apoyo, no suficiente"},
|
||||
{"value":"No, soy el/la único/a responsable","label":"No, soy el/la único/a responsable"},
|
||||
{"value":"Tengo apoyo contratado","label":"Tengo apoyo contratado"}]'::jsonb);
|
||||
-- 2.4 eliminada (Cambio 6 — feedback equipo médico, similar a 2.1). Ver OBSERVATIONS.md.
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000028','30000000-0000-0000-0000-000000000001',
|
||||
'2.5','single_choice',
|
||||
'Como cuidador/a primario, ¿presentás signos de agotamiento o estrés crónico?',28,false,false,
|
||||
'Como cuidador/a primario, ¿presentás signos de agotamiento o estrés crónico?',27,false,false,
|
||||
'[{"value":"Sí, frecuentemente","label":"Sí, frecuentemente"},
|
||||
{"value":"A veces","label":"A veces"},
|
||||
{"value":"No, lo llevo bien","label":"No, lo llevo bien"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"No, lo llevo bien","label":"No, lo llevo bien"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- SECCIÓN 3 — Impacto económico del cuidado (top-level)
|
||||
-- 3.4: is_sensitive=true + analyst-only (no exponer a org_admin)
|
||||
-- Cambio 4a: visible si 1.1='Sí' OR 1.6='Sí' OR 1.13='Sí' (eq_any)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000029','30000000-0000-0000-0000-000000000001',
|
||||
'3.1','single_choice','¿Cuánto estimás que gastás por mes en el cuidado?',29,false,false,
|
||||
'[{"value":"Sin gastos significativos","label":"Sin gastos significativos"},
|
||||
{"value":"Menos de Gs. 500.000","label":"Menos de Gs. 500.000"},
|
||||
'3.1','single_choice','¿Cuánto estimás que gastás por mes en el cuidado?',28,false,false,
|
||||
'[{"value":"Menos de Gs. 500.000","label":"Menos de Gs. 500.000"},
|
||||
{"value":"Gs. 500.000–1.500.000","label":"Gs. 500.000–1.500.000"},
|
||||
{"value":"Gs. 1.500.000–3.000.000","label":"Gs. 1.500.000–3.000.000"},
|
||||
{"value":"Gs. 3.000.000–6.000.000","label":"Gs. 3.000.000–6.000.000"},
|
||||
{"value":"Más de Gs. 6.000.000","label":"Más de Gs. 6.000.000"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"Más de Gs. 6.000.000","label":"Más de Gs. 6.000.000"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000030','30000000-0000-0000-0000-000000000001',
|
||||
'3.2','multiple_choice','¿Qué servicios o apoyos utilizás actualmente?',30,false,false,
|
||||
'3.2','multiple_choice','¿Qué servicios o apoyos utilizás actualmente?',29,false,false,
|
||||
'[{"value":"Terapias especializadas","label":"Terapias especializadas"},
|
||||
{"value":"Cuidador/a particular","label":"Cuidador/a particular"},
|
||||
{"value":"Centro de día/institución","label":"Centro de día/institución"},
|
||||
{"value":"Transporte adaptado","label":"Transporte adaptado"},
|
||||
{"value":"Medicación alto costo","label":"Medicación alto costo"},
|
||||
{"value":"Equipamiento médico/tecnología asistiva","label":"Equipamiento médico/tecnología asistiva"},
|
||||
{"value":"No utilizo servicios formales","label":"No utilizo servicios formales"}]'::jsonb);
|
||||
{"value":"No utilizo servicios formales","label":"No utilizo servicios formales"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000031','30000000-0000-0000-0000-000000000001',
|
||||
'3.3','multiple_choice','¿Cómo sostenés los gastos y responsabilidades del cuidado?',31,false,false,
|
||||
'3.3','multiple_choice','¿Cómo sostenés los gastos y responsabilidades del cuidado?',30,false,false,
|
||||
'[{"value":"Con mi empleo de tiempo completo","label":"Con mi empleo de tiempo completo"},
|
||||
{"value":"Con mi empleo de tiempo parcial","label":"Con mi empleo de tiempo parcial"},
|
||||
{"value":"Con trabajo independiente/emprendimiento","label":"Con trabajo independiente/emprendimiento"},
|
||||
{"value":"Me ayudan mis familiares","label":"Me ayudan mis familiares"},
|
||||
{"value":"Es difícil sostenerlo con mis ingresos","label":"Es difícil sostenerlo con mis ingresos"}]'::jsonb);
|
||||
{"value":"No puedo sostenerlo con mis ingresos","label":"No puedo sostenerlo con mis ingresos"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
-- 3.4: CONFIDENCIAL — is_sensitive=true, analyst-only
|
||||
-- No exponer en ninguna vista accesible a org_admin (ADR-001 addendum)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000032','30000000-0000-0000-0000-000000000001',
|
||||
'3.4','single_choice','¿En qué franja salarial mensual te ubicás?',32,true,false,
|
||||
'[{"value":"Sueldo mínimo – Gs. 5.000.000","label":"Sueldo mínimo – Gs. 5.000.000"},
|
||||
'3.4','single_choice','¿En qué franja salarial mensual te ubicás?',31,true,false,
|
||||
'[{"value":"Sueldo mínimo","label":"Sueldo mínimo"},
|
||||
{"value":"Gs. 3.000.000 a 5.000.000","label":"Gs. 3.000.000 a 5.000.000"},
|
||||
{"value":"Gs. 5.000.001–8.000.000","label":"Gs. 5.000.001–8.000.000"},
|
||||
{"value":"Gs. 8.000.001–12.000.000","label":"Gs. 8.000.001–12.000.000"},
|
||||
{"value":"Gs. 12.000.001–15.000.000","label":"Gs. 12.000.001–15.000.000"},
|
||||
{"value":"Gs. 15.000.001–18.000.000","label":"Gs. 15.000.001–18.000.000"},
|
||||
{"value":"Gs. 18.000.001–25.000.000","label":"Gs. 18.000.001–25.000.000"},
|
||||
{"value":"Gs. 25.000.001–50.000.000","label":"Gs. 25.000.001–50.000.000"},
|
||||
{"value":"Gs. 50.000.001 o más","label":"Gs. 50.000.001 o más"},
|
||||
{"value":"Prefiero no decir","label":"Prefiero no decir"}]'::jsonb);
|
||||
{"value":"Gs. 50.000.001 o más","label":"Gs. 50.000.001 o más"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000033','30000000-0000-0000-0000-000000000001',
|
||||
'3.5','rating','¿Los gastos de cuidado impactan en tu situación económica personal?',33,false,false,
|
||||
'{"min":1,"max":5,"min_label":"Sin impacto","max_label":"Muy alto impacto"}'::jsonb);
|
||||
'3.5','rating','¿Los gastos de cuidado impactan en tu situación económica personal?',32,false,false,
|
||||
'{"min":1,"max":5,"min_label":"Sin impacto","max_label":"Muy alto impacto"}'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- SECCIÓN 4 — Tiempo y descanso (top-level)
|
||||
-- Cambio 4a: visible si 1.1='Sí' OR 1.6='Sí' OR 1.13='Sí' (eq_any)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000034','30000000-0000-0000-0000-000000000001',
|
||||
'4.1','single_choice','¿Cómo describirías tu nivel de descanso habitual?',34,false,false,
|
||||
'4.1','single_choice','¿Cómo describirías tu nivel de descanso habitual?',33,false,false,
|
||||
'[{"value":"Descanso bien, me siento recuperado/a","label":"Descanso bien, me siento recuperado/a"},
|
||||
{"value":"Descanso de forma irregular, pero lo manejo","label":"Descanso de forma irregular, pero lo manejo"},
|
||||
{"value":"Me cuesta descansar, me siento cansado/a con frecuencia","label":"Me cuesta descansar, me siento cansado/a con frecuencia"},
|
||||
{"value":"Descanso muy poco, el agotamiento afecta mi día a día","label":"Descanso muy poco, el agotamiento afecta mi día a día"}]'::jsonb);
|
||||
{"value":"Descanso muy poco, el agotamiento afecta mi día a día","label":"Descanso muy poco, el agotamiento afecta mi día a día"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000035','30000000-0000-0000-0000-000000000001',
|
||||
'4.2','multiple_choice','¿Qué aspectos de tu vida se ven más afectados por tu rol de cuidador/a?',35,false,false,
|
||||
'4.2','multiple_choice','¿Qué aspectos de tu vida se ven más afectados por tu rol de cuidador/a?',34,false,false,
|
||||
'[{"value":"Tiempo libre y ocio","label":"Tiempo libre y ocio"},
|
||||
{"value":"Sueño y descanso","label":"Sueño y descanso"},
|
||||
{"value":"Vida social y amistades","label":"Vida social y amistades"},
|
||||
@@ -457,80 +460,91 @@ VALUES ('40000000-0000-0000-0000-000000000035','30000000-0000-0000-0000-00000000
|
||||
{"value":"Salud física personal","label":"Salud física personal"},
|
||||
{"value":"Salud emocional/mental","label":"Salud emocional/mental"},
|
||||
{"value":"Desarrollo profesional","label":"Desarrollo profesional"},
|
||||
{"value":"Situación económica","label":"Situación económica"}]'::jsonb);
|
||||
{"value":"Situación económica","label":"Situación económica"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000036','30000000-0000-0000-0000-000000000001',
|
||||
'4.3','rating','En una escala del 1 al 5, ¿cómo evaluás tu bienestar general en este momento?',36,false,false,
|
||||
'{"min":1,"max":5,"min_label":"Muy mal","max_label":"Muy bien"}'::jsonb);
|
||||
'4.3','rating','En una escala del 1 al 5, ¿cómo evaluás tu bienestar general en este momento?',35,false,false,
|
||||
'{"min":1,"max":5,"min_label":"Muy mal","max_label":"Muy bien"}'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- SECCIÓN 5 — Impacto en el trabajo (top-level)
|
||||
-- Cambio 4a: visible si 1.1='Sí' OR 1.6='Sí' OR 1.13='Sí' (eq_any)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000037','30000000-0000-0000-0000-000000000001',
|
||||
'5.1','single_choice',
|
||||
'En los últimos 3 meses, ¿con qué frecuencia sentiste que el cuidado afectó tu concentración o rendimiento?',
|
||||
37,false,false,
|
||||
36,false,false,
|
||||
'[{"value":"Nunca o casi nunca","label":"Nunca o casi nunca"},
|
||||
{"value":"Algunas veces al mes","label":"Algunas veces al mes"},
|
||||
{"value":"Varias veces por semana","label":"Varias veces por semana"},
|
||||
{"value":"Casi todos los días","label":"Casi todos los días"}]'::jsonb);
|
||||
{"value":"Casi todos los días","label":"Casi todos los días"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000038','30000000-0000-0000-0000-000000000001',
|
||||
'5.2','single_choice',
|
||||
'En el último año, ¿faltaste al trabajo por situaciones relacionadas al cuidado?',38,false,false,
|
||||
'En el último año, ¿faltaste al trabajo por situaciones relacionadas al cuidado?',37,false,false,
|
||||
'[{"value":"Nunca","label":"Nunca"},
|
||||
{"value":"Pocas veces (1–3 veces al año)","label":"Pocas veces (1–3 veces al año)"},
|
||||
{"value":"Varias veces (4–10 veces al año)","label":"Varias veces (4–10 veces al año)"},
|
||||
{"value":"Con frecuencia (más de 10 veces al año)","label":"Con frecuencia (más de 10 veces al año)"}]'::jsonb);
|
||||
{"value":"Con frecuencia (más de 10 veces al año)","label":"Con frecuencia (más de 10 veces al año)"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- SECCIÓN 6 — Conciencia organizacional (top-level)
|
||||
-- 6.1-6.3: Cambio 4a — visible si 1.1='Sí' OR 1.6='Sí' OR 1.13='Sí' (eq_any)
|
||||
-- 6.4-6.6: siempre visibles (destino del salto triple)
|
||||
-- 6.2: multiple_choice max_select=3 (ranking en backlog)
|
||||
-- 6.4/6.5: códigos corregidos (eran 6.2/6.3 duplicados en el HTML original)
|
||||
-- 6.6: nueva pregunta (Cambio 4b)
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000039','30000000-0000-0000-0000-000000000001',
|
||||
'6.1','single_choice',
|
||||
'¿Sentís que tu empresa conoce o comprende la realidad del cuidado y la discapacidad de su gente?',
|
||||
39,false,false,
|
||||
38,false,false,
|
||||
'[{"value":"Sí, me siento acompañado/a","label":"Sí, me siento acompañado/a"},
|
||||
{"value":"Parcialmente, hay cierta comprensión","label":"Parcialmente, hay cierta comprensión"},
|
||||
{"value":"No, es algo bastante invisible","label":"No, es algo bastante invisible"},
|
||||
{"value":"No, nunca se ha hablado del tema","label":"No, nunca se ha hablado del tema"}]'::jsonb);
|
||||
{"value":"No, no se puede hablar del tema","label":"No, no se puede hablar del tema"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,max_select,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,max_select,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000040','30000000-0000-0000-0000-000000000001',
|
||||
'6.2','multiple_choice','¿Qué apoyos de la empresa te ayudarían más? Elegí hasta 3',40,false,false,3,
|
||||
'6.2','multiple_choice','¿Qué apoyos de la empresa te ayudarían más? Elegí hasta 3',39,false,false,3,
|
||||
'[{"value":"Flexibilidad horaria o trabajo remoto","label":"Flexibilidad horaria o trabajo remoto"},
|
||||
{"value":"Apoyo económico o convenios/descuentos","label":"Apoyo económico o convenios/descuentos"},
|
||||
{"value":"Acceso a terapias o salud","label":"Acceso a terapias o salud"},
|
||||
{"value":"Contención/apoyo emocional o psicológico","label":"Contención/apoyo emocional o psicológico"},
|
||||
{"value":"Capacitación y autocuidado","label":"Capacitación y autocuidado"},
|
||||
{"value":"Redes de apoyo/grupos de pares","label":"Redes de apoyo/grupos de pares"},
|
||||
{"value":"Información sobre recursos y servicios disponibles","label":"Información sobre recursos y servicios disponibles"}]'::jsonb);
|
||||
{"value":"Información sobre recursos y servicios disponibles","label":"Información sobre recursos y servicios disponibles"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options,conditional_rules)
|
||||
VALUES ('40000000-0000-0000-0000-000000000041','30000000-0000-0000-0000-000000000001',
|
||||
'6.3','single_choice',
|
||||
'¿Estarías dispuesto/a a participar en un grupo de apoyo para cuidadores dentro de la empresa?',
|
||||
41,false,false,
|
||||
40,false,false,
|
||||
'[{"value":"Sí, definitivamente","label":"Sí, definitivamente"},
|
||||
{"value":"Tal vez, si hay más personas en la misma situación","label":"Tal vez, si hay más personas en la misma situación"},
|
||||
{"value":"No por ahora","label":"No por ahora"},
|
||||
{"value":"Prefiero mantenerlo en privado","label":"Prefiero mantenerlo en privado"}]'::jsonb);
|
||||
{"value":"Prefiero mantenerlo en privado","label":"Prefiero mantenerlo en privado"}]'::jsonb,
|
||||
'[{"if_question":["1.1","1.6","1.13"],"op":"eq_any","value":"Sí","action":"show"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
VALUES ('40000000-0000-0000-0000-000000000042','30000000-0000-0000-0000-000000000001',
|
||||
'6.4','single_choice',
|
||||
'¿Conocés a algún compañero/a de trabajo que esté al cuidado de una persona con discapacidad o dependiente?',
|
||||
42,false,false,
|
||||
41,false,false,
|
||||
'[{"value":"Sí, conozco a varias personas","label":"Sí, conozco a varias personas"},
|
||||
{"value":"Sí, conozco a una persona","label":"Sí, conozco a una persona"},
|
||||
{"value":"No conozco a nadie","label":"No conozco a nadie"},
|
||||
@@ -540,12 +554,21 @@ INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitiv
|
||||
VALUES ('40000000-0000-0000-0000-000000000043','30000000-0000-0000-0000-000000000001',
|
||||
'6.5','single_choice',
|
||||
'¿Considerás que la empresa debería ofrecer apoyos a quienes cuidan a una persona dependiente?',
|
||||
43,false,false,
|
||||
42,false,false,
|
||||
'[{"value":"Sí, definitivamente","label":"Sí, definitivamente"},
|
||||
{"value":"Tal vez, dependería del caso","label":"Tal vez, dependería del caso"},
|
||||
{"value":"No lo considero necesario","label":"No lo considero necesario"},
|
||||
{"value":"No lo sé","label":"No lo sé"}]'::jsonb);
|
||||
|
||||
INSERT INTO public.questions (id,survey_id,code,type,prompt,position,is_sensitive,required,options)
|
||||
VALUES ('40000000-0000-0000-0000-000000000045','30000000-0000-0000-0000-000000000001',
|
||||
'6.6','single_choice',
|
||||
'¿Estarías dispuesto/a a ser voluntario/a en iniciativas y/o redes de apoyo a personas con discapacidad y/o cuidadores?',
|
||||
43,false,false,
|
||||
'[{"value":"Sí","label":"Sí"},
|
||||
{"value":"No","label":"No"},
|
||||
{"value":"Tal vez","label":"Tal vez"}]'::jsonb);
|
||||
|
||||
|
||||
-- ══════════════════════════════════════════════════════════════
|
||||
-- SECCIÓN 7 — Para cerrar (top-level)
|
||||
|
||||
Reference in New Issue
Block a user