GymTeam
Gestión de clubes: una plataforma, muchos clubes
El lado del personal del ecosistema Fitofan: los clubes deportivos gestionan miembros, clases, check-in, progresión y pagos, cada club en su propio espacio privado.
- Rol
- Senior Full-Stack Engineer
- Periodo
- 2025 – 2026


Contexto
GymTeam es donde trabajan propietarios, gerentes y entrenadores de clubes; atletas y padres usan Fitofan, que además les da acceso. Lo separé de la base de código de Fitofan en un producto propio y entregué la mayor parte.
El reto
Servir a muchos clubes independientes desde una sola aplicación con aislamiento estricto de datos, aceptar pagos en todos los mercados donde operan los clubes y mantener los datos de los clubes coherentes con la plataforma de atletas en tiempo real.
Construido en todas las capas
- Panel de administración en Next.js 16 sobre Feature-Sliced Design: más de 80 páginas, 11 locales
- Backend en NestJS: un módulo por entidad con casos de uso, repositorios y DTO validados; 95 migraciones
- Aislamiento de tenants: un guard resuelve cada club por id o slug y comprueba la membresía antes de ejecutar cualquier handler
- Miembros, invitaciones y periodos de prueba, horarios semanales con listas de espera, check-in en vivo, asistencia, currículo y niveles de cinturón, exenciones de responsabilidad, tareas, evaluaciones
- Pagos: Finix, Stripe, PayPal, Square, Monopay, LiqPay, GCash y Mercado Pago más efectivo y deudas, un planificador de facturación diaria, almacenamiento de credenciales con AES-256-GCM
- Contrato RabbitMQ compartido con Fitofan: 29 routing keys, un sobre tipado con ids de correlación, topología documentada
- Inicio de sesión por QR sobre WebSockets, un gateway de sesiones Socket.IO, almacenamiento de medios compatible con S3
- Analítica de ingresos, asistencia y entrenadores con exportación a CSV y PDF
- La misma pipeline de entrega que Fitofan: gate de type-check y Jest, imagen Docker, despliegue por SSH
Puntos de ingeniería
- Alcance de tenant impuesto en el servidor, nunca confiado al cliente
- Webhooks idempotentes por proveedor e id de evento; los payment intents llevan claves de idempotencia
- Una regla ESLint propia con sus propios tests mantiene honestas las capas de Feature-Sliced
- Los flujos de registro y creación de clubes vienen de paquetes compartidos por ambos productos
Qué hace posible
Cada club recibe un producto que parece hecho a su medida, mientras la ingeniería sigue siendo una sola base de código y un solo despliegue.