@startuml MCD_UnionFlow
!theme plain
skinparam linetype ortho
skinparam packageStyle rectangle
skinparam classAttributeIconSize 0

title Modèle Conceptuel de Données - UnionFlow

' ============================================
' ENTITÉS DE BASE
' ============================================

abstract class BaseEntity {
    {abstract} --
    + {PK} id : UUID <<generated>>
    + dateCreation : LocalDateTime <<not null>>
    + dateModification : LocalDateTime
    + creePar : String
    + modifiePar : String
    + version : Long <<version>>
    + actif : Boolean <<not null, default=true>>
    --
    + onCreate() : void <<@PrePersist>>
    + onUpdate() : void <<@PreUpdate>>
}

' ============================================
' ENTITÉS MÉTIER
' ============================================

class Organisation {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + nom : String <<not null, length=200>>
    + nomCourt : String <<length=50>>
    + typeOrganisation : String <<not null, length=50>>
    + statut : String <<not null, length=50>>
    + description : String <<length=2000>>
    + dateFondation : LocalDate
    + numeroEnregistrement : String <<unique, length=100>>
    --
    ' Contact
    + email : String <<unique, not null, length=255>>
    + telephone : String <<length=20>>
    + telephoneSecondaire : String <<length=20>>
    + emailSecondaire : String <<length=255>>
    --
    ' Adresse
    + adresse : String <<length=500>>
    + ville : String <<length=100>>
    + codePostal : String <<length=20>>
    + region : String <<length=100>>
    + pays : String <<length=100>>
    + latitude : BigDecimal <<precision=9,scale=6>>
    + longitude : BigDecimal <<precision=9,scale=6>>
    --
    ' Web
    + siteWeb : String <<length=500>>
    + logo : String <<length=500>>
    + reseauxSociaux : String <<length=1000>>
    --
    ' Hiérarchie
    + organisationParenteId : UUID
    + niveauHierarchique : Integer <<not null, default=0>>
    --
    ' Statistiques
    + nombreMembres : Integer <<not null, default=0>>
    + nombreAdministrateurs : Integer <<not null, default=0>>
    --
    ' Finances
    + budgetAnnuel : BigDecimal <<precision=14,scale=2>>
    + devise : String <<length=3, default=XOF>>
    + cotisationObligatoire : Boolean <<not null, default=false>>
    + montantCotisationAnnuelle : BigDecimal <<precision=12,scale=2>>
    --
    ' Compléments
    + objectifs : String <<length=2000>>
    + activitesPrincipales : String <<length=2000>>
    + certifications : String <<length=500>>
    + partenaires : String <<length=1000>>
    + notes : String <<length=1000>>
    + organisationPublique : Boolean <<not null, default=true>>
    + accepteNouveauxMembres : Boolean <<not null, default=true>>
    --
    + getNomComplet() : String
    + getAncienneteAnnees() : int
    + isRecente() : boolean
    + isActive() : boolean
    + ajouterMembre() : void
    + retirerMembre() : void
    + activer(String utilisateur) : void
    + suspendre(String utilisateur) : void
    + dissoudre(String utilisateur) : void
}

class Membre {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + numeroMembre : String <<unique, not null, length=20>>
    + prenom : String <<not null, length=100>>
    + nom : String <<not null, length=100>>
    + email : String <<unique, not null, length=255>>
    + motDePasse : String <<length=255>>
    + telephone : String <<length=20>>
    + dateNaissance : LocalDate <<not null>>
    + dateAdhesion : LocalDate <<not null>>
    + roles : String <<length=500>>
    --
    + getNomComplet() : String
    + isMajeur() : boolean
    + getAge() : int
}

class TypeOrganisationEntity {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + code : String <<unique, not null, length=50>>
    + libelle : String <<not null, length=150>>
    + description : String <<length=500>>
    + ordreAffichage : Integer
}

class Cotisation {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + numeroReference : String <<unique, not null, length=50>>
    + typeCotisation : String <<not null, length=50>>
    + montantDu : BigDecimal <<not null, precision=12,scale=2>>
    + montantPaye : BigDecimal <<not null, default=0, precision=12,scale=2>>
    + codeDevise : String <<not null, length=3, pattern=^[A-Z]{3}$>>
    + statut : String <<not null, length=30>>
    + dateEcheance : LocalDate <<not null>>
    + datePaiement : LocalDateTime
    + description : String <<length=500>>
    + periode : String <<length=20>>
    + annee : Integer <<not null, min=2020, max=2100>>
    + mois : Integer <<min=1, max=12>>
    + observations : String <<length=1000>>
    + recurrente : Boolean <<not null, default=false>>
    + nombreRappels : Integer <<not null, default=0>>
    + dateDernierRappel : LocalDateTime
    + valideParId : UUID
    + nomValidateur : String <<length=100>>
    + dateValidation : LocalDateTime
    + methodePaiement : String <<length=50>>
    + referencePaiement : String <<length=100>>
    --
    + getMontantRestant() : BigDecimal
    + isEntierementPayee() : boolean
    + isEnRetard() : boolean
    + genererNumeroReference() : String <<static>>
}

