# Partie 5 — Rétro-documentation Cette rétro-documentation a été produite par analyse du code source réel de `gesthub-v2` (et non rédigée en amont du code), selon la démarche décrite au Bloc 4 — C1 : 1) analyse de l'arborescence, 2) lecture du code pour comprendre le rôle de chaque fonction, 3) reconstruction des flux à partir des appels de fonctions, 4) production du dictionnaire de données. ## RD-1 — Architecture en 5 couches | Couche | Répertoire | Responsabilité | |---|---|---| | Présentation | `templates/`, `static/` | Rendu HTML (Jinja2), CSS, JS (SortableJS pour le drag & drop) | | Contrôleur | `routes/` | Orchestration HTTP : authentifie, délègue, répond en JSON/HTML | | Service | `services/` | Logique métier, validation, journalisation dans `audit_log` | | Accès données | `models/` | Repository Pattern, seules requêtes SQL de tout le projet | | Infrastructure | `db.py`, `config.py`, `docker-compose.yml` | Connexion MariaDB, configuration par variables d'environnement, orchestration des conteneurs | ## RD-2 — Flux de données détaillés **Consultation des annonces :** `Navigateur → GET /api/annonces → routes/annonces.py (vérifie la session) → services/annonce_service.list_annonces → models/annonce_model.fetch_all → MariaDB (SELECT paramétré) → JSON → Navigateur` **Upload de fichier :** `Navigateur (multipart/form-data) → routes/fichiers.py → services/ fichier_service.handle_upload (8 étapes : présence → taille → MIME → extension → nom UUID → écriture disque → INSERT métadonnées → INSERT audit_log) → réponse JSON {id}` **Téléchargement de fichier :** `Navigateur → GET /api/fichiers/{id}/download → vérification des droits (propriétaire ou admin) → audit_log (SUCCESS ou REFUSED) → send_file (si autorisé) ou 403` ## RD-3 — Flux d'authentification OIDC (annoté, 7 étapes) | Étape | Description | Code | |---|---|---| | 1 | Détection de l'absence de session | `routes/dashboard.py::index` (`is_authenticated()`) | | 2 | Génération de l'URL d'autorisation + nonce anti-rejeu | `routes/auth.py::login` | | 3 | Redirection vers Keycloak | `keycloak.authorize_redirect(...)` | | 4 | Retour sur `/auth` avec le code d'autorisation | Géré automatiquement par Authlib | | 5 | Échange du code contre un token | `keycloak.authorize_access_token()` | | 6 | Vérification du token (signature + nonce) | `keycloak.parse_id_token(token, nonce=nonce)` | | 7 | Création de la session applicative | `session["user"] = userinfo` | ## RD-4 — Dictionnaire de données | Champ | Table | Type SQL | Source | Description | |---|---|---|---|---| | `id` | toutes | `INT UNSIGNED AUTO_INCREMENT` | MariaDB | Clé primaire | | `titre` | annonces, evenements | `VARCHAR(150)` | Saisie admin | Titre affiché | | `epinglee` | annonces | `TINYINT(1)` | Saisie admin | Priorité d'affichage | | `auteur_sub` / `uploader_sub` / `createur_sub` | annonces, fichiers, evenements | `VARCHAR(64)` | Claim `sub` du token OIDC | Référence utilisateur (pas de doublon des données Keycloak) | | `nom_stocke` | fichiers | `VARCHAR(64)` | Généré (UUID4) | Nom réel sur disque, anti path-traversal | | `taille_octets` | fichiers | `BIGINT UNSIGNED` | Calculé à l'upload | Taille du fichier | | `action` / `statut` | audit_log | `VARCHAR(50)` / `VARCHAR(20)` | Généré par les services | Traçabilité (ex. `CREATE_ANNONCE` / `SUCCESS`) | ## RD-5 — Table de correspondance claims JWT ↔ champs applicatifs | Claim JWT (Keycloak) | Champ applicatif | Utilisation | |---|---|---| | `sub` | `session["user"]["sub"]`, colonnes `*_sub` en base | Identifiant utilisateur unique et stable | | `preferred_username` | `session["user"]["preferred_username"]` | Affichage du nom d'utilisateur (template `index.html`) | | `email` | `session["user"]["email"]` | Non utilisé actuellement (disponible pour évolutions, ex. notifications) | | `groups` | `session["user"]["groups"]` | Contrôle d'accès (`/admin` → `is_admin()`) | | `iat`, `exp`, `iss` | Vérifiés automatiquement par Authlib | Validité temporelle et émetteur du token | En spécialité Robotique & Systèmes Embarqués, cette même logique de table de correspondance s'applique au mapping entre formats de données capteurs (ex. trame UART) et structures Python applicatives — la compétence transférée est la même : documenter précisément la correspondance entre un format source externe et le modèle interne de l'application.