Skip to content

Repository files navigation

Gestionale Gare di Scherma

Sistema completo per la gestione di gare di scherma (individuali e a squadre) secondo le Disposizioni Attività Agonistica FIS 2026-27.

Sostituisce un gestionale .NET legacy con uno stack moderno Python + Web.


Architettura

gestionale_gara/
├── backend/             # FastAPI + PostgreSQL + SQLAlchemy
├── frontend-admin/      # HTML/CSS/JS + Bootstrap 5 (richiede login JWT)
├── frontend-results/    # HTML/CSS/JS + Bootstrap 5 (pubblico, no login)
└── cyrano-bridge/       # Modulo standalone: interfaccia pedane via Cyrano

Stack:

  • Backend: FastAPI, SQLAlchemy 2.0, Alembic, psycopg2, python-jose (JWT), passlib (bcrypt), pandas
  • Frontend: HTML/CSS/JS vanilla + Bootstrap 5 CDN (no build step)
  • DB: PostgreSQL
  • Cyrano-bridge: Python standalone, protocollo seriale RS422 verso pedane Favero

Per avvio rapido e installazione vedi AVVIO.md.


Frontend Admin — Pagine

Le pagine admin sono in frontend-admin/. Richiedono autenticazione (JWT).

Pagina Descrizione
login.html Login con username/password (default admin/admin123)
index.html Dashboard: elenco tornei + creazione nuovo torneo
tournament-detail.html Dettaglio torneo: gare, import XML legacy, gestione pool arbitri, gare nascoste. Modale "Nuova Gara" con campi serie/lega/zona/categorie_unite per gare a squadre
athletes.html Anagrafica atleti: ricerca, edit, ranking per arma, società
atleti-allenamento.html Associazione atleta → società di allenamento secondarie (vincoli arbitrali)
arbitri.html Anagrafica arbitri: qualifiche per arma×genere, grado, pausa, società escluse, categorie escluse
registration.html Iscrizioni di una gara: aggiungi atleti, ranking gara, marca presenti/ritirati
teams.html Gestione squadre (gara tipo='squadre'): classica, mista_società, mista_genere (M+F), u14_categorie_unite. Import ranking.xls FIE legacy
tournament-arbitri.html Pool arbitri del torneo (un arbitro disponibile per tutte le gare)
arbitri-gara.html Assegnazione arbitri alle singole gare/gironi/assalti (auto-assign con load balancing)
formula.html Configurazione formula gara: modalità, gironi, eliminazione, tableau, decalage, raggruppamenti con altre categorie
groups-view.html Anteprima/composizione gironi, log serpentone, ricomposizione manuale
groups-scores.html Inserimento punteggi gironi (matrice assalti), classifica gironi
de-bracket.html Tabellone eliminazione diretta principale (R128..F), input punteggi assalti DE
de-playoffs.html Tabelloni Play-Off / Play-Out (squadre Serie A2/B1/B2/C, Club League C)
pedane.html Pianificazione pedane: orari appello gironi, pedana assalti DE
ranking-view.html Classifica iniziale gara basata su ranking nazionale per arma
import.html Import XML legacy .gst da gestionale .NET (atleti, iscrizioni, gironi, assalti)
import-pozzo.html Import anagrafica atleti da file "pozzo" FIS XLSX/CSV
state-history.html Storico checkpoint gara + rollback a stato precedente

Pagine pianificate ma non ancora UI dedicate (endpoint API disponibili)

  • Club League calendario Lega A/B (3 giornate × 5 turni) → endpoint POST /api/gare/{id}/club-league/calendario
  • Promozioni/Retrocessioni post-stagione → endpoint POST /api/gare/{id}/calcola-promozioni
  • Import classifica AMIS esterna per gare Master → endpoint POST /api/gare/{id}/import-amis-results
  • Backfill regioni (società/atleti) → endpoint POST /api/regioni/backfill-societa|-atleti

Frontend Results — Pagine pubbliche

Le pagine results sono in frontend-results/ e non richiedono login. Sono le pagine consultate dal pubblico durante e dopo la gara.

