- 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
5.8 KiB
5.8 KiB
Admin organisation : gestion des membres et import massif Excel avec quota
Contexte
- Un administrateur d’organisation (ADMIN_ORGANISATION) doit pouvoir gérer les membres de son organisation (liste, création unitaire, modification).
- Il doit pouvoir créer des membres en masse via un fichier Excel strictement formaté.
- Le nombre de créations doit être plafonné par le quota de la souscription (tranche/forme d’abonnement) de l’organisation.
Règles métier
-
Droits
- ADMIN_ORGANISATION : accès limité aux membres des organisations qu’il gère (liste, détail, création, mise à jour, import).
- ADMIN / SUPER_ADMIN : accès à tous les membres (comportement actuel).
-
Import massif
- Format : Excel (.xlsx) (et optionnellement CSV) avec colonnes obligatoires strictes (ex. nom, prénom, email, téléphone).
- organisationId obligatoire pour un org admin ; les membres créés sont rattachés à cette organisation (création de
MembreOrganisation). - Quota : avant d’accepter l’import, vérifier que
quota_utilise + nombre de nouveaux membres à créer ≤ quota_max
(ou pas de limite siquota_maxest null, ex. formule Crystal). - À chaque membre nouvellement créé (pas les mises à jour) : créer le lien
MembreOrganisationet incrémenterquota_utilisede la souscription. - Si le quota est dépassé en cours d’import : rejeter la requête (ou arrêter et retourner les erreurs selon le choix métier).
-
Souscription
- Une organisation (racine) a au plus une souscription active (
souscriptions_organisation). quota_max= snapshot de la formule (ex. 50 pour Starter, null pour Crystal).quota_utilise= nombre de membres comptabilisés pour cette souscription (incrémenté à chaque adhésion validée / membre créé dans l’org).
- Une organisation (racine) a au plus une souscription active (
Existant (WOU/DRY)
- Backend
MembreResource: GET list, GET /recherche, POST create, POST /import, GET /import/modele — existants ; à sécuriser et à scoper pour ADMIN_ORGANISATION.MembreImportExportService.importerMembres: import Excel/CSV existant ; prend déjàorganisationId; manque : création deMembreOrganisation, vérification et incrément du quota.- Entités :
SouscriptionOrganisation(quota_max, quota_utilise, incrementerQuota),FormuleAbonnement(max_membres),MembreOrganisation(lien membre–organisation).
- Mobile
- Annuaire membres : critères de recherche avec
organisationIds; pour org admin, passer les IDs de “mes organisations” (déjà possible côté app si l’API les filtre).
- Annuaire membres : critères de recherche avec
Implémentation préconisée
Backend
-
Sécurité et périmètre
- Sur
MembreResource: ajouter@RolesAllowedadaptés (ex. MEMBRE, ADMIN, ADMIN_ORGANISATION pour liste/création/import). - Pour un utilisateur avec rôle ADMIN_ORGANISATION (et sans ADMIN/SUPER_ADMIN) :
- Lister les organisations du membre connecté (ex.
OrganisationService.listerOrganisationsPourUtilisateur(email)). - Liste / recherche : filtrer les membres par ces
organisationIds(viaMembreOrganisation). - Création : exiger un
organisationIddans le corps (ou le déduire) et vérifier qu’il appartient à ses organisations ; créer leMembreOrganisationaprès création du membre. - Import : exiger
organisationIdet vérifier qu’il appartient à ses organisations ; appliquer la règle de quota et créer lesMembreOrganisation+ incrément de quota.
- Lister les organisations du membre connecté (ex.
- Sur
-
Quota et import
- Repository :
SouscriptionOrganisationRepositoryavecfindByOrganisationId(UUID)(souscription active si besoin). - Import (dans
MembreImportExportServiceou service appelant) :- Si
organisationId != null: charger la souscription active de l’organisation. - Pour chaque ligne du fichier : si c’est un nouveau membre (création, pas mise à jour) :
- Vérifier
souscription.getPlacesRestantes() > 0(ou pas de limite siquota_max == null). - Si dépassement : erreur explicite (ex. “Quota souscription atteint (max N membres)”) et arrêt ou rapport d’erreur.
- Après
creerMembre: créerMembreOrganisation(membre, organisation, statut, dateAdhesion), persister, puissouscription.incrementerQuota()et persister la souscription.
- Vérifier
- Si
- Repository :
-
Modèle Excel
- Conserver le modèle actuel (GET
/api/membres/import/modele) ; documenter les colonnes obligatoires et le fait que le fichier doit être strict (pas de colonnes en plus / types cohérents si besoin). - Optionnel : endpoint GET pour “quota actuel / places restantes” par organisation (pour affichage côté client).
- Conserver le modèle actuel (GET
Mobile (optionnel dans un second temps)
- Pour un org admin : envoyer en requête liste/recherche les
organisationIds(ses organisations) pour n’afficher que les membres de son périmètre. - Écran “Import membres” : choix de l’organisation (pré-rempli si une seule), upload du fichier Excel, affichage du quota restant (si l’API le fournit) et du résultat d’import (succès / erreurs).
Critères d’acceptation
- Un admin d’organisation ne voit que les membres de ses organisations (liste, recherche).
- Un admin d’organisation peut créer un membre dans une de ses organisations (et le lien MembreOrganisation est créé).
- Un admin d’organisation peut lancer un import Excel avec
organisationId; le fichier est validé (format strict), le quota souscription est vérifié avant/pendant l’import. - Les nouveaux membres créés lors de l’import sont rattachés à l’organisation et le quota souscription est incrémenté.
- Si le quota est dépassé (fichier trop gros ou quota déjà saturé), l’import est refusé ou s’arrête avec un message clair (quota max N, X demandés, etc.).