Commit Graph
12 Commits
Author SHA1 Message Date
williamandClaude Sonnet 5 9776fbc057 Score/Progression (Phase 1.1 de la feuille de route produit)
Build and deploy / test-python (push) Successful in 7m27s
Build and deploy / test-js (push) Successful in 1m16s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Concept de premier ordre, distinct du système de variables globales —
préalable identifié aux futurs exports SCORM/xAPI (note de cadrage
.claude/Forge_Engine_Cadrage.pdf) : ces standards ont besoin d'un signal
"score"/"terminé" propre, pas d'une convention sur une variable choisie
par le créateur.

- db/scoring/ (même patron que db/global_vars/) : table _scoring, un
  score numérique + un statut (non_commence/en_cours/termine/reussi/
  echoue) par joueur (voir db.PLAYER_SHARED pour l'aperçu créateur).
- Deux nouvelles actions de flux, dans les deux éditeurs (document et
  scène) : "Modifier le score" (réutilise le vocabulaire d'opérations
  déjà là pour "Modifier une variable" — incrémenter/définir/etc., aucune
  nouvelle colonne de nœud) et "Définir le statut de la partie".
- Routes créateur (routes/flow/flow_node_run_score.py,
  flow_node_run_status.py) + miroirs publics par joueur
  (routes/public_play/) — même principe que flow_node_run_variable.py.
- GET /game/<slug>/scoring/<player_id> : lecture interne, pas exposée au
  joueur, préparée pour être consommée par le futur export Web/SCORM.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 06:23:37 +02:00
williamandClaude Sonnet 5 76a50fa87a Onboarding guidé systématique + tableau de bord simplifié
Build and deploy / test-python (push) Failing after 1m48s
Build and deploy / test-js (push) Successful in 53s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Comportement SYSTÉMATIQUE à chaque création de jeu (admin compris), pas
une formalité réservée à l'inscription : /onboarding (routes/onboarding/)
devient le point d'entrée unique — 4 cartes retournables (survol =
explication au dos), défilement horizontal animé vers le nom du jeu. Un
admin y repasse à volonté (pas de project_slug dédié, jamais bloqué/
redirigé vers un projet précédent) ; un compte "user" n'en a plus qu'un
créé d'office (routes/auth/register_2fa.py), guidé ici à la place.

- db/games/game_type_catalog.py : catalogue des 4 types (Quiz/
  Embranchement-escape game/RPG/Créer mon jeu de A à Z), _meta['onboarding_type']
  décide du "kind" du premier écran créé et si le tableau de bord complet
  reste accessible.
- routes/games/game_dashboard.py, templates/game_dashboard_simple.html :
  un type restreint (quiz/embranchement/rpg) voit désormais SON tableau
  de bord (même route que "custom"), rendu en version simplifiée — juste
  ses écrans en cartes avec un aperçu RÉEL du contenu (scène mise à
  l'échelle par container query CSS, adaptée à la largeur réelle de la
  carte). "+ Ajouter un écran" n'y propose pas de choix de type : imposé
  par le projet (routes/screens/screens_new.py), verrouillé aussi côté
  serveur.
- core/auth_guard.py : plus de blocage de game_dashboard par type — la
  restriction se fait au rendu, pas à l'accès à la route.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 06:22:45 +02:00
williamandClaude Sonnet 5 0f23024882 Structure de dossiers par utilisateur : projects/<propriétaire>/<projet>/
Build and deploy / test-python (push) Failing after 3m14s
Build and deploy / test-js (push) Successful in 53s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Remplace le rangement plat projects/<slug>/ par une vraie arborescence
par compte créateur, sans toucher aux routes existantes (aucune ne
déclare de "/" dans son <slug> : le chemin composé "propriétaire_projet"
reste un détail interne à db/, décodé par db/games/project_slug.py, seul
fichier à modifier si la convention change un jour).

- db/game_dir.py, create_game.py, delete_game.py, list_games.py,
  move_game.py : résolvent/construisent ce chemin composé. Bénéfice
  direct : deux comptes différents peuvent chacun avoir un projet nommé
  pareil sans collision (l'unicité ne se vérifie plus que par dossier
  propriétaire). move_game.py renomme désormais le dossier PROPRIÉTAIRE
  entier (changement d'email), prêt pour un futur multi-projet.
- scripts/migrate_flat_project_slugs.py : migration des projets déjà
  créés sous l'ancien rangement plat (simulation par défaut, --apply
  pour exécuter).
