Supprime le type d'écran "document" et recentre le produit sur le jeu 2D
Build and deploy / test-python (push) Successful in 9m41s
Build and deploy / test-js (push) Successful in 1m0s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped

Le document de cadrage produit cible des formateurs non techniques créant
des serious games/quiz gamifiés — l'éditeur générique "document" (blocs de
logique en nœuds, timeline d'animation, définitions d'objets/relations,
templates réutilisables) est une complexité hors cible que l'effort
d'ingénierie récent avait déjà abandonnée au profit du jeu_2d.

- Onboarding : ne garde que le parcours "RPG" (jeu_2d), retire
  Quiz/Embranchement/Créer mon jeu de A à Z (tous document-only)
- Suppression en bloc des modules exclusifs au document : routes/elements,
  routes/element_types, routes/objects, routes/legacy_actions,
  screens/elements, screens/element_types, screens/widgets,
  screens/legacy_actions, le rendu render_element_html.py et son cluster,
  templates/screen_edit.html, templates/game_dashboard.html,
  flow-editor.js/tabs-and-blocks.js/animation-timeline.js
- Dashboard toujours simplifié (un seul mode possible désormais)
- Tests document-only supprimés, tests de logique partagée (flow,
  événements personnalisés, animations) retargetés sur des écrans jeu_2d
- Aucune régression jeu_2d : 299 tests passent

