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,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