Problemas Comunes de Soporte
Sección titulada «Problemas Comunes de Soporte»Esta guía cubre los escenarios de soporte más frecuentes con pasos concretos para diagnosticar y resolver cada uno.
Herramientas que necesitarás:
- Acceso al panel admin en
/admin - Acceso a Stripe Dashboard
- Prisma Studio:
wasp db studio(solo en desarrollo o con acceso a la DB)
1. Usuario pagó pero no tiene acceso al curso
Sección titulada «1. Usuario pagó pero no tiene acceso al curso»Este es el problema más común. Puede tener varias causas.
Diagnóstico paso a paso
Sección titulada «Diagnóstico paso a paso»Paso 1: Verificar en Stripe que el pago fue exitoso
- Ir a Stripe Dashboard → Payments
- Buscar el email del usuario
- Verificar que el estado del pago es “Succeeded” (no “Pending” ni “Failed”)
- Anotar el
payment_intent_idosession_id
Paso 2: Verificar que el webhook fue procesado
En Stripe Dashboard → Developers → Webhooks:
- Encontrar el webhook de producción (
/payments-webhook) - Buscar el evento
checkout.session.completedcon la fecha del pago - Si el evento tiene estado “Failed” o no existe → el webhook falló
Paso 3: Verificar la inscripción en la base de datos
Con Prisma Studio (wasp db studio) o via SQL:
-- Buscar el usuarioSELECT id, email FROM "User" WHERE email = 'usuario@ejemplo.com';
-- Ver sus inscripcionesSELECT e.*, c.title as course_titleFROM "Enrollment" eJOIN "Course" c ON e."courseId" = c.idWHERE e."userId" = <user_id>;Si no hay inscripción → el webhook no creó el registro.
Soluciones
Sección titulada «Soluciones»Si el webhook falló:
- En Stripe Dashboard → Webhooks → el evento fallido → “Resend”
- Esto reintenta el webhook y debería crear la inscripción
Si la inscripción no existe y no puedes reenviar el webhook:
Crear la inscripción manualmente con Prisma Studio:
- Abrir
wasp db studio - Tabla
Enrollment→ Add record:userId: ID del usuariocourseId: ID del curso compradoenrolledAt: fecha actualcompleted: false
- Notificar al usuario que ya tiene acceso
Si el usuario compró una suscripción y no tiene acceso:
Verificar que el campo subscriptionStatus del usuario es "active":
SELECT id, email, "subscriptionStatus", "subscriptionPlan"FROM "User"WHERE email = 'usuario@ejemplo.com';Si no es "active", puede ser un problema de sincronización con Stripe. Verificar el estado de la
suscripción en Stripe Dashboard → Customers.
2. Certificado no se generó después de completar un curso
Sección titulada «2. Certificado no se generó después de completar un curso»Diagnóstico
Sección titulada «Diagnóstico»Paso 1: Verificar que el curso realmente está completado
SELECT e.completed, e."completedAt", e."courseId"FROM "Enrollment" eWHERE e."userId" = <user_id> AND e."courseId" = <course_id>;Si completed = false → el usuario no completó el curso (todas las lecciones deben estar
completadas).
Paso 2: Verificar el progreso de lecciones
SELECT lp."lessonId", lp.completed, lp."watchedSeconds"FROM "LessonProgress" lpJOIN "Lesson" l ON lp."lessonId" = l.idWHERE lp."userId" = <user_id>AND l."courseId" = <course_id>ORDER BY l."order";Comparar con el total de lecciones del curso — todas deben estar completed = true.
Paso 3: Buscar el certificado
SELECT * FROM "Certificate"WHERE "userId" = <user_id> AND "courseId" = <course_id>;Soluciones
Sección titulada «Soluciones»Si el curso está completado pero no hay certificado:
El certificado se genera en la action completeCourse. Forzar la generación:
-
En Prisma Studio → tabla
Certificate→ Add record:userId: ID del usuariocourseId: ID del cursoissuedAt: fecha actualcertificateCode: generar UUID único (ej.cert_YYYYMMDD_userId_courseId)
-
Notificar al usuario con el link a
/certificados
Si hay lecciones sin completar:
Verificar si el usuario reporta que sí las completó. Puede ser un bug de sincronización. Revisar
LessonProgress y si corresponde, marcar manualmente:
UPDATE "LessonProgress"SET completed = true, "completedAt" = NOW()WHERE "userId" = <user_id> AND "lessonId" = <lesson_id>;3. Video no carga
Sección titulada «3. Video no carga»Los videos funcionan diferente en desarrollo y producción.
Diferencia crítica: Desarrollo vs. Producción
Sección titulada «Diferencia crítica: Desarrollo vs. Producción»| Entorno | Fuente de videos | Cómo funcionan |
|---|---|---|
| Desarrollo | MP4 públicos W3C (storageVideoKey) | URL directa, sin firma |
| Producción | AWS S3 + CloudFront o Azure | URL firmada con expiración de 1 hora |
⚠️ Importante: En producción, todos los videos deben estar en S3 o Azure Blob Storage. YouTube fue eliminado como fuente de video (abril 2026).
Diagnóstico en producción
Sección titulada «Diagnóstico en producción»Paso 1: Verificar si la URL firmada expira
Las CloudFront Signed URLs expiran en 1 hora. Si el usuario deja el video abierto más de 1 hora sin recargar, el video deja de funcionar. Solución: recargar la página.
Paso 2: Verificar las variables de entorno
Si múltiples usuarios reportan el problema:
flyctl ssh console -a talentbricksai -C "env | grep -E 'CLOUDFRONT|AWS_S3'"Verificar que todas las variables están configuradas:
CLOUDFRONT_DOMAINCLOUDFRONT_KEY_PAIR_IDCLOUDFRONT_PRIVATE_KEYAWS_S3_IAM_ACCESS_KEYAWS_S3_IAM_SECRET_KEYAWS_S3_FILES_BUCKETAWS_S3_REGION
Paso 3: Verificar que el archivo existe en S3
- Ir a AWS Console → S3
- Buscar el bucket
talentbricksai-videos - Verificar que el archivo del video existe
Paso 4: Verificar permisos de CloudFront
Verificar que la política del bucket S3 permite acceso a CloudFront OAC. Ver Despliegue → Fase 3.
4. Usuario olvidó su contraseña
Sección titulada «4. Usuario olvidó su contraseña»En desarrollo (email dummy)
Sección titulada «En desarrollo (email dummy)»En desarrollo, los emails se imprimen en la consola del servidor (no se envían). Para ver el link de reset:
# En la terminal donde corre wasp start# Buscar líneas como:# Subject: Reset your password# Body: Click this link: http://localhost:3000/password-reset?token=...En producción (SendGrid)
Sección titulada «En producción (SendGrid)»El usuario debe:
- Ir a la página de login → “¿Olvidaste tu contraseña?”
- Ingresar su email
- Revisar su bandeja de entrada (y carpeta de spam)
- Click en el link del email (válido por 1 hora)
Si el email no llega después de 5 minutos:
- Verificar en SendGrid Dashboard → Activity que el email fue enviado
- Verificar que el dominio está autenticado en SendGrid
- Verificar que
SENDGRID_API_KEYestá configurada correctamente
5. Cómo hacer a un usuario administrador
Sección titulada «5. Cómo hacer a un usuario administrador»Solo los administradores pueden hacer a otros usuarios administradores. Hay dos formas:
Vía base de datos (más directa)
Sección titulada «Vía base de datos (más directa)»En Prisma Studio o SQL:
UPDATE "User"SET "isAdmin" = trueWHERE email = 'nuevo-admin@empresa.com';Vía variable de entorno
Sección titulada «Vía variable de entorno»La variable ADMIN_EMAILS en el servidor puede listar emails que automáticamente tienen acceso
admin:
# En desarrollo (.env.server):ADMIN_EMAILS="tu@email.com,otro@email.com"
# En producción (Fly.io):wasp deploy fly cmd --context server secrets set ADMIN_EMAILS="admin1@empresa.com,admin2@empresa.com"Nota: Los cambios en
ADMIN_EMAILSsolo aplican al login siguiente del usuario. No cambia el campoisAdminen la DB automáticamente — depende de la lógica de la app.
6. Usuario pide reembolso
Sección titulada «6. Usuario pide reembolso»TalentBricksAI no tiene sistema de reembolsos automático. Los reembolsos se procesan manualmente en Stripe.
Proceso
Sección titulada «Proceso»- Ir a Stripe Dashboard → Payments
- Buscar el pago del usuario por email o monto
- Hacer clic en el pago → “Refund”
- Seleccionar monto (total o parcial) y razón
- Confirmar el reembolso
Stripe notifica automáticamente al usuario por email.
Después del reembolso, si quieres también revocar el acceso al curso:
UPDATE "Enrollment"SET completed = falseWHERE "userId" = <user_id> AND "courseId" = <course_id>;
-- O eliminar la inscripción completamente:DELETE FROM "Enrollment"WHERE "userId" = <user_id> AND "courseId" = <course_id>;Política de reembolsos: Definir e implementar una política clara antes de lanzar. Stripe permite 30 días para la mayoría de los reembolsos.
7. Queries de diagnóstico útiles con Prisma Studio
Sección titulada «7. Queries de diagnóstico útiles con Prisma Studio»Abrir con wasp db studio (corre en http://localhost:5555).
Queries frecuentes de soporte
Sección titulada «Queries frecuentes de soporte»-- Ver todos los cursos disponiblesSELECT id, title, slug, "isPublished" FROM "Course" ORDER BY title;
-- Ver inscripciones de un usuarioSELECT e.id, c.title, e."enrolledAt", e.completedFROM "Enrollment" eJOIN "Course" c ON e."courseId" = c.idWHERE e."userId" = <user_id>;
-- Ver usuarios con suscripción activaSELECT id, email, "subscriptionStatus", "subscriptionPlan"FROM "User"WHERE "subscriptionStatus" = 'active';
-- Ver certificados emitidosSELECT cert.id, u.email, c.title, cert."issuedAt"FROM "Certificate" certJOIN "User" u ON cert."userId" = u.idJOIN "Course" c ON cert."courseId" = c.idORDER BY cert."issuedAt" DESCLIMIT 20;
-- Buscar un usuario por emailSELECT id, email, "isAdmin", "subscriptionStatus", "createdAt"FROM "User"WHERE email ILIKE '%@ejemplo.com%';Escalamiento
Sección titulada «Escalamiento»Si un problema no está cubierto aquí o requiere cambios de código:
- Documentar el problema con capturas de pantalla y pasos para reproducir
- Crear un issue en GitHub con el label
bugosupport - Notificar al usuario que se está investigando y dar un tiempo estimado de respuesta