Files
motor-de-encuestas/sprints/sprint-3-infra/ETAPA_3V_PROMPT.md
2026-06-10 08:59:50 -03:00

4.8 KiB

ETAPA 3V — Vista de control: listado de respuestas

1. Objetivo

Crear una página de control operativo en /admin/responses que muestre todas las respuestas recibidas, ordenadas por fecha descendente (más recientes primero). Es una herramienta interna de diagnóstico — sin auth, sin PII, sin datos sensibles.


2. Contexto previo

  • La migración está en Supabase self-hosted.
  • Las tablas relevantes son responses, answers, questions, surveys.
  • answers.value es JSONB — contiene el valor de la respuesta.
  • Campos sensibles protegidos por RLS: answers donde question.is_sensitive=true y los tipos text_long. No mostrar esos campos aunque lleguen.
  • La página usa el cliente server-side (SUPABASE_SERVICE_ROLE_KEY) porque bypasa RLS y permite ver todos los datos. No usar el cliente anon.

3. DECISIONES YA TOMADAS — no consultar de nuevo

  • Ruta: /admin/responses — Server Component de Next.js (no client component).
  • Sin auth (es herramienta interna de control).
  • Sin paginación por ahora — mostrar las últimas 200 respuestas máximo.
  • Ordenado por submitted_at DESC.
  • HTML semántico limpio, paleta RE existente (#43BBC8, #494F4F, #F8AD13).
  • No usar componentes del dashboard existente — página standalone.

4. Qué mostrar

4.1 Encabezado de página

  • Título: "Control de respuestas"
  • Subtítulo: conteo total de respuestas en la base + fecha/hora de última actualización.
  • Botón "Actualizar" que recarga la página (simple <a href="/admin/responses">).

4.2 Tabla de respuestas (una fila por response)

Columnas:

Columna Fuente Notas
# índice visual (1, 2, 3...) más reciente = 1
Fecha responses.submitted_at formato: DD/MM/YYYY HH:mm
Encuesta surveys.title JOIN con surveys
Departamento responses.qi_zone puede ser null → mostrar "—"
Sector responses.qi_sector puede ser null → mostrar "—"
Rango etario responses.qi_age_bucket puede ser null → mostrar "—"
Respuestas count de answers para esa response número simple
IP hash responses.ip_hash primeros 8 chars + "..." — solo para dedup

4.3 Detalle expandible (opcional, Nivel 2 — reportar si se implementa)

Si el tiempo lo permite: al hacer click en una fila, mostrar un panel con las respuestas individuales (código de pregunta + valor), excluyendo:

  • Preguntas con is_sensitive = true
  • Preguntas de tipo text_long

Si no se implementa el detalle, la tabla sola es suficiente para cerrar la etapa.


5. Implementación

5.1 Query recomendada

// En un Server Component — usar el cliente con service_role
const { data: responses } = 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(200)

5.2 Cliente server-side

Usar createClient con SUPABASE_SERVICE_ROLE_KEY (server-side only, no exponer al cliente). Si existe lib/supabase-server.ts o similar, usarlo. Si no, crear el cliente inline en el Server Component con la service role key.

5.3 Estilos

  • Paleta RE: teal #43BBC8, dark #494F4F, orange #F8AD13, light #E7E6E5.
  • Tabla con filas alternadas (zebra), hover sutil.
  • Header de tabla sticky si la lista es larga.
  • Responsive — en mobile, las columnas menos importantes se ocultan.
  • Fuente: la que ya usa el proyecto (IBM Plex Sans o la que esté configurada).
  • NO usar Tailwind si el proyecto no lo usa — verificar primero con grep "tailwind" package.json.

6. Entregables (DoD)

  • Ruta /admin/responses accesible y renderiza.
  • Tabla muestra respuestas ordenadas por fecha descendente.
  • Conteo total en el encabezado.
  • Columnas: #, Fecha, Encuesta, Departamento, Sector, Rango etario, Respuestas, IP hash (truncado).
  • Campos nulos muestran "—".
  • IP hash truncada (primeros 8 chars).
  • Build sin errores (next build).
  • git diff --name-only HEAD solo en app/admin/ y posiblemente lib/.

7. Qué reportar

Verificado:
- Ruta /admin/responses accesible ✓
- Columnas presentes: [lista]
- Conteo total: [número]
- Build exitoso ✓
- Diff en scope ✓

Asumido:
- [decisiones cosméticas o de implementación]

Decisiones proactivas (Nivel 2):
- [si implementó el detalle expandible o no]

8. Qué NO hacer

  • No agregar auth — es herramienta interna, la URL es suficiente como "seguridad por oscuridad" por ahora.
  • No mostrar campos text_long ni is_sensitive=true.
  • No exponer SUPABASE_SERVICE_ROLE_KEY al cliente (solo server-side).
  • No tocar el formulario ni el dashboard existente.
  • No agregar dependencias npm.
  • No resolver ítems del backlog que no sean los listados acá.