Zum Hauptinhalt springen

Gestion des utilisateurs

La gestion des utilisateurs est au coeur de l'administration de BeePass. C'est ici que vous pouvez verifier l'etat d'un compte, investiguer un probleme de connexion, ajuster les permissions d'un eleveur ou reagir a un comportement abusif.

Cette section couvre quatre volets : la liste avec recherche et filtres, la fiche detaillee d'un utilisateur, la validation des demandes de roles proteges et la gestion des sessions.

Liste des utilisateurs

Le tableau principal (/backoffice/users) offre une vue d'ensemble de tous les comptes inscrits sur la plateforme. Il est concu pour repondre rapidement a des questions comme "Quel plan utilise cet eleveur ?", "Quand s'est-il connecte pour la derniere fois ?" ou "Son compte est-il actif ?".

Colonnes affichees :

ColonneDescription
AvatarPhoto de profil ou initiales
Nomprofiles.firstname + profiles.lastname
EmailAdresse email (depuis auth.users via getUserById(), pas depuis profiles)
Code eleveurIdentifiant unique (profiles.breeder_code, ex : FR-44-001)
RolesBadges colores pour chaque role attribue (JSONB profiles.roles)
PlanAbonnement actif : profiles.subscription_plan (discovery, breeder, selector, program)
Statut abonnementprofiles.subscription_status (active, trialing, past_due, canceled, unpaid, incomplete)
InscriptionDate de creation du compte (profiles.created_at)
Derniere connexionDate du dernier login reussi
StatutActif, banni (profiles.is_banned) ou en attente de validation

Recherche et filtres

