Story CP-015 : Améliorations UI de la Gestion des Utilisateurs¶
Module : control-plane Slice : Slice 3 from architecture (split from CP-003) Brand context : [BOTH] Papillon HR Suite + ALTARYS ENTERPRISE HR Suite Priority : 3 Depends on : CP-003 Estimated complexity : S
Objectif¶
Améliorer la page de Gestion des Utilisateurs avec l'affichage du statut d'invitation (actif/expiré avec renvoi) et l'UX de détection multi-tenant pendant le flux d'invitation. Ce sont des améliorations axées frontend qui s'appuient sur la liste d'utilisateurs et le flux d'invitation établis dans CP-003.
Périmètre Backend¶
Entités & Records¶
Aucune nouvelle entité. Cette story consomme les entités User, UserTenantMembership et autres entités connexes de CP-003.
Couche Service¶
UserService.java (ajouts) :
- resendInvitation(UUID userId, UUID tenantId) → void — Renvoie l'email d'invitation pour les invitations expirées :
1. Vérifier que l'utilisateur a le statut=INVITED et une adhésion dans le tenant
2. Appeler KeycloakAdminService.sendPasswordSetupEmail(email)
3. Publier l'événement UserInvitationResent
- checkExistingUser(String email) → Optional<UserExistsResponse> — Retourne les informations d'existence d'un utilisateur pour la détection multi-tenant :
- Si l'email existe sur la plateforme : retourne {exists: true, firstName, lastName} (pas de détails tenant — confidentialité)
- Sinon : retourne {exists: false}
DTOs (ajouts) :
public record UserExistsResponse(boolean exists, @Nullable String firstName, @Nullable String lastName) {}
Endpoints API¶
| Méthode | Chemin | Corps de requête | Réponse | Auth |
|---|---|---|---|---|
| POST | /api/v1/users/{id}/resend-invite | — | 204 | ROLE_DG, ROLE_RH_MANAGER |
| GET | /api/v1/users/check-email?email= | — | UserExistsResponse | ROLE_DG, ROLE_RH_MANAGER |
Règles de validation¶
- Renvoi d'invitation : l'utilisateur doit avoir le statut=INVITED et être membre du tenant courant
- Vérification email : format email valide, max 254 caractères
Périmètre Frontend¶
Composants¶
Utilise UserManagementPage.tsx et InviteUserSheet.tsx de CP-003. Cette story ajoute des comportements à ces composants.
Améliorations UI¶
Liste d'utilisateurs — affichage du statut d'invitation (AC-024) :
Chaque carte/ligne d'utilisateur affiche le statut :
| Statut Utilisateur | Visuel (Carte Mobile) | Visuel (Ligne Bureau) |
|---|---|---|
| ACTIVE | Point vert ● + "Actif" |
Point vert ● + "Actif" |
| INVITED (valide) | Point bleu ● + "Invitation en cours" |
Point bleu ● + "Invitation en cours" |
| INVITED (expiré) | Point orange ● + lien "Expiré — Renvoyer →" |
Point orange ● + lien "Expiré — Renvoyer →" |
| DISABLED | Point gris ● + "Désactivé" |
Point gris ● + "Désactivé" |
- Expiration de l'invitation : Les liens d'invitation expirent après 72 heures (configurable). L'expiration est déterminée en comparant
created_date + 72havec l'heure courante. - Action de renvoi : Appuyer sur "Renvoyer →" appelle
POST /api/v1/users/{id}/resend-inviteet affiche un toast : "Invitation renvoyée à {email}"
Flux d'invitation — détection multi-tenant (AC-025) :
Dans InviteUserSheet.tsx, après que l'utilisateur saisit un email et que le champ perd le focus (onBlur) :
1. Appeler GET /api/v1/users/check-email?email={email}
2. Si exists: true, afficher une bannière d'information sous le champ email :
- "Cet utilisateur existe déjà sur la plateforme. Il sera ajouté à votre entreprise avec le rôle sélectionné."
- Style : fond bleu info, icône info, texte en français
3. Si exists: false, aucune bannière affichée (flux normal)
États UI¶
| État | Comportement | Texte en Français |
|---|---|---|
| Chargement renvoi | Spinner sur le lien "Renvoyer" | — |
| Succès renvoi | Toast vert | "Invitation renvoyée à {email}" |
| Erreur renvoi | Toast rouge | "Une erreur est survenue. Veuillez réessayer." |
| Multi-tenant détecté | Bannière info sous le champ email | "Cet utilisateur existe déjà sur la plateforme. Il sera ajouté à votre entreprise avec le rôle sélectionné." |
Comportement responsive¶
Mêmes points de rupture que la page Gestion des Utilisateurs de CP-003. Les badges de statut et les liens de renvoi s'adaptent à la disposition en carte (mobile) ou en ligne de tableau (bureau).
Critères d'acceptation¶
AC-024: User list shows invite status
Given I am on the User Management page with 3 users (2 active, 1 invited with expired link)
When the page loads
Then I see 2 users with green "Actif" dots
And 1 user with "Expiré — Renvoyer →" link
AC-025: Invite flow multi-tenant detection
Given I tap "+" to invite "[email protected]" who already exists on the platform
When I enter the email and the field loses focus
Then I see the info message: "Cet utilisateur existe déjà sur la plateforme. Il sera ajouté à votre entreprise avec le rôle sélectionné."
Règles OHADA & Réglementaires¶
- Loi 2013-450 (Art. 36) : L'endpoint check-email retourne des informations minimales (exists + prénom/nom uniquement, pas de détails tenant) pour éviter de fuiter des informations inter-tenant.
Standards & Conventions¶
docs/standards/react-typescript-guidelines.md— §Composants liste, §Pattern toast, §Bannière infodocs/standards/api-guidelines.md— §Enveloppe standard
Exigences de test¶
Tests unitaires¶
- UserService.resendInvitation : envoie l'email pour une invitation expirée
- UserService.resendInvitation : rejette si l'utilisateur n'est pas INVITED
- UserService.checkExistingUser : retourne exists=true avec le nom pour un utilisateur existant
- UserService.checkExistingUser : retourne exists=false pour un email inconnu
Tests d'intégration¶
- POST /api/v1/users/{id}/resend-invite — succès pour une invitation expirée
- POST /api/v1/users/{id}/resend-invite — 400 pour un utilisateur non-INVITED
- GET /api/v1/users/check-email — utilisateur existant retourne des informations minimales
- GET /api/v1/users/check-email — email inconnu retourne exists=false
Ce que le QA validera¶
- La liste d'utilisateurs affiche les points de statut et labels corrects pour chaque état
- L'invitation expirée affiche le lien "Expiré — Renvoyer →"
- Le renvoi d'invitation envoie l'email et affiche le toast de succès
- Le message de détection multi-tenant apparaît après la saisie d'un email existant
- Aucune fuite d'informations inter-tenant dans la réponse check-email
Hors périmètre¶
- UI de désactivation/suppression d'utilisateur — V2
- UI de configuration d'expiration d'invitation — V2 (72h par défaut codé en dur)
- UI de changement de tenant — CP-011
Définition de Done¶
- [ ] La liste d'utilisateurs affiche le statut correct pour ACTIVE, INVITED (valide), INVITED (expiré), DISABLED
- [ ] Le flux de renvoi d'invitation fonctionne de bout en bout
- [ ] La bannière de détection multi-tenant s'affiche correctement
- [ ] Tous les critères d'acceptation passent manuellement
- [ ] Tests unitaires écrits et passants
- [ ] Tests d'intégration écrits et passants
- [ ] Les micro-textes français correspondent exactement à la spec design
- [ ] Tous les états UI s'affichent correctement à 360px, 768px, 1024px
- [ ] Pas de
anyTypeScript — tous les types explicites - [ ] Les réponses API respectent le format d'enveloppe standard