Initial commit: GBCM Server API with DTOs, interfaces and enums

This commit is contained in:
dahoud
2025-10-06 18:47:05 +00:00
commit 95c2552c26
8 changed files with 953 additions and 0 deletions

82
.gitignore vendored Normal file
View File

@@ -0,0 +1,82 @@
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs
hs_err_pid*
# Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
# Gradle
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
# IntelliJ IDEA
.idea/
*.iws
*.iml
*.ipr
out/
# Eclipse
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
# NetBeans
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
# VS Code
.vscode/
# Mac
.DS_Store
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# Generated sources
src/gen/
# Temporary files
*.tmp
*.temp

152
README.md Normal file
View File

@@ -0,0 +1,152 @@
# GBCM Server API
Contrats d'API et DTOs pour la plateforme GBCM (Global Business Consulting and Management).
## Description
Ce module contient les définitions d'interfaces, DTOs (Data Transfer Objects), énumérations et exceptions partagées entre le client et le serveur GBCM.
## Technologies
- **Java 17** - Langage de programmation
- **Jakarta Validation 3.0** - Validation des données
- **Jakarta REST 3.1** - Annotations REST
- **Jackson** - Sérialisation JSON
- **Swagger/OpenAPI 3** - Documentation API
- **Maven** - Gestion des dépendances
## Structure du projet
```
src/main/java/com/gbcm/server/api/
├── dto/ # Data Transfer Objects
│ ├── auth/ # DTOs authentification
│ ├── user/ # DTOs utilisateurs
│ ├── coaching/ # DTOs coaching
│ ├── workshop/ # DTOs ateliers
│ ├── billing/ # DTOs facturation
│ └── common/ # DTOs communs
├── interfaces/ # Interfaces de service
│ ├── AuthService.java
│ ├── UserService.java
│ ├── CoachingService.java
│ └── WorkshopService.java
├── enums/ # Énumérations
│ ├── UserRole.java
│ ├── ServiceType.java
│ └── PaymentStatus.java
└── exceptions/ # Exceptions métier
├── GBCMException.java
├── AuthenticationException.java
└── ValidationException.java
```
## Installation
```bash
git clone https://git.lions.dev/gbcm/gbcm-server-api.git
cd gbcm-server-api
mvn clean install
```
## Utilisation
Ce module est une dépendance partagée utilisée par :
- `gbcm-client-impl-quarkus` - Interface web
- `gbcm-server-impl-quarkus` - Implémentation serveur
- `gbcm-mobile-app` - Application mobile (via REST)
### Ajout de la dépendance
```xml
<dependency>
<groupId>com.gbcm</groupId>
<artifactId>gbcm-server-api</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
```
## DTOs Principaux
### Authentification
- `LoginRequestDTO` - Requête de connexion
- `LoginResponseDTO` - Réponse de connexion
- `UserDTO` - Informations utilisateur
### Services
- `WorkshopDTO` - Informations atelier
- `CoachingSessionDTO` - Session de coaching
- `InvoiceDTO` - Facturation
## Interfaces de Service
### AuthService
- `login()` - Authentification
- `logout()` - Déconnexion
- `refreshToken()` - Rafraîchissement token
- `validateToken()` - Validation token
### UserService
- `createUser()` - Création utilisateur
- `updateUser()` - Mise à jour
- `getUserById()` - Récupération par ID
## Énumérations
### UserRole
- `ADMIN` - Administrateur
- `COACH` - Coach/Consultant
- `CLIENT` - Client
- `PROSPECT` - Prospect
- `MANAGER` - Manager
## Validation
Toutes les DTOs incluent des annotations de validation Jakarta :
- `@NotNull`, `@NotBlank` - Champs obligatoires
- `@Email` - Format email
- `@Size` - Taille des chaînes
- `@Valid` - Validation en cascade
## Documentation OpenAPI
La documentation API est générée automatiquement via les annotations Swagger :
- Descriptions des endpoints
- Schémas des DTOs
- Exemples de requêtes/réponses
## Tests
```bash
mvn test
```
## Build
```bash
# Build standard
mvn clean package
# Installation locale
mvn clean install
# Déploiement (si configuré)
mvn deploy
```
## Versioning
Ce module suit le versioning sémantique :
- `MAJOR.MINOR.PATCH`
- Changements breaking = MAJOR
- Nouvelles fonctionnalités = MINOR
- Corrections de bugs = PATCH
## Support
- Email: support@gbcm.com
- Documentation: https://docs.gbcm.com/api
## Licence
Propriétaire - GBCM LLC © 2024

