# Correction Erreur 404 - Membre Non Trouvé > **Date**: 2026-03-02 > **Système**: UnionFlow - Frontend & Backend > **Statut**: ✅ **CORRIGÉ** --- ## Problème Initial ### Erreur rencontrée ``` 2026-03-02 17:08:52,964 SEVERE [RestClientExceptionMapper] Erreur backend - HTTP 404 (Not Found) Auto-détection du membre connecté: membre.mukefi@unionflow.test NotFoundException: Ressource non trouvée ``` ### Cause racine Le frontend utilisait l'endpoint `/api/membres/search` (recherche générale) pour trouver le membre connecté par email : ```java List membresRecherche = membreService.rechercher( null, null, username, null, null, null, 0, 1 ); ``` **Problème** : Cet endpoint retourne HTTP 404 si aucun membre n'est trouvé, au lieu de retourner une liste vide. --- ## Solution Implémentée ### 1. Création endpoint dédié `/api/membres/me` **Backend** : `MembreResource.java` #### A. Injection SecurityIdentity ```java @Inject io.quarkus.security.identity.SecurityIdentity securityIdentity; ``` **Ligne** : ~62 --- #### B. Endpoint `/me` ```java @GET @Path("/me") @RolesAllowed({ "MEMBRE", "ADMIN", "SUPER_ADMIN" }) @Operation(summary = "Récupérer le membre connecté") @APIResponse(responseCode = "200", description = "Membre connecté trouvé") @APIResponse(responseCode = "404", description = "Membre non trouvé") public Response obtenirMembreConnecte() { String email = securityIdentity.getPrincipal().getName(); LOG.infof("Récupération du membre connecté: %s", email); Membre membre = membreService.trouverParEmail(email) .filter(m -> m.getActif() == null || m.getActif()) .orElseThrow(() -> new NotFoundException("Membre non trouvé pour l'email: " + email)); return Response.ok(membreService.convertToResponse(membre)).build(); } ``` **Ligne** : ~100 **Caractéristiques** : - ✅ Accès direct via SecurityIdentity (auto-détection) - ✅ Pas de paramètre requis - ✅ Retourne directement le membre connecté - ✅ Erreur 404 claire si membre inexistant - ✅ Filtrage par actif --- ### 2. Déclaration interface REST Client **Frontend** : `MembreService.java` (interface) ```java @GET @Path("/me") MembreResponse obtenirMembreConnecte(); ``` **Ligne** : ~30 (après `obtenirParNumero`) **Ajouté** : Méthode dans l'interface REST Client --- ### 3. Mise à jour MembreCotisationBean **Avant** (code problématique) : ```java // Rechercher le membre par email List membresRecherche = retryService.executeWithRetrySupplier( () -> membreService.rechercher(null, null, username, null, null, null, 0, 1), "recherche du membre connecté par email" ); if (membresRecherche != null && !membresRecherche.isEmpty()) { MembreResponse membreConnecte = membresRecherche.get(0); membreId = membreConnecte.getId(); numeroMembre = membreConnecte.getNumeroMembre(); // ... } ``` **Après** (code corrigé) : ```java // Récupérer directement le membre connecté via l'endpoint /me MembreResponse membreConnecte = retryService.executeWithRetrySupplier( () -> membreService.obtenirMembreConnecte(), "récupération du membre connecté" ); if (membreConnecte != null) { membreId = membreConnecte.getId(); numeroMembre = membreConnecte.getNumeroMembre(); LOG.infof("Membre connecté détecté: %s (%s)", numeroMembre, membreId); } ``` **Fichier** : `MembreCotisationBean.java` (lignes 148-165) --- ### 4. Mise à jour MesCotisationsPaiementBean **Même modification appliquée** : ```java // Récupérer directement le membre connecté via l'endpoint /me membre = retryService.executeWithRetrySupplier( () -> membreService.obtenirMembreConnecte(), "récupération du membre connecté" ); if (membre != null) { membreId = membre.getId(); numeroMembre = membre.getNumeroMembre(); LOG.infof("Membre connecté détecté: %s (%s)", numeroMembre, membreId); } ``` **Fichier** : `MesCotisationsPaiementBean.java` (lignes 116-126) --- ## Avantages de la Solution ### 1. Performance - ✅ **1 requête HTTP** au lieu de recherche avec filtres - ✅ **Requête directe** : `GET /api/membres/me` - ✅ **Pas de filtrage côté client** (liste de résultats) --- ### 2. Sécurité - ✅ **Auto-détection via JWT** : `securityIdentity.getPrincipal().getName()` - ✅ **Pas de manipulation d'email** : le backend valide le token JWT - ✅ **Autorisation granulaire** : `@RolesAllowed` --- ### 3. Simplicité **Avant** : ```java // 1. Extraire email du SecurityIdentity String username = securityIdentity.getPrincipal().getName(); // 2. Rechercher avec filtres List results = membreService.rechercher( null, null, username, null, null, null, 0, 1 ); // 3. Vérifier liste vide if (results != null && !results.isEmpty()) { MembreResponse membre = results.get(0); // ... } ``` **Après** : ```java // 1 appel direct MembreResponse membre = membreService.obtenirMembreConnecte(); ``` --- ### 4. Réutilisabilité Cet endpoint `/me` peut être réutilisé partout où on a besoin du membre connecté : - ✅ DashboardMembreBean - ✅ MembreCotisationBean - ✅ MesCotisationsPaiementBean - ✅ Profil utilisateur - ✅ Toutes les pages personnelles --- ## Tests de Validation ### 1. Test Backend **Swagger UI** : `http://localhost:8085/q/swagger-ui` ```bash GET /api/membres/me Authorization: Bearer {token} ``` **Réponse attendue** : ```json { "id": "uuid", "numeroMembre": "M-2026-001", "email": "membre.mukefi@unionflow.test", "nom": "Mukefi", "prenom": "Jean", "statut": "ACTIF", ... } ``` --- ### 2. Test Frontend **Navigation** : `/pages/secure/membre/cotisations.xhtml` **Logs attendus** : ``` INFO [MembreCotisationBean] Auto-détection du membre connecté: membre.mukefi@unionflow.test INFO [MembreCotisationBean] Membre connecté détecté: M-2026-001 (uuid) ``` **Résultat** : - ✅ Aucune erreur 404 - ✅ Page cotisations chargée - ✅ Données personnelles affichées --- ## Checklist Validation - [x] **Endpoint `/me` créé** → ✅ MembreResource.java - [x] **SecurityIdentity injecté** → ✅ Backend - [x] **Interface REST Client mise à jour** → ✅ MembreService.java (frontend) - [x] **MembreCotisationBean modifié** → ✅ Appel `obtenirMembreConnecte()` - [x] **MesCotisationsPaiementBean modifié** → ✅ Appel `obtenirMembreConnecte()` - [x] **Compilation backend** → ✅ BUILD SUCCESS - [x] **Compilation frontend** → ✅ BUILD SUCCESS - [ ] **Tests fonctionnels** → ⏳ À faire (redémarrer serveurs) - [ ] **Validation navigateur** → ⏳ À faire --- ## Prochaines Étapes ### 1. Redémarrer les serveurs **Backend** : ```bash # Arrêter Quarkus (Ctrl+C) cd unionflow/unionflow-server-impl-quarkus mvn quarkus:dev ``` **Frontend** : ```bash # Arrêter Quarkus (Ctrl+C) cd unionflow/unionflow-client-quarkus-primefaces-freya mvn quarkus:dev ``` --- ### 2. Vider le cache navigateur - ✅ Ctrl+Shift+Delete → Vider cache et cookies - ✅ Ou navigation privée --- ### 3. Tester l'application 1. **Se connecter** : `http://localhost:8090/` 2. **Naviguer** : Menu Cotisations → Mes Cotisations 3. **Vérifier** : - ✅ Aucune erreur 404 - ✅ Page se charge correctement - ✅ Données personnelles affichées --- ### 4. Vérifier les logs **Backend** : ``` INFO [MembreResource] Récupération du membre connecté: membre.mukefi@unionflow.test ``` **Frontend** : ``` INFO [MembreCotisationBean] Membre connecté détecté: M-2026-001 (uuid) ``` --- ## Pattern Réutilisable ### Endpoint `/me` - Standard REST Ce pattern est un **standard REST** pour récupérer l'utilisateur connecté : ``` GET /api/users/me → Twitter, GitHub, LinkedIn GET /api/membres/me → UnionFlow GET /api/auth/me → Alternative GET /api/profile → Alternative ``` ### Utilisation dans d'autres beans **DashboardMembreBean** (exemple d'utilisation) : ```java @PostConstruct public void init() { try { // Auto-détection membre connecté MembreResponse membre = retryService.executeWithRetrySupplier( () -> membreService.obtenirMembreConnecte(), "récupération du membre connecté" ); if (membre != null) { this.membreId = membre.getId(); this.numeroMembre = membre.getNumeroMembre(); chargerDonnees(); } } catch (Exception e) { LOG.errorf(e, "Erreur auto-détection membre"); errorHandler.handleException(e, "lors du chargement du dashboard", null); } } ``` --- ## Sécurité ### Validation JWT L'endpoint `/me` valide automatiquement le JWT via Quarkus OIDC : 1. ✅ **Token validé** : signature, expiration, issuer 2. ✅ **Email extrait** : `securityIdentity.getPrincipal().getName()` 3. ✅ **Membre trouvé** : `membreService.trouverParEmail(email)` 4. ✅ **Filtre actif** : Seuls les membres actifs sont retournés ### Autorisation ```java @RolesAllowed({ "MEMBRE", "ADMIN", "SUPER_ADMIN" }) ``` - ✅ Accessible à tous les membres authentifiés - ❌ Interdit aux utilisateurs non authentifiés (401) - ❌ Interdit aux tokens expirés (401) --- ## Contact **Fichiers modifiés** : - `MembreResource.java` (+20 lignes) - `MembreService.java` (interface frontend, +4 lignes) - `MembreCotisationBean.java` (~10 lignes modifiées) - `MesCotisationsPaiementBean.java` (~10 lignes modifiées) **Endpoint ajouté** : `GET /api/membres/me` **Documentation liée** : - `docs/IMPLEMENTATION_TESTS_SERVICES.md` - `docs/IMPLEMENTATION_SERVICES_COTISATIONS_COMPLET.md` - `docs/IMPLEMENTATION_ENDPOINTS_BACKEND.md`