Conception complete (Phase 0) pour formation-hub Acadenice : - 19 docs Merise Agile + UML + GitOps + plans (tests/deploy/ops/api) cf docs/00-readme.md pour l'index complet - Stack Docker compose (Docmost + Baserow + Postgres + Redis + MinIO local FS) compose.yml + compose.staging.yml + compose.prod.yml - CI/CD GitHub Actions skeleton (ci, deploy-staging, deploy-prod) - Bridge service skeleton (Hono + TS + Biome + Vitest + zod + pino) - Templates GitHub : PR + 3 issue types + CODEOWNERS + dependabot.yml - Scripts ops : healthcheck, backup quotidien, smoke-test post-deploy - LICENSE AGPL-3.0 + SECURITY.md + CONTRIBUTING.md + CHANGELOG.md - Diagramme drawIO archi infra (XML importable dans diagrams.net) Decisions structurelles enregistrees : - Scope CFA + Agence avec entite PERSONNE pivot multi-roles (ADR-001) - Stack composite Docmost AGPL + Baserow MIT + bridge custom (ADR-001) - Path B : UX quasi-unified via Tiptap node-views custom (ADR-002) - Monorepo trunk-based development (ADR-003) - Postgres separe Docmost/Baserow (ADR-004) - Bridge stack Node 22 + Hono (ADR-005) - Repo neuf prefere a fork Docmost - Prod-like des le jour 1 (pas MVP)
234 lines
7.9 KiB
Markdown
234 lines
7.9 KiB
Markdown
# MCD — Modele Conceptuel de Donnees
|
|
|
|
> Vue conceptuelle des entites et relations. Scope B (CFA + Agence via PERSONNE pivot).
|
|
> Dictionnaire de donnees complet : `05-data-dictionary.md`.
|
|
|
|
## 1. Vue d'ensemble
|
|
|
|
**8 entites organisees en 3 zones** :
|
|
|
|
| Zone | Entites |
|
|
|------|---------|
|
|
| Pivot | PERSONNE |
|
|
| CFA | FORMATION, BLOC, MODULE + ATTRIBUTION (assoc.) |
|
|
| Agence | CLIENT, PROJET, TACHE + INTERVENTION (assoc.) |
|
|
|
|
PERSONNE est le **pivot** entre les deux activites : la meme personne peut avoir le role `formateur` (lie a ATTRIBUTION) et `developpeur` (lie a INTERVENTION). Sa capacite annuelle est splittee entre formation et agence.
|
|
|
|
## 2. Diagrammes entites-relations
|
|
|
|
Le modele complet a 9 entites — afficher tous les attributs sur un seul ER produit du spaghetti. On decompose en **5 vues** : globale simplifiee + 3 zones detaillees + lien pedagogique.
|
|
|
|
### 2.1 Vue globale (simplifiee — entites et relations seules)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
PERSONNE ||--o{ ATTRIBUTION : "formateur"
|
|
PERSONNE ||--o{ INTERVENTION : "developpeur"
|
|
FORMATION ||--o{ BLOC : ""
|
|
BLOC ||--o{ MODULE : ""
|
|
MODULE ||--o{ ATTRIBUTION : ""
|
|
CLIENT ||--o{ PROJET : ""
|
|
PROJET ||--o{ TACHE : ""
|
|
TACHE ||--o{ INTERVENTION : ""
|
|
PROJET }o--o| FORMATION : "pedagogique"
|
|
```
|
|
|
|
### 2.2 Zone CFA (formations + heures formateurs)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
FORMATION ||--o{ BLOC : "1,N contient"
|
|
BLOC ||--o{ MODULE : "1,N comprend"
|
|
MODULE ||--o{ ATTRIBUTION : "0,N attribuee"
|
|
PERSONNE ||--o{ ATTRIBUTION : "0,N enseigne"
|
|
|
|
FORMATION {
|
|
int formation_id PK
|
|
string formation_nom UK
|
|
enum formation_filiere
|
|
decimal formation_heures_totales
|
|
enum formation_statut
|
|
date formation_date_debut
|
|
date formation_date_fin
|
|
}
|
|
BLOC {
|
|
int bloc_id PK
|
|
int bloc_formation_id FK
|
|
string bloc_nom
|
|
decimal bloc_heures_prevues
|
|
int bloc_ordre
|
|
}
|
|
MODULE {
|
|
int module_id PK
|
|
int module_bloc_id FK
|
|
string module_nom
|
|
decimal module_heures_prevues
|
|
enum module_statut
|
|
}
|
|
ATTRIBUTION {
|
|
int attribution_id PK
|
|
int attribution_module_id FK
|
|
int attribution_personne_id FK
|
|
decimal heures_attribuees
|
|
decimal heures_realisees
|
|
date date_debut
|
|
enum statut
|
|
}
|
|
PERSONNE {
|
|
int personne_id PK
|
|
string nom_prenom
|
|
decimal capacite_annuelle
|
|
}
|
|
```
|
|
|
|
### 2.3 Zone Agence (projets clients + heures devs)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
CLIENT ||--o{ PROJET : "1,N a"
|
|
PROJET ||--o{ TACHE : "0,N comporte"
|
|
TACHE ||--o{ INTERVENTION : "0,N realisee"
|
|
PERSONNE ||--o{ INTERVENTION : "0,N realise"
|
|
|
|
CLIENT {
|
|
int client_id PK
|
|
string client_nom UK
|
|
string contact_email
|
|
enum statut
|
|
}
|
|
PROJET {
|
|
int projet_id PK
|
|
int projet_client_id FK
|
|
string projet_nom
|
|
enum type
|
|
decimal charge_heures
|
|
date date_debut
|
|
enum statut
|
|
}
|
|
TACHE {
|
|
int tache_id PK
|
|
int tache_projet_id FK
|
|
string titre
|
|
decimal charge_heures
|
|
enum priorite
|
|
enum statut
|
|
}
|
|
INTERVENTION {
|
|
int intervention_id PK
|
|
int intervention_tache_id FK
|
|
int intervention_personne_id FK
|
|
decimal heures
|
|
date intervention_date
|
|
enum statut
|
|
}
|
|
PERSONNE {
|
|
int personne_id PK
|
|
string nom_prenom
|
|
decimal capacite_annuelle
|
|
}
|
|
```
|
|
|
|
### 2.4 Zone Personne pivot (capacite + roles)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
PERSONNE ||--o{ ATTRIBUTION : "role formateur"
|
|
PERSONNE ||--o{ INTERVENTION : "role developpeur"
|
|
|
|
PERSONNE {
|
|
int personne_id PK
|
|
string personne_nom
|
|
string personne_prenom
|
|
string personne_email UK
|
|
decimal capacite_annuelle
|
|
decimal split_formation_pct
|
|
decimal split_agence_pct
|
|
string roles "multi-select"
|
|
decimal heures_attribuees_formation "rollup"
|
|
decimal heures_attribuees_agence "rollup"
|
|
decimal heures_restantes_total "formula"
|
|
enum statut
|
|
}
|
|
ATTRIBUTION {
|
|
int attribution_id PK
|
|
int attribution_module_id FK
|
|
int attribution_personne_id FK
|
|
decimal heures_attribuees
|
|
}
|
|
INTERVENTION {
|
|
int intervention_id PK
|
|
int intervention_tache_id FK
|
|
int intervention_personne_id FK
|
|
decimal heures
|
|
}
|
|
```
|
|
|
|
### 2.5 Lien projet pedagogique (cross CFA-Agence)
|
|
|
|
```mermaid
|
|
erDiagram
|
|
PROJET }o--o| FORMATION : "0,1 projet pedagogique"
|
|
|
|
PROJET {
|
|
int projet_id PK
|
|
int projet_formation_id FK "nullable"
|
|
string projet_nom
|
|
}
|
|
FORMATION {
|
|
int formation_id PK
|
|
string formation_nom
|
|
}
|
|
```
|
|
|
|
> **Notation** : ce lien est optionnel cote PROJET (un projet peut etre purement client). Cote FORMATION, plusieurs projets peuvent etre lies a une formation pedagogique.
|
|
|
|
## 3. Cardinalites detaillees
|
|
|
|
| Relation | Source | Cardinalite | Cible | Cardinalite | Sens metier |
|
|
|----------|--------|-------------|-------|-------------|-------------|
|
|
| CONTIENT (CFA) | FORMATION | (1,N) | BLOC | (1,1) | une formation comprend des blocs RNCP |
|
|
| COMPREND (CFA) | BLOC | (1,N) | MODULE | (1,1) | un bloc se decompose en modules |
|
|
| ATTRIBUTION (CFA) | MODULE | (0,N) | PERSONNE | (0,N) | un module est dispense par 0-N formateurs |
|
|
| EMPLOIE (Agence) | CLIENT | (1,N) | PROJET | (1,1) | un client peut avoir des projets |
|
|
| COMPORTE (Agence) | PROJET | (0,N) | TACHE | (1,1) | un projet est decoupe en taches |
|
|
| INTERVENTION (Agence) | TACHE | (0,N) | PERSONNE | (0,N) | un dev peut intervenir sur 0-N taches |
|
|
| PROJET_PEDAGOGIQUE | PROJET | (0,1) | FORMATION | (0,N) | un projet client peut servir de support pedagogique a une formation |
|
|
|
|
## 4. Calculs (rollups + formulas) cles
|
|
|
|
```
|
|
PERSONNE.heures_attribuees_formation = SUM(ATTRIBUTION.heures_attribuees)
|
|
WHERE attribution_personne_id = personne_id
|
|
AND attribution_statut != 'annule'
|
|
|
|
PERSONNE.heures_attribuees_agence = SUM(INTERVENTION.heures)
|
|
WHERE intervention_personne_id = personne_id
|
|
AND intervention_statut != 'annule'
|
|
|
|
PERSONNE.heures_restantes_total = capacite_annuelle
|
|
- heures_attribuees_formation
|
|
- heures_attribuees_agence
|
|
|
|
PROJET.heures_realisees = SUM(TACHE.heures_realisees) WHERE tache_projet_id = projet_id
|
|
TACHE.heures_realisees = SUM(INTERVENTION.heures) WHERE intervention_tache_id = tache_id
|
|
|
|
(rollups CFA inchanges depuis version precedente — voir Data Dictionary)
|
|
```
|
|
|
|
## 5. Regles de gestion (extension)
|
|
|
|
- **RG-PERSONNE-01** : `personne_split_formation_pct + personne_split_agence_pct = 100` (CHECK constraint)
|
|
- **RG-PERSONNE-02** : Une attribution ne peut etre creee que si la personne a `formateur` dans ses roles.
|
|
- **RG-PERSONNE-03** : Une intervention ne peut etre creee que si la personne a `developpeur` dans ses roles.
|
|
- **RG-PERSONNE-04** : `heures_restantes_total >= 0` est un warning UI, pas un blocage (depassement possible avec justification).
|
|
|
|
(RG CFA conserves : voir version precedente du MCD pour RG-FORMATION, RG-BLOC, RG-MODULE)
|
|
|
|
## 6. Questions ouvertes (a valider metier)
|
|
|
|
- [ ] Le split formation/agence est-il fixe par personne ou variable par periode (ex: trimestre 1 a 70/30, trimestre 2 a 50/50) ?
|
|
- [ ] Faut-il modeliser une notion de **session** (un module enseigne plusieurs fois a des promotions differentes) ?
|
|
- [ ] Faut-il une notion de **promotion** ou de **classe** dans le CFA ?
|
|
- [ ] Pour les projets pedagogiques (lien PROJET ↔ FORMATION), comment tracer les etudiants impliques ? (Si on ne modelise pas l'etudiant, on ne peut pas formellement le lier au projet — a discuter.)
|
|
- [ ] Workflow d'approbation des heures realisees (admin valide avant facturation ou paie) ?
|