Design validé en brainstorming : coquille account_shell (sidebar + offcanvas), routage /compte/* (une page par section), 3 niveaux d'accès avec stub d'abonnement, section Compte (email avec re-vérification, mot de passe, suppression via modale). Refs #73 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6.9 KiB
Espace « Mon compte » — restructuration et section Compte
Date : 2026-06-24 Statut : design validé Issue : #73 (comptes premium — abonnement mensuel à prix libre)
Contexte
La page /compte actuelle (src/pages/compte.py) est une page unique étroite
qui affiche l'email, un formulaire de changement de mot de passe (POST vers
/auth/change-password) et un bouton de déconnexion. L'authentification passe
par un Blueprint Flask /auth/* (src/auth/routes.py) avec des formulaires
HTML côté serveur ; les pages sont des register_page Dash.
L'objectif est de transformer /compte en un espace à plusieurs sections
(jusqu'à 6 à terme) avec une navigation latérale, et d'implémenter
intégralement la première section, Compte (/compte/admin).
Sections cibles
| Section | URL | Statut | Accès |
|---|---|---|---|
| Compte | /compte/admin |
ce lot | compte |
| Abonnement | /compte/abonnement |
coquille | compte |
| Mes archives | /compte/archives |
futur | abonnement |
| Mes filtres | /compte/filtres |
futur | abonnement |
| Mon SIRET | /compte/siret |
futur | abonnement |
Niveaux d'accès
Trois niveaux :
- Visiteur sans compte → redirigé vers
/connexion?next=<path>. - Compte sans abonnement valide → accès à Compte et Abonnement
uniquement ; toute page gated redirige vers
/compte/abonnement. - Compte avec abonnement valide → accès à toutes les sections.
L'abonnement n'est pas encore implémenté : on introduit une abstraction
current_user_has_subscription() -> bool qui renvoie False pour l'instant.
C'est le seul point à brancher lorsque la facturation arrivera.
Architecture
Routage (une page par section)
- Chaque section est un
register_pagedistinct sous/compte/*, fidèle à la convention « une page = un fichier » du projet. - La page
/compteactuelle devient une redirection vers/compte/admin(renvoiedcc.Location(href="/compte/admin")). - Ce lot crée
/compte/admin(section Compte) et la coquille/compte/abonnement(page enregistrée minimale, contenu de vente à venir). Les sections gated (archives,filtres,siret) ne sont pas créées dans ce lot.
Coquille partagée
Nouveau module src/pages/_compte_shell.py exposant :
-
account_shell(active: str, contenu) -> ComponentConstruit la mise en page commune :- Sidebar verticale (desktop) listant les sections accessibles à
l'utilisateur courant ; l'entrée
activeest surlignée. - Bouton « ☰ Sections » +
dbc.Offcanvas(mobile) reprenant la même liste. - Insère
contenudans la zone principale. - Sections gated masquées tant que
current_user_has_subscription()est faux (Compte + Abonnement seules visibles). La vente des fonctionnalités se fera dans le contenu de la section Abonnement, pas via des entrées verrouillées. - Construit avec Dash Bootstrap Components (
dbc.Row/dbc.Col,dbc.Nav/dbc.NavLink,dbc.Offcanvas).
- Sidebar verticale (desktop) listant les sections accessibles à
l'utilisateur courant ; l'entrée
-
account_guard(require_subscription: bool) -> Component | NoneAppelé en tête de chaquelayout():- non authentifié →
dcc.Location(href="/connexion?next=<path>") - authentifié,
require_subscriptionet pas d'abonnement →dcc.Location(href="/compte/abonnement") - sinon →
None(la page se rend normalement).
- non authentifié →
La définition des sections (libellé, URL, icône, require_subscription) est
centralisée dans une structure unique dans _compte_shell.py, pour que sidebar,
offcanvas et gardes restent cohérents et que l'ajout d'une section future tienne
en une ligne.
Section Compte (/compte/admin)
Agencement : sections empilées avec séparateurs, dans account_shell.
- Adresse email — affiche l'email actuel, champ « nouvelle adresse »,
bouton « Mettre à jour l'email » →
POST /auth/change-email. - Mot de passe — formulaire existant (mot de passe actuel + nouveau +
confirmation), inchangé →
POST /auth/change-password. Sa cible de redirection passe de/compteà/compte/admin. - Zone danger — encadré rouge, bouton « Supprimer mon compte » qui ouvre
une modale
dbc.Modalde confirmation demandant la re-saisie du mot de passe →POST /auth/delete-account.
Le bouton Déconnexion est conservé (POST /auth/logout).
Les messages de succès/erreur sont passés en query string et rendus en
dbc.Alert, sur le modèle actuel ; ERROR_MESSAGES est étendu.
Changement d'email avec re-vérification
Le changement d'email ne prend pas effet immédiatement : la nouvelle adresse doit être confirmée par email, par cohérence avec l'inscription. L'ancienne adresse reste active tant que la nouvelle n'est pas vérifiée (évite qu'une faute de frappe verrouille le compte).
Flux :
POST /auth/change-email(@login_required) :- valide la nouvelle adresse (
validate_email, normalisée en minuscules) ; - vérifie l'unicité (
get_user_by_email→ erreuremail_taken) ; - enregistre l'adresse en attente sur l'utilisateur et envoie un lien de vérification à cette nouvelle adresse (réutilise le mécanisme de jetons de vérification existant) ;
- redirige
/compte/admin?email_pending=1.
- valide la nouvelle adresse (
- Clic sur le lien → la nouvelle adresse devient l'email du compte et le
pending_emailest effacé, puis redirection vers/compte/admin?email_changed=1.
Implications stockage : ajout d'un champ pending_email à la table users
(migration de schéma) et nouvelle fonction DB update_email(user_id, email).
Le détail exact du jeton (réutilisation de create_email_verification_token vs
table dédiée) est laissé au plan d'implémentation.
Suppression de compte
POST /auth/delete-account (@login_required) :
- vérifie le mot de passe courant (
check_password_hash) → sinon?error=invalid_current_password; - purge les jetons (
delete_email_verification_tokens_for_user,delete_password_reset_tokens_for_user) puisdelete_user(current_user.id); logout_user();- redirige vers
/?account_deleted=1.
Tests
- Accès (Selenium) : les trois niveaux, avec le stub d'abonnement forcé à
True/False; redirection des non-authentifiés ; redirection des non-abonnés sur une page gated ; présence/masquage des entrées de sidebar. - Navigation (Selenium) :
/compte→/compte/admin; surlignage de la section active ; ouverture de l'offcanvas mobile. - Routes :
change-email: succès (passage en attente), email déjà pris, email invalide.delete-account: mauvais mot de passe (refus), succès (compte supprimé + déconnexion).
Hors périmètre
- Contenu réel de la section Abonnement (perks, tarifs, paiement).
- Sections Archives, Filtres, Mon SIRET.
- Implémentation réelle de la facturation derrière
current_user_has_subscription().