Les appels vers lions-user-manager nécessitent un token du realm lions-user-manager
(service account). OidcTokenPropagationHeadersFactory transmettait le token utilisateur
du realm unionflow → 401 systématique. AdminServiceTokenHeadersFactory injecte le bon
token via l'OIDC client admin-service.
- application-dev.properties : token.issuer utilise ${DEV_HOST:localhost} pour valider
les JWT émis par Keycloak via l'IP LAN (mobile physique sur réseau local)
- .env : DEV_HOST=192.168.1.13 — source unique côté backend, en sync avec
android/local.properties → dev.host côté mobile
- V24 : suppression des 8 tables fantômes issues des migrations pré-consolidation
(document, permission, favori, ticket, suggestion, suggestion_vote, configuration,
role_permission) — toutes vides, les entités JPA pointaient déjà vers les tables
plurielles correctes. Les contraintes uk_role_permission et uk_suggestion_vote
sont maintenant sur les vraies tables (roles_permissions, suggestion_votes).
ConversationResponse/MessageResponse fields (muted, pinned, archived,
edited, deleted) are primitive booleans — Lombok @Builder generates
.muted() not .isMuted(). Also use Boolean.TRUE.equals() for null-safe
unboxing from entity Boolean wrapper fields.
MembreDashboardServiceTest and OrganisationServiceTest used record
accessor syntax (e.g. result.nom()) on DTO classes that were converted
from records to @Data classes — now using getters (result.getNom()).
BUG-01: BudgetService.toResponse() — remplace doubleValue()>0 par
compareTo(BigDecimal.ZERO)>0 (précision BigDecimal) ; ajoute 2 tests
couvrant varianceRate=0 (totalPlanned=0) et varianceRate=-40%
AUTH: MembreKeycloakSyncService.changerMotDePassePremierLogin() — élargit
le catch de ForbiddenException vers WebApplicationException avec vérification
du statut HTTP (le REST client MicroProfile ne garantit pas la sous-classe)
DATA-01: MembreService.desactiverMembre() — décrémente nombreMembres sur
toutes les orgs actives du membre et passe le statutMembre à DESACTIVE
La colonne version était VARCHAR(20) au lieu de BIGINT, causant une erreur
Hibernate validate au démarrage. L'entité ModuleDisponible n'a pas de champ
version propre — la colonne était orpheline et conflicte avec BaseEntity @Version.
Fix idempotent : suppression VARCHAR + ajout BIGINT DEFAULT 0 (table vide).
- TypeReference: ajout des champs categorie et modulesRequis (colonnes DB existantes depuis V18
mais non mappées en JPA — Hibernate validate échouait silencieusement)
- OrganisationService.creerOrganisation(): lit types_reference.modules_requis pour initialiser
Organisation.modulesActifs, au lieu de dépendre uniquement du switch hardcodé dans
OrganisationModuleService.getModulesParType()
Avant: un type créé via CRUD (ex: TANTANPION) tombait dans le default du switch → aucun
module métier → rôles métier assignables mais menus jamais affichés.
Après: tout type avec modules_requis renseigné dans types_reference active correctement
ses modules à la création de l'organisation.
Hibernate validate mode in prod requires exact table names.
V1 used singular names (permission, document, suggestion, etc.)
but entities use plural names (permissions, documents, suggestions, etc.).
Hibernate update mode was masking this by auto-creating plural tables.
Renamed 23 tables to match entities.
- SystemAlert.onCreate() now calls super.onCreate() to set dateCreation (was null → NOT NULL violation every minute)
- V1: types_reference updated with full schema (domaine, est_defaut, est_systeme, ordre_affichage, modules_requis, organisation_id)
- V9: idempotent guard for categorie nullable ALTER (already nullable in updated V1)
14 fichiers de tests : rôles passés en majuscules dans @TestSecurity(roles={...})
pour correspondre exactement aux valeurs @RolesAllowed du backend.
Mapping : "admin"→"ADMIN", "admin_organisation"→"ADMIN_ORGANISATION",
"membre_actif"→"MEMBRE", "tontine_resp"→"TONTINE_RESP", etc.
Un rôle en minuscules produit un 403 silencieux sans erreur Quarkus.
MembreResource : activerAdhesion/suspendrAdhesion/radierAdhesion/archiverAdhesion
remplacent Map.of() par HashMap pour accepter dateChangementStatut null
(Map.of() lève NullPointerException sur valeur null → HTTP 500).
Sans @Column(name=...), Hibernate génère des noms camelCase (includedatabase)
alors que V16 a créé les colonnes en snake_case (include_database).
Alignement explicite avec les conventions des autres entités.
V4: system_logs colonnes niveau/stacktrace déjà renommées en prod
→ RENAME COLUMN enveloppé dans DO blocks IF EXISTS
V6: conversations/messages/conversation_participants existent déjà en prod
→ CREATE TABLE + CREATE INDEX → IF NOT EXISTS
- MembreKeycloakSyncService: completerPremierLogin retourne un enum PremierLoginResultat
(COMPLETE / REAUTH_REQUIS / NON_APPLICABLE) au lieu d'un boolean
- Détection automatique des anciens comptes (sans UPDATE_PASSWORD ni marqueur KC):
assigne UPDATE_PASSWORD + attribut premiere_password_pending dans Keycloak
et retourne REAUTH_REQUIS pour que Flutter re-déclenche AppAuth
- Détection du mot de passe changé: marqueur présent + UPDATE_PASSWORD absent → COMPLETE
- createUserDTOFromMembre: ajoute l'attribut premiere_password_pending=true à la création
- CompteAdherentResource.getMonStatut: retourne reAuthRequired=true quand REAUTH_REQUIS
formule_abonnement et souscription_organisation n'existent pas dans la DB
prod (nommées formules_abonnement/souscriptions_organisation dans l'ancien
schema). Remplacé par des DO blocks conditionnels (IF EXISTS).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- quarkus.flyway.ignore-migration-patterns=*:missing — migrations V1.2/V1.3
appliquées en DB mais absentes localement (après consolidation V1-V10)
- quarkus.log.file.enable=false — /var/log/unionflow/ absent dans le container
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implémente la sécurité au niveau Resource pour ADMIN_ORGANISATION :
les utilisateurs avec ce rôle ne peuvent gérer que les membres
de leurs organisations.
MembreService.java:
- Ajout listerMembresParOrganisations(orgIds, page, sort)
* Filtre membres par liste d'organisations avec JOIN
* Support pagination et tri
* Retourne liste vide si orgIds vide
- Ajout lierMembreOrganisationEtIncrementerQuota(membre, orgId, typeMembreDefaut)
* Crée MembreOrganisation avec statut ACTIF ou EN_ATTENTE_VALIDATION
* Incrémente quota si souscription active existe
* Gère statut selon typeMembreDefaut fourni
MembreResource.java:
- Injection OrganisationService + import Organisation entity
- GET /api/membres: sécurisé pour ADMIN_ORGANISATION
* ADMIN_ORGANISATION: filtre par ses organisations uniquement
* Utilise listerMembresParOrganisations()
* ADMIN/SUPER_ADMIN: accès complet (inchangé)
- POST /api/membres: sécurisé pour ADMIN_ORGANISATION
* @RolesAllowed: ADMIN, SUPER_ADMIN, ADMIN_ORGANISATION, MEMBRE
* ADMIN_ORGANISATION: require organisationId + validation accès
* Appelle lierMembreOrganisationEtIncrementerQuota()
* ADMIN/SUPER_ADMIN: fonctionnement inchangé
- POST /api/membres/import: sécurisé pour ADMIN_ORGANISATION
* ADMIN_ORGANISATION: require organisationId + validation accès
* Retourne 403 si tentative d'accès à org non autorisée
* Retourne 400 si organisationId manquant
Spec: admin-org-membres-import-quota.md
Critères acceptation: 8/8 ✅
- Filtrage liste membres par organisation
- Création membre avec organisationId obligatoire
- Import Excel avec orgId obligatoire
- Validation accès organisation
- Format Excel validé (déjà implémenté)
- Quota vérifié (déjà implémenté)
- Membres liés à org (déjà implémenté)
- Quota incrémenté (déjà implémenté)
Tâche: #56 - Implémenter Spec Admin Import Membres
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remplace les tests "placeholders" qui acceptaient anyOf(200, 500)
par des tests robustes avec assertions sur le contenu JSON.
Modifications:
- DashboardResourceTest: 6 → 8 tests avec setup de données réelles
* Ajout BeforeEach avec création Organisation + Membre de test
* Validation du contenu JSON (organizationId, stats, activities, events)
* Tests cas d'erreur (params manquants, UUIDs invalides)
- MembreDashboardResourceTest: 2 → 5 tests
* Tests ajustés pour fonctionner sans données seed
* Ajout test authentification (401)
* Tests 404 pour membre inexistant
- MembreDashboardServiceTest: ajusté pour absence de données seed
* Tests 404/NotFoundException au lieu d'attendre des données seed
- application-test.properties: fix wave.api.key/secret vides
* Valeurs factices pour éviter erreur config en tests
Résultat: 17 tests dashboard, 100% de réussite (0 erreurs, 0 échecs)
Tâche: #57 - Remplacer tests placeholders dashboard
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Corrections pour T027 (tests backend):
- Logger.getLogger(*.class) au lieu de *.java
- Builder pattern: setters pour champs BaseResponse hérités
Impact: Compilation 100% réussie, tests 1167/1168 passent
Signed-off-by: lions dev Team