Le rôle "admin" contournait entièrement l'isolation par projet
(core/auth_guard.py) : il pouvait ouvrir/modifier/supprimer le jeu de
n'importe quel autre compte en connaissant son slug, et la page d'accueil
listait sans filtrage tous les projets de tous les comptes.
- La propriété d'un projet se vérifie désormais sur le segment
"propriétaire" du slug (id du compte), pour tous les rôles y compris
admin — un slug "à plat" (sans compte associé) reste réservé à
l'admin, comportement historique conservé pour ce cas précis.
- routes/games/index.py ne liste plus que les projets du compte connecté.
- Le dossier propriétaire d'un projet est maintenant l'id numérique du
compte, plus jamais son email slugifié (visible en clair dans chaque
URL auparavant) — script de migration fourni et déjà exécuté sur les
données existantes.
- Changer d'email ne renomme plus aucun dossier (n'en dépend plus).
- Deux nouveaux tests de régression, fixtures corrigées en conséquence.
- README réécrit pour refléter l'état actuel du produit (jeu 2D
uniquement, plus de traces de l'ancien éditeur "document").
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>
Depuis /profile :
- "Codes de récupération 2FA" : régénère les 10 codes (invalide les 10
précédents d'un coup, voir auth.generate_recovery_codes) et les affiche
une seule fois via le même modal qu'à l'inscription (session flash,
core/recovery_codes_flash.py) — mot de passe actuel requis.
- "Adresse email" : change l'adresse (mêmes règles qu'à l'inscription —
format valide, unicité — voir auth/email_validation.py, désormais
partagé avec create_user.py au lieu d'être dupliqué). Pour un compte
"user", le dossier de son unique projet porte le nom de son adresse
(project_slug = slugify(email)) : il est renommé pour suivre le
changement (db/games/move_game.py, même logique d'unicité par suffixe
que create_game()), sans quoi project_slug ne correspondrait plus à
aucun dossier réel. Un "admin" n'a pas de project_slug dédié : rien
n'est renommé pour ce rôle.
18 nouveaux tests (tests/test_profile.py) : mauvais mot de passe refusé
pour les deux actions, mauvais format/email déjà pris refusés, dossier
bien renommé et project_slug mis à jour, connexion possible avec la
nouvelle adresse, anciens codes de récupération bien invalidés après
régénération, modal jamais réaffiché deux fois.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Le nom affiché dans la barre de navigation (base.html) devient un lien
vers /profile : informations du compte (email en lecture seule, nom/
prénom modifiables), changement de mot de passe (mot de passe actuel
requis + mêmes règles de force qu'à l'inscription/la réinitialisation),
et une section "danger" pour demander la suppression du compte.
La suppression exige le mot de passe actuel ET la saisie exacte de
"SUPPRIMER" (deux confirmations distinctes pour une action irréversible)
— routes/auth/profile.py. Pour un compte "user" (limité à un seul projet,
créé automatiquement et impossible à supprimer autrement, voir
core/auth_guard.py), supprimer le compte supprime aussi son unique projet
sur le disque, faute de quoi il resterait orphelin sans plus aucun
propriétaire. Un compte "admin" peut posséder plusieurs jeux qui ne lui
sont pas dédiés de la même façon : ses projets ne sont jamais touchés.
L'unique compte administrateur ne peut pas être supprimé (auth/
count_admins.py) — le supprimer bloquerait la création d'un nouveau
compte admin (réservée au tout premier compte jamais créé, base vide).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>