95
pom.xml Normal file
View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gbcm</groupId>
<artifactId>gbcm-server-api</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>GBCM Server API</name>
<description>Contrats d'API et DTOs pour les services GBCM</description>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Versions -->
<jakarta.validation.version>3.0.2</jakarta.validation.version>
<jakarta.ws.rs.version>3.1.0</jakarta.ws.rs.version>
<jackson.version>2.15.2</jackson.version>
<swagger.version>2.2.15</swagger.version>
</properties>
<dependencies>
<!-- Jakarta Validation -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${jakarta.validation.version}</version>
</dependency>
<!-- Jakarta REST -->
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>${jakarta.ws.rs.version}</version>
</dependency>
<!-- Jackson Annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Swagger Annotations -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
<!-- OpenAPI Generator Plugin -->
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.0.1</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/META-INF/openapi.yaml</inputSpec>
<generatorName>java</generatorName>
<configOptions>
<sourceFolder>src/gen/java/main</sourceFolder>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,77 @@
package com.gbcm.server.api.dto.auth;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
/**
* DTO pour les requêtes de connexion
*/
@Schema(description = "Requête de connexion utilisateur")
public class LoginRequestDTO {
@Schema(description = "Adresse email de l'utilisateur", example = "user@gbcm.com")
@JsonProperty("email")
@NotBlank(message = "L'email est obligatoire")
@Email(message = "Format d'email invalide")
private String email;
@Schema(description = "Mot de passe", example = "password123")
@JsonProperty("password")
@NotBlank(message = "Le mot de passe est obligatoire")
@Size(min = 6, max = 100, message = "Le mot de passe doit contenir entre 6 et 100 caractères")
private String password;
@Schema(description = "Se souvenir de moi", example = "true")
@JsonProperty("rememberMe")
private boolean rememberMe = false;
// Constructeurs
public LoginRequestDTO() {}
public LoginRequestDTO(String email, String password) {
this.email = email;
this.password = password;
}
public LoginRequestDTO(String email, String password, boolean rememberMe) {
this.email = email;
this.password = password;
this.rememberMe = rememberMe;
}
// Getters et Setters
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isRememberMe() {
return rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}
@Override
public String toString() {
return "LoginRequestDTO{" +
"email='" + email + '\'' +
", rememberMe=" + rememberMe +
'}';
}
}

View File

