metadata
title: Scouting · Racing Santander
emoji: ⚽
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: true
Scouting · Racing Santander
FastAPI + DuckDB scouting dashboard. Reuses the visual design of the static HTML report but loads data from a Hugging Face Dataset and recomputes scoring on the server.
Required Space secrets
Set these in Settings → Repository secrets of the Space:
| Secret | Required | Purpose |
|---|---|---|
APP_PASSWORD |
yes | Shared password for the login gate |
SESSION_SECRET |
yes | Random string used to sign auth cookies |
DATASET_REPO_ID |
yes | HF dataset repo id, e.g. racing-tools/scouting-data |
HF_TOKEN |
yes if dataset is private | Read-scope token for the dataset repo |
DATA_MAX_AGE_HOURS |
no | Cache TTL before re-pulling the dataset (default 24) |
Local development
cd scouting
# 1. produce parquets locally (one-time / on refresh)
python ingest_azure.py
python build_player_season.py
python enrich_attrs.py
python enrich_tm.py --skip-extra --limit 100
# 2. point app to the local data dir and run
export DATA_DIR=$(pwd)/data/clean
cd app && uvicorn main:app --reload --port 7860
Open http://localhost:7860/ — no APP_PASSWORD set means dev-mode (any
password is accepted on the login form, or skip if env unset).
Refreshing data without a Docker rebuild
HF_TOKEN=hf_xxx python scripts/push_to_hf_dataset.py
Then restart the Space (Settings → Factory rebuild) — the next boot pulls the
new parquets via huggingface_hub.snapshot_download.
Architecture
app/main.py— FastAPI app, mounts static, registers routesapp/data.py— DuckDB on parquet, registersbaseview joining player_season + tm_enrichmentapp/scoring.py— wrapsscouting_score.pyfor in-memory scoring with custom weightsapp/auth.py— signed-cookie shared-password gateapp/routes/— meta / score / player / best11 endpointsapp/static/— extracted HTML, CSS, JS fromgenerate_report.pywithfetch()calls
API quick reference
GET /api/meta— seasons, leagues, positions, blocksPOST /api/score— filtered + scored player-season rowsGET /api/player/{playerId}?season=24-25— full detailPOST /api/best11— top-1 per pitch slotPOST /api/login— set auth cookieGET /api/auth-status— whether the current session is authenticatedGET /healthz— bypasses auth, returns row counts