Pagina Descrizione
index.html Elenco tornei attivi
tournament-results.html Elenco gare del torneo
competition.html Indice fasi di una gara: ranking, gironi, DE, classifica
initial-ranking.html Ranking iniziale per ranking_gara
ranking-results.html Classifica post-gironi
groups-results.html Composizione gironi e relativi assalti
bracket-results.html Tabellone DE pubblico (read-only)
final-ranking.html Classifica finale gara

Backend — API REST

Tutti gli endpoint sono prefissati con /api e protetti da JWT (eccetto quelli pubblici di results.py). Documentazione interattiva: GET /docs.

Autenticazione

Method Path Descrizione
POST /api/auth/token Login (form-encoded: username, password) → JWT
GET /api/auth/me Dati utente corrente

Tornei e Gare

Method Path Descrizione
GET/POST /api/tornei Elenca/crea tornei
GET/PUT/DELETE /api/tornei/{id} CRUD singolo torneo
PATCH /api/tornei/{id}/visibility Toggle visibilità (nascosto)
GET /api/tornei/{id}/gare Elenco gare di un torneo
POST /api/tornei/{id}/gare Crea gara (accetta serie, lega, zona, fase, categorie_unite per squadre)
GET/PUT/DELETE /api/gare/{id} CRUD singola gara
PATCH /api/gare/{id}/visibility Toggle visibilità gara

Anagrafica

Method Path Descrizione
GET /api/categorie Mappa categoria → label
GET/POST /api/societa Elenca/crea società (regione auto-popolata da codice se omessa)
PUT /api/societa/{id} Update società
GET/POST /api/atleti Elenca (con filtri q, cognome, societa_id, genere, cat_atleti) / crea atleta
GET/PUT /api/atleti/{id} Dettaglio / update atleta

Iscrizioni

Method Path Descrizione
GET /api/gare/{id}/iscrizioni Iscrizioni della gara
POST /api/gare/{id}/iscrizioni Aggiungi iscrizione (atleta o squadra)
PATCH /api/iscrizioni/{id} Update (presente, ritirato, escluso, ranking_gara)
DELETE /api/iscrizioni/{id} Cancella iscrizione

Squadre

Method Path Descrizione
GET/POST /api/gare/{gara_id}/squadre Elenca/crea squadra
PUT/DELETE /api/gare/{gara_id}/squadre/{id} Update/elimina squadra
POST /api/gare/{gara_id}/squadre/auto-classiche Genera squadre classiche raggruppando per società
POST /api/gare/{gara_id}/squadre/import-ranking-xls Import ranking.xls FIE

Formula gara

Method Path Descrizione
GET /api/gare/{id}/formula Recupera configurazione formula
POST/PUT /api/gare/{id}/formula Crea/aggiorna formula
GET /api/gare/{id}/formula/config-gironi Configurazione gironi suggerita per N iscritti

Gironi

Method Path Descrizione
GET /api/gare/{id}/gironi Elenco gironi del turno corrente
POST /api/gare/{id}/gironi/genera Genera gironi via serpentone FIE (parametri: turno, config_override)
GET /api/gare/{id}/gironi/preview Anteprima composizione senza scrivere su DB
PUT /api/gare/{id}/gironi/composizione Ricomposizione manuale dei gironi

Tabellone DE

Method Path Descrizione
GET /api/gare/{id}/tabellone Elenco slot tabellone (filtrabile per fase)
GET /api/gare/{id}/tabellone/round/{round_size} Slot di un round specifico
POST /api/gare/{id}/tabellone/genera Genera tabellone DE (parametri: n_eliminati, perc)
POST /api/gare/{id}/tabellone/playoff-playout Nuovo: genera Play-Off / Play-Out per Serie/Club League dopo R16
POST /api/gare/{id}/tabellone/azzera Cancella tabellone
PUT /api/gare/{id}/tabellone/match/{round_size}/{idx}/pedana Assegna pedana/ora a un match

Punteggi assalti

Method Path Descrizione
GET /api/assalti?gara_id=&fase= Elenco assalti filtrabili
PUT /api/assalti/{id}/side/{1|2} Inserisci punteggio singolo lato (admin)
PUT /api/assalti/{id}/full Inserisci punteggio completo (arbitro)
GET /api/assalti/{id}/log Storico modifiche

Classifiche

Method Path Descrizione
GET /api/gare/{id}/classifica-gironi Classifica dopo gironi
GET /api/gare/{id}/classifica-finale Classifica finale (post DE)

