Ir al contenido

Self-onboarding masivo

El cuerpo técnico genera un único link grupal desde /dashboard/onboarding-link y lo reparte por WhatsApp, QR o cualquier canal. Cada jugador abre el link, se reconoce en la grilla de fotos, confirma identidad, y recibe el mail con el link a /auth/set-password para fijar contraseña.

Implementado en PR #36 — es el flujo recomendado para alta inicial del plantel completo.

  • Problema que resuelve: mandar invites uno por uno a 30+ jugadores es trabajo manual costoso. El link grupal lo reduce a un mensaje de WhatsApp al grupo del plantel.
  • Casos de uso típicos: alta inicial del plantel completo al contratar CÉNIT, alta de juveniles que ascienden en bloque, renovación de credenciales rotando el token.
  • Planes que lo incluyen: todos.
  • Diferenciador: el anti-spoofing por email pre-cargado evita el modo “alguien clickea la foto de otro y se queda con su cuenta” sin requerir verificación por SMS, DNI ni OTP adicional.

hop, dir y sc pueden generar y rotar el token. La grilla pública en /onboarding/[token] no requiere login y sirve a cualquier visitante del link.

  1. Staff entra a /dashboard/onboarding-link. Solo hop, dir y sc pueden entrar — el resto cae a /dashboard.
  2. Click “Generar link” llama a generateOrgOnboardingToken:
    • Si la org ya tiene org_onboarding_token, devuelve el existente (no rota).
    • Si no, genera 24 bytes random en base64url (~192 bits de entropía) y lo persiste en organizations.org_onboarding_token.
  3. Compartir el link por WhatsApp, QR o el canal que use el club.
  4. Opcionalmente: revisar /dashboard/onboarding-status para ver cuántos jugadores ya activaron su cuenta.
  1. Abre /onboarding/[token] → ve la grilla de jugadores activos del plantel que todavía no activaron su cuenta.
  2. Click en su foto → pantalla de confirmación.
  3. La confirmación muestra el email enmascarado (ej. p***********@example.com) si ya estaba pre-cargado en players.email, o pide que el jugador lo escriba si no.
  4. Click “Soy yo” → la acción claimPlayer(token, playerId) dispara un invite de Supabase Auth a la casilla pre-cargada (no al input). El metadata del invite lleva player_id server-trusted.
  5. El jugador recibe el mail, abre el link, fija su contraseña en /auth/set-password, y queda linkeado automáticamente.

Si el link se filtra o ya pasó el período de alta, regenerar el token desde el mismo panel invalida los links viejos. Los jugadores que ya activaron quedan intactos.

  • players.email se pre-carga desde Plantel. Si falta, el jugador lo escribe en la confirmación (fallback PR 90dabd9).
  • players.photo_url alimenta la grilla. Sin foto, aparece un placeholder con iniciales.
  • Jugador inactivo: no aparece en la grilla.
  • Jugador ya activado: desaparece de la grilla (auth_user_id IS NOT NULL o onboarding_consumed_at IS NOT NULL).
  • Anti-replay: si dos personas clickean la misma foto, el link solo activa al primero que termine /auth/set-password. El segundo intento rebota porque el slot quedó consumido.
  • Grilla pública: logo del club y fotos del plantel con dorsal y posición. No hace falta login ni la app instalada.
  • Confirmación: muestra el email enmascarado o pide tipearlo.
  • Mail de invite: template inviteEmailHtml({ forPlayer: true }). Asunto “Activá tu cuenta — [Org]”.
  • Resend envía el mail final via plantilla inviteEmailHtml.
  • Supabase Auth genera el link con metadata player_id que linkPlayerAfterPasswordSet consume después.
  • Tabla organizations persiste org_onboarding_token.
  • Tabla players lee y escribe auth_user_id y onboarding_consumed_at para evitar reusos.
  • Bug anecdótico #10: hay reportes esporádicos de jugadores que terminan el flujo pero no quedan linkeados con auth_user_id. El handler linkPlayerAfterPasswordSet es race-safe en código; pendiente repro reproducible.
  • Wellness links legacy: /w/[token] sigue activo para Nacional. Para clubes nuevos, el flujo recomendado es PWA + login + push notifications.