diff --git a/HANDOFF_COMPLET.md b/HANDOFF_COMPLET.md new file mode 100644 index 0000000..da949a7 --- /dev/null +++ b/HANDOFF_COMPLET.md @@ -0,0 +1,2626 @@ +# 🔄 HANDOFF COMPLET - LIONS-USER-MANAGER +## Document de Transfert pour Agent IA Successeur + +**Date**: 2025-11-09 +**Projet**: lions-user-manager - SystĂšme de gestion utilisateurs Keycloak +**Localisation**: C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager +**Progression globale**: 45% complĂ©tĂ© + +--- + +## 📋 TABLE DES MATIÈRES + +1. [Vue d'ensemble du projet](#1-vue-densemble-du-projet) +2. [État actuel dĂ©taillĂ©](#2-Ă©tat-actuel-dĂ©taillĂ©) +3. [Erreurs de compilation Ă  corriger](#3-erreurs-de-compilation-Ă -corriger) +4. [Architecture et dĂ©cisions techniques](#4-architecture-et-dĂ©cisions-techniques) +5. [Configuration Git](#5-configuration-git) +6. [TĂąches prioritaires](#6-tĂąches-prioritaires) +7. [TĂąches complĂštes restantes](#7-tĂąches-complĂštes-restantes) +8. [SpĂ©cifications techniques dĂ©taillĂ©es](#8-spĂ©cifications-techniques-dĂ©taillĂ©es) +9. [Commandes utiles](#9-commandes-utiles) + +--- + +## 1. VUE D'ENSEMBLE DU PROJET + +### 1.1 Objectif Principal +CrĂ©er un systĂšme complet de gestion des utilisateurs Keycloak avec: +- **Backend Quarkus**: API REST pour gĂ©rer users, rĂŽles, audit +- **Frontend PrimeFaces**: Interface JSF avec thĂšme Freya +- **Kubernetes ready**: DĂ©ploiement via Helm charts +- **CONTRAINTE CRITIQUE**: ZÉRO accĂšs direct Ă  la DB Keycloak, uniquement via Admin REST API + +### 1.2 Structure des Modules (Maven Multi-module) + +``` +lions-user-manager/ +├── pom.xml (parent) +├── lions-user-manager-server-api/ ✅ 100% COMPLÉTÉ +│ ├── src/main/java/dev/lions/user/manager/ +│ │ ├── dto/ +│ │ │ ├── base/BaseDTO.java +│ │ │ ├── user/UserDTO.java, UserSearchCriteriaDTO.java, UserSearchResultDTO.java +│ │ │ ├── role/RoleDTO.java, RoleAssignmentDTO.java +│ │ │ └── audit/AuditLogDTO.java +│ │ ├── enums/ +│ │ │ ├── user/StatutUser.java +│ │ │ ├── role/TypeRole.java +│ │ │ └── audit/TypeActionAudit.java +│ │ ├── service/ +│ │ │ ├── UserService.java (interface - 25+ mĂ©thodes) +│ │ │ ├── RoleService.java (interface - 20+ mĂ©thodes) +│ │ │ ├── AuditService.java (interface - 12+ mĂ©thodes) +│ │ │ └── SyncService.java (interface - 8+ mĂ©thodes) +│ │ └── validation/ValidationConstants.java +│ └── pom.xml +│ +├── lions-user-manager-server-impl-quarkus/ ⚠ 70% COMPLÉTÉ - ERREURS COMPILATION +│ ├── src/main/java/dev/lions/user/manager/ +│ │ ├── client/ +│ │ │ ├── KeycloakAdminClient.java ✅ OK +│ │ │ └── KeycloakAdminClientImpl.java ✅ OK (Circuit Breaker, Retry, Timeout) +│ │ ├── mapper/ +│ │ │ ├── UserMapper.java ✅ OK +│ │ │ └── RoleMapper.java ❌ ERREURS (name vs nom) +│ │ ├── service/impl/ +│ │ │ ├── UserServiceImpl.java ✅ OK +│ │ │ ├── RoleServiceImpl.java ❌ ERREURS (signatures mĂ©thodes) +│ │ │ ├── AuditServiceImpl.java ❌ ERREURS (signatures mĂ©thodes) +│ │ │ └── SyncServiceImpl.java ❌ ERREURS (signatures mĂ©thodes) +│ │ ├── resource/ +│ │ │ ├── UserResource.java ✅ OK +│ │ │ ├── RoleResource.java ❌ ERREURS +│ │ │ ├── AuditResource.java ❌ ERREURS +│ │ │ ├── SyncResource.java ❌ ERREURS +│ │ │ ├── KeycloakHealthCheck.java ✅ OK +│ │ │ └── HealthResourceEndpoint.java ✅ OK +│ │ └── src/main/resources/ +│ │ ├── application.properties ✅ OK +│ │ ├── application-dev.properties ✅ OK +│ │ └── application-prod.properties ✅ OK +│ └── pom.xml +│ +├── lions-user-manager-client-quarkus-primefaces-freya/ ⏳ 0% - PAS COMMENCÉ +│ └── pom.xml (structure de base seulement) +│ +├── README.md ✅ CRÉÉ +├── PROGRESS_REPORT.md ✅ CRÉÉ +├── HANDOFF_COMPLET.md ✅ CE FICHIER +└── .gitignore ✅ CRÉÉ +``` + +### 1.3 Technologies Stack + +**Backend**: +- Quarkus 3.15.1 +- Keycloak Admin Client 23.0.3 (avec exclusions RESTEasy) +- SmallRye Fault Tolerance (Circuit Breaker, Retry, Timeout) +- MicroProfile OpenAPI +- Jakarta EE (Validation, Inject, REST) +- Lombok 1.18.30 +- MapStruct 1.5.5.Final (pas encore utilisĂ©) + +**Frontend** (Ă  implĂ©menter): +- PrimeFaces 14.0.5 +- Freya Theme 5.0.0-jakarta (depuis git.lions.dev/lionsdev/btpxpress-maven-repo) +- JSF (Jakarta Faces) +- MicroProfile Rest Client + +**Tests** (Ă  implĂ©menter): +- JUnit 5 +- Testcontainers 1.19.3 (Keycloak, PostgreSQL) +- RestAssured +- Jacoco (objectif 80% coverage) + +--- + +## 2. ÉTAT ACTUEL DÉTAILLÉ + +### 2.1 Fichiers Créés et Fonctionnels ✅ + +#### Module server-api (15 fichiers - 100% OK) +``` +lions-user-manager-server-api/src/main/java/dev/lions/user/manager/ +├── dto/ +│ ├── base/BaseDTO.java [FONCTIONNEL] +│ ├── user/ +│ │ ├── UserDTO.java [FONCTIONNEL - 60+ champs] +│ │ ├── UserSearchCriteriaDTO.java [FONCTIONNEL] +│ │ └── UserSearchResultDTO.java [FONCTIONNEL] +│ ├── role/ +│ │ ├── RoleDTO.java [FONCTIONNEL - champ: name] +│ │ └── RoleAssignmentDTO.java [FONCTIONNEL] +│ └── audit/ +│ └── AuditLogDTO.java [FONCTIONNEL] +├── enums/ +│ ├── user/StatutUser.java [FONCTIONNEL - 7 Ă©tats] +│ ├── role/TypeRole.java [FONCTIONNEL] +│ └── audit/TypeActionAudit.java [FONCTIONNEL - 15+ actions] +├── service/ +│ ├── UserService.java [INTERFACE OK] +│ ├── RoleService.java [INTERFACE OK] +│ ├── AuditService.java [INTERFACE OK] +│ └── SyncService.java [INTERFACE OK] +└── validation/ValidationConstants.java [FONCTIONNEL] +``` + +#### Module server-impl (7 fichiers fonctionnels, 6 avec erreurs) + +**Fichiers 100% fonctionnels**: +1. `KeycloakAdminClient.java` - Interface +2. `KeycloakAdminClientImpl.java` - ImplĂ©mentation avec rĂ©silience +3. `UserMapper.java` - Conversions UserDTO <-> Keycloak +4. `UserServiceImpl.java` - Service utilisateurs (25+ mĂ©thodes) +5. `UserResource.java` - REST API users (12 endpoints) +6. `KeycloakHealthCheck.java` - Health check Keycloak +7. `HealthResourceEndpoint.java` - Endpoint health + +**Fichiers avec erreurs de compilation**: +1. `RoleMapper.java` - Utilise getNom() au lieu de getName() +2. `RoleServiceImpl.java` - Signatures mĂ©thodes incompatibles avec interface +3. `AuditServiceImpl.java` - MĂ©thodes pas dans l'interface +4. `SyncServiceImpl.java` - MĂ©thodes incompatibles +5. `RoleResource.java` - Appelle mĂ©thodes inexistantes +6. `AuditResource.java` - Appelle mĂ©thodes inexistantes +7. `SyncResource.java` - Probablement OK mais dĂ©pend de SyncServiceImpl + +### 2.2 Configuration Git ✅ + +**4 repositories configurĂ©s**: +1. **master**: https://git.lions.dev/lionsdev/lions-user-manager.git +2. **server-api**: https://git.lions.dev/lionsdev/lions-user-manager-server-api.git +3. **server-impl**: https://git.lions.dev/lionsdev/lions-user-manager-server-impl-quarkus.git +4. **client**: https://git.lions.dev/lionsdev/lions-user-manager-client-quarkus-primefaces-freya.git + +**Credentials Git**: +- Username: `lionsdev` +- Password: `lions@2025` +- Format URL: `https://lionsdev:lions%402025@git.lions.dev/...` + +**Structure Git actuelle**: +- ✅ Chaque sous-module a son propre repository Git avec UNIQUEMENT son code +- ✅ Le repository master contient tout le projet +- ✅ Tous les repos sont sur la branche `main` +- ✅ Derniers commits effectuĂ©s et pushĂ©s + +--- + +## 3. ERREURS DE COMPILATION À CORRIGER + +### 3.1 Erreurs Critiques (bloquent la compilation) + +#### Erreur #1: RoleDTO - IncohĂ©rence nom du champ +**Fichier**: `RoleDTO.java` ligne 38 +**ProblĂšme**: Le champ s'appelle `name` et non `nom` +```java +// RoleDTO.java:38 +private String name; // ✅ CORRECT dans le DTO +``` + +**Fichiers utilisant incorrectement `getNom()`**: +- `RoleMapper.java` lignes 25, 43 +- `RoleServiceImpl.java` lignes 170, 179 +- `RoleResource.java` lignes 56 + +**Solution**: Remplacer tous les `getNom()` par `getName()` et `setNom()` par `setName()` + +#### Erreur #2: RoleMapper - Mauvaise propriĂ©tĂ© dans builder +**Fichier**: `RoleMapper.java` ligne 25 +**Code actuel**: +```java +.nom(roleRep.getName()) // ❌ ERREUR +``` +**Correction**: +```java +.name(roleRep.getName()) // ✅ CORRECT +``` + +#### Erreur #3: RoleMapper - Test null incorrect +**Fichier**: `RoleMapper.java` ligne 29 +**Code actuel**: +```java +.composite(roleRep.isComposite() != null ? roleRep.isComposite() : false) // ❌ ERREUR +``` +**ProblĂšme**: `isComposite()` retourne `boolean`, pas `Boolean` +**Correction**: +```java +.composite(roleRep.isComposite()) // ✅ CORRECT +``` + +#### Erreur #4: RoleServiceImpl - Signatures incompatibles avec interface + +**Interface RoleService attend**: +```java +// RoleService.java +List getAllClientRoles(@NotBlank String realmName, @NotBlank String clientName); +Optional getRoleByName(@NotBlank String roleName, @NotBlank String realmName, + @NotNull TypeRole typeRole, String clientName); +RoleDTO createClientRole(@Valid @NotNull RoleDTO role, @NotBlank String realmName, + @NotBlank String clientName); +RoleDTO updateRole(@NotBlank String roleId, @Valid @NotNull RoleDTO role, + @NotBlank String realmName, @NotNull TypeRole typeRole, String clientName); +void deleteRole(@NotBlank String roleId, @NotBlank String realmName, + @NotNull TypeRole typeRole, String clientName); +// ... et beaucoup d'autres mĂ©thodes diffĂ©rentes +``` + +**RoleServiceImpl implĂ©mente**: +```java +// RoleServiceImpl.java - SIGNATURES DIFFÉRENTES +Optional getRealmRoleByName(String roleName, String realmName); // ❌ Pas dans interface +RoleDTO updateRealmRole(String roleName, RoleDTO roleDTO, String realmName); // ❌ Pas dans interface +void deleteRealmRole(String roleName, String realmName); // ❌ Pas dans interface +List getAllClientRoles(String clientId, String realmName); // ❌ Ordre paramĂštres inversĂ© +// ... etc +``` + +**SOLUTION RECOMMANDÉE**: +Deux options: +1. **Option A** (RECOMMANDÉE): Modifier `RoleServiceImpl` pour implĂ©menter EXACTEMENT les mĂ©thodes de l'interface +2. **Option B**: Modifier l'interface `RoleService.java` pour correspondre Ă  l'implĂ©mentation (moins propre) + +#### Erreur #5: AuditService - MĂ©thodes manquantes dans l'interface + +**AuditServiceImpl utilise**: +```java +List searchLogs(String acteur, LocalDateTime debut, LocalDateTime fin, + TypeActionAudit type, String ressourceType, Boolean succes, + int page, int pageSize); +List getLogsByActeur(String acteur, int limit); +List getLogsByRessource(String type, String id, int limit); +Map getActionStatistics(LocalDateTime debut, LocalDateTime fin); +long getFailureCount(LocalDateTime debut, LocalDateTime fin); +// ... etc +``` + +**Mais l'interface AuditService.java ne dĂ©clare pas toutes ces mĂ©thodes!** + +**SOLUTION**: Ajouter toutes les mĂ©thodes manquantes dans `AuditService.java` + +#### Erreur #6: SyncServiceImpl - Classes internes pas exportĂ©es + +**Fichier**: `SyncServiceImpl.java` +**ProblĂšme**: Classes internes `SyncResult` et `HealthStatus` utilisĂ©es dans l'interface mais non visibles + +**SOLUTION**: +1. Soit dĂ©placer ces classes dans le module `server-api` comme DTOs sĂ©parĂ©s +2. Soit les garder dans l'implĂ©mentation et crĂ©er des interfaces dans `server-api` + +#### Erreur #7: RoleResource - Appels Ă  mĂ©thodes inexistantes + +**Fichier**: `RoleResource.java` +**Lignes avec erreurs**: 91, 146, 172, 237, 292, 321, 348, 377, 457, 482 + +**Exemple ligne 91**: +```java +return roleService.getRealmRoleByName(roleName, realmName) // ❌ MĂ©thode n'existe pas +``` + +**SOLUTION**: Utiliser les mĂ©thodes correctes de l'interface aprĂšs correction de RoleService + +#### Erreur #8: Conversion Set vers List + +**Fichier**: `RoleServiceImpl.java` ligne 539 +**Code actuel**: +```java +List composites = roleResource.getRoleComposites(); // ❌ Retourne Set +``` +**Correction**: +```java +List composites = new ArrayList<>(roleResource.getRoleComposites()); +``` + +### 3.2 Plan de Correction Étape par Étape + +**ÉTAPE 1: Corriger RoleMapper** (5 minutes) +```bash +# Fichier: lions-user-manager-server-impl-quarkus/src/main/java/dev/lions/user/manager/mapper/RoleMapper.java +# Ligne 25: .nom(roleRep.getName()) → .name(roleRep.getName()) +# Ligne 29: roleRep.isComposite() != null ? ... → roleRep.isComposite() +# Ligne 43: roleDTO.getNom() → roleDTO.getName() +``` + +**ÉTAPE 2: Aligner RoleService et RoleServiceImpl** (30 minutes) +Deux sous-options: + +**Option 2A** (RECOMMANDÉE): Simplifier l'interface RoleService +```java +// Nouvelle interface simplifiĂ©e dans server-api/service/RoleService.java +public interface RoleService { + // CRUD Realm Roles + RoleDTO createRealmRole(RoleDTO roleDTO, String realmName); + Optional getRealmRoleById(String roleId, String realmName); + Optional getRealmRoleByName(String roleName, String realmName); + RoleDTO updateRealmRole(String roleName, RoleDTO roleDTO, String realmName); + void deleteRealmRole(String roleName, String realmName); + List getAllRealmRoles(String realmName); + + // CRUD Client Roles + RoleDTO createClientRole(RoleDTO roleDTO, String clientId, String realmName); + Optional getClientRoleByName(String roleName, String clientId, String realmName); + void deleteClientRole(String roleName, String clientId, String realmName); + List getAllClientRoles(String clientId, String realmName); + + // Attribution de rĂŽles + void assignRealmRolesToUser(String userId, List roleNames, String realmName); + void revokeRealmRolesFromUser(String userId, List roleNames, String realmName); + void assignClientRolesToUser(String userId, String clientId, List roleNames, String realmName); + void revokeClientRolesFromUser(String userId, String clientId, List roleNames, String realmName); + List getUserRealmRoles(String userId, String realmName); + List getUserClientRoles(String userId, String clientId, String realmName); + + // RĂŽles composites + void addCompositesToRealmRole(String roleName, List compositeRoleNames, String realmName); + void removeCompositesFromRealmRole(String roleName, List compositeRoleNames, String realmName); + List getCompositeRoles(String roleName, String realmName); + + // VĂ©rification permissions + boolean userHasRealmRole(String userId, String roleName, String realmName); + boolean userHasClientRole(String userId, String clientId, String roleName, String realmName); + List getUserEffectiveRealmRoles(String userId, String realmName); +} +``` + +**Option 2B**: Modifier RoleServiceImpl pour correspondre Ă  l'interface actuelle (plus de travail) + +**ÉTAPE 3: ComplĂ©ter AuditService.java** (10 minutes) +```java +// Ajouter dans server-api/service/AuditService.java +List searchLogs(String acteurUsername, LocalDateTime dateDebut, LocalDateTime dateFin, + TypeActionAudit typeAction, String ressourceType, Boolean succes, + int page, int pageSize); +List getLogsByActeur(String acteurUsername, int limit); +List getLogsByRessource(String ressourceType, String ressourceId, int limit); +List getLogsByAction(TypeActionAudit typeAction, LocalDateTime dateDebut, + LocalDateTime dateFin, int limit); +Map getActionStatistics(LocalDateTime dateDebut, LocalDateTime dateFin); +Map getUserActivityStatistics(LocalDateTime dateDebut, LocalDateTime dateFin); +long getFailureCount(LocalDateTime dateDebut, LocalDateTime dateFin); +long getSuccessCount(LocalDateTime dateDebut, LocalDateTime dateFin); +List exportLogsToCSV(LocalDateTime dateDebut, LocalDateTime dateFin); +void purgeOldLogs(int joursDAnciennete); +``` + +**ÉTAPE 4: CrĂ©er DTOs pour Sync** (15 minutes) +```bash +# CrĂ©er: server-api/dto/sync/SyncResultDTO.java +# CrĂ©er: server-api/dto/sync/HealthStatusDTO.java +# Modifier SyncService.java pour utiliser ces DTOs +# Modifier SyncServiceImpl.java pour retourner ces DTOs +``` + +**ÉTAPE 5: Corriger RoleServiceImpl ligne 539** (2 minutes) +```java +List composites = new ArrayList<>( + keycloakAdminClient.getInstance() + .realm(realmName) + .roles() + .get(roleName) + .getRoleComposites() +); +``` + +**ÉTAPE 6: Compiler et vĂ©rifier** (5 minutes) +```bash +cd C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager +mvn clean compile -DskipTests +``` + +--- + +## 4. ARCHITECTURE ET DÉCISIONS TECHNIQUES + +### 4.1 DĂ©cisions Architecturales ClĂ©s + +#### A. Pattern Circuit Breaker + Retry +**Localisation**: `KeycloakAdminClientImpl.java` +**Raison**: Keycloak peut ĂȘtre temporairement indisponible +**Configuration**: +```java +@Retry(maxRetries = 3, delay = 2, delayUnit = ChronoUnit.SECONDS) +@Timeout(value = 30, unit = ChronoUnit.SECONDS) +@CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 5000) +``` + +#### B. Exclusion RESTEasy Classic +**Localisation**: `server-impl/pom.xml` +**ProblĂšme rĂ©solu**: "Mixing Quarkus REST and RESTEasy Classic" +**Solution**: +```xml + + org.keycloak + keycloak-admin-client + 23.0.3 + + + org.jboss.resteasy + resteasy-client + + + org.jboss.resteasy + resteasy-multipart-provider + + + org.jboss.resteasy + resteasy-jackson2-provider + + + +``` + +#### C. Audit Logging - En MĂ©moire pour Dev +**Localisation**: `AuditServiceImpl.java` +**État actuel**: Stockage en mĂ©moire via ConcurrentHashMap +**TODO Production**: ImplĂ©menter persistence PostgreSQL avec Panache +**Logging parallĂšle**: SLF4J pour capture par systĂšmes centralisĂ©s (Graylog, ELK) + +#### D. Mappers - Statiques vs MapStruct +**État actuel**: MĂ©thodes statiques dans UserMapper et RoleMapper +**DĂ©cision**: Pas encore utilisĂ© MapStruct (dĂ©pendance prĂ©sente mais pas configurĂ©e) +**TODO**: Migrer vers MapStruct pour gĂ©nĂ©ration automatique + +#### E. SĂ©paration Dev/Prod +**Fichiers**: +- `application.properties` - Configuration de base +- `application-dev.properties` - Localhost, DEBUG logs +- `application-prod.properties` - HTTPS, DB obligatoire, SSL/TLS + +**Activation**: +```bash +# Dev +mvn quarkus:dev -Dquarkus.profile=dev + +# Prod +java -jar app.jar -Dquarkus.profile=prod +``` + +### 4.2 Contraintes Critiques du Projet + +1. **ZÉRO accĂšs direct DB Keycloak** - Utiliser UNIQUEMENT Keycloak Admin REST API +2. **Multi-realm support** - Toutes les opĂ©rations prennent `realmName` en paramĂštre +3. **Audit trail complet** - Qui, quoi, quand, IP, succĂšs/Ă©chec pour TOUTES les opĂ©rations +4. **Test coverage 80%** - Objectif Jacoco avec Testcontainers +5. **Helm charts requis** - DĂ©ploiement Kubernetes +6. **Freya theme custom** - Depuis repository Git lions.dev + +### 4.3 Patterns de Code UtilisĂ©s + +#### Pattern DTO +```java +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UserDTO extends BaseDTO { + // ... +} +``` + +#### Pattern Service/Resource +``` +Service Interface (server-api) + ↓ implĂ©mente +Service Implementation (server-impl) + ↓ injectĂ© dans +REST Resource (server-impl) + ↓ expose +API REST OpenAPI +``` + +#### Pattern Mapper +```java +public class UserMapper { + public static UserDTO toDTO(UserRepresentation keycloakUser, String realmName) { } + public static UserRepresentation toRepresentation(UserDTO userDTO) { } + public static List toDTOList(...) { } +} +``` + +--- + +## 5. CONFIGURATION GIT + +### 5.1 Structure Multi-Repository + +``` +Repository Master (contient TOUT) +https://git.lions.dev/lionsdev/lions-user-manager.git +└── C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\ + +Repository Server-API (contient UNIQUEMENT server-api) +https://git.lions.dev/lionsdev/lions-user-manager-server-api.git +└── C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-api\ + +Repository Server-Impl (contient UNIQUEMENT server-impl) +https://git.lions.dev/lionsdev/lions-user-manager-server-impl-quarkus.git +└── C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-server-impl-quarkus\ + +Repository Client (contient UNIQUEMENT client) +https://git.lions.dev/lionsdev/lions-user-manager-client-quarkus-primefaces-freya.git +└── C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager\lions-user-manager-client-quarkus-primefaces-freya\ +``` + +### 5.2 Commandes Git ConfigurĂ©es + +**Credentials**: +- Username: `lionsdev` +- Password: `lions@2025` (encoder en URL: `lions%402025`) + +**Push vers tous les repos depuis la racine**: +```bash +cd C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager + +# Commit dans le repo racine +git add . +git commit -m "feat: Description du commit" +git push origin main +``` + +**Push d'un sous-module spĂ©cifique**: +```bash +# Server-API +cd lions-user-manager-server-api +git add . +git commit -m "feat: Description" +git push origin main + +# Server-Impl +cd ../lions-user-manager-server-impl-quarkus +git add . +git commit -m "feat: Description" +git push origin main + +# Client +cd ../lions-user-manager-client-quarkus-primefaces-freya +git add . +git commit -m "feat: Description" +git push origin main +``` + +**RĂšgle de synchronisation**: +Le repository master doit TOUJOURS ĂȘtre mis Ă  jour APRÈS au moins un des repos enfants. + +### 5.3 Branches + +Toutes les branches sont sur `main` (pas `master`). + +--- + +## 6. TÂCHES PRIORITAIRES + +### PrioritĂ© 1: Corriger les erreurs de compilation (2-3 heures) + +**Objectif**: Faire compiler le projet sans erreurs + +**Étapes**: +1. ✅ Corriger RoleMapper (name vs nom) +2. ✅ Aligner RoleService interface et implĂ©mentation +3. ✅ ComplĂ©ter AuditService interface +4. ✅ CrĂ©er DTOs pour SyncService +5. ✅ Corriger RoleServiceImpl Set→List +6. ✅ VĂ©rifier compilation: `mvn clean compile -DskipTests` +7. ✅ Commit et push + +**Commande de vĂ©rification**: +```bash +cd C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager +mvn clean compile -DskipTests 2>&1 | grep -i "BUILD SUCCESS" +``` + +### PrioritĂ© 2: CrĂ©er les tests unitaires de base (3-4 heures) + +**Objectif**: Atteindre 30% de coverage minimum + +**Fichiers Ă  crĂ©er**: +``` +server-impl/src/test/java/dev/lions/user/manager/ +├── service/impl/ +│ ├── UserServiceImplTest.java +│ ├── RoleServiceImplTest.java +│ ├── AuditServiceImplTest.java +│ └── SyncServiceImplTest.java +├── mapper/ +│ ├── UserMapperTest.java +│ └── RoleMapperTest.java +└── resource/ + ├── UserResourceTest.java + ├── RoleResourceTest.java + ├── AuditResourceTest.java + └── SyncResourceTest.java +``` + +**Exemple de test**: +```java +@QuarkusTest +public class UserServiceImplTest { + + @InjectMock + KeycloakAdminClient keycloakAdminClient; + + @Inject + UserService userService; + + @Test + void testCreateUser() { + // Given + UserDTO userDTO = UserDTO.builder() + .username("testuser") + .email("test@example.com") + .build(); + + // Mock Keycloak + when(keycloakAdminClient.getInstance()...) + .thenReturn(...); + + // When + UserDTO created = userService.createUser(userDTO, "test-realm"); + + // Then + assertNotNull(created.getId()); + assertEquals("testuser", created.getUsername()); + } +} +``` + +### PrioritĂ© 3: CrĂ©er les tests d'intĂ©gration avec Testcontainers (4-6 heures) + +**Objectif**: Tests rĂ©els contre Keycloak en Docker + +**Fichiers Ă  crĂ©er**: +``` +server-impl/src/test/java/dev/lions/user/manager/integration/ +├── KeycloakTestResource.java (configure Testcontainer) +├── UserServiceIntegrationTest.java +├── RoleServiceIntegrationTest.java +└── AuditServiceIntegrationTest.java +``` + +**Configuration Testcontainer**: +```java +@QuarkusTestResource(KeycloakTestResource.class) +@QuarkusTest +public class UserServiceIntegrationTest { + + public static class KeycloakTestResource implements QuarkusTestResourceLifecycleManager { + + private static final KeycloakContainer keycloak = new KeycloakContainer() + .withRealmImportFile("test-realm.json"); + + @Override + public Map start() { + keycloak.start(); + return Map.of( + "lions.keycloak.server-url", keycloak.getAuthServerUrl(), + "lions.keycloak.admin-username", "admin", + "lions.keycloak.admin-password", "admin" + ); + } + + @Override + public void stop() { + keycloak.stop(); + } + } + + @Inject + UserService userService; + + @Test + void testCreateUserInRealKeycloak() { + // Test contre un vrai Keycloak dans Docker + UserDTO user = userService.createUser(...); + assertNotNull(user.getId()); + } +} +``` + +### PrioritĂ© 4: Commencer le module client (8-12 heures) + +**Objectif**: Interface utilisateur fonctionnelle de base + +Voir section 7.4 pour les dĂ©tails complets. + +--- + +## 7. TÂCHES COMPLÈTES RESTANTES + +### 7.1 Backend - Services Restants + +#### A. ImplĂ©menter Persistence Audit (PostgreSQL) + +**Actuellement**: Stockage en mĂ©moire dans `AuditServiceImpl` +**À faire**: Persistence PostgreSQL avec Panache + +**Étapes**: + +1. **CrĂ©er l'entitĂ© Panache**: +```java +// server-impl/src/main/java/dev/lions/user/manager/entity/AuditLogEntity.java +@Entity +@Table(name = "audit_log", indexes = { + @Index(name = "idx_audit_acteur", columnList = "acteur_username"), + @Index(name = "idx_audit_date", columnList = "date_action"), + @Index(name = "idx_audit_ressource", columnList = "ressource_type, ressource_id") +}) +public class AuditLogEntity extends PanacheEntityBase { + + @Id + @Column(length = 36) + public String id; + + @Column(name = "date_action", nullable = false) + public LocalDateTime dateAction; + + @Column(name = "acteur_username", length = 100, nullable = false) + public String acteurUsername; + + @Enumerated(EnumType.STRING) + @Column(name = "type_action", length = 50, nullable = false) + public TypeActionAudit typeAction; + + @Column(name = "ressource_type", length = 50, nullable = false) + public String ressourceType; + + @Column(name = "ressource_id", length = 100, nullable = false) + public String ressourceId; + + @Column(name = "succes", nullable = false) + public boolean succes; + + @Column(name = "adresse_ip", length = 45) + public String adresseIp; + + @Column(name = "details", length = 1000) + public String details; + + @Column(name = "message_erreur", length = 500) + public String messageErreur; + + @Column(name = "donnees_avant", columnDefinition = "TEXT") + public String donneesAvant; + + @Column(name = "donnees_apres", columnDefinition = "TEXT") + public String donneesApres; +} +``` + +2. **CrĂ©er le mapper entitĂ©**: +```java +// server-impl/.../mapper/AuditLogMapper.java +public class AuditLogMapper { + public static AuditLogEntity toEntity(AuditLogDTO dto) { } + public static AuditLogDTO toDTO(AuditLogEntity entity) { } +} +``` + +3. **CrĂ©er le repository Panache**: +```java +// server-impl/.../repository/AuditLogRepository.java +@ApplicationScoped +public class AuditLogRepository implements PanacheRepository { + + public List findByActeur(String username, int limit) { + return find("acteurUsername = ?1 ORDER BY dateAction DESC", username) + .page(0, limit).list(); + } + + public List searchLogs(String acteur, LocalDateTime debut, + LocalDateTime fin, ...) { + // Query complexe avec critĂšres dynamiques + } + + public long countFailures(LocalDateTime debut, LocalDateTime fin) { + return count("succes = false AND dateAction BETWEEN ?1 AND ?2", debut, fin); + } + + @Transactional + public void purgeOldLogs(LocalDateTime before) { + delete("dateAction < ?1", before); + } +} +``` + +4. **Modifier AuditServiceImpl**: +```java +@ApplicationScoped +@Slf4j +public class AuditServiceImpl implements AuditService { + + @Inject + AuditLogRepository repository; + + @ConfigProperty(name = "lions.audit.log-to-database", defaultValue = "false") + boolean logToDatabase; + + @Override + @Transactional + public AuditLogDTO logAction(@Valid @NotNull AuditLogDTO auditLog) { + // Log SLF4J + log.info("AUDIT | ..."); + + // Persister en DB si activĂ© + if (logToDatabase) { + AuditLogEntity entity = AuditLogMapper.toEntity(auditLog); + repository.persist(entity); + } + + return auditLog; + } + + // Modifier toutes les mĂ©thodes pour utiliser repository au lieu de Map +} +``` + +5. **CrĂ©er migration Flyway**: +```sql +-- server-impl/src/main/resources/db/migration/V1.0.0__create_audit_log.sql +CREATE TABLE audit_log ( + id VARCHAR(36) PRIMARY KEY, + date_action TIMESTAMP NOT NULL, + acteur_username VARCHAR(100) NOT NULL, + type_action VARCHAR(50) NOT NULL, + ressource_type VARCHAR(50) NOT NULL, + ressource_id VARCHAR(100) NOT NULL, + succes BOOLEAN NOT NULL, + adresse_ip VARCHAR(45), + details VARCHAR(1000), + message_erreur VARCHAR(500), + donnees_avant TEXT, + donnees_apres TEXT +); + +CREATE INDEX idx_audit_acteur ON audit_log(acteur_username); +CREATE INDEX idx_audit_date ON audit_log(date_action); +CREATE INDEX idx_audit_ressource ON audit_log(ressource_type, ressource_id); +CREATE INDEX idx_audit_type_action ON audit_log(type_action); +``` + +6. **Configurer datasource**: +```properties +# application-prod.properties +quarkus.datasource.db-kind=postgresql +quarkus.datasource.username=${DB_USERNAME:audit_user} +quarkus.datasource.password=${DB_PASSWORD:audit_password} +quarkus.datasource.jdbc.url=jdbc:postgresql://${DB_HOST:localhost}:${DB_PORT:5432}/${DB_NAME:lions_audit} + +quarkus.hibernate-orm.database.generation=none +quarkus.flyway.migrate-at-start=true + +lions.audit.log-to-database=true +``` + +#### B. Ajouter MapStruct pour Mappers + +**Actuellement**: Mappers manuels avec mĂ©thodes statiques +**À faire**: Utiliser MapStruct pour gĂ©nĂ©ration automatique + +**Étapes**: + +1. **Configurer annotation processor dans POM**: +```xml + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + +``` + +2. **CrĂ©er mapper UserMapper avec MapStruct**: +```java +@Mapper(componentModel = "cdi") +public interface UserMapper { + + @Mapping(source = "id", target = "id") + @Mapping(source = "username", target = "username") + @Mapping(source = "email", target = "email") + @Mapping(source = "enabled", target = "statut", qualifiedByName = "enabledToStatut") + UserDTO toDTO(UserRepresentation userRep, @Context String realmName); + + @Mapping(source = "username", target = "username") + @Mapping(source = "email", target = "email") + @Mapping(source = "statut", target = "enabled", qualifiedByName = "statutToEnabled") + UserRepresentation toRepresentation(UserDTO userDTO); + + @Named("enabledToStatut") + default StatutUser enabledToStatut(Boolean enabled) { + return StatutUser.fromEnabled(enabled != null ? enabled : false); + } + + @Named("statutToEnabled") + default Boolean statutToEnabled(StatutUser statut) { + return statut != null && statut.peutSeConnecter(); + } +} +``` + +#### C. ImplĂ©menter Cache avec Quarkus Cache + +**Objectif**: Cache des rĂŽles et users pour rĂ©duire appels Keycloak + +**Étapes**: + +1. **Ajouter dĂ©pendance**: +```xml + + io.quarkus + quarkus-cache + +``` + +2. **Annoter mĂ©thodes**: +```java +@ApplicationScoped +public class RoleServiceImpl implements RoleService { + + @CacheResult(cacheName = "realm-roles") + public List getAllRealmRoles(@NotBlank String realmName) { + // Appel Keycloak + } + + @CacheInvalidate(cacheName = "realm-roles") + public RoleDTO createRealmRole(RoleDTO roleDTO, String realmName) { + // CrĂ©ation role + } +} +``` + +3. **Configurer cache**: +```properties +quarkus.cache.caffeine.realm-roles.expire-after-write=5M +quarkus.cache.caffeine.client-roles.expire-after-write=5M +quarkus.cache.caffeine.users.expire-after-write=2M +``` + +### 7.2 Backend - SĂ©curitĂ© et Validation + +#### A. ImplĂ©menter OIDC Authentication + +**Objectif**: SĂ©curiser les endpoints REST avec Keycloak OIDC + +**Configuration dĂ©jĂ  prĂ©sente** dans `application.properties`: +```properties +quarkus.oidc.auth-server-url=${KEYCLOAK_URL:http://localhost:8180}/realms/master +quarkus.oidc.client-id=${KEYCLOAK_CLIENT_ID:lions-user-manager} +quarkus.oidc.credentials.secret=${KEYCLOAK_CLIENT_SECRET:secret} +``` + +**À faire**: + +1. **Tester avec vrai Keycloak** +2. **Ajouter JWT claims mapping**: +```java +@ApplicationScoped +public class UserIdentityProvider { + + @Inject + JsonWebToken jwt; + + public String getCurrentUsername() { + return jwt.getName(); + } + + public String getCurrentUserEmail() { + return jwt.getClaim("email"); + } + + public Set getCurrentUserRoles() { + return jwt.getGroups(); + } +} +``` + +3. **Utiliser dans audit logging**: +```java +@Inject +UserIdentityProvider userIdentity; + +@Override +public UserDTO createUser(UserDTO user, String realmName) { + String acteur = userIdentity.getCurrentUsername(); + + try { + UserDTO created = // ... crĂ©ation + + auditService.logSuccess(acteur, TypeActionAudit.USER_CREATE, + "user", created.getId(), ...); + return created; + } catch (Exception e) { + auditService.logFailure(acteur, TypeActionAudit.USER_CREATE, + "user", user.getUsername(), ...); + throw e; + } +} +``` + +#### B. Ajouter Validation PersonnalisĂ©e + +**Objectif**: Validateurs custom pour rĂšgles mĂ©tier complexes + +**Exemple**: Validation format tĂ©lĂ©phone français +```java +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = FrenchPhoneValidator.class) +public @interface FrenchPhone { + String message() default "NumĂ©ro de tĂ©lĂ©phone français invalide"; + Class[] groups() default {}; + Class[] payload() default {}; +} + +public class FrenchPhoneValidator implements ConstraintValidator { + + private static final Pattern FRENCH_PHONE = Pattern.compile("^(\\+33|0)[1-9](\\d{2}){4}$"); + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (value == null || value.isEmpty()) { + return true; + } + return FRENCH_PHONE.matcher(value).matches(); + } +} +``` + +**Utilisation dans UserDTO**: +```java +@FrenchPhone +private String telephone; +``` + +### 7.3 Backend - ObservabilitĂ© + +#### A. MĂ©triques Prometheus + +**Objectif**: Exposer mĂ©triques custom + +**DĂ©pendance dĂ©jĂ  prĂ©sente**: `quarkus-micrometer-registry-prometheus` + +**À implĂ©menter**: +```java +@ApplicationScoped +public class UserServiceMetrics { + + private final Counter userCreationCounter; + private final Counter userCreationFailureCounter; + private final Timer userCreationTimer; + + public UserServiceMetrics(MeterRegistry registry) { + this.userCreationCounter = registry.counter("lions.user.creation.total"); + this.userCreationFailureCounter = registry.counter("lions.user.creation.failures"); + this.userCreationTimer = registry.timer("lions.user.creation.duration"); + } + + public void recordUserCreation(boolean success, long durationMs) { + if (success) { + userCreationCounter.increment(); + } else { + userCreationFailureCounter.increment(); + } + userCreationTimer.record(durationMs, TimeUnit.MILLISECONDS); + } +} +``` + +**Utiliser dans UserServiceImpl**: +```java +@Inject +UserServiceMetrics metrics; + +@Override +public UserDTO createUser(UserDTO user, String realmName) { + long start = System.currentTimeMillis(); + try { + UserDTO created = // ... crĂ©ation + metrics.recordUserCreation(true, System.currentTimeMillis() - start); + return created; + } catch (Exception e) { + metrics.recordUserCreation(false, System.currentTimeMillis() - start); + throw e; + } +} +``` + +**VĂ©rifier mĂ©triques**: +```bash +curl http://localhost:8081/q/metrics +``` + +#### B. Tracing OpenTelemetry + +**DĂ©pendance Ă  ajouter**: +```xml + + io.quarkus + quarkus-opentelemetry + +``` + +**Configuration**: +```properties +quarkus.opentelemetry.enabled=true +quarkus.opentelemetry.tracer.exporter.otlp.endpoint=http://jaeger:4317 +``` + +### 7.4 Module Client - Interface Utilisateur + +**ÉTAT**: 0% - Non commencĂ© +**PRIORITÉ**: Haute (aprĂšs correction des erreurs backend) + +#### A. Structure du Module Client + +``` +lions-user-manager-client-quarkus-primefaces-freya/ +├── src/main/java/dev/lions/user/manager/client/ +│ ├── api/ (REST Clients vers backend) +│ │ ├── UserApiClient.java +│ │ ├── RoleApiClient.java +│ │ ├── AuditApiClient.java +│ │ └── SyncApiClient.java +│ ├── bean/ (JSF Managed Beans) +│ │ ├── user/ +│ │ │ ├── UserListBean.java (Liste utilisateurs) +│ │ │ ├── UserEditBean.java (CrĂ©ation/Édition) +│ │ │ ├── UserDetailBean.java (DĂ©tails utilisateur) +│ │ │ └── UserSearchBean.java (Recherche avancĂ©e) +│ │ ├── role/ +│ │ │ ├── RoleListBean.java +│ │ │ ├── RoleEditBean.java +│ │ │ └── RoleAssignBean.java (Attribution rĂŽles) +│ │ ├── audit/ +│ │ │ ├── AuditLogBean.java +│ │ │ └── AuditStatsBean.java +│ │ └── navigation/ +│ │ ├── MenuBean.java +│ │ └── BreadcrumbBean.java +│ ├── security/ +│ │ ├── SecurityFilter.java (VĂ©rif auth OIDC) +│ │ ├── RoleChecker.java +│ │ └── UserSessionBean.java (Session utilisateur) +│ ├── converter/ (JSF Converters) +│ │ ├── StatutUserConverter.java +│ │ └── TypeRoleConverter.java +│ └── validator/ (JSF Validators) +│ ├── UsernameValidator.java +│ └── EmailValidator.java +│ +├── src/main/resources/ +│ ├── META-INF/ +│ │ └── resources/ +│ │ ├── WEB-INF/ +│ │ │ ├── web.xml +│ │ │ ├── faces-config.xml +│ │ │ ├── template.xhtml (Layout principal) +│ │ │ └── menu.xhtml (Menu navigation) +│ │ ├── users/ +│ │ │ ├── list.xhtml (Liste utilisateurs) +│ │ │ ├── edit.xhtml (Formulaire utilisateur) +│ │ │ ├── detail.xhtml (DĂ©tails utilisateur) +│ │ │ └── search.xhtml (Recherche avancĂ©e) +│ │ ├── roles/ +│ │ │ ├── list.xhtml (Liste rĂŽles) +│ │ │ ├── edit.xhtml (Formulaire rĂŽle) +│ │ │ └── assign.xhtml (Attribution rĂŽles) +│ │ ├── audit/ +│ │ │ ├── logs.xhtml (Logs d'audit) +│ │ │ └── stats.xhtml (Statistiques) +│ │ ├── resources/ +│ │ │ ├── css/ +│ │ │ │ └── custom.css +│ │ │ └── js/ +│ │ │ └── app.js +│ │ └── index.xhtml (Page d'accueil) +│ └── application.properties +└── pom.xml +``` + +#### B. Configuration POM Client + +**DĂ©pendances critiques Ă  ajouter**: +```xml + + + + dev.lions.user.manager + lions-user-manager-server-api + ${project.version} + + + + + io.quarkiverse.myfaces + quarkus-myfaces + 3.0.0 + + + + + org.primefaces + primefaces + 14.0.5 + jakarta + + + + + org.primefaces + freya-theme + 5.0.0-jakarta + + + + + io.quarkus + quarkus-rest-client-reactive-jackson + + + + + io.quarkus + quarkus-oidc + + + + + + btpxpress-maven-repo + https://git.lions.dev/lionsdev/btpxpress-maven-repo/raw/branch/main/ + + +``` + +#### C. REST Clients vers Backend + +**Exemple**: UserApiClient.java +```java +package dev.lions.user.manager.client.api; + +import dev.lions.user.manager.dto.user.UserDTO; +import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO; +import dev.lions.user.manager.dto.user.UserSearchResultDTO; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; + +@Path("/api/users") +@RegisterRestClient(configKey = "user-api") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public interface UserApiClient { + + @POST + @Path("/search") + UserSearchResultDTO searchUsers(UserSearchCriteriaDTO criteria); + + @GET + @Path("/{userId}") + UserDTO getUser(@PathParam("userId") String userId, + @QueryParam("realm") String realmName); + + @POST + UserDTO createUser(UserDTO user, @QueryParam("realm") String realmName); + + @PUT + @Path("/{userId}") + UserDTO updateUser(@PathParam("userId") String userId, + UserDTO user, + @QueryParam("realm") String realmName); + + @DELETE + @Path("/{userId}") + void deleteUser(@PathParam("userId") String userId, + @QueryParam("realm") String realmName); +} +``` + +**Configuration**: +```properties +# application.properties +quarkus.rest-client.user-api.url=http://localhost:8081 +quarkus.rest-client.role-api.url=http://localhost:8081 +quarkus.rest-client.audit-api.url=http://localhost:8081 +``` + +#### D. JSF Managed Bean Exemple + +**UserListBean.java**: +```java +package dev.lions.user.manager.client.bean.user; + +import dev.lions.user.manager.client.api.UserApiClient; +import dev.lions.user.manager.dto.user.UserDTO; +import dev.lions.user.manager.dto.user.UserSearchCriteriaDTO; +import dev.lions.user.manager.dto.user.UserSearchResultDTO; +import jakarta.annotation.PostConstruct; +import jakarta.faces.view.ViewScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import lombok.Getter; +import lombok.Setter; +import org.eclipse.microprofile.rest.client.inject.RestClient; + +import java.io.Serializable; +import java.util.List; + +@Named("userListBean") +@ViewScoped +public class UserListBean implements Serializable { + + @Inject + @RestClient + UserApiClient userApiClient; + + @Getter + @Setter + private List users; + + @Getter + @Setter + private UserDTO selectedUser; + + @Getter + @Setter + private String searchKeyword; + + @Getter + @Setter + private String currentRealm = "master"; + + @PostConstruct + public void init() { + loadUsers(); + } + + public void loadUsers() { + UserSearchCriteriaDTO criteria = UserSearchCriteriaDTO.builder() + .realmName(currentRealm) + .keyword(searchKeyword) + .page(0) + .pageSize(50) + .build(); + + UserSearchResultDTO result = userApiClient.searchUsers(criteria); + this.users = result.getUsers(); + } + + public void deleteUser(UserDTO user) { + userApiClient.deleteUser(user.getId(), currentRealm); + loadUsers(); + } + + public String editUser(UserDTO user) { + return "edit?faces-redirect=true&userId=" + user.getId(); + } +} +``` + +#### E. Page XHTML Exemple + +**users/list.xhtml**: +```xhtml + + + + + + + + + + + +
+
+ + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+
+ +
+ +``` + +#### F. Template Principal + +**WEB-INF/template.xhtml**: +```xhtml + + + + + + + Lions User Manager + + + + + + + + + +
+

