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:
387
unionflow/docs/CHANGEMENTS_UX_MENU_APPLIQUES.md
Normal file
387
unionflow/docs/CHANGEMENTS_UX_MENU_APPLIQUES.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# Changements UX - Menu et Pages par Rôle (Appliqués)
|
||||
|
||||
> **Date**: 2026-03-02
|
||||
> **Système**: UnionFlow - Révision UX Menu et Accès par Rôle
|
||||
> **Statut**: ✅ **Phase 1 et Phase 2 APPLIQUÉES**
|
||||
|
||||
---
|
||||
|
||||
## Changements Appliqués
|
||||
|
||||
### ✅ Phase 1 : Menu - Retrait MEMBRE_ACTIF de l'Annuaire
|
||||
|
||||
**Fichier modifié** : `MenuBean.java`
|
||||
|
||||
**Méthode** : `isAnnuaireMembresVisible()`
|
||||
|
||||
#### Avant ❌
|
||||
```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 ✅
|
||||
```java
|
||||
/**
|
||||
* Annuaire des Membres - Consultation de la liste (pas de modification)
|
||||
* Visible pour les responsables et bureau SEULEMENT (PAS pour MEMBRE_ACTIF)
|
||||
*
|
||||
* Raison métier: Un membre simple n'a généralement pas besoin de voir la liste complète
|
||||
* des autres membres. Cela peut poser des problèmes de:
|
||||
* - RGPD: Exposition non justifiée de données personnelles
|
||||
* - Sécurité: Risque de spam/phishing entre membres
|
||||
* - UX: Surcharge du menu pour un usage limité
|
||||
*/
|
||||
public boolean isAnnuaireMembresVisible() {
|
||||
return hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", "SECRETAIRE", "TRESORIER",
|
||||
"RESPONSABLE_SOCIAL", "RESPONSABLE_EVENEMENTS", "RESPONSABLE_CREDIT",
|
||||
"MEMBRE_BUREAU");
|
||||
// MEMBRE_ACTIF retiré intentionnellement pour raisons UX et RGPD
|
||||
}
|
||||
```
|
||||
|
||||
**Résultat** :
|
||||
- ✅ Menu "Annuaire des Membres" **masqué** pour les utilisateurs avec rôle **MEMBRE_ACTIF**
|
||||
- ✅ Menu visible uniquement pour SECRETAIRE, TRESORIER, RESPONSABLES, ADMIN
|
||||
|
||||
---
|
||||
|
||||
### ✅ Phase 2 : Page Liste Membres - Conditionnement par Rôle
|
||||
|
||||
**Fichier modifié** : `/pages/secure/membre/liste.xhtml`
|
||||
|
||||
#### 1. KPI Statistiques (Lignes 31-64)
|
||||
|
||||
**Avant** ❌ : KPI visibles pour **TOUS**
|
||||
```xml
|
||||
<h:panelGroup id="panelStatistiques" layout="block" styleClass="grid mb-3">
|
||||
```
|
||||
|
||||
**Après** ✅ : KPI visibles uniquement pour **ADMIN**
|
||||
```xml
|
||||
<h:panelGroup id="panelStatistiques" layout="block" styleClass="grid mb-3"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}">
|
||||
```
|
||||
|
||||
**KPI conditionnés** :
|
||||
- Total Membres
|
||||
- Membres Actifs
|
||||
- Membres Inactifs/Suspendus
|
||||
- Nouveaux Membres (30j)
|
||||
|
||||
---
|
||||
|
||||
#### 2. Actions Header (Lignes 21-24)
|
||||
|
||||
**Avant** ❌ : Boutons visibles pour **TOUS**
|
||||
|
||||
**Après** ✅ : Boutons visibles uniquement pour **ADMIN**
|
||||
```xml
|
||||
<p:button value="Nouveau Membre" icon="pi pi-user-plus"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}" />
|
||||
<p:commandButton value="Import / Export" icon="pi pi-file-excel"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}" />
|
||||
```
|
||||
|
||||
**Actions conditionnées** :
|
||||
- Nouveau Membre
|
||||
- Import / Export
|
||||
|
||||
---
|
||||
|
||||
#### 3. Actions Groupées (Lignes 129-143)
|
||||
|
||||
**Avant** ❌ : Actions groupées visibles pour **TOUS** si sélection
|
||||
```xml
|
||||
<h:panelGroup id="panelActionsGroupees"
|
||||
rendered="#{not empty membreListeBean.selectedMembres}">
|
||||
```
|
||||
|
||||
**Après** ✅ : Actions groupées visibles uniquement pour **ADMIN**
|
||||
```xml
|
||||
<h:panelGroup id="panelActionsGroupees"
|
||||
rendered="#{not empty membreListeBean.selectedMembres and menuBean.gestionMembresMenuVisible}">
|
||||
```
|
||||
|
||||
**Actions conditionnées** :
|
||||
- Rappel Cotisations Groupé
|
||||
- Message Groupé
|
||||
- Exporter Sélection
|
||||
|
||||
---
|
||||
|
||||
#### 4. Colonne Sélection (Ligne 166)
|
||||
|
||||
**Avant** ❌ : Checkbox visible pour **TOUS**
|
||||
```xml
|
||||
<p:column selectionMode="multiple" headerText="" />
|
||||
```
|
||||
|
||||
**Après** ✅ : Checkbox visible uniquement pour **ADMIN**
|
||||
```xml
|
||||
<p:column selectionMode="multiple" headerText=""
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 5. Actions DataTable (Lignes 223-258)
|
||||
|
||||
##### Action "Voir Profil" - TOUS ✅
|
||||
```xml
|
||||
<!-- Voir le profil - TOUS -->
|
||||
<p:button icon="pi pi-user" outcome="membreProfilPage" title="Profil" />
|
||||
```
|
||||
**Pas de condition** : Tous les utilisateurs peuvent consulter un profil
|
||||
|
||||
##### Action "Éditer" - ADMIN SEULEMENT ✅
|
||||
```xml
|
||||
<!-- Éditer - ADMIN SEULEMENT -->
|
||||
<p:button icon="pi pi-pencil" outcome="membreModifierPage" title="Modifier"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible}" />
|
||||
```
|
||||
|
||||
##### Action "Contacter" - TOUS ✅
|
||||
```xml
|
||||
<!-- Contacter - TOUS -->
|
||||
<p:commandButton icon="pi pi-envelope" title="Contacter" />
|
||||
```
|
||||
|
||||
##### Action "Suspendre" - ADMIN SEULEMENT ✅
|
||||
```xml
|
||||
<!-- Suspendre - ADMIN SEULEMENT (visible si actif) -->
|
||||
<p:commandButton icon="pi pi-ban" title="Suspendre"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible and membre.statut == 'ACTIF'}" />
|
||||
```
|
||||
|
||||
##### Action "Réactiver" - ADMIN SEULEMENT ✅
|
||||
```xml
|
||||
<!-- Réactiver - ADMIN SEULEMENT (visible si suspendu) -->
|
||||
<p:commandButton icon="pi pi-replay" title="Réactiver"
|
||||
rendered="#{menuBean.gestionMembresMenuVisible and membre.statut == 'SUSPENDU'}" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Résultat UX par Rôle
|
||||
|
||||
### Pour MEMBRE_ACTIF 👤
|
||||
|
||||
**Menu** :
|
||||
- ❌ "Annuaire des Membres" → **MASQUÉ**
|
||||
- ✅ Uniquement les menus personnels (Mes Finances, Événements, Aide Sociale, etc.)
|
||||
|
||||
**Page `/pages/secure/membre/liste.xhtml`** (si accessible directement par URL) :
|
||||
- ❌ KPI statistiques → **MASQUÉS**
|
||||
- ❌ Bouton "Nouveau Membre" → **MASQUÉ**
|
||||
- ❌ Bouton "Import / Export" → **MASQUÉ**
|
||||
- ❌ Actions groupées (Rappel, Message, Export) → **MASQUÉES**
|
||||
- ❌ Colonne checkbox sélection → **MASQUÉE**
|
||||
- ✅ Bouton "Voir Profil" → **VISIBLE**
|
||||
- ❌ Bouton "Éditer" → **MASQUÉ**
|
||||
- ✅ Bouton "Contacter" → **VISIBLE**
|
||||
- ❌ Bouton "Suspendre/Réactiver" → **MASQUÉ**
|
||||
|
||||
**Résultat** : Page affichée en mode **lecture seule** (consultation profil + contact uniquement)
|
||||
|
||||
---
|
||||
|
||||
### Pour SECRETAIRE / ADMIN_ORGANISATION 🔐
|
||||
|
||||
**Menu** :
|
||||
- ✅ "Annuaire des Membres" → **VISIBLE**
|
||||
- ✅ "Gestion des Membres" → **VISIBLE**
|
||||
- ✅ Tous les autres menus selon leur rôle
|
||||
|
||||
**Page `/pages/secure/membre/liste.xhtml`** :
|
||||
- ✅ **TOUS les éléments visibles** (KPI, actions, boutons)
|
||||
- ✅ Mode **administration complète**
|
||||
|
||||
---
|
||||
|
||||
## Principe Métier Respecté
|
||||
|
||||
### Question Fondamentale Adressée
|
||||
|
||||
> **"Pourquoi un membre d'une mutuelle devrait-il voir la liste des membres ou rechercher un membre ?"**
|
||||
|
||||
**Réponse** :
|
||||
- ✅ Un **MEMBRE_ACTIF** n'a généralement **PAS besoin** de ces fonctions
|
||||
- ✅ C'est le rôle du **SECRETAIRE** ou **ADMIN** de gérer les membres
|
||||
- ✅ Évite les problèmes **RGPD** (exposition données personnelles)
|
||||
- ✅ Simplifie le menu et améliore l'**UX**
|
||||
|
||||
### Arguments Métier
|
||||
|
||||
| Critère | MEMBRE_ACTIF | SECRETAIRE/ADMIN |
|
||||
|---------|--------------|------------------|
|
||||
| **Voir liste complète** | ❌ Non pertinent | ✅ Nécessaire |
|
||||
| **Statistiques membres** | ❌ Non pertinent | ✅ Nécessaire |
|
||||
| **Créer/Modifier membres** | ❌ Non autorisé | ✅ Nécessaire |
|
||||
| **Actions groupées** | ❌ Non autorisé | ✅ Nécessaire |
|
||||
| **Voir profil individuel** | ✅ Pertinent (lien social) | ✅ Pertinent |
|
||||
| **Contacter un membre** | ✅ Pertinent (communication) | ✅ Pertinent |
|
||||
|
||||
---
|
||||
|
||||
## Travaux Restants
|
||||
|
||||
### Phase 3 : Configuration Optionnelle (À implémenter)
|
||||
|
||||
Si une organisation souhaite **activer l'annuaire** pour les MEMBRE_ACTIF :
|
||||
|
||||
1. Créer table `configuration_organisation`
|
||||
```sql
|
||||
CREATE TABLE configuration_organisation (
|
||||
id UUID PRIMARY KEY,
|
||||
organisation_id UUID REFERENCES organisation(id),
|
||||
annuaire_membres_actif BOOLEAN DEFAULT FALSE,
|
||||
annuaire_membres_champs_visibles TEXT[], -- ["nom", "prenom", "telephone"]
|
||||
annuaire_membres_recherche_avancee BOOLEAN DEFAULT FALSE
|
||||
);
|
||||
```
|
||||
|
||||
2. Créer `ConfigurationService`
|
||||
```java
|
||||
@ApplicationScoped
|
||||
public class ConfigurationService {
|
||||
public boolean isAnnuaireMembresActive() {
|
||||
// Lire depuis configuration_organisation
|
||||
return config != null && config.isAnnuaireMembresActif();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Modifier `MenuBean.isAnnuaireMembresVisible()`
|
||||
```java
|
||||
public boolean isAnnuaireMembresVisible() {
|
||||
// Toujours visible pour admins
|
||||
if (hasAnyRole("SUPER_ADMIN", "ADMIN_ORGANISATION", ...)) {
|
||||
return true;
|
||||
}
|
||||
// Pour MEMBRE_ACTIF: vérifier config
|
||||
if (hasAnyRole("MEMBRE_ACTIF")) {
|
||||
return configService.isAnnuaireMembresActive(); // false par défaut
|
||||
}
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
4. Créer page `/pages/secure/membre/annuaire.xhtml` (version simplifiée)
|
||||
- Pas de KPI
|
||||
- Pas d'actions administratives
|
||||
- Filtres limités (nom/prénom seulement)
|
||||
- Champs limités (pas d'email, pas d'adresse)
|
||||
|
||||
---
|
||||
|
||||
### Phase 4 : Révision Complète Menu (À implémenter)
|
||||
|
||||
Créer des menus 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 dynamiquement dans `main-template.xhtml` :
|
||||
```xml
|
||||
<c:choose>
|
||||
<c:when test="#{menuBean.membreActif and not menuBean.anyAdminRole}">
|
||||
<ui:include src="/templates/components/layout/menu-membre-actif.xhtml" />
|
||||
</c:when>
|
||||
<c:when test="#{menuBean.secretaire or menuBean.adminOrganisation}">
|
||||
<ui:include src="/templates/components/layout/menu-admin.xhtml" />
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<ui:include src="/templates/components/layout/menu.xhtml" />
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist de Validation
|
||||
|
||||
- [x] **Phase 1** : Menu "Annuaire des Membres" masqué pour MEMBRE_ACTIF
|
||||
- [x] **Phase 2** : Page liste.xhtml conditionnée selon le rôle
|
||||
- [x] KPI statistiques masqués pour MEMBRE_ACTIF
|
||||
- [x] Actions header masquées pour MEMBRE_ACTIF
|
||||
- [x] Actions groupées masquées pour MEMBRE_ACTIF
|
||||
- [x] Colonne checkbox masquée pour MEMBRE_ACTIF
|
||||
- [x] Actions DataTable conditionnées (Éditer, Suspendre, Réactiver)
|
||||
- [ ] **Phase 3** : Configuration optionnelle par organisation
|
||||
- [ ] **Phase 4** : Menus séparés par rôle
|
||||
|
||||
---
|
||||
|
||||
## Tests à Effectuer
|
||||
|
||||
### Test 1 : Utilisateur MEMBRE_ACTIF
|
||||
|
||||
1. Se connecter avec un compte **MEMBRE_ACTIF** (sans autre rôle)
|
||||
2. Vérifier menu :
|
||||
- [ ] "Annuaire des Membres" **n'apparaît PAS**
|
||||
- [ ] "Gestion des Membres" **n'apparaît PAS**
|
||||
- [ ] Menus personnels visibles (Mes Finances, Événements, etc.)
|
||||
3. Accéder directement à `/pages/secure/membre/liste.xhtml` (via URL)
|
||||
4. Vérifier page :
|
||||
- [ ] Pas de KPI statistiques en haut
|
||||
- [ ] Pas de bouton "Nouveau Membre"
|
||||
- [ ] Pas de bouton "Import / Export"
|
||||
- [ ] Pas de checkbox de sélection
|
||||
- [ ] Pas d'actions groupées
|
||||
- [ ] Bouton "Voir Profil" **visible**
|
||||
- [ ] Bouton "Éditer" **PAS visible**
|
||||
- [ ] Bouton "Contacter" **visible**
|
||||
- [ ] Bouton "Suspendre/Réactiver" **PAS visible**
|
||||
|
||||
### Test 2 : Utilisateur SECRETAIRE
|
||||
|
||||
1. Se connecter avec un compte **SECRETAIRE**
|
||||
2. Vérifier menu :
|
||||
- [ ] "Annuaire des Membres" **visible**
|
||||
- [ ] "Gestion des Membres" **visible**
|
||||
3. Accéder à `/pages/secure/membre/liste.xhtml`
|
||||
4. Vérifier page :
|
||||
- [ ] KPI statistiques **visibles**
|
||||
- [ ] Bouton "Nouveau Membre" **visible**
|
||||
- [ ] Bouton "Import / Export" **visible**
|
||||
- [ ] Checkbox de sélection **visible**
|
||||
- [ ] Actions groupées **visibles** (si sélection)
|
||||
- [ ] **Toutes** les actions DataTable **visibles**
|
||||
|
||||
### Test 3 : Utilisateur ADMIN_ORGANISATION
|
||||
|
||||
1. Se connecter avec un compte **ADMIN_ORGANISATION**
|
||||
2. Vérifier :
|
||||
- [ ] **Tous les éléments visibles** (comme SECRETAIRE)
|
||||
- [ ] Pas de restrictions
|
||||
|
||||
---
|
||||
|
||||
## Impact RGPD
|
||||
|
||||
**Avant** ❌ :
|
||||
- Tous les membres voyaient la liste complète (nom, email, téléphone, adresse potentiellement)
|
||||
- Exposition non justifiée de données personnelles
|
||||
|
||||
**Après** ✅ :
|
||||
- Seuls les **responsables autorisés** voient la liste complète
|
||||
- Conforme au principe de **minimisation** (RGPD Art. 5.1.c)
|
||||
- Conforme au principe de **limitation des finalités** (RGPD Art. 5.1.b)
|
||||
|
||||
---
|
||||
|
||||
## Contact
|
||||
|
||||
**Documentation** :
|
||||
- `docs/CHANGEMENTS_UX_MENU_APPLIQUES.md` (ce fichier)
|
||||
- `docs/UX_MENU_PAR_ROLE.md` (recommandations complètes)
|
||||
- `docs/KPI_DASHBOARD_PAR_ROLE.md` (matrice KPI)
|
||||
|
||||
**Code modifié** :
|
||||
- `MenuBean.java` (ligne 135)
|
||||
- `/pages/secure/membre/liste.xhtml` (lignes 32, 21-24, 130, 166, 234, 246, 255)
|
||||
Reference in New Issue
Block a user