GymTeam
Gestão de clubes: uma plataforma, muitos clubes
O lado do staff do ecossistema Fitofan: os clubes desportivos geram membros, aulas, check-in, progressão e pagamentos, cada clube no seu próprio espaço privado.
- Função
- Senior Full-Stack Engineer
- Período
- 2025 – 2026


Contexto
O GymTeam é onde trabalham proprietários, gestores e treinadores de clubes; atletas e pais usam a Fitofan, que também lhes dá acesso. Separei-o da base de código da Fitofan num produto próprio e entreguei a maior parte dele.
O desafio
Servir muitos clubes independentes a partir de uma só aplicação com isolamento estrito de dados, aceitar pagamentos em todos os mercados onde os clubes operam e manter os dados dos clubes coerentes com a plataforma dos atletas em tempo real.
Construído em todas as camadas
- Painel de administração em Next.js 16 sobre Feature-Sliced Design: mais de 80 páginas, 11 locales
- Backend em NestJS: um módulo por entidade com casos de uso, repositórios e DTO validados; 95 migrações
- Isolamento de tenants: um guard resolve cada clube por id ou slug e verifica a pertença antes de qualquer handler correr
- Membros, convites e períodos de experiência, horários semanais com listas de espera, check-in ao vivo, assiduidade, currículo e níveis de cinto, termos de responsabilidade, trabalhos de casa, avaliações
- Pagamentos: Finix, Stripe, PayPal, Square, Monopay, LiqPay, GCash e Mercado Pago mais numerário e dívidas, um agendador de faturação diária, armazenamento de credenciais com AES-256-GCM
- Contrato RabbitMQ partilhado com a Fitofan: 29 routing keys, um envelope tipado com ids de correlação, topologia documentada
- Login por QR sobre WebSockets, um gateway de sessões Socket.IO, armazenamento de media compatível com S3
- Análise de receitas, assiduidade e treinadores com exportação para CSV e PDF
- A mesma pipeline de entrega da Fitofan: gate de type-check e Jest, imagem Docker, deploy por SSH
Destaques de engenharia
- Âmbito de tenant imposto no servidor, nunca confiado ao cliente
- Webhooks idempotentes por fornecedor e id de evento; os payment intents levam chaves de idempotência
- Uma regra ESLint própria com os seus próprios testes mantém honestas as camadas Feature-Sliced
- Os fluxos de registo e criação de clubes vêm de pacotes partilhados pelos dois produtos
O que permite
Cada clube recebe um produto que parece feito à sua medida, enquanto a engenharia continua a ser uma só base de código e um só deploy.