← Volver al blog

Quiniela NFL entre amigos

De la hoja de cálculo olvidada a una plataforma con FastAPI, React y Docker que consulta ESPN, calcula las posiciones y se actualiza sola cada 90 segundos.

Quiniela NFL entre amigos

Cada septiembre se repite el ritual: arranca la NFL y con ella la quiniela entre amigos. Durante años el operativo fue artesanal — alguien actualizaba una hoja de cálculo a mano, los marcadores circulaban por WhatsApp y las posiciones llegaban tarde, o no llegaban. Este año decidí resolverlo como resolvería cualquier problema de producto: construyendo una herramienta que hiciera el trabajo sucio sola.

El resultado: Quiniela NFL, una plataforma web con diseño Material Design, 100% responsiva (celular, tablet, escritorio), corriendo en un contenedor Docker y accesible desde cualquier dispositivo.

Las reglas del juego

La mecánica es la clásica quiniela de amigos, simple y brutal:

  • 10 participantes con 3 equipos NFL cada uno, durante toda la temporada regular (18 semanas).
  • Victoria de alguno de tus equipos: +1 punto. Derrota o empate: 0 puntos.
  • Desempate: diferencia de puntos acumulada de tus tres equipos (PF − PA).
  • La vista principal respeta el orden de inscripción y arriba se destacan los 3 primeros lugares por puntos acumulados.
ParticipanteEquipos
Participante 1Chiefs, Dolphins, Cardinals
Participante 2Bills, Buccaneers, Saints
Participante 3Rams, Commanders, Colts
Participante 4Ravens, Jets, Vikings
Participante 5Lions, 49ers, Steelers
Participante 6Broncos, Chargers, Falcons
Participante 7Packers, Bengals, Titans
Participante 8Seahawks, Jaguars, Bears
Participante 9Eagles, Cowboys, Panthers
Participante 10Texans, Patriots, Raiders

(Browns y Giants quedaron sin dueño. Alguien tendrá que explicar esa estrategia.)

La parte interesante: resultados en vivo, sin API key

Los resultados se consultan en la API pública de ESPN — no requiere clave ni registro. Pero hay un detalle: ESPN rechaza clientes HTTP “de biblioteca”. Cuando las peticiones vienen de requests o httpx, el servidor detecta el fingerprint TLS y responde como si la API no existiera.

La solución: curl_cffi, una librería que imita el handshake TLS de Chrome. Para el servidor de ESPN, mi backend es un navegador más.

Encima puse una caché en SQLite con TTL inteligente, pensada para el ritmo real de la NFL:

  • Semanas ya terminadas → se refrescan cada 12 horas (los resultados no cambian).
  • Semanas futuras → cada 24 horas (solo cambia la agenda).
  • Semana activa → cada 90 segundos, para que los marcadores en vivo se actualicen solos mientras hay juegos.

Y si ESPN falla o se cae, se sirve la última caché buena: la app nunca se queda en blanco.

El stack

backend/    FastAPI: cliente ESPN + caché SQLite + cálculo de posiciones
frontend/   React + Vite + MUI (Material Design)
Dockerfile  multi-stage: construye el frontend → imagen final liviana

El backend expone tres endpoints: /api/health (estado del servicio), /api/standings (posiciones completas, con ?refresh=1 para forzar refresco) y /api/weeks/{n} (juegos y puntos por participante de la semana 1 a la 18). La temporada es configurable con una variable de entorno (NFL_SEASON), así que el año que viene la app sigue sirviendo sin tocar código.

Accesible desde cualquier dispositivo

La app corre en Docker en un servidor de la red local: cualquier celular, tablet o computadora en la misma WiFi la abre por el puerto del contenedor. Pero los amigos no viven en mi red — y no voy a abrir puertos del router por una quiniela.

Para eso usé Tailscale Funnel: expone el servicio en internet con HTTPS y certificado válido, sin abrir ningún puerto de casa. Ese es el link que compartimos en el grupo — funciona igual con datos móviles o en una WiFi ajena.

Lo que me dejó el proyecto

Lo que empezó como “un script para no actualizar a mano” terminó siendo un mini producto: un cliente que sortea el anti-bot de ESPN, una caché con TTL por estado de la semana, fallback ante fallos, una API limpia, un frontend responsivo y un despliegue reproducible con Docker.

Es el mismo enfoque que aplico en proyectos de clientes: identificar la fricción, automatizar lo repetitivo y diseñar para el dispositivo real donde se usa la herramienta — en este caso, el teléfono en el sofá, un domingo por la tarde, con los juegos en vivo.

La próxima temporada arranca sola. La quiniela también.

🌐 Leer en inglés
← Volver al blog