Arbitri

Method Path Descrizione
GET/PATCH /api/arbitri/atleti Anagrafica arbitri (qualifiche, grado, pausa)
GET/POST/DELETE /api/arbitri/atleti/{id}/societa-escluse Vincoli società
GET/POST/DELETE /api/arbitri/atleti/{id}/categorie-escluse Vincoli categoria (es. "Master")
GET/POST/DELETE /api/arbitri/tornei/{id}/pool Pool arbitri del torneo
GET /api/arbitri/gare/{id}/pool Pool gara (proxy del torneo con flag eligibilità)
PUT /api/arbitri/gironi/{id}/arbitro Assegna arbitro a girone (con propagazione assalti)
PUT /api/arbitri/assalti/{id}/arbitro Assegna arbitro/assessori a un assalto
POST /api/arbitri/gare/{id}/auto-assign Auto-assegnazione (scope: gironi|assalti|all)
GET /api/arbitri/gare/{id}/storico Storico arbitraggi della gara

Raggruppamenti formula

Method Path Descrizione
GET/POST /api/gruppi-formula Elenco/crea gruppo
GET /api/gare/{id}/gruppo-formula Gruppo di una gara
PUT/DELETE /api/gruppi-formula/{id} Update/scioglimento gruppo

Club League

Method Path Descrizione
POST /api/gare/{id}/club-league/calendario Genera calendario Lega A/B (16 squadre, 15 turni, 120 assalti)
POST /api/gare/{id}/club-league/girone-unico-variabile Genera girone unico per 2-16 squadre (caso Serie con <6 partecipanti)

Promozioni / AMIS / Regioni

Method Path Descrizione
POST /api/gare/{id}/calcola-promozioni Calcola promozioni/retrocessioni Serie/Lega (input: stagione es. "2026-27")
GET /api/promozioni Elenco promozioni (filtri: stagione, arma, genere, contesto)
POST /api/gare/{id}/import-amis-results Import classifica AMIS esterna per gare Master (modalità amis_external)
GET /api/regioni Mappa province → regione + zone Z1/Z2
POST /api/regioni/backfill-societa Popola Societa.regione dai codici esistenti
POST /api/regioni/backfill-atleti Propaga regione da società ad atleti

Import legacy

Method Path Descrizione
POST /api/import-xml Import XML legacy .gst (atleti, iscrizioni, gironi, assalti DE)
POST /api/import-pozzo Import anagrafica FIS da XLSX/CSV
GET /api/export-legacy-xml/{torneo_id} Export XML legacy compatibile col gestionale .NET

Stato gara

Method Path Descrizione
GET /api/gare/{id}/checkpoints Storico checkpoint
POST /api/gare/{id}/rollback/{checkpoint_id} Rollback allo stato indicato

Risultati pubblici (no auth)

Method Path Descrizione
GET /api/public/tornei Tornei pubblicati
GET /api/public/gare/{id} Dettaglio gara pubblica
GET /api/public/gare/{id}/gironi Composizione gironi
GET /api/public/gare/{id}/tabellone Tabellone DE
GET /api/public/gare/{id}/classifica Classifica finale

App arbitro (login dedicato)

Method Path Descrizione
POST /api/arbitro-app/login Login arbitro con num_fis + password
GET /api/arbitro-app/my-assignments Assegnazioni dell'arbitro corrente
PUT /api/arbitro-app/assalti/{id} Inserisci punteggio (entrambi i lati in una chiamata)

PDF export

Method Path Descrizione
GET /api/gare/{id}/pdf/{tipo} Genera PDF (tipo: gironi, sommario_gironi, gironi_con_ris, tabellone, classifica_finale, cartellino_squadra, ...)

Modalità formula supportate

Configurabili via campo FormulaGara.modalita_formula (vedi backend/app/models/formula.py):