Lions User Manager

+ +
+
+ + + + + + + + +
+ + +
+
+ +
+ +
+ +``` + +#### G. Configuration JSF + +**WEB-INF/web.xml**: +```xml + + + + Lions User Manager + + + + Faces Servlet + jakarta.faces.webapp.FacesServlet + 1 + + + + Faces Servlet + *.xhtml + + + + + primefaces.THEME + freya + + + + primefaces.FONT_AWESOME + true + + + + + jakarta.faces.PROJECT_STAGE + Development + + + + jakarta.faces.FACELETS_REFRESH_PERIOD + 0 + + + + index.xhtml + + + +``` + +**WEB-INF/faces-config.xml**: +```xml + + + + + + fr + fr + en + + + + i18n.messages + msg + + + + +``` + +### 7.5 Infrastructure - Kubernetes et Helm + +#### A. Dockerfile pour Server-Impl + +```dockerfile +# server-impl/src/main/docker/Dockerfile.jvm +FROM registry.access.redhat.com/ubi8/openjdk-17:1.18 + +ENV LANGUAGE='en_US:en' + +# Configure JVM +ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" +ENV JAVA_APP_JAR="/deployments/quarkus-run.jar" + +# Copy application +COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ +COPY --chown=185 target/quarkus-app/*.jar /deployments/ +COPY --chown=185 target/quarkus-app/app/ /deployments/app/ +COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ + +EXPOSE 8080 +USER 185 + +ENTRYPOINT [ "java", "-jar", "/deployments/quarkus-run.jar" ] +``` + +#### B. Helm Chart Structure + +``` +helm/ +├── Chart.yaml +├── values.yaml +├── values-dev.yaml +├── values-prod.yaml +└── templates/ + ├── _helpers.tpl + ├── deployment-server.yaml + ├── deployment-client.yaml + ├── service-server.yaml + ├── service-client.yaml + ├── ingress.yaml + ├── configmap.yaml + ├── secret.yaml + ├── serviceaccount.yaml + └── hpa.yaml +``` + +**Chart.yaml**: +```yaml +apiVersion: v2 +name: lions-user-manager +description: SystĂšme de gestion utilisateurs Keycloak +type: application +version: 1.0.0 +appVersion: "1.0.0" +keywords: + - keycloak + - user-management + - quarkus + - primefaces +maintainers: + - name: Lions Dev Team + email: dev@lions.dev +``` + +**values.yaml**: +```yaml +# Configuration globale +global: + environment: production + domain: lions.dev + +# Server Backend +server: + enabled: true + replicaCount: 2 + image: + repository: registry.lions.dev/lions-user-manager-server + tag: 1.0.0 + pullPolicy: IfNotPresent + + resources: + requests: + cpu: 500m + memory: 512Mi + limits: + cpu: 1000m + memory: 1Gi + + autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 + + service: + type: ClusterIP + port: 8080 + + env: + - name: QUARKUS_PROFILE + value: "prod" + - name: KEYCLOAK_URL + value: "https://security.lions.dev" + - name: KEYCLOAK_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: lions-user-manager-secrets + key: keycloak-client-secret + - name: DB_HOST + value: "postgresql.lions.svc.cluster.local" + - name: DB_USERNAME + valueFrom: + secretKeyRef: + name: lions-user-manager-secrets + key: db-username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: lions-user-manager-secrets + key: db-password + +# Client Frontend +client: + enabled: true + replicaCount: 2 + image: + repository: registry.lions.dev/lions-user-manager-client + tag: 1.0.0 + pullPolicy: IfNotPresent + + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 500m + memory: 512Mi + + service: + type: ClusterIP + port: 8080 + +# Ingress +ingress: + enabled: true + className: nginx + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/ssl-redirect: "true" + hosts: + - host: user-manager.lions.dev + paths: + - path: / + pathType: Prefix + backend: client + - path: /api + pathType: Prefix + backend: server + tls: + - secretName: user-manager-tls + hosts: + - user-manager.lions.dev + +# PostgreSQL (optionnel si base externe) +postgresql: + enabled: true + auth: + username: audit_user + password: changeme + database: lions_audit + primary: + persistence: + enabled: true + size: 10Gi +``` + +**templates/deployment-server.yaml**: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "lions-user-manager.fullname" . }}-server + labels: + {{- include "lions-user-manager.labels" . | nindent 4 }} + app.kubernetes.io/component: server +spec: + {{- if not .Values.server.autoscaling.enabled }} + replicas: {{ .Values.server.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "lions-user-manager.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: server + template: + metadata: + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + prometheus.io/path: "/q/metrics" + labels: + {{- include "lions-user-manager.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: server + spec: + serviceAccountName: {{ include "lions-user-manager.serviceAccountName" . }} + containers: + - name: server + image: "{{ .Values.server.image.repository }}:{{ .Values.server.image.tag }}" + imagePullPolicy: {{ .Values.server.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + {{- toYaml .Values.server.env | nindent 12 }} + livenessProbe: + httpGet: + path: /q/health/live + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: /q/health/ready + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + resources: + {{- toYaml .Values.server.resources | nindent 12 }} +``` + +**Installation Helm**: +```bash +# Dev +helm install lions-user-manager ./helm -f ./helm/values-dev.yaml --namespace lions-dev + +# Prod +helm install lions-user-manager ./helm -f ./helm/values-prod.yaml --namespace lions-prod +``` + +### 7.6 Scripts Keycloak - Provisioning + +#### A. Script d'initialisation Keycloak + +**scripts/keycloak-init.sh**: +```bash +#!/bin/bash +set -e + +# Configuration +KEYCLOAK_URL=${KEYCLOAK_URL:-http://localhost:8180} +ADMIN_USER=${ADMIN_USER:-admin} +ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin} + +echo "🚀 Initialisation de Keycloak pour Lions User Manager" + +# 1. Obtenir token admin +echo "📝 Obtention du token admin..." +TOKEN=$(curl -s -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "username=${ADMIN_USER}" \ + -d "password=${ADMIN_PASSWORD}" \ + -d "grant_type=password" \ + -d "client_id=admin-cli" \ + | jq -r '.access_token') + +if [ -z "$TOKEN" ] || [ "$TOKEN" == "null" ]; then + echo "❌ Erreur: Impossible d'obtenir le token admin" + exit 1 +fi + +echo "✅ Token obtenu" + +# 2. CrĂ©er le realm lions (si n'existe pas) +echo "📝 CrĂ©ation du realm 'lions'..." +curl -s -X POST "${KEYCLOAK_URL}/admin/realms" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{ + "realm": "lions", + "enabled": true, + "displayName": "Lions Realm", + "registrationAllowed": false, + "resetPasswordAllowed": true, + "rememberMe": true, + "verifyEmail": true, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "sslRequired": "external", + "passwordPolicy": "length(8) and digits(1) and lowerCase(1) and upperCase(1) and specialChars(1)", + "accessTokenLifespan": 3600, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000 + }' || echo "⚠ Realm 'lions' existe probablement dĂ©jĂ " + +# 3. CrĂ©er le client lions-user-manager +echo "📝 CrĂ©ation du client 'lions-user-manager'..." +CLIENT_ID=$(curl -s -X POST "${KEYCLOAK_URL}/admin/realms/lions/clients" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{ + "clientId": "lions-user-manager", + "name": "Lions User Manager", + "enabled": true, + "protocol": "openid-connect", + "publicClient": false, + "standardFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "redirectUris": [ + "http://localhost:8082/*", + "https://user-manager.lions.dev/*" + ], + "webOrigins": ["+"], + "attributes": { + "access.token.lifespan": "3600", + "client.secret.creation.time": "0" + } + }' \ + -w "%{http_code}" -o /tmp/client-response.json) + +if [ "$CLIENT_ID" == "201" ]; then + CLIENT_UUID=$(jq -r '.id' /tmp/client-response.json) + echo "✅ Client créé avec UUID: $CLIENT_UUID" + + # RĂ©cupĂ©rer le secret du client + CLIENT_SECRET=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/lions/clients/${CLIENT_UUID}/client-secret" \ + -H "Authorization: Bearer ${TOKEN}" \ + | jq -r '.value') + + echo "🔑 Client Secret: ${CLIENT_SECRET}" + echo " ⚠ Sauvegardez ce secret dans vos variables d'environnement!" +else + echo "⚠ Client existe probablement dĂ©jĂ " +fi + +# 4. CrĂ©er les rĂŽles realm +echo "📝 CrĂ©ation des rĂŽles realm..." +for role in admin user_manager role_manager auditor sync_manager role_viewer; do + curl -s -X POST "${KEYCLOAK_URL}/admin/realms/lions/roles" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"name\": \"${role}\", \"description\": \"Role ${role}\"}" \ + && echo " ✅ RĂŽle '${role}' créé" \ + || echo " ⚠ RĂŽle '${role}' existe dĂ©jĂ " +done + +# 5. CrĂ©er un utilisateur admin de test +echo "📝 CrĂ©ation de l'utilisateur admin de test..." +curl -s -X POST "${KEYCLOAK_URL}/admin/realms/lions/users" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{ + "username": "admin@lions.dev", + "email": "admin@lions.dev", + "firstName": "Admin", + "lastName": "Lions", + "enabled": true, + "emailVerified": true, + "credentials": [{ + "type": "password", + "value": "Admin@2025", + "temporary": false + }] + }' && echo "✅ Utilisateur admin créé" || echo "⚠ Utilisateur admin existe dĂ©jĂ " + +# 6. Assigner le rĂŽle admin Ă  l'utilisateur +echo "📝 Attribution du rĂŽle admin..." +USER_ID=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/lions/users?username=admin@lions.dev" \ + -H "Authorization: Bearer ${TOKEN}" \ + | jq -r '.[0].id') + +ADMIN_ROLE=$(curl -s -X GET "${KEYCLOAK_URL}/admin/realms/lions/roles/admin" \ + -H "Authorization: Bearer ${TOKEN}") + +curl -s -X POST "${KEYCLOAK_URL}/admin/realms/lions/users/${USER_ID}/role-mappings/realm" \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d "[${ADMIN_ROLE}]" \ + && echo "✅ RĂŽle admin attribuĂ©" || echo "⚠ Erreur attribution rĂŽle" + +echo "" +echo "🎉 Initialisation Keycloak terminĂ©e!" +echo "" +echo "📋 Informations de connexion:" +echo " URL: ${KEYCLOAK_URL}" +echo " Realm: lions" +echo " Client ID: lions-user-manager" +echo " Client Secret: ${CLIENT_SECRET:-}" +echo " Utilisateur test: admin@lions.dev / Admin@2025" +``` + +**ExĂ©cution**: +```bash +chmod +x scripts/keycloak-init.sh +./scripts/keycloak-init.sh +``` + +#### B. Realm Export JSON + +**config/lions-realm-export.json**: +```json +{ + "realm": "lions", + "enabled": true, + "displayName": "Lions Realm", + "roles": { + "realm": [ + {"name": "admin", "description": "Administrateur complet"}, + {"name": "user_manager", "description": "Gestionnaire d'utilisateurs"}, + {"name": "role_manager", "description": "Gestionnaire de rĂŽles"}, + {"name": "auditor", "description": "Auditeur (lecture seule)"}, + {"name": "sync_manager", "description": "Gestionnaire de synchronisation"}, + {"name": "role_viewer", "description": "Visualiseur de rĂŽles"} + ] + }, + "clients": [ + { + "clientId": "lions-user-manager", + "name": "Lions User Manager", + "enabled": true, + "protocol": "openid-connect", + "publicClient": false, + "standardFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "authorizationServicesEnabled": true, + "redirectUris": [ + "http://localhost:8082/*", + "https://user-manager.lions.dev/*" + ], + "webOrigins": ["+"] + } + ] +} +``` + +**Import**: +```bash +# Avec docker +docker exec -it keycloak /opt/keycloak/bin/kc.sh import \ + --file /opt/keycloak/data/import/lions-realm-export.json + +# Avec commande locale +./kc.sh import --file config/lions-realm-export.json +``` + +--- + +## 8. SPÉCIFICATIONS TECHNIQUES DÉTAILLÉES + +### 8.1 Contraintes et RĂšgles MĂ©tier + +#### A. Gestion Utilisateurs + +**RĂšgles de validation**: +- Username: 3-50 caractĂšres, alphanumĂ©rique + _ - +- Email: format RFC 5322 +- Mot de passe: min 8 caractĂšres, 1 maj, 1 min, 1 chiffre, 1 spĂ©cial +- TĂ©lĂ©phone (France): format +33XXXXXXXXX ou 0XXXXXXXXX + +**États utilisateur** (enum StatutUser): +``` +ACTIF → Peut se connecter +INACTIF → DĂ©sactivĂ© temporairement +SUSPENDU → Suspendu par admin +EN_ATTENTE → Attend validation +VERROUILLE → VerrouillĂ© aprĂšs X tentatives +EXPIRE → Compte expirĂ© +SUPPRIME → Suppression logique +``` + +**RĂšgles mĂ©tier**: +- Un utilisateur VERROUILLE peut ĂȘtre dĂ©verrouillĂ© par un admin +- Un utilisateur SUSPENDU ne peut ĂȘtre rĂ©activĂ© que par un admin +- La suppression est TOUJOURS logique (soft delete), jamais physique +- Lors de la dĂ©sactivation, toutes les sessions doivent ĂȘtre rĂ©voquĂ©es + +#### B. Gestion RĂŽles + +**Types de rĂŽles** (enum TypeRole): +``` +REALM_ROLE → RĂŽle au niveau du realm +CLIENT_ROLE → RĂŽle spĂ©cifique Ă  un client +COMPOSITE_ROLE → RĂŽle composite (contient d'autres rĂŽles) +``` + +**RĂšgles mĂ©tier**: +- Un rĂŽle composite ne peut pas ĂȘtre supprimĂ© s'il est utilisĂ© +- L'attribution de rĂŽles doit ĂȘtre auditĂ©e +- Les rĂŽles systĂšme (admin, user) ne peuvent ĂȘtre supprimĂ©s +- Un utilisateur peut avoir plusieurs rĂŽles realm ET plusieurs rĂŽles client + +#### C. Audit Trail + +**Actions auditĂ©es** (enum TypeActionAudit): +``` +USER_CREATE, USER_UPDATE, USER_DELETE +USER_ACTIVATE, USER_DEACTIVATE, USER_LOCK, USER_UNLOCK +PASSWORD_RESET, PASSWORD_CHANGE +ROLE_CREATE, ROLE_UPDATE, ROLE_DELETE +ROLE_ASSIGN, ROLE_REVOKE +SESSION_LOGOUT, SESSION_REVOKE_ALL +SYNC_USERS, SYNC_ROLES +``` + +**Informations obligatoires**: +- Qui: username de l'acteur +- Quoi: type d'action +- Quand: timestamp prĂ©cis +- Sur quoi: type et ID de la ressource +- RĂ©sultat: succĂšs ou Ă©chec +- OĂč: adresse IP de l'acteur + +**RĂ©tention**: +- Dev: 30 jours +- Prod: 2 ans minimum (contrainte lĂ©gale) + +### 8.2 SĂ©curitĂ© + +#### A. Authentication & Authorization + +**Flow OIDC**: +``` +1. Utilisateur → Frontend → Redirect vers Keycloak +2. Keycloak → Authentification → GĂ©nĂšre ID Token + Access Token +3. Frontend → Stocke tokens (HttpOnly cookies) +4. Frontend → API calls avec Access Token dans header Authorization +5. Backend → Valide token avec Keycloak +6. Backend → VĂ©rifie rĂŽles (@RolesAllowed) +7. Backend → Execute action + Audit log +``` + +**Matrice de permissions**: +``` +RĂŽle | Users | Roles | Audit | Sync +-----------------+-------+-------+-------+------ +admin | RWD | RWD | RWD | RWD +user_manager | RWD | - | R | - +role_manager | R | RWD | R | - +auditor | R | R | R | - +sync_manager | R | R | R | RWD +role_viewer | - | R | - | - + +R = Read, W = Write, D = Delete +``` + +#### B. Validation des EntrĂ©es + +**CĂŽtĂ© Backend (obligatoire)**: +- Jakarta Bean Validation sur tous les DTOs +- Custom validators pour rĂšgles complexes +- Sanitization des inputs pour prĂ©venir XSS/SQL injection + +**CĂŽtĂ© Frontend (UX)**: +- Validation JavaScript pour feedback immĂ©diat +- Messages d'erreur contextuels +- Boutons submit dĂ©sactivĂ©s si formulaire invalide + +#### C. Protection CSRF + +**Backend**: +- Validation token CSRF sur endpoints state-changing (POST, PUT, DELETE) +- Token inclus dans JWT + +**Frontend**: +- Token CSRF dans meta tag +- AjoutĂ© automatiquement dans headers Ajax + +### 8.3 Performance + +#### A. Objectifs de Performance + +**Backend**: +- Temps rĂ©ponse API: < 200ms (p95) +- Throughput: > 1000 req/s +- Taux erreur: < 0.1% + +**Frontend**: +- Time to Interactive: < 3s +- First Contentful Paint: < 1.5s +- Largest Contentful Paint: < 2.5s + +#### B. Optimisations + +**Backend**: +- Cache des rĂŽles (TTL 5min) +- Cache des users (TTL 2min) +- Connection pooling Keycloak +- Database connection pooling (HikariCP) +- Pagination systĂ©matique (max 100 items) + +**Frontend**: +- Lazy loading des composants PrimeFaces +- Compression Gzip/Brotli +- Cache statique (CSS, JS, images) +- CDN pour Freya theme + +### 8.4 Monitoring et Alerting + +#### A. MĂ©triques ClĂ©s + +**MĂ©triques applicatives**: +``` +lions_user_creation_total Counter +lions_user_creation_failures Counter +lions_user_creation_duration_ms Histogram +lions_keycloak_api_calls_total Counter +lions_keycloak_api_errors_total Counter +lions_audit_logs_total Counter +``` + +**MĂ©triques systĂšme**: +``` +jvm_memory_used_bytes +jvm_threads_current +http_server_requests_seconds +``` + +#### B. Alertes Critiques + +``` +Alert: KeycloakDown +Condition: up{job="keycloak"} == 0 +Severity: Critical +Action: Page on-call + +Alert: HighErrorRate +Condition: rate(lions_user_creation_failures[5m]) > 0.1 +Severity: Warning +Action: Notify team + +Alert: SlowResponse +Condition: histogram_quantile(0.95, lions_user_creation_duration_ms) > 500 +Severity: Warning +Action: Investigate performance +``` + +#### C. Logs CentralisĂ©s + +**Format JSON structurĂ©**: +```json +{ + "timestamp": "2025-11-09T14:30:00Z", + "level": "INFO", + "logger": "UserServiceImpl", + "message": "User created", + "userId": "123-456", + "username": "jdoe", + "acteur": "admin@lions.dev", + "realmName": "lions", + "duration_ms": 45 +} +``` + +**Stack recommandĂ©**: +- Filebeat → collect logs +- Logstash → parse et enrich +- Elasticsearch → store +- Kibana → visualize + +--- + +## 9. COMMANDES UTILES + +### 9.1 Build et Compilation + +```bash +# Compilation complĂšte +cd C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager +mvn clean compile -DskipTests + +# Compilation avec tests +mvn clean test + +# Package (JAR) +mvn clean package + +# Package natif (GraalVM - long!) +mvn clean package -Pnative + +# Install dans repo Maven local +mvn clean install +``` + +### 9.2 ExĂ©cution + +```bash +# Dev mode avec hot reload +cd lions-user-manager-server-impl-quarkus +mvn quarkus:dev + +# Dev mode avec profil dev +mvn quarkus:dev -Dquarkus.profile=dev + +# Dev mode avec debug port 5005 +mvn quarkus:dev -Ddebug=5005 + +# ExĂ©cution du JAR packagĂ© +java -jar target/quarkus-app/quarkus-run.jar + +# ExĂ©cution avec profil prod +java -jar target/quarkus-app/quarkus-run.jar -Dquarkus.profile=prod +``` + +### 9.3 Tests + +```bash +# Tous les tests +mvn test + +# Tests d'un module spĂ©cifique +cd lions-user-manager-server-impl-quarkus +mvn test + +# Test d'une classe spĂ©cifique +mvn test -Dtest=UserServiceImplTest + +# Test d'une mĂ©thode spĂ©cifique +mvn test -Dtest=UserServiceImplTest#testCreateUser + +# Tests d'intĂ©gration uniquement +mvn verify -Pintegration-tests + +# Coverage Jacoco +mvn clean test jacoco:report +# Rapport: target/site/jacoco/index.html +``` + +### 9.4 Git + +```bash +# Status de tous les modules +cd C:\Users\dadyo\PersonalProjects\lions-workspace\lions-user-manager +git status + +# Commit et push repository master +git add . +git commit -m "feat: Description" +git push origin main + +# Commit et push sous-module server-api +cd lions-user-manager-server-api +git add . +git commit -m "feat: Description" +git push origin main +cd .. + +# Commit et push sous-module server-impl +cd lions-user-manager-server-impl-quarkus +git add . +git commit -m "feat: Description" +git push origin main +cd .. + +# Commit et push sous-module client +cd lions-user-manager-client-quarkus-primefaces-freya +git add . +git commit -m "feat: Description" +git push origin main +cd .. + +# Puis mettre Ă  jour le master +git add . +git commit -m "chore: Sync submodules" +git push origin main +``` + +### 9.5 Docker + +```bash +# Build image Docker +docker build -f src/main/docker/Dockerfile.jvm -t lions-user-manager-server:1.0.0 . + +# Run container +docker run -p 8081:8080 \ + -e KEYCLOAK_URL=http://keycloak:8080 \ + -e KEYCLOAK_CLIENT_SECRET=secret \ + lions-user-manager-server:1.0.0 + +# Docker Compose (si créé) +docker-compose up -d + +# Voir logs +docker logs -f lions-user-manager-server +``` + +### 9.6 Kubernetes + +```bash +# Apply manifests +kubectl apply -f k8s/ + +# Helm install dev +helm install lions-user-manager ./helm -f ./helm/values-dev.yaml -n lions-dev + +# Helm upgrade +helm upgrade lions-user-manager ./helm -f ./helm/values-prod.yaml -n lions-prod + +# Check pods +kubectl get pods -n lions-prod + +# Logs d'un pod +kubectl logs -f deployment/lions-user-manager-server -n lions-prod + +# Port-forward pour debug +kubectl port-forward svc/lions-user-manager-server 8081:8080 -n lions-prod +``` + +### 9.7 Keycloak Admin + +```bash +# Obtenir token admin +curl -X POST http://localhost:8180/realms/master/protocol/openid-connect/token \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "username=admin" \ + -d "password=admin" \ + -d "grant_type=password" \ + -d "client_id=admin-cli" + +# Lister les users d'un realm +curl -X GET http://localhost:8180/admin/realms/lions/users \ + -H "Authorization: Bearer ${TOKEN}" + +# CrĂ©er un user +curl -X POST http://localhost:8180/admin/realms/lions/users \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"username": "test", "email": "test@example.com", "enabled": true}' +``` + +### 9.8 OpenAPI / Swagger + +```bash +# AccĂ©der Ă  Swagger UI (en dev mode) +http://localhost:8081/q/swagger-ui + +# TĂ©lĂ©charger spec OpenAPI +curl http://localhost:8081/q/openapi -o openapi.json +``` + +--- + +## 10. CHECKLIST FINALE POUR LE PROCHAIN AGENT + +### ✅ Actions ImmĂ©diates (1-2 heures) + +- [ ] Lire entiĂšrement ce document HANDOFF_COMPLET.md +- [ ] VĂ©rifier que tous les fichiers sont prĂ©sents dans le workspace +- [ ] Compiler le projet: `mvn clean compile -DskipTests` +- [ ] **Corriger les erreurs de compilation** (voir section 3) + - [ ] RoleMapper: name vs nom + - [ ] RoleServiceImpl: signatures mĂ©thodes + - [ ] AuditService: complĂ©ter interface + - [ ] SyncService: crĂ©er DTOs +- [ ] Re-compiler pour vĂ©rifier: `mvn clean compile -DskipTests` +- [ ] Commit et push les corrections + +### 📊 Phase 1: Stabilisation Backend (3-5 heures) + +- [ ] CrĂ©er tests unitaires de base (30% coverage minimum) +- [ ] CrĂ©er tests d'intĂ©gration avec Testcontainers +- [ ] ImplĂ©menter persistence audit PostgreSQL + Panache +- [ ] Migrer vers MapStruct pour les mappers +- [ ] Ajouter cache Quarkus pour rĂ©duire appels Keycloak +- [ ] VĂ©rifier coverage Jacoco: `mvn test jacoco:report` +- [ ] Commit et push + +### 🎹 Phase 2: Module Client (10-15 heures) + +- [ ] Configurer POM avec PrimeFaces + Freya +- [ ] CrĂ©er REST Clients (@RegisterRestClient) +- [ ] CrĂ©er template principal + menu +- [ ] CrĂ©er pages Users (list, edit, detail, search) +- [ ] CrĂ©er pages Roles (list, edit, assign) +- [ ] CrĂ©er pages Audit (logs, stats) +- [ ] Tester interface en local +- [ ] Commit et push + +### 🚀 Phase 3: Infrastructure (8-12 heures) + +- [ ] CrĂ©er Dockerfiles optimisĂ©s +- [ ] CrĂ©er Helm charts complets +- [ ] CrĂ©er scripts Keycloak provisioning +- [ ] Tester dĂ©ploiement Kubernetes local (minikube/kind) +- [ ] CrĂ©er pipeline CI/CD (GitHub Actions ou GitLab CI) +- [ ] Documenter procĂ©dure de dĂ©ploiement +- [ ] Commit et push + +### 📈 Phase 4: Monitoring & Docs (5-8 heures) + +- [ ] ImplĂ©menter mĂ©triques Prometheus custom +- [ ] Configurer tracing OpenTelemetry +- [ ] CrĂ©er dashboards Grafana +- [ ] Configurer alertes critiques +- [ ] Écrire documentation utilisateur +- [ ] CrĂ©er guide d'administration +- [ ] CrĂ©er guide de contribution dĂ©veloppeurs +- [ ] Commit et push + +### 🎯 Phase 5: Production Readiness (3-5 heures) + +- [ ] Load testing avec Gatling ou k6 +- [ ] Security scanning (OWASP ZAP, Snyk) +- [ ] Performance tuning +- [ ] Backup/restore procedures +- [ ] Disaster recovery plan +- [ ] Runbook pour on-call +- [ ] Final QA testing +- [ ] Release 1.0.0 🎉 + +--- + +## 11. CONTACTS ET RESSOURCES + +### Documentation Externe + +**Quarkus**: +- Guide: https://quarkus.io/guides/ +- REST Client: https://quarkus.io/guides/rest-client +- OIDC: https://quarkus.io/guides/security-oidc-code-flow-authentication + +**Keycloak**: +- Admin REST API: https://www.keycloak.org/docs-api/23.0.3/rest-api/index.html +- Admin Client Java: https://www.keycloak.org/docs/latest/server_development/#admin-rest-api + +**PrimeFaces**: +- Showcase: https://www.primefaces.org/showcase/ +- Freya Theme: (repository custom lions.dev) + +**Testcontainers**: +- Keycloak Module: https://java.testcontainers.org/modules/databases/keycloak/ + +### Repositories Git + +- Master: https://git.lions.dev/lionsdev/lions-user-manager +- Server-API: https://git.lions.dev/lionsdev/lions-user-manager-server-api +- Server-Impl: https://git.lions.dev/lionsdev/lions-user-manager-server-impl-quarkus +- Client: https://git.lions.dev/lionsdev/lions-user-manager-client-quarkus-primefaces-freya +- Maven Repo: https://git.lions.dev/lionsdev/btpxpress-maven-repo + +--- + +## 🎯 OBJECTIF FINAL + +**Livrer un systĂšme de gestion utilisateurs Keycloak production-ready** comprenant: + +1. ✅ Backend REST API complet et testĂ© (80% coverage) +2. ✅ Frontend PrimeFaces ergonomique et responsive +3. ✅ Audit trail complet de toutes les opĂ©rations +4. ✅ DĂ©ploiement Kubernetes via Helm +5. ✅ Monitoring et alerting opĂ©rationnels +6. ✅ Documentation complĂšte (technique + utilisateur) +7. ✅ CI/CD pipeline automatisĂ© + +**DurĂ©e estimĂ©e restante**: 40-60 heures de dĂ©veloppement + +**PrioritĂ© absolue**: Corriger les erreurs de compilation AVANT toute autre tĂąche! + +--- + +## 📝 NOTES FINALES + +Ce document contient TOUTES les informations nĂ©cessaires pour continuer le dĂ©veloppement de maniĂšre autonome. + +**Points d'attention critiques**: +1. Ne JAMAIS accĂ©der directement Ă  la DB Keycloak +2. Toujours auditer les actions sensibles +3. Respecter la structure Git multi-repository +4. Tester avec Testcontainers avant dĂ©ploiement +5. Maintenir 80% de test coverage minimum + +**En cas de blocage**, se rĂ©fĂ©rer aux sections: +- Section 3 pour les erreurs de compilation +- Section 7 pour les implĂ©mentations dĂ©taillĂ©es +- Section 9 pour les commandes utiles + +Bon dĂ©veloppement! 🚀 + +--- + +**Document gĂ©nĂ©rĂ© le**: 2025-11-09 +**Par**: Agent IA Claude (Anthropic) +**Pour**: Continuation projet lions-user-manager +**Version**: 1.0.0