Todo empezó por una molestia simple: para seguir el fútbol que me gusta —argentino, uruguayo e italiano— tenía que saltar entre varios sitios, cada uno con su publicidad, su cuenta y sus resultados a medias. Quería fixture, resultados y posiciones en un solo lugar. De ahí nació El Bagual del Gol, un proyecto personal que hoy está en producción en bagualgol.duckdns.org.
No es un trabajo para un cliente ni un producto comercial: es un hobby de un apasionado del fútbol, hecho para otros aficionados. El pie del sitio lo dice mejor que cualquier pitch: “Hecho por un bagual para otros baguales futboleros”.

Qué muestra hoy#
- Partidos del día, con filtro de todos / en vivo, marcador, DTs y estadio.
- Competiciones agrupadas en el menú: Mundial, Uruguay, Internacional, selecciones, Argentina, Inglaterra, España, Italia y más.
- Mundial 2026: grupos, tabla de posiciones, partidos por jornada y ranking de goleadores.
- Noticias de fútbol desde fuentes RSS, con titulares y antigüedad.
Cómo está armado#
El frontend es una SPA con React 19 + Vite 7 + TailwindCSS 4. El backend es Express 5 sobre Node, que expone una API REST. Lo interesante está en los datos: hay varias fuentes conviviendo.
- API-Football y SportsRC (planes gratuitos): fixtures, resultados y posiciones de las ligas.
- PostgreSQL: modelo propio con 23 tablas —torneos, jugadores, eventos, predicciones, entrenadores y alineaciones—.
- MongoDB: el Mundial 2026 vive ahí: grupos, partidos, equipos y estadios.
- RSS: noticias de Google News y Ovación, cacheadas cada 15 minutos.
Para no quedar atado a un proveedor, el backend usa un patrón provider: cada fuente implementa la misma interfaz (getFixtures(), getLiveFixtures(), getCompetitions()) y un factory decide cuál responde según la liga. Los DTOs normalizan la respuesta cruda de cada proveedor a una misma forma antes de salir por la API. Sumar una fuente nueva es crear un archivo y registrarla en dos lugares: cero cambios en controllers, services o rutas.
También hay un openapi.yaml con el contrato de la API, que es lo que uso de referencia cuando vuelvo al proyecto después de un tiempo.
Cómo quedó desplegado#
Autohospedado, como casi todo lo que corro: un solo servidor Debian con Nginx Proxy Manager terminando TLS con Let’s Encrypt, nginx sirviendo los estáticos del build de Vite y proxeando /api/ al backend, PM2 manteniendo vivo el proceso Node y DuckDNS resolviendo el dominio dinámico.

Un par de detalles que parecen menores y no lo son:
- Cache agresiva para assets: Vite hashea los nombres, así que
/assets/se cachea un año conimmutable. El HTML nunca se cachea. - Headers de seguridad y bloqueos:
X-Frame-Options,nosniff,Referrer-Policy, y sin acceso a archivos ocultos, source maps,node_modulesni.git. - SPA fallback: cualquier ruta desconocida responde
index.html, para que la navegación del frontend no dé 404.
Lo que aprendí#
- Un hobby merece el mismo rigor que un trabajo facturado. Documentar el despliegue en una guía paso a paso fue lo que me permitió retomar el proyecto después de semanas sin tocarlo.
- Hay que diseñar para datos incompletos. Los planes gratuitos limitan consultas y cobertura: puede haber retrasos o información desactualizada. El sitio lo dice en su aviso legal. Mejor asumirlo desde el diseño que prometer exactitud.
- El patrón provider y los DTOs rindieron más de lo que esperaba. Cambiar o sumar fuentes de datos tocó un solo archivo por fuente, sin reescribir media API.
- Las partes aburridas son las que sostienen: cache, logs, reinicio automático, respaldos y headers de seguridad.
Estado actual: en pausa, a propósito#
El sitio está en vivo y funcionando, pero el desarrollo está en pausa: hace tiempo que no le sumo funcionalidades nuevas, y está bien así. Cuando tenga más tiempo libre quiero volver: más estadísticas, resultados históricos y planteles, que es justo lo que está en proceso de incorporación continua.
Mientras tanto sigue ahí, gratis y sin registrarse, por si alguien quiere mirar un rato el fútbol que sigo. Y si encontrás un dato raro o querés sugerir una liga, el aviso legal del sitio tiene un correo para eso.