class Adhesion {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + numeroReference : String <<unique, not null, length=50>>
    + dateDemande : LocalDate <<not null>>
    + fraisAdhesion : BigDecimal <<not null, precision=12,scale=2>>
    + montantPaye : BigDecimal <<not null, default=0, precision=12,scale=2>>
    + codeDevise : String <<not null, length=3, pattern=^[A-Z]{3}$>>
    + statut : String <<not null, length=30>>
    + dateApprobation : LocalDate
    + datePaiement : LocalDateTime
    + methodePaiement : String <<length=20>>
    + referencePaiement : String <<length=100>>
    + motifRejet : String <<length=1000>>
    + observations : String <<length=1000>>
    + approuvePar : String <<length=255>>
    + dateValidation : LocalDate
    --
    + isPayeeIntegralement() : boolean
    + isEnAttentePaiement() : boolean
    + getMontantRestant() : BigDecimal
}

class Evenement {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + titre : String <<not null, length=200>>
    + description : String <<length=2000>>
    + dateDebut : LocalDateTime <<not null>>
    + dateFin : LocalDateTime
    + lieu : String <<length=500>>
    + adresse : String <<length=1000>>
    + typeEvenement : TypeEvenement <<enum>>
    + statut : StatutEvenement <<enum, not null, default=PLANIFIE>>
    + capaciteMax : Integer <<min=0>>
    + prix : BigDecimal <<precision=10,scale=2>>
    + inscriptionRequise : Boolean <<not null, default=false>>
    + dateLimiteInscription : LocalDateTime
    + instructionsParticulieres : String <<length=1000>>
    + contactOrganisateur : String <<length=500>>
    + materielRequis : String <<length=2000>>
    + visiblePublic : Boolean <<not null, default=true>>
    --
    + isOuvertAuxInscriptions() : boolean
    + getNombreInscrits() : int
    + isComplet() : boolean
    + isEnCours() : boolean
    + isTermine() : boolean
    + getDureeEnHeures() : Long
    + getPlacesRestantes() : Integer
    + isMemberInscrit(UUID membreId) : boolean
    + getTauxRemplissage() : Double
}

class InscriptionEvenement {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + dateInscription : LocalDateTime <<not null, default=now()>>
    + statut : StatutInscription <<enum, default=CONFIRMEE>>
    + commentaire : String <<length=500>>
    --
    + isConfirmee() : boolean
    + isEnAttente() : boolean
    + isAnnulee() : boolean
    + confirmer() : void
    + annuler(String commentaire) : void
    + mettreEnAttente(String commentaire) : void
    + refuser(String commentaire) : void
}

class DemandeAide {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + titre : String <<not null, length=200>>
    + description : String <<not null, TEXT>>
    + typeAide : TypeAide <<enum, not null>>
    + statut : StatutAide <<enum, not null>>
    + montantDemande : BigDecimal <<precision=10,scale=2>>
    + montantApprouve : BigDecimal <<precision=10,scale=2>>
    + dateDemande : LocalDateTime <<not null>>
    + dateEvaluation : LocalDateTime
    + dateVersement : LocalDateTime
    + justification : String <<TEXT>>
    + commentaireEvaluation : String <<TEXT>>
    + urgence : Boolean <<not null, default=false>>
    + documentsFournis : String
    --
    + isEnAttente() : boolean
    + isApprouvee() : boolean
    + isRejetee() : boolean
    + isUrgente() : boolean
    + getPourcentageApprobation() : BigDecimal
}

class AuditLog {
    + {PK} id : UUID <<inherited>>
    + dateCreation : LocalDateTime <<inherited>>
    + dateModification : LocalDateTime <<inherited>>
    + creePar : String <<inherited>>
    + modifiePar : String <<inherited>>
    + version : Long <<inherited>>
    + actif : Boolean <<inherited>>
    --
    + typeAction : String <<not null, length=50>>
    + severite : String <<not null, length=20>>
    + utilisateur : String <<length=255>>
    + role : String <<length=50>>
    + module : String <<length=50>>
    + description : String <<length=500>>
    + details : String <<TEXT>>
    + ipAddress : String <<length=45>>
    + userAgent : String <<length=500>>
    + sessionId : String <<length=255>>
    + dateHeure : LocalDateTime <<not null>>
    + donneesAvant : String <<TEXT>>
    + donneesApres : String <<TEXT>>
    + entiteId : String <<length=255>>
    + entiteType : String <<length=100>>
}

