feat: WebSocket temps réel + Finance Workflow + corrections
- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics) * Backend: KafkaEventProducer, KafkaEventConsumer * Mobile: WebSocketService (reconnection, heartbeat, typed events) * DashboardBloc: Auto-refresh depuis WebSocket events - Finance Workflow: approbations + budgets (backend + mobile) * Backend: entities, services, resources, migrations Flyway V6 * Mobile: features finance_workflow complète avec BLoC - Corrections DI: interfaces IRepository partout * IProfileRepository, IOrganizationRepository, IMembreRepository * GetIt configuré avec @injectable - Spec-Kit: constitution + templates mis à jour * .specify/memory/constitution.md enrichie * Templates agent, plan, spec, tasks, checklist - Nettoyage: fichiers temporaires supprimés Signed-off-by: lions dev Team
This commit is contained in:
415
unionflow/docs/UX_MENU_PAR_ROLE.md
Normal file
415
unionflow/docs/UX_MENU_PAR_ROLE.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# Révision UX - Menu et Pages par Rôle
|
||||
|
||||
> **Date**: 2026-03-02
|
||||
> **Système**: UnionFlow - Navigation et Accès par Rôle
|
||||
> **Principe**: **Chaque membre ne voit que ce qui est pertinent pour SON rôle**
|
||||
|
||||
---
|
||||
|
||||
## Problème Identifié
|
||||
|
||||
### État Actuel ❌
|
||||
|
||||
**Ligne 48-52 de menu.xhtml** : "Annuaire des Membres" est visible pour **TOUS** incluant **MEMBRE_ACTIF**
|
||||
|
||||
```xml
|
||||
<!-- Annuaire des Membres (MEMBRE_ACTIF et plus - Consultation) -->
|
||||
<p:submenu id="m_annuaire" label="Annuaire des Membres" icon="pi pi-users"
|
||||
rendered="#{menuBean.annuaireMembresVisible}">
|
||||
<p:menuitem id="m_liste_membres_lecture" value="Liste des Membres"
|
||||
icon="pi pi-list" outcome="/pages/secure/membre/liste" />
|
||||
<p:menuitem id="m_recherche_membres" value="Rechercher un Membre"
|
||||
icon="pi pi-search" outcome="/pages/secure/membre/recherche" />
|
||||
</p:submenu>
|
||||
```
|
||||
|
||||
**Problèmes UX** :
|
||||
1. ❌ Un membre simple d'une mutuelle n'a **pas besoin** de voir la liste de tous les membres
|
||||
2. ❌ Exposition de données personnelles (RGPD) sans raison métier
|
||||
3. ❌ La page `/pages/secure/membre/liste.xhtml` affiche des **KPI administratifs** :
|
||||
- Total Membres
|
||||
- Membres Actifs/Inactifs
|
||||
- Nouveaux Membres (30j)
|
||||
4. ❌ Actions administratives non pertinentes :
|
||||
- Nouveau Membre
|
||||
- Import/Export
|
||||
- Suspendre/Réactiver
|
||||
- Rappel Cotisations Groupé
|
||||
|
||||
---
|
||||
|
||||
## Question Métier Fondamentale
|
||||
|
||||
**Pour un MEMBRE_ACTIF d'une mutuelle, quels sont ses besoins réels ?**
|
||||
|
||||
✅ **Besoins légitimes** :
|
||||
- SON dashboard personnel
|
||||
- SES cotisations
|
||||
- SON compte épargne
|
||||
- SES inscriptions aux événements
|
||||
- SES demandes d'aide sociale
|
||||
- Consulter les événements publics (pour s'inscrire)
|
||||
- Voir ses notifications personnelles
|
||||
- Accéder à SON profil
|
||||
|
||||
❌ **Besoins NON légitimes** (rôles admin) :
|
||||
- Voir la liste complète des membres
|
||||
- Rechercher d'autres membres
|
||||
- Voir les statistiques globales de l'organisation
|
||||
- Créer/Modifier/Suspendre des membres
|
||||
- Importer/Exporter des membres
|
||||
- Envoyer des rappels de cotisations
|
||||
- Voir la trésorerie globale
|
||||
|
||||
---
|
||||
|
||||
## Solution Recommandée
|
||||
|
||||
### 1. Révision du Menu par Rôle
|
||||
|
||||
#### A. Menu pour **MEMBRE_ACTIF** (Minimal)
|
||||
|
||||
```xml
|
||||
<!-- MEMBRE_ACTIF - Menu Personnel Uniquement -->
|
||||
<fr:menu widgetVar="FreyaMenuWidget">
|
||||
<!-- Dashboard Personnel -->
|
||||
<p:menuitem value="Mon Espace" icon="pi pi-home"
|
||||
outcome="/pages/secure/dashboard-membre" />
|
||||
|
||||
<!-- Mes Finances -->
|
||||
<p:submenu label="Mes Finances" icon="pi pi-wallet">
|
||||
<p:menuitem value="Mes Cotisations" icon="pi pi-credit-card"
|
||||
outcome="/pages/secure/membre/cotisations" />
|
||||
<p:menuitem value="Payer mes Cotisations" icon="pi pi-dollar"
|
||||
outcome="/pages/secure/cotisation/paiement" />
|
||||
<p:menuitem value="Mon Épargne" icon="pi pi-money-bill"
|
||||
outcome="/pages/secure/epargne/mon-compte" />
|
||||
<p:menuitem value="Mes Prêts" icon="pi pi-briefcase"
|
||||
outcome="/pages/secure/credit/mes-prets"
|
||||
rendered="#{config.moduleCredit}" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Événements -->
|
||||
<p:submenu label="Événements" icon="pi pi-calendar">
|
||||
<p:menuitem value="Calendrier" icon="pi pi-calendar-plus"
|
||||
outcome="/pages/secure/evenement/calendrier" />
|
||||
<p:menuitem value="Mes Inscriptions" icon="pi pi-list"
|
||||
outcome="/pages/secure/evenement/mes-inscriptions" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Aide Sociale -->
|
||||
<p:submenu label="Aide Sociale" icon="pi pi-heart">
|
||||
<p:menuitem value="Faire une Demande" icon="pi pi-plus"
|
||||
outcome="/pages/secure/aide/demande" />
|
||||
<p:menuitem value="Mes Demandes" icon="pi pi-list"
|
||||
outcome="/pages/secure/aide/mes-demandes" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Communication -->
|
||||
<p:submenu label="Communication" icon="pi pi-envelope">
|
||||
<p:menuitem value="Mes Notifications" icon="pi pi-bell"
|
||||
outcome="/pages/secure/communication/notifications" />
|
||||
<p:menuitem value="Annonces" icon="pi pi-megaphone"
|
||||
outcome="/pages/secure/communication/annonces" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Mon Profil -->
|
||||
<p:menuitem value="Mon Profil" icon="pi pi-user"
|
||||
outcome="/pages/secure/membre/mon-profil" />
|
||||
|
||||
<!-- Aide -->
|
||||
<p:menuitem value="Aide" icon="pi pi-question-circle"
|
||||
outcome="/pages/secure/aide/support" />
|
||||
</fr:menu>
|
||||
```
|
||||
|
||||
**Total items** : ~10 items pertinents (vs ~50+ actuellement)
|
||||
|
||||
#### B. Menu pour **SECRETAIRE** (Gestion Administrative)
|
||||
|
||||
```xml
|
||||
<!-- SECRETAIRE - Administration + Personnel -->
|
||||
<fr:menu>
|
||||
<!-- Tous les items MEMBRE_ACTIF + -->
|
||||
|
||||
<!-- Gestion des Membres -->
|
||||
<p:submenu label="Gestion des Membres" icon="pi pi-users-cog">
|
||||
<p:menuitem value="Nouvelle Inscription" outcome="/pages/secure/membre/inscription" />
|
||||
<p:menuitem value="Liste Complète" outcome="/pages/secure/membre/liste" />
|
||||
<p:menuitem value="Validation Inscriptions" outcome="/pages/secure/membre/validation" />
|
||||
<p:menuitem value="Import/Export" outcome="/pages/secure/membre/import" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Gestion Événements -->
|
||||
<p:submenu label="Gestion Événements" icon="pi pi-calendar-clock">
|
||||
<p:menuitem value="Nouvel Événement" outcome="/pages/secure/evenement/creation" />
|
||||
<p:menuitem value="Planification" outcome="/pages/secure/evenement/planification" />
|
||||
<p:menuitem value="Gestion Participations" outcome="/pages/secure/evenement/participation" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Communication -->
|
||||
<p:submenu label="Communication" icon="pi pi-megaphone">
|
||||
<p:menuitem value="Envoyer SMS/Email" outcome="/pages/secure/communication/envoi" />
|
||||
<p:menuitem value="Annonces Officielles" outcome="/pages/secure/communication/annonces-admin" />
|
||||
</p:submenu>
|
||||
</fr:menu>
|
||||
```
|
||||
|
||||
#### C. Menu pour **TRESORIER** (Gestion Financière)
|
||||
|
||||
```xml
|
||||
<!-- TRESORIER - Finances + Personnel -->
|
||||
<fr:menu>
|
||||
<!-- Tous les items MEMBRE_ACTIF + -->
|
||||
|
||||
<!-- Gestion Financière -->
|
||||
<p:submenu label="Gestion Financière" icon="pi pi-dollar">
|
||||
<p:menuitem value="Trésorerie" outcome="/pages/secure/finance/tresorerie" />
|
||||
<p:menuitem value="Cotisations Globales" outcome="/pages/admin/cotisations/gestion" />
|
||||
<p:menuitem value="Comptabilité" outcome="/pages/secure/comptabilite/gestion" />
|
||||
<p:menuitem value="Relances Cotisations" outcome="/pages/secure/cotisation/relances" />
|
||||
<p:menuitem value="Rapports Financiers" outcome="/pages/secure/finance/rapports" />
|
||||
</p:submenu>
|
||||
|
||||
<!-- Épargne et Crédit (si module actif) -->
|
||||
<p:submenu label="Épargne et Crédit" icon="pi pi-money-bill">
|
||||
<p:menuitem value="Demandes de Crédit" outcome="/pages/secure/credit/demandes" />
|
||||
<p:menuitem value="Suivi des Crédits" outcome="/pages/secure/credit/suivi" />
|
||||
<p:menuitem value="Remboursements" outcome="/pages/secure/credit/remboursements" />
|
||||
</p:submenu>
|
||||
</fr:menu>
|
||||
```
|
||||
|
||||
#### D. Menu pour **ADMIN_ORGANISATION** (Tout)
|
||||
|
||||
```xml
|
||||
<!-- ADMIN_ORGANISATION - Tous les menus -->
|
||||
<fr:menu>
|
||||
<!-- Dashboard Admin -->
|
||||
<p:menuitem value="Dashboard Admin" outcome="/pages/secure/dashboard" />
|
||||
|
||||
<!-- Tous les menus de gestion -->
|
||||
<!-- + Tous les items personnels -->
|
||||
</fr:menu>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Révision des Pages par Rôle
|
||||
|
||||
#### A. `/pages/secure/membre/liste.xhtml`
|
||||
|
||||
**État actuel** : Une seule page pour tous (admin + membres)
|
||||
|
||||
**Solution** : Conditionner l'affichage selon le rôle
|
||||
|
||||
```xml
|
||||
<!-- KPI Statistiques - Visible uniquement pour SECRETAIRE, ADMIN -->
|
||||
<h:panelGroup id="panelStatistiques" layout="block" styleClass="grid mb-3"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:decorate template="/templates/components/cards/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreListeBean.totalMembres}" />
|
||||
<ui:param name="label" value="Total Membres" />
|
||||
</ui:decorate>
|
||||
</div>
|
||||
<!-- Autres KPI... -->
|
||||
</h:panelGroup>
|
||||
|
||||
<!-- Actions Admin - Visible uniquement pour SECRETAIRE, ADMIN -->
|
||||
<ui:define name="actions">
|
||||
<p:button value="Nouveau Membre" icon="pi pi-user-plus"
|
||||
outcome="membreInscriptionPage"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}"
|
||||
styleClass="ui-button-success mr-2" />
|
||||
<p:commandButton value="Import / Export" icon="pi pi-file-excel"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}"
|
||||
onclick="PF('dlgImportExport').show();" />
|
||||
</ui:define>
|
||||
|
||||
<!-- Actions en DataTable - Visible uniquement pour SECRETAIRE, ADMIN -->
|
||||
<ui:define name="actions">
|
||||
<!-- Voir le profil - TOUS -->
|
||||
<p:button icon="pi pi-user" outcome="membreProfilPage" title="Profil" />
|
||||
|
||||
<!-- Éditer - ADMIN SEULEMENT -->
|
||||
<p:button icon="pi pi-pencil" outcome="membreModifierPage" title="Modifier"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}" />
|
||||
|
||||
<!-- Contacter - TOUS -->
|
||||
<p:commandButton icon="pi pi-envelope" title="Contacter" />
|
||||
|
||||
<!-- Suspendre - ADMIN SEULEMENT -->
|
||||
<p:commandButton icon="pi pi-ban" title="Suspendre"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible and membre.statut == 'ACTIF'}" />
|
||||
</ui:define>
|
||||
```
|
||||
|
||||
**Alternative** : Créer 2 pages séparées
|
||||
|
||||
- `/pages/secure/membre/liste.xhtml` → Admin seulement (avec KPI et actions)
|
||||
- `/pages/secure/membre/annuaire.xhtml` → Tous (lecture seule, pas de KPI)
|
||||
|
||||
#### B. `/pages/secure/dashboard.xhtml` vs `/pages/secure/dashboard-membre.xhtml`
|
||||
|
||||
**Actuellement** : Bien séparés ✅
|
||||
|
||||
- `dashboard.xhtml` → ADMIN, RESPONSABLES (KPI globaux)
|
||||
- `dashboard-membre.xhtml` → MEMBRE_ACTIF (données personnelles)
|
||||
|
||||
**À conserver** tel quel.
|
||||
|
||||
---
|
||||
|
||||
### 3. Modification de MenuBean.java
|
||||
|
||||
#### Réviser `isAnnuaireMembresVisible()`
|
||||
|
||||
**Avant** (ligne 135-139) :
|
||||
```java
|
||||
public boolean isAnnuaireMembresVisible() {
|
||||
return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "TRESORIER",
|
||||
"RESPONSABLE_SOCIAL", "RESPONSABLE_EVENEMENTS", "RESPONSABLE_CREDIT",
|
||||
"MEMBRE_BUREAU", "MEMBRE_ACTIF"); // ← PROBLÈME
|
||||
}
|
||||
```
|
||||
|
||||
**Après** (Option 1 - Restrictif) :
|
||||
```java
|
||||
/**
|
||||
* Annuaire des Membres - Consultation limitée
|
||||
* Visible pour les responsables et bureau SEULEMENT (pas MEMBRE_ACTIF)
|
||||
*
|
||||
* Raison métier: Un membre simple n'a pas besoin de voir la liste complète
|
||||
* des autres membres (RGPD, pertinence métier limitée)
|
||||
*/
|
||||
public boolean isAnnuaireMembresVisible() {
|
||||
return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "TRESORIER",
|
||||
"RESPONSABLE_SOCIAL", "RESPONSABLE_EVENEMENTS", "RESPONSABLE_CREDIT",
|
||||
"MEMBRE_BUREAU");
|
||||
// MEMBRE_ACTIF retiré intentionnellement
|
||||
}
|
||||
```
|
||||
|
||||
**Après** (Option 2 - Configurable par Organisation) :
|
||||
```java
|
||||
@Inject
|
||||
ConfigurationService configService; // Service qui lit config de l'organisation
|
||||
|
||||
/**
|
||||
* Annuaire des Membres - Consultation limitée
|
||||
* Visible selon configuration de l'organisation
|
||||
*/
|
||||
public boolean isAnnuaireMembresVisible() {
|
||||
// Toujours visible pour les admins
|
||||
if (hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "TRESORIER",
|
||||
"RESPONSABLE_SOCIAL", "RESPONSABLE_EVENEMENTS", "RESPONSABLE_CREDIT",
|
||||
"MEMBRE_BUREAU")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pour MEMBRE_ACTIF: vérifier si l'organisation autorise l'annuaire
|
||||
if (hasAnyRole("MEMBRE_ACTIF")) {
|
||||
return configService.isAnnuaireMembresActive(); // false par défaut
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cas d'Usage Métier - Annuaire pour MEMBRE_ACTIF ?
|
||||
|
||||
### ✅ Arguments POUR (lien social)
|
||||
|
||||
1. **Faciliter la communication** entre membres
|
||||
2. **Créer du lien social** dans la mutuelle
|
||||
3. **Trouver des contacts** pour covoiturage aux événements
|
||||
4. **Identifier des compétences** (ex: trouver un plombier membre)
|
||||
|
||||
### ❌ Arguments CONTRE (protection données)
|
||||
|
||||
1. **RGPD** : Exposition non justifiée de données personnelles
|
||||
2. **Sécurité** : Risque de phishing/spam entre membres
|
||||
3. **Pertinence limitée** : Un membre n'a généralement pas besoin de la liste complète
|
||||
4. **Surcharge cognitive** : Menu trop chargé pour un usage quotidien limité
|
||||
|
||||
### 💡 Recommandation
|
||||
|
||||
**Option privilégiée** : **Désactiver par défaut**, rendre **configurable par organisation**
|
||||
|
||||
```java
|
||||
// Configuration dans table `configuration_organisation`
|
||||
{
|
||||
"annuaire_membres_actif": false, // Par défaut : désactivé
|
||||
"annuaire_membres_champs_visibles": ["nom", "prenom", "telephone"], // Pas email
|
||||
"annuaire_membres_recherche_avancee": false // Recherche simple seulement
|
||||
}
|
||||
```
|
||||
|
||||
Si l'organisation **active** l'annuaire pour MEMBRE_ACTIF :
|
||||
- ✅ Afficher une **version limitée** (pas de KPI, pas d'actions admin)
|
||||
- ✅ Masquer certains champs sensibles (email optionnel, pas d'adresse)
|
||||
- ✅ Limiter la recherche (nom/prénom seulement, pas de filtres avancés)
|
||||
|
||||
---
|
||||
|
||||
## Plan d'Action
|
||||
|
||||
### Phase 1 : Menu ✅ (Immédiat)
|
||||
|
||||
- [ ] Modifier `MenuBean.isAnnuaireMembresVisible()` pour exclure `MEMBRE_ACTIF`
|
||||
- [ ] Tester que le menu "Annuaire des Membres" n'apparaît plus pour MEMBRE_ACTIF
|
||||
- [ ] Vérifier que les autres menus sont bien visibles selon les rôles
|
||||
|
||||
### Phase 2 : Pages Conditionnelles 🔧 (Court terme)
|
||||
|
||||
- [ ] Ajouter `rendered="#{menuBean.gestionMembresMenuVisible}"` sur les KPI de `liste.xhtml`
|
||||
- [ ] Ajouter `rendered="#{menuBean.gestionMembresMenuVisible}"` sur les actions admin
|
||||
- [ ] Conditionner les actions du DataTable (Éditer, Suspendre) selon le rôle
|
||||
- [ ] Tester avec un utilisateur MEMBRE_ACTIF : pas de KPI, pas d'actions admin
|
||||
|
||||
### Phase 3 : Configuration Optionnelle 🚀 (Moyen terme)
|
||||
|
||||
- [ ] Créer table `configuration_organisation` avec champ `annuaire_membres_actif`
|
||||
- [ ] Créer `ConfigurationService.isAnnuaireMembresActive()`
|
||||
- [ ] Modifier `MenuBean.isAnnuaireMembresVisible()` pour utiliser la config
|
||||
- [ ] Créer page admin `/pages/admin/configuration/annuaire.xhtml` pour activer/désactiver
|
||||
- [ ] Si activé : créer page `/pages/secure/membre/annuaire.xhtml` (version simplifiée)
|
||||
|
||||
### Phase 4 : Révision Complète Menu 📋 (Long terme)
|
||||
|
||||
- [ ] Créer des fichiers menu séparés par rôle :
|
||||
- `menu-membre-actif.xhtml` (10 items)
|
||||
- `menu-secretaire.xhtml` (20 items)
|
||||
- `menu-tresorier.xhtml` (15 items)
|
||||
- `menu-admin.xhtml` (50+ items)
|
||||
- [ ] Charger le bon menu selon le rôle dans `main-template.xhtml`
|
||||
- [ ] Simplifier `MenuBean` en supprimant les méthodes deprecated
|
||||
|
||||
---
|
||||
|
||||
## Checklist de Validation UX
|
||||
|
||||
Avant de déployer un menu ou une page, vérifier :
|
||||
|
||||
- [ ] **Pertinence métier** : L'utilisateur a-t-il besoin de cette fonction pour SON rôle ?
|
||||
- [ ] **Moindre privilège** : La fonction n'expose-t-elle que les données nécessaires ?
|
||||
- [ ] **Clarté** : L'intitulé du menu est-il explicite ? ("Mes Cotisations" vs "Cotisations")
|
||||
- [ ] **Cohérence** : Les fonctions "MES" vs "GESTION" sont-elles bien séparées ?
|
||||
- [ ] **Simplicité** : Le menu n'est-il pas surchargé ? (max 10-15 items pour MEMBRE_ACTIF)
|
||||
|
||||
---
|
||||
|
||||
## Contact
|
||||
|
||||
**Documentation** :
|
||||
- `docs/UX_MENU_PAR_ROLE.md` (ce fichier)
|
||||
- `docs/KPI_DASHBOARD_PAR_ROLE.md` (matrice KPI)
|
||||
- `docs/PERMISSIONS_MATRIX.md` (permissions pages)
|
||||
|
||||
**Code** :
|
||||
- `MenuBean.java` - Logique de visibilité
|
||||
- `menu.xhtml` - Structure du menu
|
||||
- `liste.xhtml` - Page à conditionner
|
||||
Reference in New Issue
Block a user