Config strictement stricte partout (ruff, mypy --strict, bandit, vulture,
import-linter, eslint, stylelint), aucune regle desactivee "pour ne pas
casser le build" - l'existant a ete corrige pour la satisfaire plutot que
l'inverse. Hooks pre-commit locaux (language: system) bloquants.
- Typage mypy --strict propage a tout le moteur (db, screens, auth, core,
ai, routes, puis publish/scripts/tests/app.py/build_css.py).
- Securite : fuite de handle fichier Windows corrigee dans l'export SCORM
(routes/publish/export_scorm.py), CSRF/RNG non-crypto/xAPI documentes
(# nosec, # NOSONAR justifies), nouveau db.json_for_script() (echappe
"</script>" dans le JSON embarque en <script>, 25 sites).
- Architecture : imports circulaires/F811 nettoyes, contrats
import-linter respectes, code mort retire (vulture).
- Accessibilite : 69 champs de formulaire sans label correctement
associe corriges (for/id ou aria-label) sur 11 templates.
- ESLint/Stylelint : lot mecanique JS/CSS, regles ajustees puis
appliquees (aucune desactivee sans verification individuelle).
- Tests : isolation du compte admin partage (nettoyage ponctuel +
fixture de teardown automatique en filet de securite), suite complete
verte (591 tests Python, 241 tests JS).
- SonarQube Community Build self-heberge (Docker + PostgreSQL) : rapport
complet analyse point par point, faux positifs documentes.
- .gitattributes ajoute (LF force) : core.autocrlf=true sur cette machine
faisait echouer ESLint (linebreak-style) via un bug connu de git
(checkout "en place" qui ignore l'eol force sur un fichier deja
present sur disque - contourne en supprimant puis recreant chaque
fichier suivi).
djLint (H021, styles inline) volontairement saute pour ce commit -
backlog assume, deja documente, traite dans un lot separe.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Première moitié de la fonctionnalité "événements" (NEED_ACTION et
autres) : une entité game-wide (nom, description, "a un paramètre
élément" oui/non), déclenchable comme nouvelle action du graphe de
logique depuis n'importe quelle scène/modèle, et écoutable comme
nouveau type de déclencheur depuis n'importe quel autre. L'UI (nouvel
onglet "Événements" dans screen_edit.html, formulaires de nœud, exécution
côté client dans play.html) suit dans un commit séparé.
- db/custom_events/ (calqué sur db/global_vars/) : CRUD de la table
_custom_events (nom unique, description, has_element_param).
create_custom_event est idempotent par nom (même convention que
create_global_variable) — sans risque en cas de double soumission.
- screens/flow/ : 3 nouvelles colonnes sur _flow_nodes
(trigger_custom_event_id/target_custom_event_id : quel événement un
nœud écoute/déclenche ; target_element_from_event : indicateur
réutilisable par n'importe quel nœud Action utilisant déjà
target_element_id, pour résoudre "l'élément transmis par l'événement
en cours" au lieu d'une cible fixe — contourne la contrainte de clé
étrangère de target_element_id, qui empêche d'y stocker un sentinel
comme EVENT_ROW_ID directement). Nouveau trigger_event "evenement" et
action_type "declencher_evenement".
- screens/custom_events/ (PAS dans db/, même séparation que
screens/elements/delete_element.py) : delete_custom_event, la SEULE
suppression d'entité game-wide du moteur à vraiment cascader (demande
explicite) — supprime tous les nœuds/arêtes qui référencent
l'événement, sur TOUTES les scènes ET tous les modèles à la fois
(aucun filtre screen_id nécessaire : un modèle est un écran caché,
même table _flow_nodes). list_custom_event_usages : où un événement
est écouté/déclenché, pour l'onglet Événements à venir.
- routes/custom_events/ : CRUD monté sous /game/<slug>/events/...,
redirige vers l'éditeur de scène/modèle d'origine (screen_id transmis
par le formulaire) avec l'onglet "events" à ouvrir.
tests/test_custom_events.py (nouveau) : idempotence à la création,
usages détectés sur deux écrans différents, suppression qui retire bien
les DEUX nœuds (un sur une vraie scène, un sur un modèle/écran caché)
en une seule opération, sans toucher aux écrans eux-mêmes. 207 tests au
total.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>