@@ -0,0 +1,118 @@
package com.gbcm.server.api.dto.auth;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.gbcm.server.api.dto.user.UserDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDateTime;
/**
* DTO pour les réponses de connexion
*/
@Schema(description = "Réponse de connexion utilisateur")
public class LoginResponseDTO {
@Schema(description = "Succès de la connexion", example = "true")
@JsonProperty("success")
private boolean success;
@Schema(description = "Message de réponse", example = "Connexion réussie")
@JsonProperty("message")
private String message;
@Schema(description = "Token d'authentification JWT")
@JsonProperty("token")
private String token;
@Schema(description = "Date d'expiration du token")
@JsonProperty("expiresAt")
private LocalDateTime expiresAt;
@Schema(description = "Informations utilisateur")
@JsonProperty("user")
private UserDTO user;
@Schema(description = "Token de rafraîchissement")
@JsonProperty("refreshToken")
private String refreshToken;
// Constructeurs
public LoginResponseDTO() {}
public LoginResponseDTO(boolean success, String message) {
this.success = success;
this.message = message;
}
public static LoginResponseDTO success(String token, LocalDateTime expiresAt, UserDTO user) {
LoginResponseDTO response = new LoginResponseDTO(true, "Connexion réussie");
response.setToken(token);
response.setExpiresAt(expiresAt);
response.setUser(user);
return response;
}
public static LoginResponseDTO failure(String message) {
return new LoginResponseDTO(false, message);
}
// Getters et Setters
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public LocalDateTime getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(LocalDateTime expiresAt) {
this.expiresAt = expiresAt;
}
public UserDTO getUser() {
return user;
}
public void setUser(UserDTO user) {
this.user = user;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
@Override
public String toString() {
return "LoginResponseDTO{" +
"success=" + success +
", message='" + message + '\'' +
", token='" + (token != null ? "[PROTECTED]" : null) + '\'' +
", expiresAt=" + expiresAt +
", user=" + user +
'}';
}
}

View File

@@ -0,0 +1,178 @@
package com.gbcm.server.api.dto.user;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.gbcm.server.api.enums.UserRole;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* DTO pour les informations utilisateur
*/
@Schema(description = "Informations utilisateur")
public class UserDTO {
@Schema(description = "Identifiant unique", example = "1")
@JsonProperty("id")
private Long id;
@Schema(description = "Prénom", example = "John")
@JsonProperty("firstName")
@NotBlank(message = "Le prénom est obligatoire")
private String firstName;
@Schema(description = "Nom de famille", example = "Doe")
@JsonProperty("lastName")
@NotBlank(message = "Le nom est obligatoire")
private String lastName;
@Schema(description = "Adresse email", example = "john.doe@gbcm.com")
@JsonProperty("email")
@NotBlank(message = "L'email est obligatoire")
@Email(message = "Format d'email invalide")
private String email;
@Schema(description = "Numéro de téléphone", example = "+1234567890")
@JsonProperty("phone")
private String phone;
@Schema(description = "Rôle utilisateur")
@JsonProperty("role")
@NotNull(message = "Le rôle est obligatoire")
private UserRole role;
@Schema(description = "Statut actif", example = "true")
@JsonProperty("active")
private boolean active = true;
@Schema(description = "Date de création")
@JsonProperty("createdAt")
private LocalDateTime createdAt;
@Schema(description = "Date de dernière modification")
@JsonProperty("updatedAt")
private LocalDateTime updatedAt;
@Schema(description = "Date de dernière connexion")
@JsonProperty("lastLoginAt")
private LocalDateTime lastLoginAt;
// Constructeurs
public UserDTO() {}
public UserDTO(String firstName, String lastName, String email, UserRole role) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.role = role;
}
// Méthodes utilitaires
public String getFullName() {
return firstName + " " + lastName;
}
public String getInitials() {
String firstInitial = firstName != null && !firstName.isEmpty() ?
firstName.substring(0, 1).toUpperCase() : "";
String lastInitial = lastName != null && !lastName.isEmpty() ?
lastName.substring(0, 1).toUpperCase() : "";
return firstInitial + lastInitial;
}
// Getters et Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public UserRole getRole() {
return role;
}
public void setRole(UserRole role) {
this.role = role;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public LocalDateTime getLastLoginAt() {
return lastLoginAt;
}
public void setLastLoginAt(LocalDateTime lastLoginAt) {
this.lastLoginAt = lastLoginAt;
}
@Override
public String toString() {
return "UserDTO{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", role=" + role +
", active=" + active +
'}';
}
}

View File

@@ -0,0 +1,107 @@
package com.gbcm.server.api.enums;
import com.fasterxml.jackson.annotation.JsonValue;
/**
* Énumération des rôles utilisateur dans GBCM
*/
public enum UserRole {
/**
* Administrateur système - Accès complet
*/
ADMIN("ADMIN", "Administrateur", "Accès complet au système"),
/**
* Coach/Consultant - Gestion des clients et programmes
*/
COACH("COACH", "Coach", "Gestion des clients et programmes de coaching"),
/**
* Client - Accès aux services souscrits
*/
CLIENT("CLIENT", "Client", "Accès aux services et programmes souscrits"),
/**
* Prospect - Accès limité pour découverte
*/
PROSPECT("PROSPECT", "Prospect", "Accès limité aux ressources de découverte"),
/**
* Manager - Gestion opérationnelle
*/
MANAGER("MANAGER", "Manager", "Gestion opérationnelle et supervision");
private final String code;
private final String displayName;
private final String description;
UserRole(String code, String displayName, String description) {
this.code = code;
this.displayName = displayName;
this.description = description;
}
@JsonValue
public String getCode() {
return code;
}
public String getDisplayName() {
return displayName;
}
public String getDescription() {
return description;
}
/**
* Trouve un rôle par son code
*/
public static UserRole fromCode(String code) {
if (code == null) {
return null;
}
for (UserRole role : values()) {
if (role.code.equalsIgnoreCase(code)) {
return role;
}
}
throw new IllegalArgumentException("Rôle inconnu: " + code);
}
/**
* Vérifie si le rôle a des privilèges administrateur
*/
public boolean isAdmin() {
return this == ADMIN;
}
/**
* Vérifie si le rôle peut gérer des clients
*/
public boolean canManageClients() {
return this == ADMIN || this == COACH || this == MANAGER;
}
/**
* Vérifie si le rôle peut accéder aux services
*/
public boolean canAccessServices() {
return this == CLIENT || this == COACH || this == ADMIN || this == MANAGER;
}
/**
* Vérifie si le rôle peut voir les rapports
*/
public boolean canViewReports() {
return this == ADMIN || this == MANAGER;
}
@Override
public String toString() {
return displayName;
}
}

View File

