Facundo Cornejo.
Volver a proyectos

Case study

Liga Al Touch — Gestión de una liga amateur

Una liga de fútbol amateur parece un CRUD hasta que aparecen las suspensiones, los comodines y el derecho de piso. La decisión que sostiene todo el sistema es cuál dato se deriva y cuál no.

Todavia sin desplegar: sale con la proxima temporada de la liga
Next.jsTypeScriptPostgreSQLBetter Auth
Liga Al Touch — Gestión de una liga amateur

Contexto

Liga Al Touch organiza un torneo de fútbol amateur en Paraná. La tabla, los goleadores, el fair play, los cruces de playoffs y las sanciones del tribunal se llevaban a mano, repartidos entre planillas y grupos de WhatsApp. Me contrataron para hacer la plataforma: un sitio público donde los jugadores miran su equipo, y un panel donde la organización carga los partidos.

Problema

El dominio es más complejo de lo que aparenta. Un partido no es solo un resultado: puede haber walkover, tarjetas que arrastran suspensiones a fechas futuras, un comodín que perdona una roja, ajustes disciplinarios que suman o restan puntos fuera de la cancha, y playoffs de Oro y Plata que se arman con los cruces según cómo terminó la fase regular. Si eso se modela mal, la tabla miente. Y en una liga, una tabla que miente es una discusión con la gente.

La decisión de fondo: qué se deriva y qué no

El sistema está partido en dos capas que nunca se mezclan. En una viven los hechos del partido —quién jugó, quién hizo los goles, qué tarjetas hubo— y de ahí se DERIVA todo lo calculable: tabla de posiciones, goleadores, fair play, valla menos vencida. En la otra vive el estado administrativo: suspensiones, comodines, ajustes disciplinarios. Eso NO se deriva: tiene su propia tabla y su propio ciclo de vida. La razón es que una decisión administrativa es un acto, no un cálculo. Si la derivás de los hechos, no la podés revertir, no sabés quién la tomó y no la podés auditar cuando alguien reclama. Separarlas hizo que agregar reglas nuevas —los playoffs de Oro y Plata llegaron después— no tocara nada de lo que ya andaba.

Seguridad y datos personales

  • Cada acción de servidor es, en los hechos, un endpoint público. Por eso la autorización es denegar por defecto en cada una, sin excepción. Es el error que más veces vi: confiar en que la pantalla que llama a la acción ya validó el rol.
  • El archivo de proxy solo pone cabeceras y hace redirecciones. Jamás autoriza. Es la trampa clásica del framework: parece el lugar natural para poner el guardián de auth, y es el peor.
  • Todo se valida en el servidor con esquemas que rechazan campos inesperados. El rol nunca se lee de lo que manda el front.
  • El DNI de los jugadores no aparece en ninguna proyección pública, ni en logs, ni en nada cacheado. Las vistas públicas usan objetos de transferencia sin campos internos.
  • Toda mutación deja registro de auditoría en la misma transacción, y ese registro no lleva datos personales.
  • El caché público se invalida por etiqueta al guardar una ficha. Nada personal entra jamás en algo cacheable.

Lo que decidí NO hacer

Nada de Redis, colas, microservicios ni separación de lecturas y escrituras. Es un monolito por capas y la escala es chica: una liga, unas decenas de equipos. Lo escribí como regla en el repo para no tentarme más adelante. La complejidad que no agregás es la única que seguro no te va a fallar un domingo a la noche antes de la fecha.

Mi rol

Freelance, todo: modelo de dominio, backend, sitio público, panel de administración y las rondas de devolución con la organización de la liga. Varias features salieron de esas devoluciones, no del plan original — la descarga de la tabla y de los cuadros como imagen, por ejemplo, porque así es como se comparten en los grupos.

Estado

Funcional y probado en local, con el fixture, los playoffs Oro y Plata, el tribunal y el panel completos. Todavía sin desplegar: sale con la próxima temporada de la liga, sobre mi propio servidor.