Initial commit: GBCM Server Quarkus implementation with JPA entities and services
This commit is contained in:
106
.gitignore
vendored
Normal file
106
.gitignore
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
# Quarkus
|
||||||
|
.quarkus/
|
||||||
|
|
||||||
|
# Database
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# JWT Keys
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.dockerignore
|
||||||
|
Dockerfile.jvm
|
||||||
|
Dockerfile.native
|
||||||
220
README.md
Normal file
220
README.md
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
# GBCM Server Implementation - Quarkus
|
||||||
|
|
||||||
|
Implémentation serveur de la plateforme GBCM (Global Business Consulting and Management) avec Quarkus.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Ce module contient l'implémentation complète des services backend GBCM, incluant l'authentification, la gestion des utilisateurs, les services de coaching et la facturation.
|
||||||
|
|
||||||
|
## Technologies
|
||||||
|
|
||||||
|
- **Quarkus 3.6.0** - Framework Java moderne
|
||||||
|
- **Hibernate ORM with Panache** - ORM et accès aux données
|
||||||
|
- **PostgreSQL** - Base de données principale
|
||||||
|
- **JWT** - Authentification et autorisation
|
||||||
|
- **RESTEasy Reactive** - Services REST
|
||||||
|
- **Flyway** - Migration de base de données
|
||||||
|
- **Mailer** - Envoi d'emails
|
||||||
|
- **OpenAPI/Swagger** - Documentation API
|
||||||
|
- **Maven** - Gestion des dépendances
|
||||||
|
|
||||||
|
## Prérequis
|
||||||
|
|
||||||
|
- Java 17 ou supérieur
|
||||||
|
- Maven 3.8+
|
||||||
|
- PostgreSQL 13+
|
||||||
|
- SMTP Server (pour les emails)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Cloner le repository
|
||||||
|
```bash
|
||||||
|
git clone https://git.lions.dev/gbcm/gbcm-server-impl-quarkus.git
|
||||||
|
cd gbcm-server-impl-quarkus
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Installer les dépendances
|
||||||
|
```bash
|
||||||
|
mvn clean install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Configuration de la base de données
|
||||||
|
```sql
|
||||||
|
CREATE DATABASE gbcm_server;
|
||||||
|
CREATE USER gbcm_server WITH PASSWORD 'gbcm_server_password';
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE gbcm_server TO gbcm_server;
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Configuration
|
||||||
|
Copier `application.properties.example` vers `application.properties` et configurer :
|
||||||
|
- Base de données PostgreSQL
|
||||||
|
- Configuration SMTP
|
||||||
|
- Clés JWT
|
||||||
|
- Paramètres métier
|
||||||
|
|
||||||
|
## Développement
|
||||||
|
|
||||||
|
### Démarrage en mode développement
|
||||||
|
```bash
|
||||||
|
mvn quarkus:dev
|
||||||
|
```
|
||||||
|
|
||||||
|
L'application sera accessible sur :
|
||||||
|
- API: http://localhost:8081/api/v1
|
||||||
|
- Swagger UI: http://localhost:8081/swagger
|
||||||
|
- Health Check: http://localhost:8081/health
|
||||||
|
|
||||||
|
### Base de données H2 (développement)
|
||||||
|
En mode dev, une base H2 en mémoire est utilisée automatiquement.
|
||||||
|
|
||||||
|
## Structure du projet
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── main/
|
||||||
|
│ ├── java/com/gbcm/server/
|
||||||
|
│ │ ├── entities/ # Entités JPA
|
||||||
|
│ │ ├── repositories/ # Repositories Panache
|
||||||
|
│ │ ├── services/ # Services métier
|
||||||
|
│ │ │ ├── impl/ # Implémentations
|
||||||
|
│ │ │ └── security/ # Services sécurité
|
||||||
|
│ │ ├── resources/ # Endpoints REST
|
||||||
|
│ │ ├── config/ # Configuration
|
||||||
|
│ │ └── utils/ # Utilitaires
|
||||||
|
│ └── resources/
|
||||||
|
│ ├── application.properties
|
||||||
|
│ ├── import.sql # Données de test
|
||||||
|
│ └── db/migration/ # Scripts Flyway
|
||||||
|
└── test/ # Tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
### Authentification
|
||||||
|
- `POST /api/v1/auth/login` - Connexion
|
||||||
|
- `POST /api/v1/auth/logout` - Déconnexion
|
||||||
|
- `POST /api/v1/auth/refresh` - Rafraîchissement token
|
||||||
|
- `GET /api/v1/auth/validate` - Validation token
|
||||||
|
|
||||||
|
### Utilisateurs
|
||||||
|
- `GET /api/v1/users` - Liste des utilisateurs
|
||||||
|
- `GET /api/v1/users/{id}` - Utilisateur par ID
|
||||||
|
- `POST /api/v1/users` - Création utilisateur
|
||||||
|
- `PUT /api/v1/users/{id}` - Mise à jour utilisateur
|
||||||
|
|
||||||
|
### Coaching
|
||||||
|
- `GET /api/v1/coaching/sessions` - Sessions de coaching
|
||||||
|
- `POST /api/v1/coaching/sessions` - Nouvelle session
|
||||||
|
- `PUT /api/v1/coaching/sessions/{id}` - Mise à jour session
|
||||||
|
|
||||||
|
### Ateliers
|
||||||
|
- `GET /api/v1/workshops` - Liste des ateliers
|
||||||
|
- `POST /api/v1/workshops` - Nouvel atelier
|
||||||
|
- `POST /api/v1/workshops/{id}/register` - Inscription
|
||||||
|
|
||||||
|
## Base de données
|
||||||
|
|
||||||
|
### Migrations Flyway
|
||||||
|
Les scripts de migration sont dans `src/main/resources/db/migration/` :
|
||||||
|
- `V1__create_users.sql` - Table utilisateurs
|
||||||
|
- `V2__create_clients.sql` - Table clients
|
||||||
|
- `V3__create_workshops.sql` - Tables ateliers
|
||||||
|
|
||||||
|
### Entités principales
|
||||||
|
- `User` - Utilisateurs système
|
||||||
|
- `Client` - Clients GBCM
|
||||||
|
- `Coach` - Coachs/consultants
|
||||||
|
- `Workshop` - Ateliers Strategic
|
||||||
|
- `CoachingSession` - Sessions de coaching
|
||||||
|
- `Invoice` - Factures
|
||||||
|
|
||||||
|
## Sécurité
|
||||||
|
|
||||||
|
### JWT
|
||||||
|
- Tokens signés avec clé privée RSA
|
||||||
|
- Durée de vie configurable
|
||||||
|
- Refresh tokens pour sessions longues
|
||||||
|
- Blacklist des tokens révoqués
|
||||||
|
|
||||||
|
### Rôles et permissions
|
||||||
|
- `ADMIN` - Accès complet
|
||||||
|
- `COACH` - Gestion clients et sessions
|
||||||
|
- `CLIENT` - Accès services souscrits
|
||||||
|
- `MANAGER` - Gestion opérationnelle
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tests unitaires
|
||||||
|
mvn test
|
||||||
|
|
||||||
|
# Tests d'intégration
|
||||||
|
mvn verify
|
||||||
|
|
||||||
|
# Tests avec Testcontainers
|
||||||
|
mvn test -Dtest.containers=true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build et déploiement
|
||||||
|
|
||||||
|
### Build JVM
|
||||||
|
```bash
|
||||||
|
mvn clean package
|
||||||
|
java -jar target/quarkus-app/quarkus-run.jar
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build natif
|
||||||
|
```bash
|
||||||
|
mvn clean package -Pnative
|
||||||
|
./target/gbcm-server-impl-quarkus-1.0.0-SNAPSHOT-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
```bash
|
||||||
|
# Build image
|
||||||
|
docker build -t gbcm-server .
|
||||||
|
|
||||||
|
# Run container
|
||||||
|
docker run -p 8081:8081 \
|
||||||
|
-e DATABASE_URL=jdbc:postgresql://host:5432/gbcm \
|
||||||
|
-e DB_USERNAME=gbcm_server \
|
||||||
|
-e DB_PASSWORD=password \
|
||||||
|
gbcm-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Variables d'environnement principales
|
||||||
|
- `DATABASE_URL` - URL base de données
|
||||||
|
- `DB_USERNAME` - Utilisateur DB
|
||||||
|
- `DB_PASSWORD` - Mot de passe DB
|
||||||
|
- `SMTP_USERNAME` - Utilisateur SMTP
|
||||||
|
- `SMTP_PASSWORD` - Mot de passe SMTP
|
||||||
|
- `JWT_PRIVATE_KEY` - Clé privée JWT
|
||||||
|
|
||||||
|
### Configuration métier
|
||||||
|
- `gbcm.business.workshop.max-participants` - Participants max par atelier
|
||||||
|
- `gbcm.business.coaching.session-duration` - Durée session coaching
|
||||||
|
- `gbcm.business.billing.currency` - Devise facturation
|
||||||
|
|
||||||
|
## Monitoring
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
- `/health` - Statut général
|
||||||
|
- `/health/ready` - Prêt à recevoir du trafic
|
||||||
|
- `/health/live` - Application vivante
|
||||||
|
|
||||||
|
### Métriques
|
||||||
|
- `/metrics` - Métriques Prometheus
|
||||||
|
- Métriques métier personnalisées
|
||||||
|
- Monitoring des performances
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
- Email: support@gbcm.com
|
||||||
|
- Documentation: https://docs.gbcm.com
|
||||||
|
- API Docs: https://api.gbcm.com/swagger
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
Propriétaire - GBCM LLC © 2024
|
||||||
179
pom.xml
Normal file
179
pom.xml
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<?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-impl-quarkus</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>GBCM Server Implementation - Quarkus</name>
|
||||||
|
<description>Implémentation serveur GBCM avec Quarkus</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 -->
|
||||||
|
<quarkus.version>3.6.0</quarkus.version>
|
||||||
|
<testcontainers.version>1.19.3</testcontainers.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-bom</artifactId>
|
||||||
|
<version>${quarkus.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- GBCM Server API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.gbcm</groupId>
|
||||||
|
<artifactId>gbcm-server-api</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Quarkus Core -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-arc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-resteasy-reactive</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Database -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-orm-panache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-flyway</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Security -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-security-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-jwt</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Validation -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- OpenAPI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-openapi</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Health Check -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-smallrye-health</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Metrics -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-micrometer</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Email -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-mailer</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Scheduler -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-scheduler</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Cache -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Test Dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-junit5</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.rest-assured</groupId>
|
||||||
|
<artifactId>rest-assured</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${testcontainers.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-test-h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>io.quarkus</groupId>
|
||||||
|
<artifactId>quarkus-maven-plugin</artifactId>
|
||||||
|
<version>${quarkus.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>build</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.11.0</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.1.2</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
180
src/main/java/com/gbcm/server/entities/User.java
Normal file
180
src/main/java/com/gbcm/server/entities/User.java
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package com.gbcm.server.entities;
|
||||||
|
|
||||||
|
import com.gbcm.server.api.enums.UserRole;
|
||||||
|
import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
|
||||||
|
import io.quarkus.security.jpa.Password;
|
||||||
|
import io.quarkus.security.jpa.Roles;
|
||||||
|
import io.quarkus.security.jpa.UserDefinition;
|
||||||
|
import io.quarkus.security.jpa.Username;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import jakarta.validation.constraints.Email;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entité utilisateur pour l'authentification et la gestion des profils
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name = "users", indexes = {
|
||||||
|
@Index(name = "idx_user_email", columnList = "email", unique = true),
|
||||||
|
@Index(name = "idx_user_role", columnList = "role"),
|
||||||
|
@Index(name = "idx_user_active", columnList = "active")
|
||||||
|
})
|
||||||
|
@UserDefinition
|
||||||
|
public class User extends PanacheEntityBase {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
public Long id;
|
||||||
|
|
||||||
|
@Column(name = "first_name", nullable = false, length = 100)
|
||||||
|
@NotBlank(message = "Le prénom est obligatoire")
|
||||||
|
public String firstName;
|
||||||
|
|
||||||
|
@Column(name = "last_name", nullable = false, length = 100)
|
||||||
|
@NotBlank(message = "Le nom est obligatoire")
|
||||||
|
public String lastName;
|
||||||
|
|
||||||
|
@Column(name = "email", nullable = false, unique = true, length = 255)
|
||||||
|
@NotBlank(message = "L'email est obligatoire")
|
||||||
|
@Email(message = "Format d'email invalide")
|
||||||
|
@Username
|
||||||
|
public String email;
|
||||||
|
|
||||||
|
@Column(name = "password_hash", nullable = false)
|
||||||
|
@NotBlank(message = "Le mot de passe est obligatoire")
|
||||||
|
@Password
|
||||||
|
public String passwordHash;
|
||||||
|
|
||||||
|
@Column(name = "phone", length = 20)
|
||||||
|
public String phone;
|
||||||
|
|
||||||
|
@Column(name = "role", nullable = false, length = 20)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
@NotNull(message = "Le rôle est obligatoire")
|
||||||
|
@Roles
|
||||||
|
public UserRole role;
|
||||||
|
|
||||||
|
@Column(name = "active", nullable = false)
|
||||||
|
public boolean active = true;
|
||||||
|
|
||||||
|
@Column(name = "email_verified", nullable = false)
|
||||||
|
public boolean emailVerified = false;
|
||||||
|
|
||||||
|
@Column(name = "created_at", nullable = false)
|
||||||
|
public LocalDateTime createdAt;
|
||||||
|
|
||||||
|
@Column(name = "updated_at")
|
||||||
|
public LocalDateTime updatedAt;
|
||||||
|
|
||||||
|
@Column(name = "last_login_at")
|
||||||
|
public LocalDateTime lastLoginAt;
|
||||||
|
|
||||||
|
@Column(name = "password_reset_token")
|
||||||
|
public String passwordResetToken;
|
||||||
|
|
||||||
|
@Column(name = "password_reset_expires_at")
|
||||||
|
public LocalDateTime passwordResetExpiresAt;
|
||||||
|
|
||||||
|
@Column(name = "email_verification_token")
|
||||||
|
public String emailVerificationToken;
|
||||||
|
|
||||||
|
// Constructeurs
|
||||||
|
public User() {
|
||||||
|
this.createdAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String firstName, String lastName, String email, String passwordHash, UserRole role) {
|
||||||
|
this();
|
||||||
|
this.firstName = firstName;
|
||||||
|
this.lastName = lastName;
|
||||||
|
this.email = email;
|
||||||
|
this.passwordHash = passwordHash;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPasswordResetTokenValid() {
|
||||||
|
return passwordResetToken != null &&
|
||||||
|
passwordResetExpiresAt != null &&
|
||||||
|
passwordResetExpiresAt.isAfter(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateLastLogin() {
|
||||||
|
this.lastLoginAt = LocalDateTime.now();
|
||||||
|
this.updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callbacks JPA
|
||||||
|
@PreUpdate
|
||||||
|
public void preUpdate() {
|
||||||
|
this.updatedAt = LocalDateTime.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes de recherche Panache
|
||||||
|
public static User findByEmail(String email) {
|
||||||
|
return find("email", email).firstResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User findByEmailAndActive(String email, boolean active) {
|
||||||
|
return find("email = ?1 and active = ?2", email, active).firstResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User findByPasswordResetToken(String token) {
|
||||||
|
return find("passwordResetToken", token).firstResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static User findByEmailVerificationToken(String token) {
|
||||||
|
return find("emailVerificationToken", token).firstResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long countByRole(UserRole role) {
|
||||||
|
return count("role", role);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long countActiveUsers() {
|
||||||
|
return count("active", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// equals et hashCode
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
User user = (User) o;
|
||||||
|
return Objects.equals(id, user.id) && Objects.equals(email, user.email);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, email);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" +
|
||||||
|
"id=" + id +
|
||||||
|
", firstName='" + firstName + '\'' +
|
||||||
|
", lastName='" + lastName + '\'' +
|
||||||
|
", email='" + email + '\'' +
|
||||||
|
", role=" + role +
|
||||||
|
", active=" + active +
|
||||||
|
", createdAt=" + createdAt +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
249
src/main/java/com/gbcm/server/services/impl/AuthServiceImpl.java
Normal file
249
src/main/java/com/gbcm/server/services/impl/AuthServiceImpl.java
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
package com.gbcm.server.services.impl;
|
||||||
|
|
||||||
|
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 com.gbcm.server.api.interfaces.AuthService;
|
||||||
|
import com.gbcm.server.entities.User;
|
||||||
|
import com.gbcm.server.services.security.JwtService;
|
||||||
|
import com.gbcm.server.utils.EmailUtils;
|
||||||
|
|
||||||
|
import io.quarkus.elytron.security.common.BcryptUtil;
|
||||||
|
import io.quarkus.logging.Log;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implémentation du service d'authentification
|
||||||
|
*/
|
||||||
|
@ApplicationScoped
|
||||||
|
public class AuthServiceImpl implements AuthService {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
JwtService jwtService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
EmailUtils emailUtils;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public LoginResponseDTO login(@Valid LoginRequestDTO loginRequest)
|
||||||
|
throws AuthenticationException, GBCMException {
|
||||||
|
|
||||||
|
Log.infof("Tentative de connexion pour: %s", loginRequest.getEmail());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Recherche de l'utilisateur
|
||||||
|
User user = User.findByEmailAndActive(loginRequest.getEmail(), true);
|
||||||
|
if (user == null) {
|
||||||
|
Log.warnf("Utilisateur non trouvé ou inactif: %s", loginRequest.getEmail());
|
||||||
|
throw new AuthenticationException("Identifiants invalides");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérification du mot de passe
|
||||||
|
if (!BcryptUtil.matches(loginRequest.getPassword(), user.passwordHash)) {
|
||||||
|
Log.warnf("Mot de passe incorrect pour: %s", loginRequest.getEmail());
|
||||||
|
throw new AuthenticationException("Identifiants invalides");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mise à jour de la dernière connexion
|
||||||
|
user.updateLastLogin();
|
||||||
|
user.persist();
|
||||||
|
|
||||||
|
// Génération du token JWT
|
||||||
|
String token = jwtService.generateToken(user);
|
||||||
|
LocalDateTime expiresAt = LocalDateTime.now().plusHours(1);
|
||||||
|
|
||||||
|
// Création de la réponse
|
||||||
|
UserDTO userDTO = mapToUserDTO(user);
|
||||||
|
LoginResponseDTO response = LoginResponseDTO.success(token, expiresAt, userDTO);
|
||||||
|
|
||||||
|
if (loginRequest.isRememberMe()) {
|
||||||
|
String refreshToken = jwtService.generateRefreshToken(user);
|
||||||
|
response.setRefreshToken(refreshToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.infof("Connexion réussie pour: %s", loginRequest.getEmail());
|
||||||
|
return response;
|
||||||
|
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors de la connexion pour: %s", loginRequest.getEmail());
|
||||||
|
throw new GBCMException("Erreur système lors de la connexion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void logout(String authToken) throws AuthenticationException {
|
||||||
|
try {
|
||||||
|
// Extraction du token (suppression du préfixe "Bearer ")
|
||||||
|
String token = extractToken(authToken);
|
||||||
|
|
||||||
|
// Validation et extraction des informations utilisateur
|
||||||
|
UserDTO userDTO = jwtService.validateToken(token);
|
||||||
|
|
||||||
|
// Ajout du token à la blacklist
|
||||||
|
jwtService.blacklistToken(token);
|
||||||
|
|
||||||
|
Log.infof("Déconnexion réussie pour l'utilisateur: %s", userDTO.getEmail());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors de la déconnexion");
|
||||||
|
throw new AuthenticationException("Erreur lors de la déconnexion");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoginResponseDTO refreshToken(String refreshToken) throws AuthenticationException {
|
||||||
|
try {
|
||||||
|
// Validation du refresh token
|
||||||
|
UserDTO userDTO = jwtService.validateRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
// Recherche de l'utilisateur
|
||||||
|
User user = User.findByEmail(userDTO.getEmail());
|
||||||
|
if (user == null || !user.active) {
|
||||||
|
throw new AuthenticationException("Utilisateur non trouvé ou inactif");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Génération d'un nouveau token
|
||||||
|
String newToken = jwtService.generateToken(user);
|
||||||
|
LocalDateTime expiresAt = LocalDateTime.now().plusHours(1);
|
||||||
|
|
||||||
|
return LoginResponseDTO.success(newToken, expiresAt, userDTO);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors du rafraîchissement du token");
|
||||||
|
throw new AuthenticationException("Token de rafraîchissement invalide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDTO validateToken(String authToken) throws AuthenticationException {
|
||||||
|
try {
|
||||||
|
String token = extractToken(authToken);
|
||||||
|
return jwtService.validateToken(token);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors de la validation du token");
|
||||||
|
throw new AuthenticationException("Token invalide");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void forgotPassword(String email) throws GBCMException {
|
||||||
|
try {
|
||||||
|
User user = User.findByEmailAndActive(email, true);
|
||||||
|
if (user == null) {
|
||||||
|
// Pour des raisons de sécurité, on ne révèle pas si l'email existe
|
||||||
|
Log.warnf("Demande de réinitialisation pour email inexistant: %s", email);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Génération du token de réinitialisation
|
||||||
|
String resetToken = UUID.randomUUID().toString();
|
||||||
|
user.passwordResetToken = resetToken;
|
||||||
|
user.passwordResetExpiresAt = LocalDateTime.now().plusHours(24);
|
||||||
|
user.persist();
|
||||||
|
|
||||||
|
// Envoi de l'email
|
||||||
|
emailUtils.sendPasswordResetEmail(user.email, user.getFullName(), resetToken);
|
||||||
|
|
||||||
|
Log.infof("Email de réinitialisation envoyé à: %s", email);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors de l'envoi de l'email de réinitialisation");
|
||||||
|
throw new GBCMException("Erreur lors de l'envoi de l'email");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void resetPassword(String resetToken, String newPassword) throws GBCMException {
|
||||||
|
try {
|
||||||
|
User user = User.findByPasswordResetToken(resetToken);
|
||||||
|
if (user == null || !user.isPasswordResetTokenValid()) {
|
||||||
|
throw new GBCMException("Token de réinitialisation invalide ou expiré");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mise à jour du mot de passe
|
||||||
|
user.passwordHash = BcryptUtil.bcryptHash(newPassword);
|
||||||
|
user.passwordResetToken = null;
|
||||||
|
user.passwordResetExpiresAt = null;
|
||||||
|
user.updatedAt = LocalDateTime.now();
|
||||||
|
user.persist();
|
||||||
|
|
||||||
|
Log.infof("Mot de passe réinitialisé pour: %s", user.email);
|
||||||
|
|
||||||
|
} catch (GBCMException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors de la réinitialisation du mot de passe");
|
||||||
|
throw new GBCMException("Erreur lors de la réinitialisation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void changePassword(String authToken, String oldPassword, String newPassword)
|
||||||
|
throws AuthenticationException, GBCMException {
|
||||||
|
try {
|
||||||
|
// Validation du token et récupération de l'utilisateur
|
||||||
|
UserDTO userDTO = validateToken(authToken);
|
||||||
|
User user = User.findByEmail(userDTO.getEmail());
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
throw new AuthenticationException("Utilisateur non trouvé");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérification de l'ancien mot de passe
|
||||||
|
if (!BcryptUtil.matches(oldPassword, user.passwordHash)) {
|
||||||
|
throw new GBCMException("Ancien mot de passe incorrect");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mise à jour du mot de passe
|
||||||
|
user.passwordHash = BcryptUtil.bcryptHash(newPassword);
|
||||||
|
user.updatedAt = LocalDateTime.now();
|
||||||
|
user.persist();
|
||||||
|
|
||||||
|
Log.infof("Mot de passe changé pour: %s", user.email);
|
||||||
|
|
||||||
|
} catch (AuthenticationException | GBCMException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.errorf(e, "Erreur lors du changement de mot de passe");
|
||||||
|
throw new GBCMException("Erreur lors du changement de mot de passe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthodes utilitaires privées
|
||||||
|
private String extractToken(String authToken) throws AuthenticationException {
|
||||||
|
if (authToken == null || !authToken.startsWith("Bearer ")) {
|
||||||
|
throw new AuthenticationException("Format de token invalide");
|
||||||
|
}
|
||||||
|
return authToken.substring(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserDTO mapToUserDTO(User user) {
|
||||||
|
UserDTO dto = new UserDTO();
|
||||||
|
dto.setId(user.id);
|
||||||
|
dto.setFirstName(user.firstName);
|
||||||
|
dto.setLastName(user.lastName);
|
||||||
|
dto.setEmail(user.email);
|
||||||
|
dto.setPhone(user.phone);
|
||||||
|
dto.setRole(user.role);
|
||||||
|
dto.setActive(user.active);
|
||||||
|
dto.setCreatedAt(user.createdAt);
|
||||||
|
dto.setUpdatedAt(user.updatedAt);
|
||||||
|
dto.setLastLoginAt(user.lastLoginAt);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
src/main/resources/application.properties
Normal file
103
src/main/resources/application.properties
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
# GBCM Server Configuration
|
||||||
|
quarkus.application.name=gbcm-server
|
||||||
|
quarkus.application.version=1.0.0-SNAPSHOT
|
||||||
|
|
||||||
|
# Server Configuration
|
||||||
|
quarkus.http.port=8081
|
||||||
|
quarkus.http.host=0.0.0.0
|
||||||
|
quarkus.http.cors=true
|
||||||
|
quarkus.http.cors.origins=http://localhost:8080,https://gbcm.com
|
||||||
|
quarkus.http.cors.methods=GET,PUT,POST,DELETE,OPTIONS
|
||||||
|
quarkus.http.cors.headers=accept,authorization,content-type,x-requested-with
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
quarkus.datasource.db-kind=postgresql
|
||||||
|
quarkus.datasource.username=gbcm_server
|
||||||
|
quarkus.datasource.password=gbcm_server_password
|
||||||
|
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/gbcm_server
|
||||||
|
|
||||||
|
# Hibernate Configuration
|
||||||
|
quarkus.hibernate-orm.database.generation=validate
|
||||||
|
quarkus.hibernate-orm.log.sql=false
|
||||||
|
quarkus.hibernate-orm.sql-load-script=import.sql
|
||||||
|
|
||||||
|
# Flyway Configuration
|
||||||
|
quarkus.flyway.migrate-at-start=true
|
||||||
|
quarkus.flyway.locations=db/migration
|
||||||
|
quarkus.flyway.baseline-on-migrate=true
|
||||||
|
|
||||||
|
# Security Configuration
|
||||||
|
quarkus.security.auth.enabled=true
|
||||||
|
|
||||||
|
# JWT Configuration
|
||||||
|
mp.jwt.verify.publickey.location=META-INF/resources/publicKey.pem
|
||||||
|
mp.jwt.verify.issuer=https://gbcm.com
|
||||||
|
smallrye.jwt.sign.key.location=META-INF/resources/privateKey.pem
|
||||||
|
smallrye.jwt.new-token.issuer=https://gbcm.com
|
||||||
|
smallrye.jwt.new-token.audience=gbcm-users
|
||||||
|
smallrye.jwt.new-token.lifespan=3600
|
||||||
|
|
||||||
|
# OpenAPI Configuration
|
||||||
|
quarkus.smallrye-openapi.path=/swagger-ui
|
||||||
|
quarkus.swagger-ui.always-include=true
|
||||||
|
quarkus.swagger-ui.path=/swagger
|
||||||
|
mp.openapi.extensions.smallrye.info.title=GBCM Server API
|
||||||
|
mp.openapi.extensions.smallrye.info.version=1.0.0
|
||||||
|
mp.openapi.extensions.smallrye.info.description=API pour les services GBCM
|
||||||
|
mp.openapi.extensions.smallrye.info.contact.email=support@gbcm.com
|
||||||
|
mp.openapi.extensions.smallrye.info.contact.name=GBCM Support
|
||||||
|
mp.openapi.extensions.smallrye.info.license.name=Proprietary
|
||||||
|
mp.openapi.extensions.smallrye.info.license.url=https://gbcm.com/license
|
||||||
|
|
||||||
|
# Health Check Configuration
|
||||||
|
quarkus.smallrye-health.root-path=/health
|
||||||
|
|
||||||
|
# Metrics Configuration
|
||||||
|
quarkus.micrometer.enabled=true
|
||||||
|
quarkus.micrometer.export.prometheus.enabled=true
|
||||||
|
|
||||||
|
# Email Configuration
|
||||||
|
quarkus.mailer.from=noreply@gbcm.com
|
||||||
|
quarkus.mailer.host=smtp.gmail.com
|
||||||
|
quarkus.mailer.port=587
|
||||||
|
quarkus.mailer.start-tls=REQUIRED
|
||||||
|
quarkus.mailer.username=${SMTP_USERNAME:}
|
||||||
|
quarkus.mailer.password=${SMTP_PASSWORD:}
|
||||||
|
|
||||||
|
# Cache Configuration
|
||||||
|
quarkus.cache.caffeine.default.initial-capacity=100
|
||||||
|
quarkus.cache.caffeine.default.maximum-size=1000
|
||||||
|
quarkus.cache.caffeine.default.expire-after-write=PT30M
|
||||||
|
|
||||||
|
# Logging Configuration
|
||||||
|
quarkus.log.level=INFO
|
||||||
|
quarkus.log.category."com.gbcm".level=DEBUG
|
||||||
|
quarkus.log.category."org.hibernate.SQL".level=DEBUG
|
||||||
|
|
||||||
|
# Development Profile
|
||||||
|
%dev.quarkus.log.level=DEBUG
|
||||||
|
%dev.quarkus.hibernate-orm.log.sql=true
|
||||||
|
%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:gbcm_server_dev;DB_CLOSE_DELAY=-1
|
||||||
|
%dev.quarkus.datasource.db-kind=h2
|
||||||
|
%dev.quarkus.hibernate-orm.database.generation=drop-and-create
|
||||||
|
%dev.quarkus.flyway.migrate-at-start=false
|
||||||
|
|
||||||
|
# Test Profile
|
||||||
|
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:gbcm_server_test;DB_CLOSE_DELAY=-1
|
||||||
|
%test.quarkus.datasource.db-kind=h2
|
||||||
|
%test.quarkus.hibernate-orm.database.generation=drop-and-create
|
||||||
|
%test.quarkus.flyway.migrate-at-start=false
|
||||||
|
|
||||||
|
# Production Profile
|
||||||
|
%prod.quarkus.log.level=WARN
|
||||||
|
%prod.quarkus.hibernate-orm.log.sql=false
|
||||||
|
%prod.quarkus.datasource.jdbc.url=${DATABASE_URL}
|
||||||
|
%prod.quarkus.datasource.username=${DB_USERNAME}
|
||||||
|
%prod.quarkus.datasource.password=${DB_PASSWORD}
|
||||||
|
|
||||||
|
# Business Configuration
|
||||||
|
gbcm.business.workshop.max-participants=20
|
||||||
|
gbcm.business.coaching.session-duration=60
|
||||||
|
gbcm.business.billing.currency=USD
|
||||||
|
gbcm.business.notification.email.enabled=true
|
||||||
|
gbcm.business.notification.sms.enabled=false
|
||||||
Reference in New Issue
Block a user