Valore Articolo Disp. Descrizione
standard art. 5/7 Formula zonale/regionale: gironi (1-2 turni) con eliminazione 0-30% + DE integrale
campionato_italiano art. 5 Campionati Italiani Juniores/Cadetti/Giovani/Assoluti: nessuna eliminazione post-gironi + ricomposizione "teste di serie" se top-N assenti
nazionale_giovani_cadetti art. 5 Cadetti/Giovani fioretto M e spada: bypass top-16 in gironi + DE128 con preliminare (qualifica 64 al principale)
nazionale_assoluti art. 5 Nazionale Assoluti: bypass top-8 (fioretto/sciabola) o top-16 (spada) + DE integrale senza preliminare
gpg_regionale art. 30 GPG prove regionali: gironi 7/6 senza eliminazione
gpg_campionato art. 30 GPG Campionato Italiano e U14: doppia tornata gironi 0-20% + DE fino a 256 atleti
gpg_maschietti_finale art. 30 GPG Maschietti/Bambine finale: 3 turni (gironi senza elim → gironi con elim 50% → DE integrale)
girone_unico art. 6 Club League Lega A/B (16 squadre): girone unico in 3 giornate × 5 turni × 8 incontri. Anche per Serie con <6 squadre
amis_external art. 45 Gare Master: nessuna generazione gironi/DE, classifica importata da sistema AMIS esterno

Campi correlati su FormulaGara:

  • num_teste_serie_bypass (default 16) — quante teste di serie saltano i gironi (bypass)
  • num_qualificati_diretti (default 48) — quanti qualificati post-gironi entrano direttamente nel principale (modalità nazionale)
  • tableau_preliminare_enabled (default True) — se False salta il preliminare anche con modalità Cadetti/Giovani (variante fioretto F / sciabola)
  • perc_eliminazione_turno2 — % elim tra turno 1 e 2 (GPG Maschietti finale: default 50%)
  • stoccate_per_frazione_squadre (default 5) — soglia max per frazione della staffetta a squadre (5 → 45 totali, 4 → 36 U14 Maschietti/Giovanissimi)
  • tipo_decalagesocieta | regione | nessuno
  • incontri_utili_fino_a — posizione massima utile (Serie C / Club League D: 6); marca automaticamente non_disputato=True sui bouts ininfluenti
  • finale_3_4_posto — abilita finalina 3°/4°

Tipi di squadra

Configurabili via Squadra.tipo_squadra (vedi backend/app/services/team_composer.py):

Valore Composizione Vincoli
classica 3-4 atleti stessa società suffisso -2, -3, … per società con più squadre
mista_societa 3-4 atleti ≥2 società diverse societa_id=None
mista_genere 2 atleti, 1 M + 1 F qualsiasi società
u14_categorie_unite 3-4 atleti (3+1 riserva) stessa società, categorie tra quelle dichiarate in Gara.categorie_unite

Provincia → Regione + Zone Z1/Z2

Modulo backend/app/services/regioni.py:

  • PROVINCIA_REGIONE: 107 sigle attive + 4 storiche sarde (CI/OG/OT/VS)
  • REGIONI_PROVINCE: reverse map regione → set(sigle)
  • ZONE_INDIVIDUALI: Z1 (8 regioni Nord) e Z2 (12 regioni Centro-Sud), Disp. art. 31/38
  • regione_da_codice_societa(codice) — prime 2 lettere → regione
  • zona_individuale_da_regione(regione)'Z1' | 'Z2'
  • backfill_regione_societa(db) / backfill_regione_atleti(db)

Le società create via POST /api/societa ottengono regione automaticamente dal codice se non esplicitata. Gli atleti propagano la regione dalla loro società alla creazione.


Modelli DB principali