' ============================================
' ENUMS
' ============================================

enum TypeEvenement {
    ASSEMBLEE_GENERALE
    REUNION
    FORMATION
    CONFERENCE
    ATELIER
    SEMINAIRE
    EVENEMENT_SOCIAL
    MANIFESTATION
    CELEBRATION
    AUTRE
}

enum StatutEvenement {
    PLANIFIE
    CONFIRME
    EN_COURS
    TERMINE
    ANNULE
    REPORTE
}

enum StatutInscription {
    CONFIRMEE
    EN_ATTENTE
    ANNULEE
    REFUSEE
}

enum TypeAide {
    FINANCIERE
    MATERIELLE
    ALIMENTAIRE
    MEDICALE
    SCOLAIRE
    LOGEMENT
    EMPLOI
    FORMATION
    AUTRE
}

enum StatutAide {
    BROUILLON
    SOUMISE
    EN_ATTENTE
    EN_COURS_EVALUATION
    INFORMATIONS_REQUISES
    APPROUVEE
    APPROUVEE_PARTIELLEMENT
    EN_COURS_TRAITEMENT
    EN_COURS_VERSEMENT
    VERSEE
    LIVREE
    TERMINEE
    REJETEE
    ANNULEE
    EXPIREE
    SUSPENDUE
    EN_SUIVI
    CLOTUREE
}

' ============================================
' RELATIONS
' ============================================

BaseEntity <|-- Organisation
BaseEntity <|-- Membre
BaseEntity <|-- TypeOrganisationEntity
BaseEntity <|-- Cotisation
BaseEntity <|-- Adhesion
BaseEntity <|-- Evenement
BaseEntity <|-- InscriptionEvenement
BaseEntity <|-- DemandeAide
BaseEntity <|-- AuditLog

' Relations Organisation
Organisation "1" *-- "0..*" Membre : "appartient à"
Organisation "0..1" --o "0..*" Organisation : "parente >\n(organisationParenteId)"

' Relations Membre
Membre "1" *-- "0..*" Cotisation : "a des"
Membre "1" *-- "0..*" Adhesion : "demande"
Membre "1" *-- "0..*" Evenement : "organise"
Membre "1" *-- "0..*" InscriptionEvenement : "s'inscrit"
Membre "1" *-- "0..*" DemandeAide : "demande (demandeur)"
Membre "0..1" *-- "0..*" DemandeAide : "évalue (evaluateur)"

' Relations Organisation (suite)
Organisation "1" *-- "0..*" Adhesion : "reçoit"
Organisation "1" *-- "0..*" Evenement : "organise"
Organisation "1" *-- "0..*" DemandeAide : "traite"

' Relations Evenement
Evenement "1" *-- "0..*" InscriptionEvenement : "a des inscriptions"

' Relations Enums
Evenement ..> TypeEvenement : "utilise"
Evenement ..> StatutEvenement : "utilise"
InscriptionEvenement ..> StatutInscription : "utilise"
DemandeAide ..> TypeAide : "utilise"
DemandeAide ..> StatutAide : "utilise"

note right of Organisation
    **Hiérarchie** :
    - organisationParenteId : UUID (référence)
    - niveauHierarchique : 0 = racine
    - Auto-référence pour structure hiérarchique
end note

note right of Membre
    **Génération automatique** :
    - numeroMembre : auto-généré si non fourni
    - dateAdhesion : auto-générée à LocalDate.now() si null
    - dateNaissance : auto-générée à il y a 18 ans si null
end note

note right of Cotisation
    **Statuts possibles** :
    - EN_ATTENTE
    - PAYEE
    - EN_RETARD
    - PARTIELLEMENT_PAYEE
    - ANNULEE
end note

note right of Adhesion
    **Statuts possibles** :
    - EN_ATTENTE
    - APPROUVEE
    - REJETEE
    - ANNULEE
    - EN_PAIEMENT
    - PAYEE
end note

note right of Evenement
    **Gestion des inscriptions** :
    - inscriptionRequise : Boolean
    - capaciteMax : Integer
    - dateLimiteInscription : LocalDateTime
    - Méthodes : isOuvertAuxInscriptions(),
      getNombreInscrits(), isComplet()
end note

note right of DemandeAide
    **Workflow d'aide** :
    - demandeur : Membre (obligatoire)
    - evaluateur : Membre (optionnel)
    - organisation : Organisation (obligatoire)
    - Statuts multiples avec workflow
end note

@enduml

