Files
motor-de-encuestas/sprints/sprint-2/ETAPA_2A_PROMPT.md
2026-06-04 14:30:28 -03:00

6.7 KiB
Raw Permalink Blame History

ETAPA 2A — Motor del formulario (render + lógica condicional, sin persistir)

Prompt versionado (Patrón B.1). Primera pieza de cara al usuario. Claude Code lo ejecuta tras leer CLAUDE.md, DATA_MODEL.md, SEED_SPEC.md, ADR-002, sprints/sprint-2/BRIEF.md y este prompt.

1. Objetivo

Construir el motor del formulario: una app Next.js que lee la encuesta live desde Supabase con la anon key, renderiza las 44 preguntas (instrumento v2) con el widget correcto por tipo, ejecuta la lógica condicional, valida, es mobile-first y accesible (WCAG AA), no pierde lo cargado al refrescar, y al enviar muestra un resumen de respuestas. NO escribe nada en la base (eso es 2B).

2. Contexto previo

La fundación de datos (Sprint 1) está cerrada y verificada en Cloud: esquema, RLS, seed real de 44 preguntas (instrumento v2, Jun 2026), k-anonimato. El proyecto Supabase está linkeado. Todavía no existe app frontend — esta etapa la scaffolding. responses.consent_record_id es NOT NULL, por eso 2A no persiste: la escritura requiere el consentimiento, que es 2B. El mockup formulario_mapeo.html (en el historial del proyecto) es el contrato visual: replicar su look y flujo, pero leyendo del esquema, no hardcoded.

3. Decisiones ya tomadas (no consultar de nuevo)

  • Stack: Next.js (App Router) + react-hook-form + zod + @supabase/supabase-js (o @supabase/ssr). Sin librería de gráficos (eso es Sprint 3).
  • El cliente usa la anon key (pública, respeta RLS), desde NEXT_PUBLIC_SUPABASE_URL y NEXT_PUBLIC_SUPABASE_ANON_KEY en .env.local. El service_role NUNCA va a una variable NEXT_PUBLIC_ ni al cliente (regla 9 de CLAUDE.md).
  • options: array para single_choice/multiple_choice; objeto {min,max,min_label,max_label} para rating (3.5, 4.3); null para text_short/text_long. Manejar las tres formas.
  • Tipos de widget: single_choice→radio, multiple_choice→checkbox, rating→escala 1-5, text_long→textarea, text_short<input type="text"> de una línea (A1/A2/A3: País, Ciudad, Sede).
  • Condicionales: cada pregunta dependiente trae conditional_rules con {if_question, op:'eq', value:'Sí', action:'show'}. Triggers: 1.1 (→1.21.5), 1.6 (→1.71.12), 1.13 (→1.141.16). Con "No"/"Prefiero no decir" ocultar y limpiar las respuestas del bloque.
  • 6.2 = multiple_choice con max_select=3 (impedir marcar más de 3).
  • 2A no escribe responses/answers/consent_records. Al enviar → pantalla de resumen.

4. Tareas

  1. Scaffolding de la app Next.js (App Router) en el repo. Setear el cliente Supabase con la anon key desde .env.local. Crear .env.example (sin valores) documentando las dos variables.
  2. Leer desde Supabase (anon) la encuesta status='live' + sus 44 questions ordenadas por position, con sus options, type, max_select, is_sensitive, conditional_rules. (Si la encuesta seed no está live, dejar documentado que el director debe setearla a live, o leer por id — NO cambiar el estado desde el cliente.)
  3. Renderizar cada tipo con su widget: single_choice→radios, multiple_choice→checkboxes (con tope max_select), rating→escala 1-5 (usando el objeto options), text_long→textarea, text_short→input de una línea (A1/A2/A3).
  4. Motor de lógica condicional data-driven: evaluar conditional_rules para mostrar/ocultar; al ocultar un bloque, limpiar sus valores.
  5. Validación con zod (tipos correctos; respetar max_select; required según el campo required de cada pregunta — hoy todas false, así que validación liviana).
  6. UX: mobile-first fluida, replicando el contrato visual del mockup (secciones, progreso, estados de opción). Accesibilidad WCAG 2.2 AA: HTML semántico, <label> asociado a cada input, navegación y operación completa por teclado, foco visible, contraste suficiente, y anunciar a lectores de pantalla la aparición/desaparición de los bloques condicionales (aria-expanded/aria-live).
  7. Resiliencia lite: persistir las respuestas en progreso en localStorage (clave por survey_id) para sobrevivir un refresh; limpiar al enviar. No guardar nada identificable.
  8. Al enviar: validar y mostrar una pantalla de resumen con las respuestas dadas. NO llamar a la base para escribir.

5. Definition of Done

  • npm run dev levanta la app y carga la encuesta desde Supabase (anon).
  • Se renderizan las 44 preguntas; los 3 bloques condicionales aparecen/desaparecen con 1.1/1.6/1.13.
  • 6.2 no deja marcar más de 3; rating (3.5/4.3) funciona con el formato objeto; A1/A2/A3 son inputs de texto.
  • Navegable y operable solo con teclado; pasa una auditoría a11y básica (axe o Lighthouse) sin errores AA.
  • Refresh conserva lo cargado; enviar limpia el almacenamiento y muestra el resumen.
  • npm run build limpio; ninguna variable NEXT_PUBLIC_ contiene el service_role.
  • git diff --name-only HEAD solo con archivos de la app nueva + .env.example.

6. Validaciones automatizadas mandatorias (antes de entregar)

  • La carga lee 44 preguntas desde la base (logear el conteo), no un número hardcodeado.
  • Las 13 condicionales se evalúan desde conditional_rules (no con if cableados por código).
  • max_select de 6.2 se respeta en runtime (test o verificación manual reproducible).
  • npm run build sin errores.
  • Auditoría a11y (axe-core o lighthouse) sobre la página del formulario: 0 violaciones de nivel AA.
  • Grep de seguridad: service_role NO aparece en ningún archivo del cliente ni en NEXT_PUBLIC_*.
  • Si CUALQUIERA falla: NO declarar lista la etapa. Reportar y esperar.

7. Qué reportar

  • Verificado: conteo de preguntas cargadas, resultado de la auditoría a11y (con la herramienta y el puntaje/violaciones), confirmación de que el build pasa, salida del grep de service_role.
  • Asumido / Hallazgos / Decisiones por iniciativa (clasificadas por nivel).
  • git diff --name-only HEAD pegado.
  • Indicar cómo levantar la app localmente para que el director la abra (el comando y la URL).

8. Qué NO hacer

  • NO escribir en responses, answers ni consent_records (es 2B).
  • NO construir el flujo de consentimiento ni el dashboard.
  • NO hardcodear las preguntas: todo se lee del esquema.
  • NO poner el service_role en el cliente ni en variables NEXT_PUBLIC_.
  • NO recolectar ni guardar nada identificable del respondente (sin respondent_id, sin fingerprinting, sin claves de localStorage que identifiquen a la persona). El anonimato es la premisa.
  • NO cambiar el estado de la encuesta (draft/live) desde el cliente.
  • Ante conflicto entre una restricción y "que compile/funcione": detenerse y reportar.