Vital
- NestJS
- PostgreSQL
- Prisma
- React
- MUI
- Redux Toolkit
- Arduino
- Capacitor
- Mercado Pago
- AFIP
Gimnasio familiar · Sistema en producción · Argentina
El gimnasio de mi familia corriendo sobre un solo sistema: el socio entra pasando su credencial por el molinete, paga y factura sin fricción, y entrena con su rutina en el celular. Tres aplicaciones, una misma fuente de verdad.
¿Qué problema resuelve Vital?
Vital es el gimnasio de mi familia. Como todo gimnasio de barrio que crece, durante años se manejó con una mezcla de planilla de Excel, un cuaderno en la recepción y grupos de WhatsApp. Con varios cientos de socios activos, esa forma de trabajar ya no daba: nadie sabía con certeza quién tenía la cuota al día, la puerta la abría alguien a ojo, la facturación era un trámite manual a fin de mes y el socio no tenía ninguna herramienta propia más allá de mensajear al profe.
Lo construí para nuestra operación real, con un solo sistema que cubre las tres caras del negocio a la vez: la operación de la recepción (quién entra, quién debe, quién se anota), el cumplimiento fiscal (cobros y facturas de verdad, con AFIP y Mercado Pago) y la experiencia del socio (su rutina, su progreso, su acceso). El desafío no era ninguna de esas piezas por separado, sino que convivieran sobre un mismo modelo de datos sin duplicar la verdad.
¿Cómo está construido Vital?
Lo armé como un monorepo con tres aplicaciones independientes que comparten una única API. En el centro, un backend en NestJS con PostgreSQL y Prisma, diseñado event-driven: los módulos no se llaman entre sí a mano, emiten eventos y otros reaccionan. Cuando el molinete lee una credencial, eso dispara una cadena —verificar acceso → registrar asistencia → notificar— sin acoplar el hardware a la lógica de negocio.
Cada superficie tiene un usuario y un propósito distinto, pero todas hablan con la misma API. Esa fue la decisión estructural que sostiene el resto: una sola fuente de verdad para membresías, pagos, asistencias y rutinas.
¿Qué decisiones técnicas sostienen Vital?
Las partes que más me importan de Vital no son las pantallas, son los sistemas que las conectan con el mundo físico y con la AFIP.
El molinete que sabe quién sos
El acceso no es un botón: es hardware real. Un servicio liviano sin interfaz se comunica por puerto serie (serialport) con un Arduino que controla el molinete. Cuando alguien pasa la credencial, el sistema valida contra la API si la membresía está activa y solo entonces abre la puerta — sin una aplicación de escritorio de por medio.
- Lectura de credencial vía Arduino → evento en NestJS → verificación de acceso desacoplada del hardware
- Check-in alternativo por QR: tokens de un solo uso con expiración a los 5 minutos, generados desde la app del socio
- Cada ingreso queda registrado como asistencia y dispara notificaciones sin bloquear la puerta
Cobrar y facturar de verdad, en Argentina
Un gimnasio que factura en serio necesita hablar con la AFIP y con un medio de pago. Vital integra facturación electrónica contra la AFIP por SOAP (con manejo de certificados) y cobros con Mercado Pago, incluyendo webhooks idempotentes para no procesar dos veces el mismo pago.
- Facturación electrónica AFIP con validación de certificados y diagnóstico propio
- Pagos con Mercado Pago y una tabla de webhooks procesados para garantizar idempotencia
- Un bot de WhatsApp (vía Twilio) que le permite al staff emitir facturas conversando desde el celular, con una máquina de estados por sesión
La deuda se persigue sola
La plata que se pierde en un gimnasio casi siempre es plata que nadie fue a cobrar. Por eso la cobranza (dunning) es un subsistema propio que corre por cron y escala solo: primero reintenta, después avisa, después da gracia y finalmente suspende — sin que nadie tenga que acordarse.
- Scheduler con tres etapas: procesar reintentos → enviar avisos (email/SMS) → suspender al vencer la gracia
- Semáforo de membresías (activo / por vencer / vencido) como estado central de toda la app
- Notificaciones multicanal: email (SMTP), SMS (Twilio) y push (Firebase) según el evento
Entrenar, no solo pagar
La PWA de socios —empaquetada con Capacitor para iOS y Android— es lo que hace que el sistema no sea solo administrativo. El socio ve su rutina asignada, la ejecuta bloque por bloque y registra cada serie; el sistema le lleva el historial y le detecta récords personales.
- Catálogo público de rutinas + asignaciones por socio o por grupo, con días, bloques y ejercicios
- Registro de sesiones de entrenamiento: series, cargas y récords personales automáticos
- Reserva de clases, métricas de salud, check-in por QR y notificaciones push
Las tres superficies
React 19 + MUI para la recepción. Diseñado como bandeja de tareas, no como dashboard: check-in con ⌘K, cobros y estado de membresías con acciones directas en cada fila.
PWA con Capacitor: rutinas, progreso, clases y acceso por QR, publicable en las tiendas como app nativa.
NestJS event-driven sobre PostgreSQL/Prisma. Una sola fuente de verdad para las superficies, las integraciones externas y el molinete por serie — sin capas de más.
Cierre
Vital es el proyecto donde más se nota lo que significa llevar algo de punta a punta: no termina en una pantalla bonita, termina en un molinete que se abre, en una factura válida ante la AFIP y en un socio anotando su serie desde el celular. Tres aplicaciones, un modelo de datos, y un montón de decisiones —event-driven, idempotencia de pagos, cobranza automática, hardware por serie— que existen porque el sistema corre en el gimnasio de mi familia todos los días. Incluso el control de acceso terminó siendo un servicio mínimo: la primera versión fue una app de escritorio que resultó ser de más, y quedó reemplazada por algo mucho más chico que hace exactamente lo necesario.