Skip to content
← All work

Fantasy Voley

A fantasy league for Spanish volleyball, with real users and a scraper that has to behave.

Year
2024 — present
Role
Sole engineer — data ingestion, API, front end
Stack
Python PostgreSQL Neon Railway Vue

Problem

Spanish volleyball has a passionate following and no fantasy league. The federation publishes squads and results through a legacy ASP.NET portal with no API, unstable team identifiers, and markup that changes between seasons.

Approach

I built an ingestion layer that treats the federation portal as a hostile data source: player identifiers are stable and used as the join key, team identifiers are not and are resolved per season. Scraping runs on a schedule, writes to a staging table, and only promotes a season once the row counts look sane — so a silent markup change degrades into "no update" instead of "everyone's squad is empty".

Outcome

A working league with real players in it, refreshed automatically through the season, and a data model that survived a federation site redesign without a rewrite.

The lesson: trust nothing upstream

Every scraper eventually breaks. The difference between a weekend project and something people use is what happens when it does. Here, a validation gate between staging and live means a broken parse is visible as stale data, not as corrupted data — which is always the cheaper failure.

Add the numbers when you have them: registered users, matches ingested, seasons covered.