Architecture technique

État au moment de la lecture

Cette page décrit l’état réellement construit (v0.1 et extensions), pas seulement le plan initial – voir User stories & points ouverts pour le détail incrément par incrément et les décisions prises en cours de route.

Stack

🐍 Python

Structure src layout, setuptools_scm pour le versioning, PyInstaller pour le packaging.

🗄️ SQLite

Fichier local, pas de serveur distant, pas d’écriture concurrente à gérer (poste unique organisateur).

🖥️ customtkinter

GUI organisateur : 6 écrans (Accueil, Compétitions, Compétiteurs, Saisie des scores, Classement, Aide).

📄 openpyxl / fpdf2

Export Excel et PDF du classement – CSV via la stdlib.

Note

CI/CD : reprise telle quelle de la configuration FletchTime (test.yml, docs.yml, build.yml ; dédup GitHub Pages restreinte aux tags/Release/workflow_dispatch). Voir User stories & points ouverts pour les deux bugs de déclencheur rencontrés et corrigés sur la première vraie Release.

Vue d’ensemble des flux (v0.1 + v0.2)

        flowchart TB
    subgraph "Poste organisateur (construit, v0.1)"
        GUI["gui/ (10 écrans)"]
        SERVICES[services.py]
        DB[(SQLite local)]
        SCORING[scoring/]
        GUI --> SERVICES
        SERVICES --> SCORING
        SERVICES --> DB
    end

    DB --> EXPORT["io/export/"]
    EXPORT --> XLSX[Excel]
    EXPORT --> PDF[PDF]
    EXPORT --> CSV[CSV]

    subgraph "Vue compétiteur (construite, v0.2)"
        WEB["api/competiteur.py\n(http.server, thread séparé)"]
        NAVIGATEUR["Navigateur du compétiteur\n(même wifi que le club)"]
        NAVIGATEUR -->|GET/POST, token optionnel| WEB
    end

    DB -.connexion SQLite dédiée, lecture seule (mode=ro) pour la\nconsultation, écriture pour rattachement/messages.-> WEB
    

Vue compétiteur + token/rattachement construits (v0.2)

api/competiteur.py sert le classement live (lecture seule), la demande/confirmation de rattachement, la confirmation d’un code d’accès, et une messagerie organisateur → compétiteur (ciblée ou diffusée, via un cookie de session signé HMAC). api/organisateur.py reste un fichier vide – la proposition de score par le compétiteur et sa validation restent prévues v0.3, voir User stories & points ouverts.

Arborescence réelle (v0.1)

fletchscore/
├── src/fletchscore/
│   ├── models/            # Club, Style, Competiteur, Competition,
│   │                      # Epreuve, EpreuveTemplate, Bareme,
│   │                      # Inscription, Score, Token,
│   │                      # DemandeRattachement
│   ├── storage/
│   │   ├── db.py          # schéma SQLite + CRUD, seuls fonctions
│   │   │                  # publiques -- pas d'ORM
│   │   └── migrations/    # vide -- pas de vrai système de migration
│   │                      # pour l'instant (voir dépannage utilisateur)
│   ├── referentiels/      # chargement/validation du référentiel styles
│   ├── scoring/
│   │   └── classement.py  # classement par catégorie + classement
│   │                      # global multi-épreuves, départage au X,
│   │                      # podium -- isolé, testable sans DB ni GUI
│   ├── io/
│   │   ├── import_csv.py  # import ET export CSV des référentiels
│   │   └── export/        # classement : par épreuve et global
│   │       ├── csv.py
│   │       ├── excel.py
│   │       └── pdf.py
│   ├── services.py        # TOUS les cas d'usage organisateur --
│   │                      # seule couche connue à la fois de gui/ et
│   │                      # des tests ; ErreurMetier pour les messages
│   │                      # lisibles par l'organisateur
│   ├── gui/
│   │   ├── app.py               # fenêtre principale, navigation
│   │   ├── config.py            # préférences GUI (thème), atomique
│   │   ├── robustesse.py        # absence d'affichage, Ctrl+C/kill
│   │   ├── dialogue_fichier.py  # sélecteur de chemin maison (pas
│   │   │                        # tkinter.filedialog -- bug Pydroid)
│   │   └── ecran_*.py           # un fichier par écran
│   ├── api/
│   │   ├── competiteur.py        # serveur HTTP (v0.2 -- classement,
│   │   │                         # rattachement, messagerie)
│   │   └── organisateur.py       # squelette vide -- v0.3
│   └── __main__.py         # argparse (-h, -V, -v, -d, --db, --http-port)
├── tests/                  # ~250 tests -- voir :doc:`roadmap`
├── exemples/                # CSV d'exemple pour tests manuels
├── branding/                # logo (svg, png, ico)
├── docs/                   # Sphinx (ce site) + sphinx-design + mermaid
└── .github/workflows/       # test.yml, docs.yml, build.yml

Tip

Pourquoi services.py et pas un module par écran ?

Toute la logique métier (créer une compétition, saisir un score, calculer un classement…) vit dans services.py, jamais dans gui/. Conséquence directe : chaque écran GUI reste un simple assemblage de widgets, et l’intégralité des règles métier est testable sans jamais avoir besoin d’un affichage – ce qui a permis de développer et tester tout FletchScore dans un environnement sans tkinter ni customtkinter installés (voir User stories & points ouverts).