Migrations Alembic in backend/alembic/versions/ (001..024). Idempotenti (usano inspect() per check colonne/tabelle prima di create/drop).

  • Torneo (id, nome, data, luogo, variante_categoria fis|amis) → 1:N Gara, 1:N GruppoFormula
  • GruppoFormula (torneo_id, nome, gironi_uniti, de_unito) → 1:N Gara
  • Gara (torneo_id, arma, genere, categoria, tipo, stato_fase, gruppo_formula_id, ordine_in_gruppo, serie, lega, zona, fase, categorie_unite) → 1:1 FormulaGara, 1:N Iscrizione/Girone/TabelloneED
  • FormulaGara (gara_id unico; dim_gironi_min/max, perc_eliminazione, perc_eliminazione_turno2, num_minimo_qualificati, tableau_size, decalage_societa, tipo_decalage, finale_3_4_posto, modalita_formula, num_teste_serie_bypass, num_qualificati_diretti, tableau_preliminare_enabled, stoccate_per_frazione_squadre, incontri_utili_fino_a)
  • Iscrizione (gara_id, atleta_id XOR squadra_id, ranking_gara, presente, ritirato, escluso, classifica_finale)
  • Squadra (gara_id, nome, societa_id?, tipo_squadra, suffisso_numerico) → 1:N SquadraAtleta
  • SquadraAtleta (squadra_id, atleta_id, ordine, is_riserva)
  • Atleta (num_fis, cognome, nome, societa_id, data_nascita, genere, ranking_fioretto/spada/sciabola, cat_atleti, regione, is_arbitro + qualifiche_arbitro)
  • Societa (codice, denominazione, citta, sigla, data_scadenza, regione)
  • Girone (gara_id, turno, numero_girone, completato, pedana, ora_appello, arbitro_id)
  • GironeAtleta (girone_id, iscrizione_id, ordine_nel_girone, vinti, assalti, sd, sr, vm, classifica_girone)
  • Assalto (gara_id, fase: girone|de|spareggio|girone_unico, fase_tabellone, girone_id?, de_round?, de_slot?, ordine, iscrizione1/2_id, stoccate1/2 + _input, vittoria1/2, completato, pedana, ora_inizio, arbitro_id, assessore1/2_id, video_arbitro_id, non_disputato, numero_turno, numero_giornata)
  • TabelloneED (gara_id, fase_tabellone: principale|preliminare|playoff|playout|finale_5_8|finale_3_4, round_size, slot_number, iscrizione_id, is_bye, assalto_id, vincitore_id, seed, pedana, ora_inizio)
  • PromozioneRetrocessione (stagione, torneo_id?, squadra_id, arma, genere, contesto: serie|club_league, serie_from/to, lega_from/to, zona, tipo: promozione|retrocessione, classifica_finale)
  • StatoGaraCheckpoint (gara_id, fase_al_momento, descrizione, snapshot_json) — per rollback
  • LogAzione (gara_id, tipo, testo) — log testuale generazioni/import
  • TorneoArbitro / ArbitroSocietaEsclusa / ArbitroCategoriaEsclusa

In grassetto i campi aggiunti per Disp. FIS 2026-27 (migrations 021-024).


Servizi backend chiave

Sotto backend/app/services/:

Modulo Responsabilità
group_composer.py Orchestrazione generazione gironi: serpentone FIE, gironi uniti, gestione turni multipli (incluso elim 50% turno 2 GPG Maschietti), verifica "teste di serie" Campionato Italiano
serpentone_fie.py Algoritmo serpentone con decalage società o regione
de_builder.py Generazione tabellone DE con seeding FIE; supporto modalità nazionale (bypass top-N) con/senza preliminare; ROUND_SIZES fino a 256; genera_playoff_playout per Serie/Club League; marca_incontri_ininfluenti
de_classifica.py Calcolo classifica finale post-DE (popola Iscrizione.classifica_finale)
de_propagation.py Propagazione vincitori DE ai round successivi
girone_unico.py Girone unico Club League Lega A/B (calendario hardcoded 15 turni × 8 incontri) + girone unico variabile 2-16 (caso Serie con <6 squadre)
promozioni.py Calcolo post-stagione promozioni/retrocessioni Serie A1..C e Club League A..D
amis_external.py Import classifica AMIS esterna per gare Master
team_composer.py Validazione composizione squadre (4 tipi), auto-generazione classiche, validazione categorie Master squadre
categorie.py Mappa categoria → label (FIS + AMIS); categorie_amis_squadre_ammesse(arma, genere)
regioni.py Mappa province → regione + zone Z1/Z2 + backfill
referee_assigner.py Algoritmo eligibilità arbitri e auto-assegnazione con load balancing
ranking_calc.py Calcolo classifica gironi (V/M, indicatore, stoccate date), eliminazione, pool DE per gironi uniti
ranking_xls.py Parser ranking FIE legacy (sheets SPM/SPF/SCM/SCF/FM/FF)
bout_score_service.py Applicazione punteggio assalto con propagazione DE; gestione fase 'girone_unico' e staffetta a frazioni
bout_score_parser.py Parser input punteggio ("V5", "5/3", etc.)
bout_order.py Ordine assalti FIE per gironi 3-13 (incluso varianti per 2 pedane)
state_manager.py Checkpoint/rollback stato gara
action_logger.py Log testuali generazioni gironi/DE/import
gruppo_formula.py Helper raggruppamenti categorie (gironi/DE uniti)
display.py Label uniforme partecipante (atleta o squadra)
planner.py Pianificazione orari/pedane gironi
pdf_renderer.py / pdf_data.py Generazione PDF (gironi, tabellone, classifica)
legacy_xml_export.py Export XML compatibile col gestionale .NET

