dahoud ed0d74e124
Some checks failed
CI/CD Pipeline / pipeline (push) Failing after 3m3s
feat(sprint-17 backend 2026-04-25): Public KPI Sharing — token signé HMAC-SHA256 + endpoints admin/public
Transparency réglementaire (Sprint 16.D différé livré en S17). Permet aux autorités
externes (BCEAO, ARTCI, CENTIF, contrôleurs UEMOA) de consulter les KPI agrégés
d'une organisation sans login, via lien signé temporairement.

Architecture sécurité
- KpiShareTokenService : HMAC-SHA256 + base64url, format orgId.expiryMillis.signature
- Vérification time-constant via MessageDigest.isEqual (résistant timing attacks)
- Secret @ConfigProperty unionflow.kpi.share.secret (défaut TTL 7 jours)
- Pas de DB — token autosuffisant, révocable seulement par rotation du secret

KpiPublicService
- snapshotPublic(orgId) : extrait sous-ensemble safe de ComplianceSnapshot
- Audit chaque accès public (méta-traçabilité — qui/quand consulté quoi)

Endpoints
- GET /api/admin/kpi/share-link/{orgId}?ttlSeconds=...
  @RolesAllowed ADMIN_ORGANISATION, PRESIDENT, COMPLIANCE_OFFICER, SUPER_ADMIN
  Retourne {token, ttlSeconds, publicUrl, publicWebPath}
- GET /api/public/kpi?token=...
  @PermitAll (whitelist /api/public/* dans application.properties)
  Retourne KpiPublicSnapshot ou 401/404 si token invalide/expiré ou org introuvable

Bump dépendance api 1.0.9 → 1.0.10 (DTO KpiPublicSnapshot ajouté)

Tests KpiShareTokenService (9 tests)
- Round-trip orgId, ttl 0/<=0 défaut, orgId null exception
- Token expiré (signature fake), tampering signature, tampering orgId
- Malformé (< 3 parts, > 4 parts)
- Null/blank
- Encode/decode round-trip avec caractères spéciaux

ACTION USER : mvn install api 1.0.10 puis tester impl/web.
2026-04-25 16:48:47 +00:00

UnionFlow Backend - API REST Quarkus

Java Quarkus PostgreSQL Kafka License

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


📋 Table des Matières


🏗️ 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)

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

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 :

<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

# 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

# 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

# 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 :

# 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)

./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

# 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

# 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

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

# Ou manuellement
./mvnw flyway:migrate

Commandes utiles

# 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

@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 pour l'architecture complète.


🔌 WebSocket Temps Réel

Endpoint

URL : ws://localhost:8085/ws/dashboard

Classe WebSocket

Fichier : DashboardWebSocket.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) :

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

🧪 Tests

Lancer les tests

# 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)

# 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


🔒 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

@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

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


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

Description
No description provided
Readme MIT 16 MiB
Languages
Java 99.4%
PowerShell 0.3%
PLpgSQL 0.2%