feat(engagement): add admin engagement screen (#182)#234
Conversation
🔧 Fix del CI:
|
| Probe | Respuesta | Qué ejercita |
|---|---|---|
sin apikey |
{"error":"Missing Authorization header"} |
early-return, nada |
con apikey |
{"error":"Unauthorized"} |
Kong inyecta Authorization → createClient + getUser (camino caro) |
Arreglo (dos partes)
1. .github/workflows/ci.yml — el probe ahora envía apikey (leída de supabase status -o env) y espera hasta obtener el Unauthorized de la propia función, que prueba que createClient + getUser ya están calientes. Así el arranque en frío se paga dentro del step de CI, fuera de cualquier timeout de Jest. Ventana ampliada a 60 intentos con -m 30 por petición.
2. supabase/functions/track-engagement/index.ts — imports movidos del CDN esm.sh a los registros oficiales:
import { createClient } from 'jsr:@supabase/supabase-js@2' // antes: https://esm.sh/...
import { z } from 'npm:zod@3.23.8' // antes: https://esm.sh/...Ataca la causa de fondo (la lentitud/flakiness del cold start venía de descargar el grafo de módulos desde un CDN de terceros) y alinea con la convención que ya seguía scrape-og en este repo, que usa jsr:.
Verificación
Simulé el step de CI eliminando el contenedor del edge runtime para forzar arranque desde cero:
- Probe caliente en 1 s · 6/6 tests de
trackEngagementPASS · sin errores en el log de la función. - Suite de integración completa → 4 suites, 13 tests PASS.
pnpm typecheck✅ ·pnpm lint --max-warnings=0✅.
Nota: en local el caché de módulos de Deno persiste, así que no se reproduce al 100 % el cold start de CI (la descarga real). Pero el probe ahora bloquea hasta que el camino caro responde, que es justo lo que faltaba.
Ficheros
.github/workflows/ci.ymlsupabase/functions/track-engagement/index.ts
Read per-post metrics from the post_engagement_daily view (never raw engagement_sessions), aggregate the last 30 days and show one row per post with unique clicks, click rate, average rating and reactions, including loading/empty/error states. Summing unique_readers across days is safe because engagement_sessions holds one row per (user_id, post_id); averages are weighted and left null when there is no denominator. Staff is redirected away as UX only — the view's is_manager() guard is what enforces access. Reachable from the admin hub and, for managers, from the profile screen.
Closes #182