Guía de Pruebas - Sistema B2B
Sección titulada «Guía de Pruebas - Sistema B2B»Resumen del Sistema
Sección titulada «Resumen del Sistema»El sistema de organizaciones permite a empresas comprar suscripciones de equipo con múltiples asientos (seats) y gestionar el acceso de sus miembros a los cursos de TalentBricksAI.
Roles y Permisos
Sección titulada «Roles y Permisos»| Rol | Descripción | Permisos |
|---|---|---|
| Platform Admin | Administrador de la plataforma | • Ver todas las organizaciones • Gestionar cualquier organización • Acceso completo al admin dashboard |
| OWNER | Dueño de la organización | • Gestionar suscripción y facturación • Invitar/remover miembros • Asignar cursos • Cambiar roles de miembros • Eliminar organización • Ver analíticas |
| ADMIN | Administrador de equipo | • Invitar/remover miembros • Asignar cursos • Ver analíticas • NO puede gestionar facturación ni eliminar la organización |
| MEMBER | Miembro del equipo | • Acceder a cursos asignados a la organización • Ver progreso personal • NO puede invitar usuarios ni gestionar el equipo |
Preparación del Entorno de Prueba
Sección titulada «Preparación del Entorno de Prueba»Crear Datos de Prueba
Sección titulada «Crear Datos de Prueba»cd appwasp db seed seedOrganizationTestData🔑 Credenciales de Prueba
Sección titulada «🔑 Credenciales de Prueba»Platform Admin
Sección titulada «Platform Admin»| Password | Dashboard | |
|---|---|---|
admin@talentbricks.ai | Admin123! | /admin/organizations |
Usuarios de Organizaciones (Password: Test123!)
Sección titulada «Usuarios de Organizaciones (Password: Test123!)»| Password | Rol | Organización | Seats | |
|---|---|---|---|---|
owner@talentbricks.test | Test123! | OWNER | TalentBricks Corp | 10 |
admin@talentbricks.test | Test123! | ADMIN | TalentBricks Corp | 10 |
member1@talentbricks.test | Test123! | MEMBER | TalentBricks Corp | 10 |
member2@talentbricks.test | Test123! | MEMBER | TalentBricks Corp | 10 |
owner@acme.test | Test123! | OWNER | Acme Inc | 25 |
admin@acme.test | Test123! | ADMIN | Acme Inc | 25 |
owner@startup.test | Test123! | OWNER | StartupXYZ | 5 |
Datos Creados por el Seed
Sección titulada «Datos Creados por el Seed»-
3 organizaciones de prueba:
- TalentBricks Corp (10 seats)
- Acme Inc (25 seats)
- StartupXYZ (5 seats)
-
7 usuarios de prueba (ver tabla arriba)
-
Cursos asignados:
- TalentBricks Corp tiene acceso a los primeros 2 cursos
- Acme Inc tiene acceso al primer curso
Flujos de Prueba
Sección titulada «Flujos de Prueba»Flujo 1: Compra de Plan de Equipo (E2E)
Sección titulada «Flujo 1: Compra de Plan de Equipo (E2E)»Objetivo: Verificar el flujo completo de compra de una suscripción de equipo.
Pasos:
- Inicia sesión con un usuario regular
- Navega a
/teams/purchase - Selecciona un plan de equipo (ej: 10 seats)
- Completa el formulario (nombre de org, email de facturación)
- Haz clic en “Continuar al checkout”
- Completa el checkout de Stripe (tarjeta de prueba:
4242 4242 4242 4242) - Verifica redirección a
/team/{organizationId}
Verificaciones:
# Verificar nueva organizaciónpsql $DATABASE_URL -c "SELECT id, name, maxSeats, subscriptionStatus FROM \"Organization\" ORDER BY \"createdAt\" DESC LIMIT 1;"
# Verificar membresíapsql $DATABASE_URL -c "SELECT om.role, u.email FROM \"OrganizationMember\" om JOIN \"User\" u ON om.\"userId\" = u.id WHERE om.\"organizationId\" = '{organization_id}';"Resultados esperados:
- ✅ Nueva organización creada
- ✅
subscriptionStatus = 'active' - ✅
maxSeatscoincide con plan - ✅ Usuario es OWNER
- ✅
usedSeats = 1
Flujo 2: Invitar Miembros al Equipo
Sección titulada «Flujo 2: Invitar Miembros al Equipo»Objetivo: Verificar que OWNER y ADMIN pueden invitar miembros.
Como OWNER:
Sección titulada «Como OWNER:»- Inicia sesión como
owner@talentbricks.test - Navega a
/team/{organizationId}/members - Haz clic en “Invitar Miembro”
- Ingresa email:
newmember@test.com, Rol: MEMBER - Envía la invitación
- Verifica que aparezca en “Invitaciones Pendientes”
Como MEMBER:
Sección titulada «Como MEMBER:»- Inicia sesión como
member1@talentbricks.test - Verifica que NO aparezca el botón “Invitar Miembro”
Verificaciones:
psql $DATABASE_URL -c "SELECT email, role, \"invitedBy\", \"expiresAt\" FROM \"OrganizationInvitation\" WHERE \"organizationId\" = '{organization_id}';"Resultados esperados:
- ✅ OWNER puede invitar miembros
- ✅ ADMIN puede invitar miembros
- ✅ MEMBER NO puede invitar miembros
- ✅ Token único generado
- ✅ Expiración = 7 días
Flujo 3: Aceptar Invitación
Sección titulada «Flujo 3: Aceptar Invitación»Objetivo: Verificar que usuarios invitados puedan unirse.
Pasos:
- Obtén el token de invitación:
psql $DATABASE_URL -c "SELECT token FROM \"OrganizationInvitation\" WHERE email = 'newmember@test.com' LIMIT 1;"- Si el usuario no existe, créalo en
/signup - Navega a
/invitation/{token} - Acepta la invitación
- Verifica redirección a
/team/{organizationId}
Verificaciones:
# Verificar nuevo miembropsql $DATABASE_URL -c "SELECT om.role, u.email FROM \"OrganizationMember\" om JOIN \"User\" u ON om.\"userId\" = u.id WHERE u.email = 'newmember@test.com';"
# Verificar usedSeats incrementadopsql $DATABASE_URL -c "SELECT \"usedSeats\", \"maxSeats\" FROM \"Organization\" WHERE id = '{organization_id}';"Resultados esperados:
- ✅ Usuario es miembro
- ✅
usedSeatsincrementado - ✅
acceptedAtestablecido - ✅ Rol correcto
Flujo 4: Asignar Cursos a la Organización
Sección titulada «Flujo 4: Asignar Cursos a la Organización»Objetivo: Verificar que admins pueden asignar cursos.
Como OWNER:
Sección titulada «Como OWNER:»- Inicia sesión como
owner@talentbricks.test - Navega a
/team/{organizationId}/courses - Asigna un curso
Como MEMBER:
Sección titulada «Como MEMBER:»- Verifica que NO aparezca el botón “Asignar Curso”
- Solo ve los cursos ya asignados
Verificaciones:
psql $DATABASE_URL -c "SELECT c.title, u.email as \"assignedBy\" FROM \"OrganizationEnrollment\" oe JOIN \"Course\" c ON oe.\"courseId\" = c.id JOIN \"User\" u ON oe.\"assignedById\" = u.id WHERE oe.\"organizationId\" = '{organization_id}';"Resultados esperados:
- ✅ OWNER y ADMIN pueden asignar
- ✅ MEMBER NO puede asignar
- ✅
assignedByIdregistra quién asignó
Flujo 5: Acceso a Cursos por Miembros
Sección titulada «Flujo 5: Acceso a Cursos por Miembros»Objetivo: Verificar que miembros pueden acceder a cursos asignados.
Pasos:
- Asigna un curso a la organización
- Inicia sesión como
member1@talentbricks.test - Navega a
/courses/{slug}/learn - Reproduce una lección
- Verifica que el progreso se guarde
Como usuario sin membresía:
- Inicia sesión con un usuario NO miembro
- Intenta acceder al curso
- Verifica denegación de acceso (403)
Resultados esperados:
- ✅ Miembros pueden acceder
- ✅ No-miembros NO pueden
- ✅ Progreso se guarda
- ✅ Videos se cargan
Flujo 6: Gestión de Roles
Sección titulada «Flujo 6: Gestión de Roles»Objetivo: Verificar que solo OWNER puede cambiar roles.
Como OWNER:
Sección titulada «Como OWNER:»- Promover MEMBER a ADMIN
- Degradar ADMIN a MEMBER
- Verificar cambios en BD
Como ADMIN:
Sección titulada «Como ADMIN:»- Verificar que NO aparezca “Cambiar Rol”
Verificaciones:
psql $DATABASE_URL -c "SELECT u.email, om.role FROM \"OrganizationMember\" om JOIN \"User\" u ON om.\"userId\" = u.id WHERE om.\"organizationId\" = '{organization_id}' ORDER BY om.role;"Resultados esperados:
- ✅ Solo OWNER puede cambiar roles
- ✅ Cambios se reflejan en BD y UI
Flujo 7: Remover Miembros
Sección titulada «Flujo 7: Remover Miembros»Objetivo: Verificar que OWNER y ADMIN pueden remover.
Pasos:
- Como OWNER, remueve un miembro
- Verifica que
usedSeatsdecrementa - Inicia sesión como usuario removido
- Verifica pérdida de acceso a
/team/{organizationId}(403) - Verifica pérdida de acceso a cursos
Verificaciones:
# Verificar usuario removidopsql $DATABASE_URL -c "SELECT * FROM \"OrganizationMember\" WHERE \"organizationId\" = '{organization_id}' AND \"userId\" = '{removed_user_id}';"
# Verificar usedSeatspsql $DATABASE_URL -c "SELECT \"usedSeats\" FROM \"Organization\" WHERE id = '{organization_id}';"Resultados esperados:
- ✅ OWNER y ADMIN pueden remover
- ✅
usedSeatsdecrementa - ✅ Usuario pierde acceso
- ✅ Registro eliminado
Flujo 8: Admin Dashboard
Sección titulada «Flujo 8: Admin Dashboard»Objetivo: Verificar que platform admins pueden gestionar organizaciones.
Pasos:
- Inicia sesión como
admin@talentbricks.ai - Navega a
/admin/organizations - Usa filtros (nombre, subscription status)
- Haz clic en una organización
- Edita: cambia nombre o
maxSeats - Verifica actualización en BD
Resultados esperados:
- ✅ Admin ve todas las organizaciones
- ✅ Filtros funcionan
- ✅ Admin puede editar
- ✅ Analíticas correctas
Flujo 9: Límite de Asientos
Sección titulada «Flujo 9: Límite de Asientos»Objetivo: Verificar que no se pueden exceder los seats.
Setup:
psql $DATABASE_URL -c "UPDATE \"Organization\" SET \"maxSeats\" = 3 WHERE name = 'TalentBricks Corp';"Pasos:
- Con 2 miembros actuales (owner + 1)
- Invita a 1 usuario → Debe funcionar (3/3)
- Intenta invitar otro → Debe fallar
- Verifica error: “No hay asientos disponibles”
Resultados esperados:
- ✅ Invitación falla cuando
usedSeats >= maxSeats - ✅ Mensaje de error claro
- ✅ UI muestra contador de seats
Flujo 10: Facturación y Gestión
Sección titulada «Flujo 10: Facturación y Gestión»Objetivo: Verificar que OWNER puede gestionar facturación.
Pasos:
- Como OWNER, navega a
/team/{organizationId}/billing - Verifica información mostrada (plan, seats, próxima facturación)
- Haz clic en “Gestionar en Stripe”
- Verifica apertura del portal
Como ADMIN:
Sección titulada «Como ADMIN:»- Intenta acceder a
/team/{organizationId}/billing - Verifica denegación (403) u ocultamiento
Resultados esperados:
- ✅ Solo OWNER puede acceder
- ✅ Información correcta
- ✅ Portal de Stripe funciona
Flujo 11: Expiración de Suscripción
Sección titulada «Flujo 11: Expiración de Suscripción»Objetivo: Verificar que el acceso se revoca al expirar.
Setup:
psql $DATABASE_URL -c "UPDATE \"Organization\" SET \"subscriptionStatus\" = 'past_due' WHERE name = 'TalentBricks Corp';"Pasos:
- Como MEMBER, intenta acceder a curso
- Verifica denegación
- Verifica mensaje: “Problemas de pago”
Como OWNER:
Sección titulada «Como OWNER:»- Verifica banner de advertencia
- Haz clic en “Actualizar método de pago”
Restaurar:
Sección titulada «Restaurar:»psql $DATABASE_URL -c "UPDATE \"Organization\" SET \"subscriptionStatus\" = 'active' WHERE name = 'TalentBricks Corp';"Resultados esperados:
- ✅ Acceso se revoca cuando
!= 'active' - ✅ Banner para OWNER
- ✅ Acceso se restaura al reactivar
Casos Edge
Sección titulada «Casos Edge»1. Invitación Expirada
Sección titulada «1. Invitación Expirada»psql $DATABASE_URL -c "UPDATE \"OrganizationInvitation\" SET \"expiresAt\" = NOW() - INTERVAL '1 day' WHERE email = 'test@example.com';"- Verifica mensaje “Invitación expirada”
- OWNER puede reenviar
2. Usuario Ya Miembro
Sección titulada «2. Usuario Ya Miembro»- Invita a usuario existente
- Verifica error
3. Email Ya Invitado
Sección titulada «3. Email Ya Invitado»- Envía dos invitaciones al mismo email
- Verifica comportamiento
4. Remover Único OWNER
Sección titulada «4. Remover Único OWNER»- Intenta remover o cambiar rol del único OWNER
- Verifica error: “Debe haber al menos un OWNER”
5. Stripe Webhooks
Sección titulada «5. Stripe Webhooks»Cambio de Seats:
- Modifica quantity en Stripe
- Verifica actualización de
maxSeats
Cancelación:
- Cancela suscripción
- Verifica
subscriptionStatus = 'cancel_at_period_end' - Acceso persiste hasta fecha de fin
Pago Fallido:
- Fuerza pago fallido
- Verifica
subscriptionStatus = 'past_due' - Email al OWNER
Comandos de Debugging
Sección titulada «Comandos de Debugging»Ver Estructura Completa
Sección titulada «Ver Estructura Completa»psql $DATABASE_URL -c "SELECT o.id, o.name, o.\"maxSeats\", o.\"usedSeats\", o.\"subscriptionStatus\", json_agg(json_build_object('email', u.email, 'role', om.role)) as membersFROM \"Organization\" oLEFT JOIN \"OrganizationMember\" om ON o.id = om.\"organizationId\"LEFT JOIN \"User\" u ON om.\"userId\" = u.idWHERE o.name = 'TalentBricks Corp'GROUP BY o.id;"Ver Todos los Cursos Asignados
Sección titulada «Ver Todos los Cursos Asignados»psql $DATABASE_URL -c "SELECT o.name as organization, c.title as course, u.email as assigned_byFROM \"OrganizationEnrollment\" oeJOIN \"Organization\" o ON oe.\"organizationId\" = o.idJOIN \"Course\" c ON oe.\"courseId\" = c.idJOIN \"User\" u ON oe.\"assignedById\" = u.idORDER BY oe.\"assignedAt\" DESC;"Limpiar Datos de Prueba
Sección titulada «Limpiar Datos de Prueba»psql $DATABASE_URL -c "DELETE FROM \"OrganizationInvitation\" WHERE \"organizationId\" IN (SELECT id FROM \"Organization\" WHERE name LIKE '%Test%');"psql $DATABASE_URL -c "DELETE FROM \"OrganizationEnrollment\" WHERE \"organizationId\" IN (SELECT id FROM \"Organization\" WHERE name LIKE '%Test%');"psql $DATABASE_URL -c "DELETE FROM \"OrganizationMember\" WHERE \"organizationId\" IN (SELECT id FROM \"Organization\" WHERE name LIKE '%Test%');"psql $DATABASE_URL -c "DELETE FROM \"Organization\" WHERE name LIKE '%Test%';"Checklist de Funcionalidad
Sección titulada «Checklist de Funcionalidad»Autenticación y Permisos
Sección titulada «Autenticación y Permisos»- Platform admin puede ver todas las organizaciones
- OWNER tiene acceso completo
- ADMIN puede gestionar miembros y cursos
- MEMBER solo ve cursos asignados
Gestión de Miembros
Sección titulada «Gestión de Miembros»- OWNER puede invitar
- ADMIN puede invitar
- MEMBER no puede invitar
- Tokens únicos generados
- Invitaciones expiran (7 días)
- usedSeats incrementa/decrementa
- No se puede exceder maxSeats
Gestión de Cursos
Sección titulada «Gestión de Cursos»- OWNER y ADMIN pueden asignar
- Miembros acceden a cursos asignados
- No-miembros no pueden acceder
- Progreso se guarda correctamente
Facturación
Sección titulada «Facturación»- Solo OWNER ve facturación
- Portal de Stripe funciona
- Webhooks actualizan subscriptionStatus
- Webhooks actualizan maxSeats
- Acceso se revoca al expirar
Admin Dashboard
Sección titulada «Admin Dashboard»- Lista de organizaciones
- Filtros funcionan
- Edición funciona
- Analíticas correctas
Problemas Conocidos
Sección titulada «Problemas Conocidos»Ver la Guía Rápida - Troubleshooting para soluciones comunes.