Plataforma de gestión de club deportivo - Escuela del Corredor de Almansa
Plataforma de gestión para un club de atletismo en Rails 8: socios, cuotas domiciliadas con prorrateo, planes de entrenamiento y autonomía total del cliente.
El encargo era una votación para elegir la camiseta del club.
Lo que hay hoy en producción gestiona el club entero: 138 socios, sus cuotas domiciliadas, seis grupos de entrenamiento, la documentación de la entidad, los correos que salen a nombre de la directiva y los planes de entrenamiento que publican los entrenadores cada mes.
Entre una cosa y la otra hubo una observación que decidió el proyecto: la Escuela del Corredor de Almansa es un club popular, con una junta directiva de voluntarios que se renueva y sin nadie de sistemas. Un club así no puede permitirse un software que dependa de una persona concreta — y menos si esa persona no está en el club.
Una directiva que cambia no puede depender de un programador que no cambia
El reto
Todo lo que solo se pueda cambiar tocando código es una llamada al desarrollador. Un importe de trimestre, el texto de un correo de bienvenida, el CIF en el aviso legal, el orden en que se listan los grupos. Cada uno de esos detalles, si vive en el repositorio, es una dependencia permanente. Y una dependencia que la directiva no puede pagar es un sistema que acaba congelado.
Tres públicos con tres niveles de confianza. Cualquiera que entra en la web, la directiva que ve DNI y cuentas bancarias, y los entrenadores que solo deben ver sus grupos. Con una particularidad: el socio no debería tener contraseña. Pedir a 138 corredores que recuerden una credencial para votar el color de una camiseta es la forma más segura de que no vote nadie.
El club ya trabajaba, y trabajaba bien. Tenía su Excel de socios y sus Word de entrenamientos con un formato propio de años. Exigirles que cambiaran su manera de trabajar para adaptarse a la aplicación era garantizar que la aplicación no se usara.
Las cuotas son dinero real de 138 personas. Alguien se da de alta a mitad de trimestre, otro tiene descuento, otro se da de baja después de haber generado los recibos. Un recibo duplicado o un cargo a quien ya no está no es un bug: es una llamada incómoda de un vecino a un tesorero voluntario.
DNI e IBAN de 138 personas, en una entidad sin departamento de sistemas. La responsabilidad sobre esos datos no desaparece por que el cliente sea pequeño.
Una baja no es un interruptor. En un club popular la gente se va, vuelve al año siguiente, se apunta un hijo. Un campo "activo" borra esa historia justo cuando hace falta para calcular una cuota.
La solución
— La configuración es parte del producto, no un archivo del servidor
Los importes de cada trimestre, los textos de los cuatro correos del sistema, los datos de la entidad que alimentan el aviso legal y la política de privacidad, el orden de los grupos, qué documento se adjunta a la bienvenida: todo se edita desde el panel.
Las plantillas de correo se escriben con el formato que la directiva ya usa a diario —el de WhatsApp: asteriscos para negrita, guiones bajos para cursiva— con variables, envío de prueba al propio buzón y posibilidad de restaurar el texto original. Nadie tiene que aprender un lenguaje de plantillas para cambiar una frase.
Cambiar el domicilio social del club no toca una línea de código. Ese es el criterio, y atraviesa el proyecto entero.
— Tres aplicaciones dentro de una
Web pública, backoffice de la directiva y área de entrenadores, con tres identidades separadas y reglas distintas. En ninguna de las tres hay registro público: las cuentas las crea alguien de dentro.
El socio es el caso interesante: se identifica con un dato que ya conoce, sin contraseña. Suficiente para votar una vez y no más, y sin la fricción que habría dejado la participación en cero.
— El Excel y el Word del club, como formato de entrada
El importador lee el fichero real del club, con sus acentos, sus cabeceras variables y sus fechas en número de serie de Excel. Crea los grupos que falten, identifica por DNI para no duplicar, y silencia los correos durante la carga: importar 200 socios no puede significar 200 correos de bienvenida a las once de la noche.
Es la clase de detalle que no aparece en ningún requisito y que decide si una puesta en producción sale bien o acaba en disculpas.
— El parser del Word, y dónde se pone la IA
La pieza técnica más interesante del proyecto es la importación de los planes de entrenamiento desde el Word que el club lleva años usando: un formato con sus semanas, sus días y su taquigrafía propia (20´C.C. SUAVE + GIMNASIO, 3(3000)).
Se resolvió con un parser determinista, sin IA y sin red, que extrae fecha, tipo, calentamiento, volumen, series, ritmo y lugar. Y que nunca decide por su cuenta: lo que no entiende con certeza lo lleva a una pantalla de revisión donde el entrenador confirma antes de guardar.
La IA está en el proyecto, pero acotada a lo que la IA hace bien: resumir documentación y proponer una estructura de mesociclos. Lo que tiene que ser fiable es código auditable; lo que admite un error es lo que se delega a un modelo. Es la decisión de la que más orgulloso puede estar el proyecto, porque es la contraria a la que se está tomando por defecto en todas partes.
— Recibos que se pueden volver a generar sin miedo
La generación aplica prorrateo por los días realmente de alta y el descuento de cada socio, es idempotente, nunca toca un recibo ya pagado y vuelve a cuadrar el periodo con el historial en cada pasada: si alguien se dio de baja después de la primera generación, su recibo desaparece.
La exportación al gestor lleva exactamente lo que el gestor pide, ni un campo más: nombre, apellidos, DNI, IBAN, importe y concepto.
— Historia en lugar de interruptores
Los socios tienen periodos de alta y baja, no un campo booleano: alguien puede irse y volver, y el sistema conserva la línea de tiempo que las cuotas necesitan para calcularse bien.
Con las cuentas, el mismo principio: se desactivan, no se borran. Quien deja la directiva deja de entrar, pero su nombre sigue firmando lo que hizo mientras estuvo.
— Privacidad enseñada, no prometida
El IBAN se muestra enmascarado salvo donde de verdad hace falta entero. Antes de que ningún texto salga hacia un servicio externo, un redactor local tapa por patrón DNI, IBAN, teléfonos, correos y tarjetas, y la función se lanza a mano, nunca de forma automática al subir un documento.
Y se presenta al usuario como "anonimizado", no como "sin datos personales garantizado", porque ningún patrón detecta un nombre propio. Prometer de menos y cumplir es la única política sostenible cuando se manejan datos de los vecinos de tu pueblo.
— Operación, que también es el trabajo
Despliegue con Kamal sobre Docker en servidor propio, con SSL propio y dominio propio. Copias de seguridad que guardan las dos cosas que solo sirven juntas —el volcado de la base y los ficheros— y que verifican que el volcado se puede leer antes de darlo por bueno, con 14 días en local y 90 en un bucket privado. Una copia que nadie ha probado a restaurar no es una copia.
Y en desarrollo, un interceptor que impide escribir a un socio real aunque alguien lo intente sin querer.
Stack
Backend: Ruby on Rails 8.1 · Ruby 3.4.8 · PostgreSQL
Frontend: Hotwire (Turbo + Stimulus) e Importmap — interfaz reactiva sin Node ni build de JavaScript · Tailwind · Propshaft · Active Storage con variantes WebP
Infraestructura de Rails 8: Solid Queue, Cache y Cable — colas, caché y websockets sobre la propia base de datos, sin Redis · Puma + Thruster
Identidades: Devise en tres ámbitos · socio sin contraseña · registro público cerrado
IA: OpenAI con salida JSON forzada, acotada a resumen y estructura; redacción local de datos personales previa
Despliegue: Kamal / Docker en servidor propio · Let's Encrypt · copias verificadas con retención local y en S3
Calidad: Brakeman, bundler-audit y RuboCop en el flujo · rate limiting nativo de Rails 8 · Ransack saneado · tests de integración sobre los flujos críticos
Cifras
En uso diario | 138 socios · 6 grupos · directiva y entrenadores |
Alcance funcional | 3 áreas con identidad propia · 40 controladores · 26 tablas |
Desarrollo | Producto, diseño, desarrollo, despliegue y operación |
Pruebas | ~55 ficheros de test sobre los flujos que no pueden romperse |
Resultados
Antes había un Excel, unas carpetas con Word, papel para las altas y un grupo de WhatsApp. Cada una de esas herramientas funcionaba; el problema era que ninguna sabía de las otras. El Excel no sabía quién se había dado de baja en marzo, el Word no sabía qué grupo entrenaba a quién, y el papel del alta no llegaba nunca al recibo.
Qué se llevó el cliente: un sistema que la directiva gobierna sola. Los importes, los textos legales, los correos y los catálogos se cambian desde el panel; las cuotas se calculan solas con sus prorrateos y sus descuentos; y cuando dentro de dos años entre otra junta, encontrará un sistema que puede manejar sin llamar a nadie.
Galería
¿Un proyecto parecido en mente?
Hablemos