Wiki / Documentación interna / Historial

Incidencias resueltas

Memoria institucional: qué pasó, por qué, y cómo se solucionó. Orden cronológico inverso.

19/09/2026 — Cadena de fallos en la recuperación de contraseña

Reportado como un único síntoma ("no me llegan los emails de recuperación / el enlace inicia sesión directamente") que resultó ser tres causas independientes, encontradas y corregidas una por una.

1. Secreto del webhook desincronizado

Síntoma: los correos de autenticación no seguían la plantilla personalizada ni dejaban registro en email_log.

Causa raíz: AUTH_EMAIL_HOOK_SECRET en Vercel y el secreto que Supabase Auth usaba para firmar las llamadas al Send Email Hook llevaban tiempo desincronizados — nunca se había ejecutado supabase config push desde que se activó el hook. Cada llamada fallaba la verificación (401), Supabase caía a su plantilla nativa por defecto.

Solución: secreto regenerado y fijado a la vez en Vercel (vercel env add) y en Supabase (supabase config push), evitando depender de adivinar cuál de los dos valores existentes era el correcto.

Lección: cualquier cambio en supabase/config.toml (Auth, no solo migraciones SQL) necesita config push explícito. No pasa solo.

2. Zona horaria incorrecta en los logs

Síntoma: las fechas en los logs de email, auditoría, PDFs e historial de socios aparecían con 1-2 horas menos de la hora real de España.

Causa raíz: Vercel ejecuta sus funciones en UTC. toLocaleString("es-ES") sin timeZone explícito usa la zona horaria del proceso, no la del lector.

Solución: src/lib/format/fecha.ts, con timeZone: "Europe/Madrid" forzado en todo formateo de fecha del lado servidor (y también del cliente, por consistencia, ya que la plataforma es de uso exclusivo en España).

3. Dominio de Resend cayendo en spam

Síntoma: el correo salía bien de Resend (estado Delivered) pero Gmail lo clasificaba como spam.

Causa raíz: faltaba un registro DMARC para el dominio (tecvalencia.com). Al añadirlo, se creó un segundo registro _dmarc sin borrar ningún anterior — dos registros DMARC en el mismo host invalidan la evaluación completa para cualquier proveedor de correo.

Solución: un único registro v=DMARC1; p=none; adkim=r; aspf=r. Confirmado: el siguiente envío llegó a la bandeja principal.

4. Doble canje del código PKCE en /auth/callback

Síntoma: incluso con el email llegando bien y con la plantilla correcta, al pulsar el enlace de recuperación la aplicación iniciaba sesión directamente, sin pasar nunca por la pantalla de nueva contraseña.

Causa raíz: detectSessionInUrl (activado por defecto en createBrowserClient) hace que el SDK de Supabase detecte y canjee él solo el ?code= de la URL en cuanto se crea el cliente — antes de que pagina-callback.tsx llegara a su propia llamada explícita a exchangeCodeForSession(). Esa segunda llamada manual fallaba (código ya gastado), caía al "enlace inválido" y navegaba a /login — pero la sesión ya se había abierto en el primer canje automático, así que el middleware, al ver a alguien ya autenticado en /login, lo redirigía derecho a su sociedad.

Solución: detectSessionInUrl: false en src/lib/supabase/client.ts. El canje queda exclusivamente en manos de pagina-callback.tsx, la única página que necesita interpretar esa URL.

Este bug es genuinamente sutil: el síntoma (inicio de sesión directo) parece justo lo contrario de un fallo, así que fácilmente pasa desapercibido en pruebas superficiales. Solo apareció al probar el flujo de verdad, de principio a fin, en el mismo navegador.