Stato implementazione FIS 2026-27

✅ Implementato

  • Tutte le 9 modalità formula (vedi tabella sopra)
  • Tabellone DE128 con preliminare (Cadetti/Giovani fioretto M e spada)
  • Tabellone DE senza preliminare (Cadetti/Giovani fioretto F/sciabola, Assoluti)
  • Tabellone fino a DE256 (GPG/U14 numerosi)
  • Play-Off / Play-Out per Serie A2/B1/B2/C e Club League C
  • Club League Lega A/B con girone unico 3 giornate × 5 turni
  • Girone unico variabile per Serie <6 squadre
  • 4 tipi di squadra (classica, mista_societa, mista_genere, u14_categorie_unite)
  • Decalage per società o regione (configurabile)
  • Stoccate per frazione configurabili (45 vs 36 staffetta)
  • Eliminazione 50% turno 2 GPG Maschietti finale
  • Clamp 20% Cadetti in doppia tornata, 0% Juniores zonali/regionali
  • Validazione Master squadre (cat. A/B, eccezione fioretto F/sciabola F solo A)
  • Import classifica AMIS esterna per Master
  • Calcolo promozioni/retrocessioni Serie A1..C e Club League A..D
  • Marker "incontri non disputati" automatico per Play-Out se incontri_utili_fino_a < 9
  • 107 province italiane + zone Z1/Z2
  • Auto-popolamento regione da codice società

⏸ Parziale / in attesa

  • Composizione zone Club League A/B/C/D: non specificata nelle Disp. Att., in attesa di Circolare Federale dedicata.
  • Fase Finale Lega A (8 squadre, 2 gironi × 4 + Play-Off senza 5°-8°): building block _build_subtableau disponibile, funzione dedicata da scrivere quando arriva la circolare con regole esatte (8 squadre = top 2 per zona o top 4 per zona?).
  • UI dedicate per Club League calendario, promozioni e import AMIS: endpoint API funzionanti via Swagger UI (/docs).
  • Caso "17 squadre" in Serie A2/B1/B2: la prima per ranking entra direttamente al DE16. Endpoint generico DE non lo gestisce ancora.

❌ Fuori scope corrente

  • Gran Premio Paralimpico (carrozzina): richiede classificazione disabilità su atleta + tabelle gironi dedicate + coefficienti Kt.
  • Gran Premio di Scherma Integrata.
  • Non Vedenti (Spada M/F) con DE 15 stoccate × 3 tempi.

Queste tre aree sono state escluse dal piano implementativo corrente per decisione esplicita: richiedono infrastruttura nuova (classificazione atleta, tipo gara dedicato, durata DE custom) da pianificare separatamente.


Convenzioni di sviluppo

  • Migrations idempotenti: ogni migration usa _has_column() / _has_constraint() per evitare conflitti con Base.metadata.create_all() che gira al lifespan.
  • State autoflush=False: chiamare db.flush() esplicito dopo db.add() prima di query dipendenti.
  • Test smoke: dopo modifiche pesanti, eseguire cd backend && .venv/Scripts/python.exe -m alembic heads per verificare la catena migrations.

Licenza

GPL-2.0 (vedi AVVIO.md per il testo completo).


Riferimenti

  • Disp. Att. FIS 2026-27: Disp.-Att.-Ag.-2026-27.pdf
  • Regolamento Organizzazione FIE: art. o.68 (serpentone gironi)
  • Regolamento Tecnico FIE: art. t.124 (passività), T 70 (materiali)

About

Questo è un progetto personale, usato per testare le potenzialità di claude opus e generare un gestionale per le gare di scherma, liberamente utilizzabile da tutti secondo la licenza indicata

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages