Con el listado de encuestas cargadas/respondidas

This commit is contained in:
markosbenitez
2026-06-10 08:59:50 -03:00
parent 2f39ce555c
commit bf963e8894
6 changed files with 1119 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
# 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
```typescript
// 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á.