@@ -0,0 +1,144 @@
package com.gbcm.server.api.interfaces;
import com.gbcm.server.api.dto.auth.LoginRequestDTO;
import com.gbcm.server.api.dto.auth.LoginResponseDTO;
import com.gbcm.server.api.dto.user.UserDTO;
import com.gbcm.server.api.exceptions.AuthenticationException;
import com.gbcm.server.api.exceptions.GBCMException;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
* Interface de service pour l'authentification
*/
@Path("/auth")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Tag(name = "Authentication", description = "Services d'authentification et autorisation")
public interface AuthService {
/**
* Connexion utilisateur
*/
@POST
@Path("/login")
@Operation(
summary = "Connexion utilisateur",
description = "Authentifie un utilisateur avec email et mot de passe"
)
@ApiResponse(responseCode = "200", description = "Connexion réussie")
@ApiResponse(responseCode = "401", description = "Identifiants invalides")
@ApiResponse(responseCode = "400", description = "Données de requête invalides")
LoginResponseDTO login(
@Parameter(description = "Informations de connexion", required = true)
LoginRequestDTO loginRequest
) throws AuthenticationException, GBCMException;
/**
* Déconnexion utilisateur
*/
@POST
@Path("/logout")
@Operation(
summary = "Déconnexion utilisateur",
description = "Invalide le token d'authentification"
)
@ApiResponse(responseCode = "200", description = "Déconnexion réussie")
@ApiResponse(responseCode = "401", description = "Token invalide")
void logout(
@Parameter(description = "Token d'authentification", required = true)
@HeaderParam("Authorization") String authToken
) throws AuthenticationException;
/**
* Rafraîchissement du token
*/
@POST
@Path("/refresh")
@Operation(
summary = "Rafraîchissement du token",
description = "Génère un nouveau token d'authentification"
)
@ApiResponse(responseCode = "200", description = "Token rafraîchi")
@ApiResponse(responseCode = "401", description = "Token de rafraîchissement invalide")
LoginResponseDTO refreshToken(
@Parameter(description = "Token de rafraîchissement", required = true)
@FormParam("refreshToken") String refreshToken
) throws AuthenticationException;
/**
* Validation du token
*/
@GET
@Path("/validate")
@Operation(
summary = "Validation du token",
description = "Vérifie la validité d'un token d'authentification"
)
@ApiResponse(responseCode = "200", description = "Token valide")
@ApiResponse(responseCode = "401", description = "Token invalide ou expiré")
UserDTO validateToken(
@Parameter(description = "Token d'authentification", required = true)
@HeaderParam("Authorization") String authToken
) throws AuthenticationException;
/**
* Demande de réinitialisation de mot de passe
*/
@POST
@Path("/forgot-password")
@Operation(
summary = "Mot de passe oublié",
description = "Envoie un email de réinitialisation de mot de passe"
)
@ApiResponse(responseCode = "200", description = "Email envoyé")
@ApiResponse(responseCode = "404", description = "Utilisateur non trouvé")
void forgotPassword(
@Parameter(description = "Adresse email", required = true)
@FormParam("email") String email
) throws GBCMException;
/**
* Réinitialisation du mot de passe
*/
@POST
@Path("/reset-password")
@Operation(
summary = "Réinitialisation du mot de passe",
description = "Réinitialise le mot de passe avec un token de réinitialisation"
)
@ApiResponse(responseCode = "200", description = "Mot de passe réinitialisé")
@ApiResponse(responseCode = "400", description = "Token invalide ou expiré")
void resetPassword(
@Parameter(description = "Token de réinitialisation", required = true)
@FormParam("resetToken") String resetToken,
@Parameter(description = "Nouveau mot de passe", required = true)
@FormParam("newPassword") String newPassword
) throws GBCMException;
/**
* Changement de mot de passe
*/
@PUT
@Path("/change-password")
@Operation(
summary = "Changement de mot de passe",
description = "Change le mot de passe d'un utilisateur authentifié"
)
@ApiResponse(responseCode = "200", description = "Mot de passe changé")
@ApiResponse(responseCode = "401", description = "Non autorisé")
@ApiResponse(responseCode = "400", description = "Ancien mot de passe incorrect")
void changePassword(
@Parameter(description = "Token d'authentification", required = true)
@HeaderParam("Authorization") String authToken,
@Parameter(description = "Ancien mot de passe", required = true)
@FormParam("oldPassword") String oldPassword,
@Parameter(description = "Nouveau mot de passe", required = true)
@FormParam("newPassword") String newPassword
) throws AuthenticationException, GBCMException;
}