From 65a9d03c00969b6133e6b337e48773b700daafdb Mon Sep 17 00:00:00 2001
From: dahoud <41957584+DahoudG@users.noreply.github.com>
Date: Sat, 25 Apr 2026 12:31:43 +0000
Subject: [PATCH] =?UTF-8?q?feat(sprint-10=20api=202026-04-25):=20bump=201.?=
=?UTF-8?q?0.8=20+=20DTOs=20UBO/audit-trail/d=C3=A9l=C3=A9gation=20+=20Upd?=
=?UTF-8?q?ateOrganisationRequest=20enrichi?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Pré-requis pour exposer les features Sprints 1-2 via REST. Architecture stricte :
DTOs en module api (contrat public), aucune logique métier.
Version : 1.0.7 → 1.0.8
DTOs UBO (Instr. BCEAO 003-03-2025)
- CreateBeneficiaireEffectifRequest : validation pays ISO-3, regex natureControle (5 valeurs), pourcentages 0-100
- UpdateBeneficiaireEffectifRequest : tous optionnels (PATCH partiel)
- BeneficiaireEffectifResponse : vue read-only
DTOs audit trail (Sprint 1)
- AuditTrailOperationResponse : payloadAvant/payloadApres/metadata en String JSONB
DTOs délégation rôles (Sprint 2)
- CreateRoleDelegationRequest : regex rôle uppercase + dates futures
- RoleDelegationResponse : statut + estActive (calculé)
Enrich UpdateOrganisationRequest
- referentielComptable (regex SYSCOHADA|SYCEBNL|PCSFD_UMOA)
- complianceOfficerId UUID (Instr. BCEAO 001-03-2025)
À publier sur Gitea via script/publish-api.sh — user action requise.
---
pom.xml | 2 +-
.../response/AuditTrailOperationResponse.java | 36 +++++++++
.../request/CreateRoleDelegationRequest.java | 42 ++++++++++
.../response/RoleDelegationResponse.java | 27 +++++++
.../CreateBeneficiaireEffectifRequest.java | 79 +++++++++++++++++++
.../UpdateBeneficiaireEffectifRequest.java | 40 ++++++++++
.../BeneficiaireEffectifResponse.java | 43 ++++++++++
.../request/UpdateOrganisationRequest.java | 12 ++-
8 files changed, 279 insertions(+), 2 deletions(-)
create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/audit/response/AuditTrailOperationResponse.java
create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/delegation/request/CreateRoleDelegationRequest.java
create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/delegation/response/RoleDelegationResponse.java
create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/CreateBeneficiaireEffectifRequest.java
create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/UpdateBeneficiaireEffectifRequest.java
create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/kyc/response/BeneficiaireEffectifResponse.java
diff --git a/pom.xml b/pom.xml
index ec85c0c..1451815 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
Les payloads JSONB ({@code payloadAvant}, {@code payloadApres}, {@code metadata}) + * sont sérialisés en string ; le frontend les parse selon les besoins. + * + * @since 2026-04-25 (Sprint 10) + */ +@Builder +public record AuditTrailOperationResponse( + UUID id, + UUID userId, + String userEmail, + String roleActif, + UUID organisationActiveId, + String actionType, + String entityType, + UUID entityId, + String description, + String ipAddress, + String userAgent, + UUID requestId, + String payloadAvant, + String payloadApres, + String metadata, + Boolean sodCheckPassed, + String sodViolations, + LocalDateTime operationAt +) { +} diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/delegation/request/CreateRoleDelegationRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/delegation/request/CreateRoleDelegationRequest.java new file mode 100644 index 0000000..740d92e --- /dev/null +++ b/src/main/java/dev/lions/unionflow/server/api/dto/delegation/request/CreateRoleDelegationRequest.java @@ -0,0 +1,42 @@ +package dev.lions.unionflow.server.api.dto.delegation.request; + +import jakarta.validation.constraints.Future; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import java.time.LocalDateTime; +import java.util.UUID; +import lombok.Builder; + +/** + * Requête de création d'une délégation de rôle temporaire. + * + * @since 2026-04-25 (Sprint 10 — service existant Sprint 2) + */ +@Builder +public record CreateRoleDelegationRequest( + @NotNull(message = "L'organisation est obligatoire") + UUID organisationId, + + @NotNull(message = "Le déléguant est obligatoire") + UUID delegantUserId, + + @NotNull(message = "Le délégataire est obligatoire") + UUID delegataireUserId, + + @NotBlank(message = "Le rôle délégué est obligatoire") + @Pattern(regexp = "^[A-Z_]{3,50}$", message = "Format de rôle invalide (uppercase + underscore)") + String roleDelegue, + + @NotNull(message = "La date de début est obligatoire") + LocalDateTime dateDebut, + + @NotNull(message = "La date de fin est obligatoire") + @Future(message = "La date de fin doit être future") + LocalDateTime dateFin, + + @Size(max = 500) + String motif +) { +} diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/delegation/response/RoleDelegationResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/delegation/response/RoleDelegationResponse.java new file mode 100644 index 0000000..0827713 --- /dev/null +++ b/src/main/java/dev/lions/unionflow/server/api/dto/delegation/response/RoleDelegationResponse.java @@ -0,0 +1,27 @@ +package dev.lions.unionflow.server.api.dto.delegation.response; + +import java.time.LocalDateTime; +import java.util.UUID; +import lombok.Builder; + +/** + * Vue d'une délégation de rôle. + * + * @since 2026-04-25 (Sprint 10) + */ +@Builder +public record RoleDelegationResponse( + UUID id, + UUID organisationId, + UUID delegantUserId, + UUID delegataireUserId, + String roleDelegue, + LocalDateTime dateDebut, + LocalDateTime dateFin, + String motif, + String statut, + LocalDateTime dateRevocation, + LocalDateTime dateCreation, + boolean estActive +) { +} diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/CreateBeneficiaireEffectifRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/CreateBeneficiaireEffectifRequest.java new file mode 100644 index 0000000..d6f0573 --- /dev/null +++ b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/CreateBeneficiaireEffectifRequest.java @@ -0,0 +1,79 @@ +package dev.lions.unionflow.server.api.dto.kyc.request; + +import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.UUID; +import lombok.Builder; + +/** + * Création d'un Bénéficiaire Effectif (UBO) — Instruction BCEAO 003-03-2025. + * + *
Lié à un {@code KycDossier} d'entreprise. Au moins un identifiant cible est requis : + * {@code kycDossierId} pour KYC personne morale, ou {@code organisationCibleId} + + * {@code membreId} pour membre individuel à risque. + * + * @since 2026-04-25 (Sprint 10) + */ +@Builder +public record CreateBeneficiaireEffectifRequest( + UUID kycDossierId, + UUID organisationCibleId, + UUID membreId, + + @NotBlank(message = "Le nom est obligatoire") + @Size(max = 100) + String nom, + + @NotBlank(message = "Les prénoms sont obligatoires") + @Size(max = 200) + String prenoms, + + @NotNull(message = "La date de naissance est obligatoire") + LocalDate dateNaissance, + + @Size(max = 200) + String lieuNaissance, + + @NotBlank(message = "La nationalité est obligatoire (ISO-3)") + @Pattern(regexp = "^[A-Z]{3}$", message = "Code ISO-3 (ex: CIV, FRA)") + String nationalite, + + @Pattern(regexp = "^[A-Z]{3}$|^$", message = "Code ISO-3") + String paysResidence, + + TypePieceIdentite typePieceIdentite, + + @Size(max = 50) + String numeroPieceIdentite, + + LocalDate dateExpirationPiece, + + @DecimalMin(value = "0.00") + @DecimalMax(value = "100.00") + BigDecimal pourcentageCapital, + + @DecimalMin(value = "0.00") + @DecimalMax(value = "100.00") + BigDecimal pourcentageDroitsVote, + + @NotBlank(message = "La nature du contrôle est obligatoire") + @Pattern(regexp = "^(DETENTION_CAPITAL|DROITS_VOTE|CONTROLE_DE_FAIT|BENEFICIAIRE_ULTIME|MANDAT_REPRESENTATION)$", + message = "Nature du contrôle invalide") + String natureControle, + + Boolean estPep, + @Size(max = 100) String pepCategorie, + @Pattern(regexp = "^[A-Z]{3}$|^$") String pepPays, + @Size(max = 200) String pepFonction, + + Boolean presenceListesSanctions, + @Size(max = 1000) String detailsListesSanctions +) { +} diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/UpdateBeneficiaireEffectifRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/UpdateBeneficiaireEffectifRequest.java new file mode 100644 index 0000000..bb3166f --- /dev/null +++ b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/request/UpdateBeneficiaireEffectifRequest.java @@ -0,0 +1,40 @@ +package dev.lions.unionflow.server.api.dto.kyc.request; + +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import java.math.BigDecimal; +import java.time.LocalDate; +import lombok.Builder; + +/** + * Mise à jour partielle d'un Bénéficiaire Effectif (UBO). + * Tous les champs sont optionnels — seul ce qui est fourni est mis à jour. + * + * @since 2026-04-25 (Sprint 10) + */ +@Builder +public record UpdateBeneficiaireEffectifRequest( + @Size(max = 100) String nom, + @Size(max = 200) String prenoms, + LocalDate dateNaissance, + @Size(max = 200) String lieuNaissance, + @Pattern(regexp = "^[A-Z]{3}$|^$") String nationalite, + @Pattern(regexp = "^[A-Z]{3}$|^$") String paysResidence, + + @DecimalMin("0.00") @DecimalMax("100.00") BigDecimal pourcentageCapital, + @DecimalMin("0.00") @DecimalMax("100.00") BigDecimal pourcentageDroitsVote, + + @Pattern(regexp = "^(DETENTION_CAPITAL|DROITS_VOTE|CONTROLE_DE_FAIT|BENEFICIAIRE_ULTIME|MANDAT_REPRESENTATION)?$") + String natureControle, + + Boolean estPep, + @Size(max = 100) String pepCategorie, + @Pattern(regexp = "^[A-Z]{3}$|^$") String pepPays, + @Size(max = 200) String pepFonction, + + Boolean presenceListesSanctions, + @Size(max = 1000) String detailsListesSanctions +) { +} diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/kyc/response/BeneficiaireEffectifResponse.java b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/response/BeneficiaireEffectifResponse.java new file mode 100644 index 0000000..bd93ca3 --- /dev/null +++ b/src/main/java/dev/lions/unionflow/server/api/dto/kyc/response/BeneficiaireEffectifResponse.java @@ -0,0 +1,43 @@ +package dev.lions.unionflow.server.api.dto.kyc.response; + +import dev.lions.unionflow.server.api.enums.membre.TypePieceIdentite; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.UUID; +import lombok.Builder; + +/** + * Vue d'un Bénéficiaire Effectif (UBO). + * + * @since 2026-04-25 (Sprint 10) + */ +@Builder +public record BeneficiaireEffectifResponse( + UUID id, + UUID kycDossierId, + UUID organisationCibleId, + UUID membreId, + String nom, + String prenoms, + LocalDate dateNaissance, + String lieuNaissance, + String nationalite, + String paysResidence, + TypePieceIdentite typePieceIdentite, + String numeroPieceIdentite, + LocalDate dateExpirationPiece, + BigDecimal pourcentageCapital, + BigDecimal pourcentageDroitsVote, + String natureControle, + boolean estPep, + String pepCategorie, + String pepPays, + String pepFonction, + boolean presenceListesSanctions, + String detailsListesSanctions, + LocalDateTime dateCreation, + LocalDateTime dateModification, + Boolean actif +) { +} diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/organisation/request/UpdateOrganisationRequest.java b/src/main/java/dev/lions/unionflow/server/api/dto/organisation/request/UpdateOrganisationRequest.java index 0701594..6e22d5d 100644 --- a/src/main/java/dev/lions/unionflow/server/api/dto/organisation/request/UpdateOrganisationRequest.java +++ b/src/main/java/dev/lions/unionflow/server/api/dto/organisation/request/UpdateOrganisationRequest.java @@ -2,9 +2,11 @@ package dev.lions.unionflow.server.api.dto.organisation.request; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; import java.math.BigDecimal; import java.time.LocalDate; +import java.util.UUID; import lombok.Builder; @@ -51,5 +53,13 @@ public record UpdateOrganisationRequest( @Size(max = 100) String pays, @Size(max = 20) String codePostal, Boolean organisationPublique, - Boolean accepteNouveauxMembres) { + Boolean accepteNouveauxMembres, + + /** Référentiel comptable applicable (Sprint 1) — SYSCOHADA / SYCEBNL / PCSFD_UMOA. */ + @Pattern(regexp = "^(SYSCOHADA|SYCEBNL|PCSFD_UMOA)?$", + message = "Référentiel comptable invalide") + String referentielComptable, + + /** UUID du Compliance Officer désigné (Instr. BCEAO 001-03-2025). */ + UUID complianceOfficerId) { }