feat(sprint-10 api 2026-04-25): bump 1.0.8 + DTOs UBO/audit-trail/délégation + UpdateOrganisationRequest enrichi

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.
This commit is contained in:
dahoud
2026-04-25 12:31:43 +00:00
parent 2d21a580de
commit 65a9d03c00
8 changed files with 279 additions and 2 deletions

View File

@@ -6,7 +6,7 @@
<groupId>dev.lions.unionflow</groupId> <groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-server-api</artifactId> <artifactId>unionflow-server-api</artifactId>
<version>1.0.7</version> <version>1.0.8</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>UnionFlow Server API</name> <name>UnionFlow Server API</name>

View File

@@ -0,0 +1,36 @@
package dev.lions.unionflow.server.api.dto.audit.response;
import java.time.LocalDateTime;
import java.util.UUID;
import lombok.Builder;
/**
* Vue d'une opération d'audit trail enrichi (Sprint 1, exposée Sprint 10).
*
* <p>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
) {
}

View File

@@ -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
) {
}

View File

@@ -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
) {
}

View File

@@ -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.
*
* <p>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
) {
}

View File

@@ -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
) {
}

View File

@@ -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
) {
}

View File

@@ -2,9 +2,11 @@ package dev.lions.unionflow.server.api.dto.organisation.request;
import jakarta.validation.constraints.Email; import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size; import jakarta.validation.constraints.Size;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.UUID;
import lombok.Builder; import lombok.Builder;
@@ -51,5 +53,13 @@ public record UpdateOrganisationRequest(
@Size(max = 100) String pays, @Size(max = 100) String pays,
@Size(max = 20) String codePostal, @Size(max = 20) String codePostal,
Boolean organisationPublique, 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) {
} }