Vai al contenuto

Come funziona — Dati & statistiche

Come un payload di un provider diventa una statistica sul sito: la pipeline è a 3 strati persistenti e ri-proiettabili, con un principio unico — nessun dato inventato, ogni numero tracciabile fino alla fonte.

La pipeline in una riga

provider → ingest (raw, dedup sha256) → projection (fatti tipizzati) → feature store (agg_*) → 64 statistiche → widget

Le fonti

Provider Copertura Badge nel sito
api-football (piano Pro) backbone di tutte le leghe di club: fixture, statistiche match, formazioni, classifiche, quote multi-book, xG dove la lega li fornisce blu
Sportmonks (WC Special) solo Mondiale 2026 (torneo concluso, oggi archivio): live, eventi, voti, cronaca, trends, meteo arancio
modello BAP statistiche derivate in-house dallo storico Postgres proprietario verde

Ogni chiamata provider passa da un budget-guard (limiti giornalieri e al minuto del piano) e da un provider-registry con routing per-dominio validato al boot: i provider sono sostituibili senza toccare il resto del sistema.

Team of the Week — statistica proprietaria calcolata dallo storico BAP

Strato 1 — Raw store ri-proiettabile

Ogni payload provider viene persistito grezzo in ingest_payloads con dedup sha256, nella stessa transazione della projection. Conseguenza pratica: se un mapper aveva un bug o una formula cambia, lo storico si ri-proietta dal raw con zero nuove chiamate provider — il dato grezzo non si perde mai.

Strato 2 — Fatti tipizzati

Il punto d'ingresso dell'ingest è unico (ingest/service.py): fine-match live, endpoint admin e backfill convergono tutti lì, così budget e idempotenza valgono ovunque. La projection trasforma il raw in dimensioni (leagues, teams, players, …) e fatti per-match (matches, match_events, match_team_stats, player_match_stats, formazioni). I campi provider non mappati finiscono in colonne JSONB extra: niente si butta.

Strato 3 — Feature store

Le tabelle agg_* (forma squadra, stagione giocatore, H2H, arbitro, Elo, fasce gol) sono aggregati pre-calcolati con refresh-on-ingest mirato: quando arriva un match si aggiornano solo le chiavi toccate (2 squadre, ~40 giocatori, 1 coppia H2H, 1 arbitro).

Dalle tabelle alle 64 statistiche

Le statistiche derivate vivono in un registry (stats_registry/registry.yaml): oltre 60 voci, ognuna con formula dichiarata, funzione di calcolo registrata (fail-fast al boot se manca), parametri regolabili a caldo dal pannello admin e possibilità di accensione/spegnimento per lega. Le statistiche sono scope-aware: badge di scope e toggle competizione dove una squadra gioca più tornei.

Le principali sono spiegate una per una in Le statistiche BAP spiegate.

Il live

Un solo poller per processo interroga il feed live (cadenza 20s con match in corso, 60s a riposo), scrive lo snapshot in cache e fa fan-out via SSE a tutti i client connessi: il sito mantiene una sola connessione al flusso e ticker, liste partite, header match e classifica live si aggiornano da soli. A fine match il sistema ingerisce automaticamente statistiche e formazioni definitive; uno sweep periodico recupera i match persi durante eventuali restart.

Le garanzie di onestà

  • Lineage visibile: il bottone "i" accanto a ogni statistica mostra fonte, formula in italiano e frequenza di aggiornamento.
  • Honest-empty: se lo storico non basta (poche partite, lega non ingerita, xG assente), il widget sparisce o dichiara il limite — mai numeri "riempitivi".
  • Solo osservato: le serie live (es. momentum) esistono solo per i minuti realmente osservati; non vengono mai ricostruite a posteriori.

I termini ricorrenti (honest-empty, lineage…) sono nel Glossario; cosa il sito NON promette è in Limiti & disclaimer.