Carte d'onboarding retravaillée : argumentaire RH non technique (liste à
coche, badge "Compatible LMS"), taille et interaction de retournement
ajustées.
This commit is contained in:
william
2026-09-04 20:56:32 +02:00
parent 00f7191a8b
commit 50835a18e2
221 changed files with 1239 additions and 12245 deletions
+4 -89
View File
@@ -15,77 +15,8 @@ def ensure_schema(slug):
is_template INTEGER NOT NULL DEFAULT 0,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS _element_types (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
icon TEXT NOT NULL DEFAULT '🧩',
default_widget TEXT NOT NULL DEFAULT 'conteneur',
default_content TEXT NOT NULL DEFAULT '',
default_attributes TEXT NOT NULL DEFAULT '{}',
default_style TEXT NOT NULL DEFAULT '{}',
template_screen_id INTEGER REFERENCES _screens(id),
bound_definition_id INTEGER,
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS _screen_elements (
id INTEGER PRIMARY KEY AUTOINCREMENT,
screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE,
parent_id INTEGER REFERENCES _screen_elements(id) ON DELETE CASCADE,
widget TEXT NOT NULL DEFAULT 'conteneur',
element_type_id INTEGER REFERENCES _element_types(id),
name TEXT,
content TEXT NOT NULL DEFAULT '',
attributes TEXT NOT NULL DEFAULT '{}',
x REAL NOT NULL DEFAULT 10,
y REAL NOT NULL DEFAULT 10,
width REAL NOT NULL DEFAULT 20,
height REAL NOT NULL DEFAULT 10,
z_index INTEGER NOT NULL DEFAULT 1,
style TEXT NOT NULL DEFAULT '{}',
created_at TEXT DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS _actions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
element_id INTEGER NOT NULL REFERENCES _screen_elements(id) ON DELETE CASCADE,
trigger_event TEXT NOT NULL,
action_type TEXT NOT NULL,
target_screen_id INTEGER REFERENCES _screens(id),
target_element_id INTEGER REFERENCES _screen_elements(id),
element_property TEXT,
element_value TEXT,
target_definition_id INTEGER,
target_row_id INTEGER,
target_field TEXT,
data_operation TEXT,
data_value TEXT
);
"""
)
cols = {r["name"] for r in conn.execute("PRAGMA table_info(_screen_elements)").fetchall()}
if "widget" not in cols:
conn.execute("ALTER TABLE _screen_elements ADD COLUMN widget TEXT NOT NULL DEFAULT 'conteneur'")
if "attributes" not in cols:
conn.execute("ALTER TABLE _screen_elements ADD COLUMN attributes TEXT NOT NULL DEFAULT '{}'")
if "parent_id" not in cols:
conn.execute("ALTER TABLE _screen_elements ADD COLUMN parent_id INTEGER REFERENCES _screen_elements(id) ON DELETE CASCADE")
if "name" not in cols:
conn.execute("ALTER TABLE _screen_elements ADD COLUMN name TEXT")
type_cols = {r["name"] for r in conn.execute("PRAGMA table_info(_element_types)").fetchall()}
if "default_widget" not in type_cols:
conn.execute("ALTER TABLE _element_types ADD COLUMN default_widget TEXT NOT NULL DEFAULT 'conteneur'")
conn.execute("ALTER TABLE _element_types ADD COLUMN default_content TEXT NOT NULL DEFAULT ''")
conn.execute("ALTER TABLE _element_types ADD COLUMN default_attributes TEXT NOT NULL DEFAULT '{}'")
if "template_screen_id" not in type_cols:
# Un élément de jeu n'est plus un simple widget isolé : c'est un
# conteneur avec un vrai arbre d'éléments imbriqués à l'intérieur,
# construit exactement comme le contenu de n'importe quel conteneur
# sur un écran — ce petit arbre vit dans un écran-modèle CACHÉ
# (voir "is_template" ci-dessous), pointé par cette colonne.
conn.execute("ALTER TABLE _element_types ADD COLUMN template_screen_id INTEGER REFERENCES _screens(id)")
if "bound_definition_id" not in type_cols:
# "Objet lié" optionnel — comme pour le Répéteur de données, rend
# {{nom_du_champ}} disponible dans tout l'arbre de ce modèle.
conn.execute("ALTER TABLE _element_types ADD COLUMN bound_definition_id INTEGER")
screen_cols = {r["name"] for r in conn.execute("PRAGMA table_info(_screens)").fetchall()}
if "is_template" not in screen_cols:
# Un écran-modèle héberge le contenu d'un élément de jeu réutilisable
@@ -124,26 +55,10 @@ def ensure_schema(slug):
conn.execute("ALTER TABLE _screens ADD COLUMN scene_width INTEGER NOT NULL DEFAULT 960")
conn.execute("ALTER TABLE _screens ADD COLUMN scene_height INTEGER NOT NULL DEFAULT 540")
if "kind" not in screen_cols:
# Fusion des moteurs — "document" (écran %) ou "jeu_2d" (scène
# pixels) devient une propriété PAR ÉCRAN plutôt que par projet
# (voir db/games/get_game_type.py, désormais lu UNIQUEMENT ici,
# pour la rétro-compatibilité) : un même jeu peut mélanger les
# deux types d'écran librement (voir routes/screens/screen_edit.py,
# qui dispatche maintenant sur screen["kind"]).
conn.execute("ALTER TABLE _screens ADD COLUMN kind TEXT NOT NULL DEFAULT 'document'")
# Un seul moteur d'écran désormais : "jeu_2d" (scène pixels — voir
# db/games/get_game_type.py, conservé pour la rétro-compatibilité
# d'un jeu créé avant l'existence de cette colonne).
conn.execute("ALTER TABLE _screens ADD COLUMN kind TEXT NOT NULL DEFAULT 'jeu_2d'")
conn.execute("UPDATE _screens SET kind = ?", (db.get_game_type(slug),))
action_cols = {r["name"] for r in conn.execute("PRAGMA table_info(_actions)").fetchall()}
for col_name, col_def in [
("target_element_id", "INTEGER REFERENCES _screen_elements(id)"),
("element_property", "TEXT"),
("element_value", "TEXT"),
("target_definition_id", "INTEGER"),
("target_row_id", "INTEGER"),
("target_field", "TEXT"),
("data_operation", "TEXT"),
("data_value", "TEXT"),
]:
if col_name not in action_cols:
conn.execute(f"ALTER TABLE _actions ADD COLUMN {col_name} {col_def}")
conn.commit()
conn.close()