- routes/auth/profile.py, tests/conftest.py : suppression de compte/jeu
  de test via db.delete_game (nettoie aussi le dossier propriétaire
  devenu vide) plutôt qu'un shutil.rmtree direct du seul dossier projet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 06:22:03 +02:00
williamandClaude Sonnet 5 efa7d1d9b0 Fondations multi-éditeurs (1/3) : game_type + schéma/CRUD des objets de scène
Build and deploy / test-python (push) Successful in 1m41s
Build and deploy / test-js (push) Successful in 7s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Première brique du plan "Fondations d'une plateforme multi-éditeurs" —
l'utilisateur veut un éditeur dédié aux jeux 2D/serious games (scène à
coordonnées pixel fixes, objets en couches, collision, personnages
animés), distinct de l'éditeur générique actuel, sans dupliquer ce qui
peut être partagé (comptes, objets de données, moteur de logique de
flow, hébergement/publication).

- db/games/get_game_type.py (nouveau) : "document" (défaut, éditeur
  actuel) ou "jeu_2d" (nouveau), stocké dans _meta comme
  is_public_played — aucune migration pour les jeux déjà créés
  (retombent sur "document"). Choisi obligatoirement à la création
  (templates/index.html), jamais modifiable ensuite.
- screens/scenes/ (nouveau sous-module) : table _scene_objects (une
  scène = des objets en pixels fixes, pas les % fluides de
  _screen_elements — indispensable pour la collision/l'animation),
  CRUD complet, rendu HTML. kind="personnage" réutilise TELLE QUELLE la
  structure _personnage_data et les fonctions resolve_personnage_* déjà
  écrites pour le widget "personnage" de l'éditeur document (Phase 8) —
  même bibliothèque Forge, même moteur d'animation, juste une autre
  table de stockage.
- screens/flow/ensure_flow_schema.py : += trigger_object_id/
  target_object_id (ALTER TABLE sans contrainte FK, même patron que
  cond_element_a) — le moteur de logique de flow (_flow_nodes/_flow_edges,
  flow-engine.js) reste EXACTEMENT le même pour les deux éditeurs, seule
  la palette de nœuds change (screens/scenes/flow_palette.py, nouveau :
  sous-ensemble direct des triggers/actions existants, déjà génériques).
- screens/screens_repo/ensure_schema.py : += scene_width/scene_height
  sur _screens (taille de scène fixe en pixels, sans effet sur un écran
  "document").

Reste à faire (prochains commits) : route + template de l'éditeur de
scène, puis le rendu en mode jouable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-31 09:42:38 +02:00
williamandClaude Sonnet 5 3c39f1a249 Phase 1 (2/3) : route publique /jouer/<slug> + identité visiteur
Build and deploy / test (push) Failing after 8s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Ajoute la vraie route hébergée multi-joueurs qui manquait totalement
(voir le constat d'exploration : /game/<slug>/play est réservé au
créateur connecté, "Publier" ne génère qu'un exécutable mono-joueur) —
un visiteur anonyme peut maintenant jouer un jeu explicitement publié en
ligne, avec sa propre partie (variables/objets per_player posés dans le
commit précédent).

core/player_identity.py : identité visiteur via un cookie NON SIGNÉ
(forge_player_id, secrets.token_urlsafe(16), 1 an) — une simple clé de
partition, jamais un jeton d'autorisation.

routes/public_play/ : 4 routes, miroirs des routes existantes de l'aperçu
créateur mais threadées avec le vrai player_id du cookie au lieu du
sentinel PLAYER_SHARED :
- GET /jouer/<slug> (game_play_public.py)
- GET /jouer/<slug>/runtime-payload
- POST /jouer/<slug>/flow/nodes/<id>/run-data
- POST /jouer/<slug>/flow/nodes/<id>/run-variable
Chacune vérifie elle-même db.is_public_played(slug) (404 sinon) — un jeu
n'est exposé publiquement que si le créateur l'a explicitement basculé
"Publier en ligne" (nouveau db/games/is_public_played.py, réutilise la
table générique _meta, comme game_meta.py pour 'name').

core/auth_guard.py : les 4 endpoints publics ajoutés à _PUBLIC_ENDPOINTS
— la garde générique de connexion les laisse passer sans session, mais
chaque vue vérifie quand même is_public_played elle-même (défense en
profondeur, pas seulement une liste d'exceptions). CSRF (core/csrf_guard.py)
n'a besoin d'AUCUN changement : le jeton est déjà lié à la session Flask,
qui existe pour n'importe quel visiteur (connecté ou non).

templates/play.html : FORGE_PLAY_URLS (posé en Phase -1) ne construit
plus ses URLs via des noms de endpoint fixes (url_for('runtime_payload',
...)) mais reçoit des URLs déjà résolues par la route elle-même
(runtime_payload_url/flow_node_run_data_url/flow_node_run_variable_url)
— nécessaire puisque ce même template sert maintenant DEUX familles de
routes (aperçu créateur ET partie publique), chacune avec ses propres
noms de endpoint. routes/play/game_play.py (aperçu créateur, INCHANGÉ
comportement) et game_play_public.py passent chacun ses propres URLs.

templates/base.html : bascule "🌐 Publier en ligne" dans la barre de
navigation du jeu, à côté de "📦 Publier" (export .zip) — deux
fonctionnalités distinctes. db/games/game_meta.py expose maintenant
is_public_played, disponible partout où `game` est dans le contexte.

Vérifié : 237 tests passent (5 nouveaux dans test_public_play.py, dont un
bout-en-bout via HTTP avec deux VRAIS clients de test anonymes — deux
cookies forge_player_id différents — qui obtiennent des valeurs de
variable indépendantes, et un qui verrouille que l'aperçu créateur reste
inchangé). Syntaxe JS validée sur les deux variantes de play.html rendu
(aperçu créateur et partie publique).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-30 15:46:00 +02:00
williamandClaude Sonnet 5 0e390a679b Ajoute l'onglet "Données" au panneau objet, retire object_view.html
Suite de la demande : le panneau "Modifier un objet" (crayon ✏️, onglet
Objets du tableau de bord) a maintenant 2 sous-onglets — "Champs" (déjà
en place) et "Données", qui reprend data_list.html + data_form.html
(retirés) : ajouter une entrée (une ligne compacte avec le bon type de
champ par colonne — texte/nombre/case à cocher/date/relation, comme
l'ancien formulaire), modifier/supprimer une entrée existante (tableau
dense, cellules éditables en ligne, même principe que "Champs
existants").

Sous-onglets scopés au panneau de LEUR objet (switchObjectPanelTab(),
classes .objectPanelTabs/.objectPanelTabPanel distinctes de .builderTabs/
.builderTabPanel) — plusieurs objets ont chacun leurs propres
sous-onglets indépendants sur la même page, sans jamais interférer avec
les onglets du tableau de bord lui-même.

routes/games/game_dashboard.py fournit maintenant, par objet : ses lignes
(rows_by_definition), les libellés lisibles de ses champs relation
(relation_labels_by_definition, pour l'affichage) et leurs options
(relation_options_by_definition, pour les <select>), ainsi que
referenced_by_definition (avertissement permanent si un autre objet a
une relation vers celui-ci — repris de l'ancien object_view.py, affiché
maintenant en continu plutôt qu'après une tentative de suppression
échouée).

data_form.py (partagé par data_new/data_edit), data_delete.py et
object_delete.py redirigent maintenant vers le tableau de bord
(?edit=<id>&subtab=data, +?blocked_row=<id> si la suppression d'une
entrée est bloquée par une relation) au lieu de object_view/object_edit.

Piège évité : de nombreux tests déduisent l'id d'un objet fraîchement
créé du DERNIER SEGMENT du chemin dans le header Location d'une
redirection (.../objects/<id>) — rediriger object_new directement vers
le tableau de bord (chemin sans id) cassait donc 33 tests d'un coup.
Fix : object_view.py reste en place, mais seulement comme redirecteur
(plus de page rendue) — object_new redirige toujours vers lui (chemin
qui se termine par l'id, donc les tests continuent de fonctionner), qui
redirige à son tour vers le tableau de bord.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 12:13:05 +02:00
williamandClaude Sonnet 5 b8dfdcb205 Corrige la nav pjax, panneau déplaçable/redimensionnable pour éditer un objet
1) Bug pjax trouvé : swapDocument() cherchait "header.topbar", qui n'a
jamais existé (c'est un <nav>, pas un <header>) — la barre de navigation
du jeu (ajoutée après pjax.js) n'était donc jamais mise à jour pendant
une navigation pjax : absente en arrivant sur un jeu sans Ctrl+F5, et
inversement laissée en place en revenant sur l'accueil où elle n'a rien
à faire. Fix : tout ce qui est hors <main> mais doit changer d'une page
à l'autre (topbar + barre du jeu) est regroupé dans un nouveau conteneur
stable #pageChrome, que pjax.js remplace en bloc — plus fiable qu'un
sélecteur qui ne correspondait à rien. CSS (flex:0 0 auto des layouts
plein-écran) mis à jour en conséquence.

2) Renommages demandés : onglet/panneau "Écrans du jeu" -> "Écrants",
"Éléments de jeu" -> "Templates" (tab, titre de panneau, bouton
"+ Créer un template", état vide, infobulle, confirmation de
suppression).

3) Le crayon ✏️ sur une ligne d'objet ouvre désormais un panneau
déplaçable ET redimensionnable (nouveau coin de redimensionnement
générique, .floatPanelResizeHandle) au lieu de naviguer vers
object_edit.html (retirée) — un panneau par objet, pré-rendu et
caché par défaut. Reprend telles quelles les fonctionnalités de
l'ancienne page : renommer l'objet, ajouter un champ (ligne compacte),
modifier/supprimer un champ existant (tableau dense déjà repris pour
"Nouvel objet"), supprimer l'objet. Les routes de champs (object_field_
add/edit/delete) et object_edit lui-même redirigent maintenant vers le
tableau de bord avec ?edit=<id>, pour rouvrir automatiquement le bon
panneau après l'action plutôt que de le fermer silencieusement.

makeFloatPanelDraggable()/makeFloatPanelResizable() généralisées pour
être partagées entre "Nouvel objet" et les panneaux d'édition, plutôt
que du code dupliqué par panneau.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 11:56:49 +02:00
williamandClaude Sonnet 5 d875557254 Fusionne les 4 pages de création dans le dashboard, retire le titre/BDD
Suite de la demande précédente : les 4 pages autrefois listées dans la
barre de navigation n'existent plus en tant que pages séparées — tout
vit désormais dans les onglets du tableau de bord (commit précédent) ou,
pour la création d'un objet, dans un panneau déplaçable.

- screens_list.html + sa route (screens_list) : supprimés (l'onglet
  "Écrans du jeu" du dashboard couvre déjà tout : créer, réordonner,
  éditer, supprimer). screen_new/screen_move/screen_delete redirigent
  maintenant vers le dashboard (tab=screens) au lieu de cette page.
- element_types.html : supprimé, mais la route element_types est
  conservée (GET redirige vers le dashboard, POST — utilisé par la barre
  de création repliable de l'onglet "Éléments de jeu" — continue de
  fonctionner). element_type_edit/element_type_delete redirigent aussi
  vers le dashboard.
- game_variables.html + sa route (game_variables) : supprimés (l'onglet
  "Variables" du dashboard couvre déjà tout). create_global_var/
  global_var_edit/global_var_delete redirigent vers le dashboard
  (tab=variables) au lieu de cette page.
- object_form.html : supprimé. La route object_new (POST) est conservée
  pour traiter la soumission du panneau — voir plus bas — mais ne rend
  plus de page pour un GET (redirige vers le dashboard).

Nouveau panneau déplaçable "Nouvel objet" sur le dashboard (bouton
"+ Nouvel objet" de l'onglet Objets) : réutilise .floatPanel/
.floatPanelHeader/.floatPanelBody (déjà utilisées dans l'éditeur d'écran)
avec une nouvelle variante centrée (.floatPanel--center) et son propre
glisser-déposer minimal (pas de position persistée, contrairement aux
panneaux de l'éditeur d'écran — inutile pour un panneau ouvert
ponctuellement). Contenu et script (object_form.js) repris tels quels de
l'ancienne page.

base.html : la barre de navigation du jeu n'a donc plus que 2 liens —
"📊 Tableau de bord" (nouveau) et "▶️ Jouer" (toujours en dernier).

game_dashboard.html : titre du jeu et chemin de la base de données
retirés (redondants avec le nom déjà visible dans l'onglet du
navigateur/la barre de nav).

Les liens "crée-en un"/"gérer les variables" dans l'éditeur d'écran
(screen_edit.html) pointent maintenant vers le dashboard avec le bon
onglet (?tab=...), lu et appliqué au chargement de la page
(switchDashTab() côté JS).

2 tests (test_screens_and_elements.py) mis à jour : ils vérifiaient le
contenu des pages supprimées (element-types, screens) — adaptés pour
vérifier la même chose sur le dashboard, qui porte maintenant cette
information.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 10:54:19 +02:00
williamandClaude Sonnet 5 65450a5719 Refait le dashboard en fenêtre à onglets avec de vrais tableaux
Le précédent dashboard (grille de cartes compactes) ne correspondait pas
à ce que l'utilisateur voulait : une seule fenêtre avec de vrais tableaux
de données (denses, colonnes nettes), un bouton "Créer" par catégorie
dans l'en-tête, et une navigation horizontale pour passer d'une catégorie
à l'autre.

Réutilise telles quelles .builderTabs/.builderTabBtn/.builderTabPanel
(déjà utilisées pour "Écran / Logique / Timeline" dans l'éditeur d'écran)
plutôt que d'inventer un 2e système d'onglets — même sensation partout
dans l'outil. Un onglet par catégorie (Écrans/Objets/Éléments de
jeu/Variables), chacun avec :
  - un bouton "+ Créer" dans l'en-tête qui révèle une barre de création
    compacte (repliée par défaut) — sauf pour les Objets, dont la
    création (plusieurs champs typés) reste sur sa propre page dédiée,
    trop complexe pour tenir dans une barre ;
  - le VRAI tableau de gestion de cette catégorie (colonnes, actions),
    repris tel quel de screens_list.html/element_types.html/
    game_variables.html plutôt que réinventé en version appauvrie.

La page défile désormais normalement (retrait de body.objectEditBody/
content-objectEdit, pensés pour une hauteur figée avec défilement
interne) — une liste peut être longue, pas besoin d'un défilement séparé
par panneau ici.

routes/games/game_dashboard.py fournit en plus variable_types
(db.GLOBAL_VARIABLE_TYPES) pour la barre de création de variable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 10:15:37 +02:00
williamandClaude Sonnet 5 8f45169209 Retire le fil d'Ariane, centre/réordonne la barre de nav, refait le dashboard
Trois demandes distinctes de l'utilisateur, regroupées car elles touchent
toutes à la navigation d'un jeu :

1. Fil d'Ariane retiré (devenu redondant avec la barre de navigation du
   jeu ajoutée au commit précédent) : bloc breadcrumb_wrap retiré de
   base.html, et son override ({% block breadcrumb %}) retiré des 9
   templates qui le définissaient encore. .breadcrumbBar (CSS) retiré,
   y compris des règles flex:0 0 auto de body.objectEditBody/builderBody.

2. Liens de .gameNavBar centrés (justify-content:center).

3. "Jouer" déplacé en dernier lien (c'est une action à part — ouvre
   l'aperçu jouable dans un nouvel onglet — pas un éditeur de plus comme
   les 4 autres).

4. game_dashboard.html devient un vrai tableau de bord : une grille de
   cartes (Écrans/Objets/Éléments de jeu/Variables), chacune listant les
   entrées existantes avec un accès direct (clic = éditeur concerné) et
   un lien "Gérer" vers la page dédiée pour créer/réorganiser. Remplace
   l'ancien panneau "Créer" (redondant avec la barre de navigation
   persistante) et la simple table "Objets définis". routes/games/
   game_dashboard.py alimente maintenant aussi screen_list, element_types
   (+ usage) et variables, en réutilisant list_screens/
   list_element_types/element_type_usage_count/list_global_variables déjà
   utilisés ailleurs.

Vérifié en rendant toutes les pages concernées via le client de test
Flask : barre de nav présente partout où un `game` est dans le contexte
(absente sur l'accueil), fil d'Ariane absent partout, ordre des liens
avec "Jouer" en dernier.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 10:04:09 +02:00
william 2bb0c253f9 Fix object-form breaking on repeat pjax visits, and stray autofill in game rename field
object_form.js declared top-level const bindings, which pjax replays verbatim on every visit — the second visit threw "already declared" and silently broke "Ajouter un champ"/"Créer l'objet". Wrapped it in an IIFE. Also renamed the generic name="name" rename-game field to name="game_name" with autocomplete off, since browsers were autofilling it with unrelated previously-typed values.
2026-08-24 09:21:19 +02:00
williamandwilliam 3f4ebc4527 first commit
Build and deploy / build-and-push (push) Successful in 17s
Build and deploy / deploy (push) Successful in 10s
2026-08-21 16:23:49 +02:00