Compare clubs or search by country to explore player careers, available match statistics and shareable profiles. Install it on your phone.
The challenge
Reconcile fragmented club records and multilingual names, while keeping results available when Wikidata is slow or offline.
My role
I built the interface, data pipeline, SQLite cache, scheduled updates and share cards, including Docker deployment.
Architecture
Where each part runs. Red follows the example flow.
- L1 Interface Runs on: Browser
Club and country searches, career pages and sharing. Installable, with light and dark themes.
- Nuxt 4
- Nuxt UI 4
- Installable web app
- L2 Edge Runs on: Cloudflare
Caches pages for ten minutes; clears them after the previous container stops serving.
- Cloudflare cache
- L3 Server Runs on: Docker on an Oracle Cloud VM
Handles API requests, share cards and scheduled updates with Nitro and Dokploy.
- Node 24
- Nitro
- Docker
- Dokploy
- Takumi
- L4 Data Runs on: SQLite on a Docker volume
Persistent results, profiles and a player index covering 150 clubs.
- SQLite
- Result cache
- Local player index
- L5 External services Runs on: Wikidata
Career records and available statistics through SPARQL; photos from Wikimedia Commons.
- Wikidata SPARQL
- Wikimedia Commons
Step by step: Who played for Beşiktaş and Galatasaray?
- L1 · Interface Two clubs are selected; /api/common-players receives the request.
- L3 · Server Related Wikidata club entries are grouped.
- L4 · Data SQLite serves cached results, refreshing expired entries in the background.
- L5 · External services On a cache miss, SPARQL fetches players and career records.
- L3 · Server Names and spells are merged; players receive a 0 to 100 score.
- L1 · Interface Results appear; a local index covers Wikidata outages.
Key decisions
- 01
Background refresh
Freshness lasts one day during transfer periods, one week otherwise. Expired results are served while refreshing.
- 02
Scheduled updates
Overnight refreshes run daily during transfer periods and weekly otherwise.
- 03
Club aliases
Alias groups combine football teams and multi-sport parent records before querying.
- 04
Name matching
Turkish and English names use normalisation, initials and Jaro-Winkler matching. Single-word names require an exact normalised match.
- 05
Share cards
Takumi renders 1200×630 cards in about 40 ms in recorded tests. Images remain cached until profiles change.
- 06
Deployment cache
Cloudflare’s cache is cleared after the old container stops serving, reducing references to outdated scripts.