Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fantasta — applicativo web per l'asta del fantacalcio

Gestione completa di un'asta del fantacalcio: catalogo listone versionato, progetti di tag personali, aste con regole configurabili e una home page live aggiornata via WebSocket.

  • Backend: Python + FastAPI, SQLAlchemy 2 async, PostgreSQL, Alembic, WebSocket nativi Starlette.
  • Frontend: React + TypeScript + Vite, responsive (PC, tablet, smartphone).
  • Infrastruttura: Docker Compose (postgres + api + web + scheduler).
  • Scraping automatico: listone ufficiale e storico statistiche giocatori da fantacalcio.it, senza credenziali (vedi sotto).

Avvio rapido

docker compose up --build
Servizio URL
Frontend http://localhost:5173
API http://localhost:8010
Swagger http://localhost:8010/docs
Postgres localhost:5433 (utente/password/db: fantasta)

L'API è esposta sulla 8010 e non sulla 8000, che su molte macchine è già occupata. Le migrazioni Alembic vengono applicate automaticamente all'avvio del container api.

Accesso da altri dispositivi

Funziona senza configurazione: apri http://<ip-del-server>:5173 da telefono, tablet o un altro PC. Il frontend deriva l'indirizzo dell'API dall'host da cui è stata servita la pagina (stesso host, porta 8010), e il backend accetta in CORS qualunque origine sulla porta 5173.

Serve solo che le porte 5173 e 8010 siano raggiungibili dal dispositivo. Imposta VITE_API_URL unicamente se metti l'API su un host o una porta diversi.

Prima di andare in produzione:

  • sostituire JWT_SECRET con un valore casuale di almeno 32 byte;
  • svuotare CORS_ORIGIN_REGEX e pinnare CORS_ORIGINS sul dominio reale;
  • allineare APP_BASE_URL, usato per i link di invito restituiti dall'API (l'interfaccia web costruisce comunque il link sull'origine corrente).

Scraping automatico da fantacalcio.it

Un servizio separato (scheduler, stessa immagine di api) scarica in automatico:

  1. Listone ufficiale — ogni giorno alle 2:00, dalla pagina pubblica delle quotazioni. Scrive sulla list_version fissa PREDEFINITO (configurabile via OFFICIAL_LIST_VERSION), sempre la stessa: non va rinominata di anno in anno. L'upload manuale CSV resta disponibile per qualunque altra versione (mercati di riparazione, listoni di test), e qualunque versione — inclusa PREDEFINITO — si può eliminare da Listone se non più usata da progetti o aste.
  2. Statistiche storiche dei giocatorimercoledì e sabato alle 1:30 (la notte tra martedì/mercoledì e tra venerdì/sabato). Per un giocatore mai visto scarica lo storico fino a un massimo di 5 stagioni; per un giocatore già noto aggiorna solo la stagione corrente, senza mai ri-scaricare le stagioni passate.

Nessuna delle due pagine richiede login: sono pubbliche e permesse da robots.txt. Il client HTTP resta comunque a concorrenza limitata e con un piccolo delay fra le richieste, per non generare carico sul sito.

Per ogni giocatore viene salvata anche l'immagine ("campioncino") — mostrata a fianco del nome nel listone di tagging progetto e in quello d'asta, con fallback alle iniziali finché il giocatore non è ancora stato scrapato — e le statistiche di stagione (presenze, presenze da titolare, gol, gol subiti per i portieri, assist, media voto, fantamedia), scelte con il selettore di stagione in alto a sinistra e attivate come colonne con i bottoni in alto a destra. Le statistiche per singola giornata (voto, fantavoto, minuti di entrata/uscita, bonus/malus) sono salvate in Postgres ma non ancora esposte in UI — solo un endpoint di lettura minimale (GET /catalog/players/{external_id}/stats), in attesa di specificarne il layout.

Trigger manuali (utili senza aspettare lo scheduler):

curl -X POST http://localhost:8010/api/v1/scraping/listone/refresh -H "Authorization: Bearer $TOKEN"
curl -X POST http://localhost:8010/api/v1/scraping/players/{external_id}/refresh-stats -H "Authorization: Bearer $TOKEN"
curl -X POST http://localhost:8010/api/v1/scraping/players/refresh-stats -H "Authorization: Bearer $TOKEN"

