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:
dahoud
2026-03-15 02:12:17 +00:00
parent bbc409de9d
commit e8ad874015
635 changed files with 58160 additions and 20674 deletions

View 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)