La barre de recherche permet de filtrer par nom, email ou code eleveur avec un debounce (leger delai avant d'executer la recherche, pour eviter de surcharger le serveur a chaque frappe). Les filtres avances sont combinables :

FiltreValeurs
Roleeleveur, testeur, groupe_selection, research_center, admin, super_admin
PlanDiscovery, Breeder, Selector, Selection Group
StatutActif, Banni, En attente

Actions

ActionDescriptionRestriction
Voir le detailOuvre la fiche complete /backoffice/users/[id]admin
ModifierEdition du profil et des rolesadmin
Bannir / DebannirSuspend ou reactive l'acces au compteadmin
SupprimerSuppression definitive avec protocole FK safetysuper_admin uniquement
Creer un utilisateurCreation avec mot de passe aleatoire crypto.randomUUID()super_admin pour roles admin
Export CSVTelechargement du tableau filtre au format CSVadmin

API Routes

RouteMethodeDescription
/api/admin/usersGETTous les profils + emails auth.users, pagination, filtres, recherche
/api/admin/usersPOSTCreation utilisateur (super_admin requis pour roles admin)
/api/admin/users/[id]GETDetail utilisateur enrichi
/api/admin/users/[id]PUTModification profil et roles
/api/admin/users/[id]DELETESuppression FK safety (super_admin requis)
/api/admin/users/[id]/banPOSTBannir/debannir (action: ban ou unban)
Suppression de compte

Supprimer un utilisateur n'est pas un simple DELETE en base de donnees. Un eleveur peut avoir des reines, des evaluations, des messages de chat, des tickets de support, des fichiers stockes... Tout est lie par des cles etrangeres (FK). Supprimer brutalement le compte casserait ces liens et provoquerait des erreurs en cascade.

C'est pourquoi la suppression suit un protocole strict ou chaque etape est executee dans un ordre precis :

1. Audit log -> event_type = 'account_deletion'
2. Anonymiser les donnees genetiques :
- queens_f0.owner_id + claimed_by -> NULL
- queens_f1.owner_id -> NULL
- queen_evaluations.owner_id -> NULL
- queen_lifecycle_events -> DELETE
- site_settings.updated_by -> NULL
3. Re-claim orphaned queens via claim_unclaimed_queens()
4. Supprimer donnees personnelles :
- notifications, known_devices, verification_codes, profiles -> DELETE
5. Detacher storage : cleanup_storage_owner(user_id) via RPC SECURITY DEFINER
6. deleteUser() -> DELETE FROM auth.users
-> FK CASCADE : chat_*, calendar_*, ticket_attachments
-> FK SET NULL : queens, evaluations (deja nettoyees)

Ne jamais inserer ou supprimer directement dans auth.users via SQL, sous peine de casser listUsers().

Detail utilisateur

La fiche detaillee (/backoffice/users/[id]) rassemble toutes les informations d'un compte en un seul endroit. Elle est organisee en sections avec un header card affichant l'avatar, les badges de roles et les dates cles. C'est la page de reference pour investiguer un probleme lie a un utilisateur specifique.

Informations du profil

ChampColonne DBNotes
Nom completprofiles.firstname + profiles.lastname--
Emailauth.users.email via getUserById()Jamais depuis profiles
Telephoneprofiles.phone--
Adresseprofiles.address, profiles.city, profiles.country--
Code postalprofiles.zip_code--
Code eleveurprofiles.breeder_codeIdentifiant unique par eleveur
Races travailleesprofiles.races--
Site webprofiles.website--
Reseaux sociauxprofiles.facebook, profiles.instagram, profiles.youtube, profiles.tiktok, profiles.x_twitter, profiles.linkedinIcones Simple Icons colorees
Avatarprofiles.avatarStocke dans bucket Supabase Storage
Email et profils

Le champ email n'existe pas dans la table profiles. Il est toujours recupere separement via supabase.auth.admin.getUserById(). Pourquoi cette separation ? Parce que Supabase gere les emails dans sa propre table auth.users, distincte de la table profiles qui contient les informations metier. Ne jamais tenter un SELECT email FROM profiles -- cela casserait silencieusement la requete PostgREST (la requete retourne null au lieu de generer une erreur explicite).

Schema DB profiles

ColonneTypeDescription
idUUID PKFK vers auth.users(id) ON DELETE CASCADE
firstnameTEXTPrenom
lastnameTEXTNom de famille
phoneTEXTTelephone
addressTEXTAdresse postale
cityTEXTVille
countryTEXTPays
zip_codeTEXTCode postal
breeder_codeTEXTCode eleveur unique
racesTEXTRaces d'abeilles travaillees
rolesJSONBTableau de roles (ex : ["eleveur", "testeur"])
requested_rolesJSONBRoles en attente de validation admin
is_bannedBOOLEANCompte banni (defaut false)
avatarTEXTChemin avatar Storage
subscription_planTEXT NOT NULLPlan actif : discovery, breeder, selector, program (defaut discovery)
subscription_statusTEXT NOT NULLStatut Stripe : active, trialing, past_due, canceled, unpaid, incomplete
stripe_customer_idTEXT UNIQUEStripe Customer ID (cus_...)
subscription_stripe_idTEXTStripe Subscription ID (sub_...)
subscription_current_period_endTIMESTAMPTZFin de la periode de facturation
subscription_trial_endTIMESTAMPTZFin de la periode d'essai
totp_secretTEXTSecret TOTP Base32 (NULL si non configure)
totp_enabledBOOLEAN NOT NULLTOTP 2FA active (defaut false)
totp_enabled_atTIMESTAMPTZDate d'activation TOTP
notification_prefsJSONBPreferences de notifications admin (toggles par type)
created_atTIMESTAMPTZDate de creation du compte
updated_atTIMESTAMPTZDerniere modification (trigger auto)

Gestion des roles

Les roles definissent ce qu'un utilisateur peut faire sur la plateforme. Certains roles sont attribues automatiquement, d'autres necessitent une validation manuelle -- ce systeme a deux niveaux existe pour proteger les fonctionnalites sensibles (acces aux donnees de groupe, outils de recherche) tout en simplifiant l'inscription pour les utilisateurs standards.

L'administrateur peut ajouter ou retirer des roles depuis cette section. Les roles sont stockes dans le champ JSONB profiles.roles.

TypeRolesAttributionValidation
Publiceleveur, testeurAutomatique a l'inscription ou par l'adminAucune
Protegegroupe_selection, research_centerDemande par l'utilisateurValidation admin requise
Adminadmin, super_adminAttribution manuelleSuper-admin uniquement

Chaque changement de role :

  • Declenche un evenement role_change dans le journal d'audit
  • Est valide cote base de donnees par le trigger validate_user_roles()
  • Est notifie a l'utilisateur par email (Brevo) + notification in-app

Le trigger validate_user_roles() empeche les combinaisons invalides et protege les roles admin contre les attributions non autorisees. La fonction get_protected_roles() renvoie la liste des roles proteges incluant admin/super_admin.

Abonnement

Cette section affiche l'etat actuel de l'abonnement Stripe de l'utilisateur. Elle est particulierement utile pour diagnostiquer les problemes de facturation ("Mon plan n'est pas actif" = verifier subscription_status).

InformationColonneDescription
Plan actifsubscription_planNom du plan Stripe en cours
Statutsubscription_statusactive, trialing, past_due, canceled...
Periode finsubscription_current_period_endProchaine date de facturation
Fin essaisubscription_trial_endDate de fin d'essai gratuit
Stripe Customer IDstripe_customer_idLien direct vers le client dans le Stripe Dashboard

Sessions actives

Pouvoir voir et revoquer les sessions d'un utilisateur est essentiel en cas de compromission de compte. Si un eleveur signale un acces suspect, l'admin peut immediatement revoquer toutes les sessions pour forcer une deconnexion globale.

Liste des sessions en cours pour cet utilisateur, geree par les fonctions SQL SECURITY DEFINER (fonctions qui s'executent avec des privileges eleves, permettant d'acceder a la table auth.sessions normalement protegee) :

Fonction RPCDescription
get_user_sessions(user_id)Liste les sessions actives depuis auth.sessions
revoke_user_session(session_id)Supprime une session (invalide le refresh token)
revoke_all_user_sessions(user_id)Revoque toutes les sessions de l'utilisateur

Pour chaque session :

  • Adresse IP source
  • User agent (navigateur / OS)
  • Date de derniere activite (heartbeat toutes les 5 minutes via getUser() dans AuthContext)
  • Bouton Revoquer pour forcer la deconnexion d'un appareil specifique

La revocation genere un evenement session_revoked dans le journal d'audit.

MFA (Authentification multi-facteur)

L'authentification multi-facteur ajoute une couche de securite au-dela du mot de passe. Meme si le mot de passe d'un utilisateur est compromis, l'attaquant aurait encore besoin du deuxieme facteur (code email ou code TOTP) pour acceder au compte.

BeePass supporte deux niveaux de MFA :

TypeCibleObligatoireDesactivation
MFA emailTous les utilisateursSur nouvel appareil--
TOTP 2FAEleveurs (optionnel)NonAutorisee
TOTP 2FAAdminsOuiInterdite (403)

MFA Email : Lors d'une connexion depuis un appareil inconnu (identifie par un fingerprint base sur le Canvas et le User Agent), un code a 6 chiffres est envoye par email (Brevo). Le code est genere via crypto.randomInt() (generateur cryptographiquement sur), expire en 10 minutes, avec 3 tentatives maximum. La verification est atomique via la RPC increment_verification_attempts (evite les conditions de concurrence si plusieurs requetes arrivent simultanement).

TOTP Eleveur : Activation volontaire depuis SecurityTab. 4 routes API /api/auth/totp/{setup,verify,validate,disable}. Un cookie beepass-totp-verified est emis apres validation.

TOTP Admin : Obligatoire. Pre-auth cookie (10 min TTL) puis validation TOTP avant emission du cookie HMAC admin. 8 backup codes SHA-256 avec salt (table admin_backup_codes). Rate limit : 5 tentatives / 15 min.

Journal d'audit utilisateur

Historique des dernieres actions de securite pour ce compte : connexions, changements de mot de passe, activations MFA, etc. Ce journal est un extrait filtre du journal d'audit global, centre sur un seul utilisateur. Il permet de reconstituer rapidement la chronologie d'un incident.

Validation des roles proteges

Certains roles donnent acces a des fonctionnalites avancees (donnees de groupe, outils de recherche) qui necessitent une verification humaine. Un eleveur qui demande le role groupe_selection doit etre un vrai selectionneur participant a un programme -- pas simplement un curieux. C'est pourquoi ces roles passent par une validation manuelle.

Les roles groupe_selection et research_center necessitent une approbation manuelle de l'administrateur. La page /backoffice/role-validation liste les demandes en attente.

Flux de validation

1. L'utilisateur demande un role protege depuis son profil
|
2. La demande est stockee dans profiles.requested_roles (JSONB)
|
3. Une notification synthetique apparait dans la cloche admin
|
4. L'admin consulte le profil du demandeur (eleveur, code, historique)
|
5. Approbation ou rejet (avec message optionnel)
|
6. L'utilisateur est notifie par email Brevo + notification in-app

Actions disponibles

ActionEffetAPI
ApprouverLe role est ajoute au JSONB profiles.roles + evenement audit role_changePOST /api/admin/roles
RejeterLa demande est archivee avec le motif de rejetPOST /api/admin/roles
Roles publics

Les roles eleveur et testeur ne necessitent aucune validation. Ils sont attribues automatiquement a l'inscription ou peuvent etre ajoutes par un admin depuis la fiche utilisateur.

Rate limiting

Pour se proteger contre les attaques par force brute (essayer des milliers de mots de passe) et les abus, les operations d'authentification sont protegees par des limites de debit via Upstash Redis :

OperationLimiteFenetre
Login eleveur10 tentatives15 min
Login admin5 tentatives15 min
TOTP admin5 tentatives15 min
TOTP eleveur5 tentatives15 min
Inscription3 inscriptions1 heure
Reset mot de passe3 demandes1 heure
Envoi code MFA5 envois10 min
Verification code10 verifications1 min
Creation cle API10 creations1 heure
Renvoi confirmation3 renvois1 heure
Changement mot de passe admin3 tentatives15 min
Suppression utilisateur admin5 suppressions1 heure
Bannissement admin10 actions15 min
Approbation role admin10 actions1 heure
Modification utilisateur admin30 modifications15 min
Modification plan admin10 modifications1 heure

Password reset personnalise

Plutot que d'utiliser le flux de reinitialisation par defaut de Supabase (qui offre peu de controle), BeePass utilise un systeme personnalise base sur HMAC-SHA256 (une methode cryptographique qui garantit l'integrite et l'authenticite du token). Ce flux permet un controle total sur les emails envoyes, le rate limiting et la revocation des sessions apres changement.

1. POST /api/auth/password-reset (rate limit 3/h)
|
2. Generation token v2 : userId:expiry:nonce:signature (HMAC-SHA256)
|
3. Email Brevo avec lien contenant le token
|
4. PUT /api/auth/update-password (timingSafeEqual + backend regex validation)
|
5. Revocation de toutes les sessions (revoke_all_user_sessions)
|
6. Nettoyage token de l'URL

Le timing de reponse est normalise (anti-enumeration) : qu'un email existe ou non, le temps de reponse est identique. Cela empeche un attaquant de determiner si un email est inscrit sur la plateforme en mesurant le temps de reponse.

Confirmation email

Depuis AUTH v3.0.0, l'inscription par email utilise un flow de confirmation HMAC personnalise (meme pattern que le password reset) au lieu du flow natif Supabase :

Flux

1. POST /api/auth/register (rate limit 3/h)
|
2. Generation token HMAC : userId:expiry:nonce:signature
|
3. Email Brevo de confirmation avec lien
|
4. GET /api/auth/confirm-email (verification HMAC + activation compte)
|
5. Redirect vers /auth/login avec message de succes

Page confirm-pending

Apres l'inscription, l'utilisateur est redirige vers /auth/confirm-pending qui affiche un message "Verifiez votre email". Le middleware bloque l'acces au dashboard tant que email_confirmed_at est null.

Renvoi

L'endpoint POST /api/auth/resend-confirm permet de renvoyer l'email de confirmation (rate limit 3/h). Le nonce est regenere a chaque renvoi.


Voir aussi : Journal d'audit | Finances & Abonnements | Vue d'ensemble