Files
motor-de-encuestas/sprints/sprint-2/ETAPA_2A_PROMPT.md
2026-06-02 10:27:52 -03:00

6.3 KiB

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 34 preguntas 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 34 preguntas, 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 (F3, G4). Manejar las dos formas.
  • Condicionales: cada pregunta dependiente trae conditional_rules con {if_question, op:'eq', value:'Sí', action:'show'}. Mostrar solo si el disparador (B1/C1/D1) = "Sí"; con "No"/"Prefiero no decir" ocultar y limpiar las respuestas de ese bloque.
  • H1 = 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 34 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.
  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 34 preguntas; los 3 bloques condicionales aparecen/desaparecen con B1/C1/D1.
  • H1 no deja marcar más de 3; rating funciona con el formato objeto.
  • 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 34 preguntas desde la base (logear el conteo), no un número hardcodeado.
  • Las 12 condicionales se evalúan desde conditional_rules (no con if cableados por código).
  • max_select de H1 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.