# UnionFlow Backend - API REST Quarkus

![Java](https://img.shields.io/badge/Java-17-blue)
![Quarkus](https://img.shields.io/badge/Quarkus-3.27.3_LTS-red)
![PostgreSQL](https://img.shields.io/badge/PostgreSQL-15-blue)
![Kafka](https://img.shields.io/badge/Kafka-Enabled-orange)
![License](https://img.shields.io/badge/License-Proprietary-red)

Backend REST API pour UnionFlow - Gestion des mutuelles, associations et organisations Lions Club.

---

## 📋 Table des Matières

- [Architecture](#architecture)
- [Technologies](#technologies)
- [Prérequis](#prérequis)
- [Installation](#installation)
- [Configuration](#configuration)
- [Lancement](#lancement)
- [API Documentation](#api-documentation)
- [Base de données](#base-de-données)
- [Kafka Event Streaming](#kafka-event-streaming)
- [WebSocket Temps Réel](#websocket-temps-réel)
- [Tests](#tests)
- [Déploiement](#déploiement)

---

## 🏗️ Architecture

### Clean Architecture + DDD

```
src/main/java/dev/lions/unionflow/
├── domain/                    # Domain Layer (Entities métier)
│   ├── entities/             # Entités JPA (37 entités)
│   └── repositories/         # Repositories Panache
├── application/               # Application Layer (Use Cases)
│   └── services/             # Services métier
├── infrastructure/            # Infrastructure Layer
│   ├── rest/                 # REST Controllers
│   ├── messaging/            # Kafka Producers
│   ├── websocket/            # WebSocket endpoints
│   └── persistence/          # Configuration JPA
└── shared/                    # Shared Kernel
    ├── dto/                  # DTOs (Request/Response)
    ├── exceptions/           # Custom exceptions
    └── mappers/              # MapStruct mappers
```

### Pattern Repository avec Panache

Tous les repositories étendent `PanacheRepositoryBase<Entity, UUID>` pour :
- CRUD automatique
- Queries typées
- Streaming support
- Active Record pattern (optionnel)

---

## 🛠️ Technologies

| Composant | Version | Usage |
|-----------|---------|-------|
| **Java** | 17 (LTS) | Langage |
| **Quarkus** | 3.27.3 LTS | Framework application |
| **Hibernate ORM (Panache)** | 6.4+ | Persistence |
| **PostgreSQL** | 15 | Base de données |
| **Flyway** | 9.22+ | Migrations DB |
| **Kafka** | SmallRye Reactive Messaging | Event streaming |
| **WebSocket** | Quarkus WebSockets Next | Temps réel |
| **Keycloak** | OIDC/JWT | Authentification |
| **OpenPDF** | 1.3.30 | Export PDF |
| **MapStruct** | 1.5+ | Mapping DTO ↔ Entity |
| **Lombok** | 1.18.34 | Réduction boilerplate |
| **RESTEasy** | Reactive | REST endpoints |
| **SmallRye Health** | - | Health checks |
| **SmallRye OpenAPI** | - | Documentation API |

---

## 📦 Prérequis

### Environnement de développement

- **Java Development Kit**: OpenJDK 17 ou supérieur
- **Maven**: 3.8+
- **Docker**: 20.10+ (pour PostgreSQL, Keycloak, Kafka)
- **Git**: 2.30+

### Services externes (via Docker Compose)

```bash
cd unionflow/
docker-compose up -d
```

Services démarrés :
- **PostgreSQL** : `localhost:5432` (DB: `unionflow`, user: `unionflow`, pass: `unionflow`)
- **Keycloak** : `localhost:8180` (realm: `unionflow`, client: `unionflow-mobile`)
- **Kafka** : `localhost:9092` (topics auto-créés)
- **Zookeeper** : `localhost:2181`
- **MailDev** : `localhost:1080` (SMTP testing)

---

## 🚀 Installation

### 1. Cloner le projet

```bash
git clone https://git.lions.dev/lionsdev/unionflow-server-impl-quarkus.git
cd unionflow-server-impl-quarkus
```

### 2. Configurer Maven

Ajouter le repository Gitea à `~/.m2/settings.xml` :

```xml
<settings>
  <servers>
    <server>
      <id>gitea-lionsdev</id>
      <username>${env.GITEA_USERNAME}</username>
      <password>${env.GITEA_TOKEN}</password>
    </server>
  </servers>

  <mirrors>
    <mirror>
      <id>gitea-maven</id>
      <mirrorOf>external:*</mirrorOf>
      <url>https://git.lions.dev/api/packages/lionsdev/maven</url>
    </mirror>
  </mirrors>
</settings>
```

### 3. Compiler

```bash
# Compilation standard
./mvnw clean package

# Sans tests (rapide)
./mvnw clean package -DskipTests

# Avec profil production
./mvnw clean package -Pproduction
```

---

## ⚙️ Configuration

### Variables d'environnement

#### Développement

```bash
# Base de données
export DB_URL=jdbc:postgresql://localhost:5432/unionflow
export DB_USERNAME=unionflow
export DB_PASSWORD=unionflow

# Keycloak
export KEYCLOAK_URL=http://localhost:8180/realms/unionflow
export KEYCLOAK_CLIENT_SECRET=votre-secret-dev

# Kafka
export KAFKA_BOOTSTRAP_SERVERS=localhost:9092
```

#### Production

```bash
# Base de données
export DB_URL=jdbc:postgresql://postgresql-service.postgresql.svc.cluster.local:5432/unionflow
export DB_USERNAME=unionflow
export DB_PASSWORD=${SECURE_DB_PASSWORD}

# Keycloak
export KEYCLOAK_URL=https://security.lions.dev/realms/unionflow
export KEYCLOAK_CLIENT_SECRET=${SECURE_CLIENT_SECRET}

# Kafka
export KAFKA_BOOTSTRAP_SERVERS=kafka-service.kafka.svc.cluster.local:9092

# CORS
export CORS_ORIGINS=https://unionflow.lions.dev,https://api.lions.dev
```

### application.properties

**Dev** : `src/main/resources/application.properties`
**Prod** : `src/main/resources/application-prod.properties`

Propriétés clés :
```properties
# HTTP
quarkus.http.port=8085
quarkus.http.cors.origins=http://localhost:3000,http://localhost:8086

# Database
quarkus.datasource.db-kind=postgresql
quarkus.hibernate-orm.database.generation=validate  # Production
quarkus.flyway.migrate-at-start=true

# Keycloak OIDC
quarkus.oidc.auth-server-url=${KEYCLOAK_URL}
quarkus.oidc.client-id=unionflow-backend
quarkus.oidc.credentials.secret=${KEYCLOAK_CLIENT_SECRET}

# Kafka
kafka.bootstrap.servers=${KAFKA_BOOTSTRAP_SERVERS:localhost:9092}
mp.messaging.outgoing.finance-approvals.connector=smallrye-kafka

# WebSocket
quarkus.websockets.enabled=true
```

---

## 🏃 Lancement

### Mode développement (Live Reload)

```bash
./mvnw quarkus:dev

# Accès
# - API: http://localhost:8085
# - Swagger UI: http://localhost:8085/q/swagger-ui
# - Health: http://localhost:8085/q/health
# - Dev UI: http://localhost:8085/q/dev
```

### Mode production

```bash
# Build
./mvnw clean package -Pproduction

# Run
java -jar target/quarkus-app/quarkus-run.jar

# Ou avec profil spécifique
java -Dquarkus.profile=prod -jar target/quarkus-app/quarkus-run.jar
```

### Docker

```bash
# Build image
docker build -f src/main/docker/Dockerfile.jvm -t unionflow-backend:latest .

# Run container
docker run -p 8085:8085 \
  -e DB_URL=jdbc:postgresql://host.docker.internal:5432/unionflow \
  -e DB_USERNAME=unionflow \
  -e DB_PASSWORD=unionflow \
  -e KEYCLOAK_CLIENT_SECRET=secret \
  unionflow-backend:latest
```

---

## 📚 API Documentation

### Swagger UI

**Dev** : http://localhost:8085/q/swagger-ui
**Prod** : https://api.lions.dev/unionflow/q/swagger-ui

### Endpoints principaux

#### Finance Workflow

- `GET /api/v1/finance/approvals` - Liste des approbations en attente
- `POST /api/v1/finance/approvals/{id}/approve` - Approuver transaction
- `POST /api/v1/finance/approvals/{id}/reject` - Rejeter transaction
- `GET /api/v1/finance/budgets` - Liste des budgets
- `POST /api/v1/finance/budgets` - Créer budget

#### Dashboard

- `GET /api/v1/dashboard/stats` - Stats organisation
- `GET /api/v1/dashboard/kpi` - KPI temps réel
- `GET /api/v1/dashboard/activities` - Activités récentes

#### Membres

- `GET /api/v1/membres` - Liste membres
- `GET /api/v1/membres/{id}` - Détails membre
- `POST /api/v1/membres` - Créer membre
- `PUT /api/v1/membres/{id}` - Modifier membre

#### Cotisations

- `GET /api/v1/cotisations` - Liste cotisations
- `POST /api/v1/cotisations` - Enregistrer cotisation
- `GET /api/v1/cotisations/member/{memberId}` - Cotisations d'un membre

#### Notifications

- `GET /api/v1/notifications` - Liste notifications user
- `PUT /api/v1/notifications/{id}/read` - Marquer comme lue

---

## 🗄️ Base de données

### Schéma - 37 Entités

**Entités principales** :
- `BaseEntity` (classe abstraite) : id (UUID), dateCreation, dateModification, actif, version
- `Organisation` : nom, type, quota
- `Membre` : nom, prenom, email, telephone, organisation
- `Cotisation` : membre, montant, periode, statut
- `Adhesion` : membre, type, dateDebut, dateFin
- `Evenement` : titre, date, lieu, organisation
- `DemandeAide` : membre, categorie, montant, statut
- `TransactionApproval` : type, montant, statut (PENDING/APPROVED/REJECTED)
- `Budget` : nom, periode, année, lignes budgétaires
- `Notification` : user, titre, message, lu

### Migrations Flyway

**Localisation** : `src/main/resources/db/migration/`

- `V1.0__Initial_Schema.sql` - Création tables initiales
- `V2.0__Finance_Workflow.sql` - Tables Finance Workflow
- `V2.1__Add_Indexes.sql` - Index performance
- `V3.0__Kafka_Events.sql` - Support event sourcing (futur)

### Exécution migrations

```bash
# Automatique au démarrage (quarkus.flyway.migrate-at-start=true)
./mvnw quarkus:dev

# Ou manuellement
./mvnw flyway:migrate
```

### Commandes utiles

```bash
# Info migrations
./mvnw flyway:info

# Repair (en cas d'erreur)
./mvnw flyway:repair

# Baseline (migration existante DB)
./mvnw flyway:baseline
```

---

## 📡 Kafka Event Streaming

### Topics configurés

- `unionflow.finance.approvals` - Workflow approbations
- `unionflow.dashboard.stats` - Stats dashboard
- `unionflow.notifications.user` - Notifications utilisateurs
- `unionflow.members.events` - Événements membres
- `unionflow.contributions.events` - Cotisations

### Producer Kafka

**Classe** : `KafkaEventProducer`

```java
@ApplicationScoped
public class KafkaEventProducer {

    @Channel("finance-approvals")
    Emitter<String> financeEmitter;

    public void publishApprovalPending(TransactionApproval approval) {
        var event = Map.of(
            "eventType", "APPROVAL_PENDING",
            "timestamp", Instant.now().toString(),
            "approval", toDTO(approval)
        );
        financeEmitter.send(toJson(event));
    }
}
```

Voir [KAFKA_WEBSOCKET_ARCHITECTURE.md](../docs/KAFKA_WEBSOCKET_ARCHITECTURE.md) pour l'architecture complète.

---

## 🔌 WebSocket Temps Réel

### Endpoint

**URL** : `ws://localhost:8085/ws/dashboard`

### Classe WebSocket

**Fichier** : `DashboardWebSocket.java`

```java
@ServerEndpoint("/ws/dashboard")
@ApplicationScoped
public class DashboardWebSocket {

    @OnOpen
    public void onOpen(Session session) {
        sessions.add(session);
    }

    @Incoming("finance-approvals")
    public void handleFinanceEvent(String event) {
        broadcast(event);  // Broadcast à tous les clients connectés
    }
}
```

**Connexion mobile (Flutter)** :

```dart
final channel = WebSocketChannel.connect(
  Uri.parse('ws://localhost:8085/ws/dashboard')
);
channel.stream.listen((message) {
  print('Event received: $message');
});
```

---

## 🧪 Tests

### Lancer les tests

```bash
# Tous les tests
./mvnw test

# Tests unitaires seulement
./mvnw test -Dtest="*Test"

# Tests d'intégration seulement
./mvnw test -Dtest="*IT"

# Avec couverture
./mvnw test jacoco:report
```

### Structure tests

```
src/test/java/
├── domain/
│   └── entities/
│       └── MembreTest.java
├── application/
│   └── services/
│       └── FinanceWorkflowServiceTest.java
└── infrastructure/
    └── rest/
        └── FinanceResourceIT.java
```

---

## 🚢 Déploiement

### Kubernetes (Production)

**Outil** : `lionsctl` (CLI Go custom)

```bash
# Déploiement complet
lionsctl pipeline \
  -u https://git.lions.dev/lionsdev/unionflow-server-impl-quarkus \
  -b main \
  -j 21 \
  -e production \
  -c k1 \
  -p prod

# Étapes :
# 1. Clone repo Git
# 2. mvn clean package -Pprod
# 3. docker build -f Dockerfile (racine, fast-jar, ubi8/openjdk-21:1.21, UID 1001)
# 4. push registry.lions.dev
# 5. kubectl apply (Deployment + Service + Ingress)
# 6. Health check
# 7. Email notification
```

**Pré-requis infrastructure** avant pipeline (migration Helm → lionsctl pipeline) :
- Secret K8s `unionflow-server-impl-quarkus-db-secret` (clés `QUARKUS_DATASOURCE_USERNAME` + `QUARKUS_DATASOURCE_PASSWORD`)
- DB PostgreSQL `unionflow` (override `QUARKUS_DATASOURCE_JDBC_URL` sur le deployment car lionsctl nomme la DB comme l'app)
- Deployment Helm existant supprimé au préalable (selector immutable)
- Service selector à repatcher après pipeline (retirer les labels `app.kubernetes.io/*`)

### Fichiers Kubernetes

**Localisation** : `src/main/kubernetes/`

- `deployment.yaml` - Deployment (3 replicas)
- `service.yaml` - Service ClusterIP
- `ingress.yaml` - Ingress HTTPS
- `configmap.yaml` - Configuration
- `secret.yaml` - Secrets (DB, Keycloak)

### Accès production

- **API** : https://api.lions.dev/unionflow
- **Swagger** : https://api.lions.dev/unionflow/q/swagger-ui
- **Health** : https://api.lions.dev/unionflow/q/health

---

## 🔒 Sécurité

### Authentification

- **Méthode** : OIDC/JWT via Keycloak
- **Rôles** : SUPER_ADMIN, ADMIN_ORGANISATION, MEMBRE_ACTIF, MEMBRE
- **Token** : Bearer token dans header `Authorization`

### Endpoints protégés

```java
@RolesAllowed({"SUPER_ADMIN", "ADMIN_ORGANISATION"})
@POST
@Path("/budgets")
public Response createBudget(BudgetRequest request) {
    // ...
}
```

### CORS

Production : CORS configuré pour `https://unionflow.lions.dev`

---

## 📊 Monitoring

### Health Checks

- **Liveness** : `GET /q/health/live`
- **Readiness** : `GET /q/health/ready`

### Metrics (Prometheus-compatible)

- **Endpoint** : `GET /q/metrics`

### Logs structurés

```java
Logger.info("Finance approval created",
    kv("approvalId", approval.getId()),
    kv("organizationId", orgId),
    kv("amount", amount)
);
```

---

## 📝 Contribution

1. Fork le projet
2. Créer une branche feature (`git checkout -b feature/AmazingFeature`)
3. Commit changes (`git commit -m 'Add AmazingFeature'`)
4. Push to branch (`git push origin feature/AmazingFeature`)
5. Ouvrir une Pull Request

---

## 📄 Licence

Propriétaire - © 2026 Lions Club Côte d'Ivoire - Tous droits réservés

---

## 📞 Support

- **Email** : support@lions.dev
- **Issue Tracker** : https://git.lions.dev/lionsdev/unionflow-server-impl-quarkus/issues

---

**Version** : 2.0.0
**Dernière mise à jour** : 2026-03-14
**Auteur** : Équipe UnionFlow
