@battle-racing/br-common-lib
Version:
Common library for all Battle Racing Repositorios
111 lines (77 loc) • 7.12 kB
Markdown
# Flujo de Compra de Tickets y Separación User/Player
Este documento explica de forma detallada cómo está estructurado el flujo de compra de tickets en **Battle Racing**, cómo se separa la entidad que paga (User) de la entidad que corre (Player), qué hemos implementado hasta ahora y qué nos hace falta por implementar.
---
## 👥 1. Separación: Users vs. Players
Para asegurar "cero fricción" en el entorno físico de la pista, hemos separado estrictamente el concepto de la cuenta (quien paga) del corredor (quien se sube al Kart).
### `User` (La Cuenta / El Pagador)
- **Propósito:** La persona física que se registra, gestiona un método de pago y posee el historial transaccional de compras.
- **Autenticación:** Usa `email` o `phoneNumber` (sin `username`), contraseña y roles (`SUPER_ADMIN`, `CASHIER`, `PLAYER`).
- **Relaciones:**
- Tiene un `defaultPlayerId` que apunta a su propio perfil de corredor.
- Puede ser tutor y ser "dueño" (`ownerUserId`) de múltiples `Players` menores de edad (`MINOR`).
### `Player` (El Corredor / Perfil Gamificado)
- **Propósito:** Es la entidad gamificada que se asigna físicamente a un Kart y cuyo nombre sale en las pantallas.
- **Identificador (`nickname`):** No son únicos en la base de datos. Varios corredores pueden llamarse "Maverick" al mismo tiempo para no generar errores al registrarse rápidamente en el POS.
- **Waivers:** Contiene el estado de la firma del documento de exención de responsabilidad (`waiver`).
- **Relaciones:** Si es un invitado anónimo (`isGuest`), no está atado a ningún `User`. Si es un menor, su firma (`waiver`) es implícitamente otorgada por el `User` tutor.
---
## 🎟️ 2. Flujo de Compras (Purchases y Tickets)
La adquisición de carreras sigue un ciclo de vida de tres grandes capas:
### Capa 1: La Compra (`Purchase`)
1. **Creación:** Se crea un `Purchase` agrupando varios ítems de compra (ej. 3 tickets de tipo `RACE`).
- Se crea en el endpoint: `POST /ticketing/purchases`
- Si el cliente está logueado en la Web App, se asocia su `buyerUserId`.
- Si la compra es 100% anónima en la sucursal (POS), `buyerUserId` es `null` y se usan `guestName` y `guestContact`.
2. **Pago:** El pago se confirma asíncronamente vía Webhooks (`POST /ticketing/webhook/payment`) o manualmente en caja registradora (`POST /ticketing/purchases/:id/manual-payment`).
3. **Generación de GameTickets:** Una vez confirmada y pagada la compra, esta se _desfragmenta_ y la base de datos genera los `GameTicket` individuales correspondientes (con estado `CREATED`).
### Capa 2: La Sesión (`Game Session`)
Dado que una persona puede comprar 10 tickets, pero a la pista se van a subir sus 5 amigos 2 veces, se usa una **Session**.
1. **Creación:** Se agrupan tickets recién comprados bajo un código alfanumérico corto (ej. `A1B2C3`).
2. **Unión:** Los amigos escanean un QR o dictan el código para unirse a la sesión (`POST /sessions/:code/join`). Aquí sus `Players` ingresan a la sesión.
3. **Asignación:** Se asigna cada `GameTicket` disponible en la sesión a un `playerId` específico (`POST /sessions/:code/tickets/assign`).
### Capa 3: El Turno Físico en Pista (`Game Turn`)
1. **Cola de Carrera:** Cuando el grupo de la sesión está listo (o el operador del POS organiza la carrera), se crea un `GameTurn`.
- Endpoint: `POST /game-turns` o `POST /game-turns/bulk`.
2. **Vinculación Final:** El `GameTurn` toma los `GameTickets` asignados y los `playerIds` correspondientes, bloqueándolos para esta carrera específica.
3. **Ejecución y Hardware:** El hardware vincula a los jugadores con sus respectivos Karts y avanza las tareas de la carrera (preparación, en sus marcas, carrera, meta).
- El progreso se guarda mediante: `POST /game-turns/:id/tasks/:taskId/complete`
---
## ✅ 3. ¿Qué tenemos implementado hasta ahora?
### En `br-common-lib` (Schemas)
- Zod schemas altamente detallados para `User`, `Player`, `Session`, `Ticketing` (Purchase y Tickets) y `Payment`.
- Control absoluto y fuente de verdad centralizada para la validación de estos modelos.
### En `game-manager-backend` (REST API)
- **Módulo `ticketing`:**
- Creación de compras.
- Procesamiento manual de pagos (para POS/Cashiers).
- Cancelación de compras.
- Recepción de webhooks de pasarelas de pago.
- Listado mis compras y resumen de mis tickets (`my-purchases`, `my-tickets`).
- **Módulo `session`:**
- Obtener sesión por código corto.
- Unirse (y unirse en bulk) a una sesión.
- Asignar tickets a jugadores dentro de la sesión.
- **Módulo `game-turn`:**
- Listado general de turnos (`GET /game-turns`).
- Creación de turnos y turnos en bloque.
- Avance de etapas (tasks) dentro del turno (`completeTask`).
- Capacidad para avanzar (`/advance`) o posponer (`/postpone`) el turno en la fila.
- **Módulo `player` & `user`:**
- Estructuras en DB/Repositorios y controladores listos para manipular estos perfiles.
---
## 🚧 4. ¿Qué nos hace falta implementar? (Faltantes / TODOs)
1. **Autenticación Severa (Guards):**
- Varios enpoints importantes como la creación de compras y modificación de sesiones todavía usan `request.user?.id` asumiendo que el usuario está inyectado, pero faltan **Guards** (e.g., JWT Guards) sólidos y globales para denegar acceso a usuarios no autorizados de forma segura o están marcados como `@Public()`.
2. **Validación de Identidad de Email/Teléfono (`User`):**
- Aunque la base de datos soporta `isEmailVerified` e `isPhoneVerified`, el mecanismo de envío de OTP / SMS / Enlace Mágico para confirmar la propiedad aún no está programado.
3. **Verificación de Seguridad de Asignación de Tickets:**
- Comprobar que un User no pueda asignar tickets de un Purchase que NO le pertenece (cuando la abstracción de sesión permita saltos de seguridad).
- Actualmente falta un "Ownership Check" robusto en varios GET de compras y lectura de turnos.
4. **Actualización Automática de Estadísticas del Player:**
- Actualmente la base de datos de Players tiene sub-schemas listos para Stats (`totalRaces`, `bestTimeMs`, `xp`). Sin embargo, una vez que el `GameTurn` se completa en la pista, falta implementar el webhook o servicio que **calcule los resultados finales y actualice estos stats** dentro de cada `Player` que participó.
5. **Flujos de Error de Pagos y Reembolsos Avanzados:**
- Manejo exhaustivo de reembolsos desde Stripe hacia el sistema para revocar `GameTickets` si una persona pide chargeback manual.
6. **Integración Completa con POS (Front-end UI):**
- Falta validar en el frontend de POS que estos flujos asíncronos (como el crear compra en cash, asignar players de forma anónima) no se bloqueen por dependencias de cuentas "Guest". Asegurarse de que el frontend POS pueda transitar estas 3 capas sin recargar.
7. **Asociación Dinámica de Hardware (Karts ↔ Players) en el GameTurn:**
- Hay que madurar la lógica donde un `playerId` que entra a un `GameTurn` es asignado al IP / Socket / ID Hardware específico del Kart en el que se acaba de sentar.