Primo utilizzo

  1. Registrati dalla schermata di accesso.

  2. Listone → carica il file delle quotazioni scaricato da fantacalcio.it (.xlsx o .csv) indicando una versione, es. 2025-26. Il caricamento è idempotente: ripeterlo aggiorna le quotazioni senza duplicare i giocatori.

    Vengono importate le colonne Id, R, RM, Nome, Squadra, Qt.A (quotazione attuale), Qt.I (quotazione iniziale) e FVM (fantavalore di mercato). Le varianti Mantra (Qt.A M, Qt.I M, FVM M) e le colonne Diff. vengono ignorate.

  3. Progetti → crea un progetto sulla stessa versione di listone e assegna i tuoi tag slot (raggruppamento) e info (nota libera). Nell'editor: ricerca per sottostringa, filtri per ruolo e per squadra, colonne ordinabili (default FVM decrescente) e click sulla riga per aprire l'editor dei tag del giocatore.

  4. Aste → crea l'asta indicando nome squadra, modalità, crediti e ordine di chiamata.

  5. Configura → imposta gli slot per ruolo, poi copia il link di invito e distribuiscilo. Il pulsante Riallinea listone riporta nell'asta le novità del catalogo: aggiunge i giocatori mancanti e aggiorna anagrafica, quotazioni e FVM di quelli già presenti, lasciando intatti assegnazioni, stato dei giocatori e override di ruolo.

  6. Gli altri partecipanti aprono il link, scelgono nome squadra e quale proprio progetto portare.

  7. Avvia asta e si opera dalla pagina live. Il listone d'asta ha gli stessi filtri dell'editor tag (ricerca per sottostringa, bottoni ruolo, squadre, colonne ordinabili con default FVM decrescente), più il filtro "solo disponibili" e il raggruppamento per tag slot. I tag qui si vedono ma non si modificano: esistono solo se importati da un progetto.

Modello dei dati

accounts ──┬─ projects ── project_tags ──▶ players_catalog (listone master, versionato)
           │
           └─ auction_participants ──┬── auction_player_tags ──▶ auction_players
                                     ├── roster (storico: ordine di chiamata + prezzo)
                                     └── call_order
auctions ──┬── auction_role_config
           ├── auction_players (copia del listone per l'asta, con override di ruolo)
           └── auction_state (stato live, non storicizzato)

Concetti chiave:

  • Progetto: spazio personale con i tag su una versione di listone, indipendente da ogni asta.
  • Ingresso in asta: i project_tags vengono copiati una tantum in auction_player_tags. Da quel momento vivono dentro l'asta: modificare il progetto non tocca le aste già avviate. Un progetto è importabile solo se project.list_version == auction.list_version.
  • Tag privati: ogni partecipante vede solo i tag che ha portato con sé.
  • Storico: si registra solo l'ordine di chiamata e il prezzo finale (roster). I rilanci intermedi e le chiamate annullate non lasciano traccia.

Offerta massima

offerta_massima = crediti_residui − (slot_ancora_da_riempire − 1)

Ogni altro slot va coperto da almeno un credito. La regola è applicata sia sui rilanci sia sull'assegnazione finale, insieme alla verifica che lo slot del ruolo scelto sia ancora libero.

Eventi WebSocket

Canale: ws://<host>/ws/{auction_id}?token=<jwt>. Alla connessione il server invia uno snapshot completo; poi arrivano gli eventi in broadcast.

Evento Quando
snapshot all'apertura della connessione
player_called un giocatore è stato messo in asta
bid_update rilancio: prezzo/leader correnti
call_cleared chiamata annullata, il giocatore torna disponibile
player_assigned assegnazione: roster, crediti e disponibilità aggiornati
role_closed una squadra ha completato gli slot di un ruolo
participant_joined nuova squadra entrata
auction_started l'admin ha avviato l'asta
auction_closed l'admin ha chiuso l'asta
player_updated override di ruolo applicato dall'admin
call_order_updated ordine di chiamata modificato

Il client invia ping come keepalive; tutte le azioni passano dalle REST API, che poi fanno il broadcast.

Test

docker compose run --rm --no-deps api python -m pytest -q

Coprono: formula dell'offerta massima e validazioni di assegnazione, ruoli Classic/Mantra e override, parser del listone (csv e xlsx), formato di export, e il flusso API completo (listone → progetto → asta → ingresso con import tag → live → export → chiusura).

Type-check e build del frontend:

docker compose run --rm --no-deps web npm run build

Migrazioni

docker compose run --rm api alembic revision --autogenerate -m "descrizione"
docker compose run --rm api alembic upgrade head

Punti aperti

  • Formato di export Leghe Fantacalcio: CSV senza intestazione, una riga per calciatore nel formato <Squadra>,<Id>,<Costo> (id = quello di fantacalcio.it, lo stesso usato per lo scraping) — così come richiesto dal modale "Importa rose" dell'interfaccia attuale. Il formato può cambiare tra una stagione e l'altra e non è ancora stato verificato con un vero import: va controllato sul modale corrente di Leghe Fantacalcio. Tutta la conoscenza del formato è in export_leghe.py.
  • Ordine di chiamata: la turnazione fixed_list è esposta come suggerimento (GET /auctions/{id}/live/next-caller) e non blocca le chiamate, perché le chiamate annullate non vengono storicizzate e il turno non sarebbe ricostruibile in modo affidabile.
  • Scalabilità WebSocket: il registro delle connessioni è in-process. Con più worker uvicorn serve un pub/sub (es. Redis) per propagare i broadcast tra processi.
  • PWA: non ancora configurata; l'interfaccia è responsive ma non installabile.

About

Your privata fantacalcio asta tool

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages