1. Contexte
Migration des données du webform Drupal "Espace de Dépôt" vers le système BDES.
- Source
-
Drupal Webform (https://dce.presidence.bj)
- Destination
-
BDES (PostgreSQL via API)
- Période des données
-
21/11/2024 - 05/01/2026
2. Extraction des données
2.1. Contraintes techniques
|
2.2. Stratégie d’extraction
L’extraction a été réalisée par lots en utilisant la date de création comme filtre pour contourner l’erreur 500.
2.3. Lots d’extraction
| Période | Statut | Nombre de soumissions |
|---|---|---|
21/11/2024 - 30/11/2024 |
OK |
32 |
01/12/2024 - 05/12/2024 |
OK |
76 |
06/12/2024 - 08/12/2024 |
OK |
138 |
09/12/2024 - 09/12/2024 |
OK |
105 |
10/12/2024 - 10/12/2024 |
OK |
218 |
11/12/2024 - 11/12/2024 |
OK |
25 |
12/12/2024 - 14/12/2024 |
OK |
24 |
15/12/2024 - 30/12/2024 |
OK |
27 |
31/12/2024 - 31/12/2025 |
OK |
292 |
01/01/2026 - 05/01/2026 |
OK |
1 |
Total soumissions extraites : 938
2.4. Statistiques des fichiers
| Métrique | Valeur |
|---|---|
Fichiers JSON présents |
938 |
Plage des IDs |
264 → 4643 |
Plage théorique |
4380 |
IDs manquants |
3442 |
| Les IDs manquants correspondent à des soumissions supprimées, d’autres webforms, ou des brouillons non exportés. L’ID de soumission (sid) est global à Drupal, pas au webform. |
3. Format des données
3.1. Choix du format : JSON
| Critère | CSV | JSON | YAML |
|---|---|---|---|
Structure préservée |
Non |
Oui |
Oui |
Parsing programmatique |
Difficile |
Natif |
Natif |
Données imbriquées |
Texte brut |
Arrays |
Arrays |
Références fichiers |
URLs |
IDs |
IDs |
JSON retenu car il préserve la structure hiérarchique des données (enseignements, articles, recherches).
3.2. Limitation : Références des fichiers
|
Le format JSON exporte les IDs internes Drupal des fichiers, pas leurs URLs. |
{
"annee_academique": "2024-2025",
"code_ec": "1MEH1503",
"code_ue": "MEH1503",
"intitule_ec": "Réseau et techniques d'irrigation",
"joindre_support": "21360", // <-- ID interne, pas l'URL
"nature_support": "Syllabus"
}
Joindre le support: https://dce.presidence.bj/system/files/webform/espace_de_depot/277/formation_43_277_90401378.pdf
4. Structure des données
4.1. Schéma d’une soumission
{
"serial": "344",
"sid": "344",
"uuid": "fd5c83fe-b6fa-4451-abb5-97675155db64",
"created": "1733208750",
"changed": "1734466474",
"in_draft": "1",
"uid": "114",
"webform_id": "espace_de_depot",
"data": {
// Identification
"nom": "...",
"prenom": "...",
"date_de_naissance": "...",
"numero_matricule": "...",
"grade": "...",
"specialite": "...",
// Établissement
"nature_de_l_etablissement_de_rattachement": "...",
"denomination_de_l_etablissement_de_rattachement_upb": "...",
"denomination_de_l_ufr_ecole": "...",
// Enseignements (array)
"ajouter_un_element": [
{
"annee_academique": "...",
"code_ue": "...",
"code_ec": "...",
"intitule_ue": "...",
"intitule_ec": "...",
"semestre": "...",
"type_activite": "...",
"nature_support": "...",
"joindre_support": "..." // file_id
}
],
// Articles (array)
"article": [...],
// Recherches (array)
"travaux_de_recherche_2": [...],
// Rapports de performance (array)
"rapport_de_performance": [...]
}
}
5. Règles de transformation et chargement
5.1. Légende
| Symbole | Signification |
|---|---|
✅ |
Mapping direct depuis le JSON source |
🔄 |
Transformation ou lookup sur une table de référence |
❌ |
Donnée non disponible dans la source |
⚠️ |
Valeur générée ou par défaut |
5.2. Génération des codes
Les codes sont générés automatiquement via un hash SHA256 encodé en base62 :
-
Format :
PREFIX_+ 8 caractères (ex:GRADE_iL8S4JVG) -
Déterministe : même libellé produit toujours le même code
-
Unique : probabilité de collision ~1/218 billions
5.3. Tables de référence
5.3.1. reference.grade_enseignant
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Direct, dédupliqué |
|
— |
❌ Non alimenté |
|
— |
❌ Non alimenté |
|
— |
❌ Non alimenté |
|
— |
⚠️ Défaut : |
5.3.2. reference.statut_enseignant
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Direct, dédupliqué |
|
— |
❌ Non alimenté |
|
— |
⚠️ Défaut : |
5.3.3. reference.domaine_resao
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Union de tous les champs |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
5.3.4. reference.domaine_specialite
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Direct, dédupliqué |
|
|
🔄 Lookup sur |
|
— |
⚠️ Défaut : |
5.3.5. reference.type_diplome
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Union de ces champs, dédupliqué |
|
— |
🔄 Extrait entre parenthèses (ex: "Licence (L)" → "L") |
|
— |
⚠️ Défaut : |
5.3.6. reference.nature_support_cours
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Direct, dédupliqué |
|
— |
❌ Non alimenté |
|
— |
❌ Non alimenté |
|
— |
⚠️ Défaut : |
5.3.7. reference.type_structure
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
|
✅ Direct, dédupliqué |
|
— |
🔄 Calculé : université=1, faculté/école=2, département=3 |
|
— |
⚠️ Défaut : |
5.4. Tables golden
5.4.1. golden.personne_physique
| Attribut | Source JSON | Règle |
|---|---|---|
|
|
✅ Direct, clé de déduplication |
|
|
✅ Direct |
|
|
🔄 Normalisé : M./Monsieur → |
|
|
✅ Direct |
|
|
✅ Direct |
|
|
✅ Copie de nom_famille |
|
|
🔄 Déduit : M → |
|
|
🔄 Déduit : M → |
|
|
✅ Direct |
|
|
✅ Direct |
|
|
🔄 Lookup sur |
|
— |
⚠️ Défaut : |
|
|
🔄 Lookup sur |
|
|
✅ Direct |
|
|
🔄 Lookup sur |
|
|
🔄 Lookup sur |
|
|
🔄 Lookup sur |
|
|
🔄 Converti : "1" → |
|
— |
⚠️ Défaut : |
Les lookups sur reference.ville et reference.statut_civil nécessitent que ces tables soient préalablement alimentées.
|
5.4.2. golden.formation
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash de l’intitulé |
|
|
✅ Direct, dédupliqué |
|
|
🔄 Lookup sur |
|
|
🔄 Lookup sur |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Date d’insertion (NOT NULL) |
|
— |
⚠️ Défaut : |
5.4.3. golden.unite_enseignement
| Attribut | Source JSON | Règle |
|---|---|---|
|
|
✅ Direct, dédupliqué |
|
|
✅ Direct |
|
|
🔄 Lookup sur |
|
|
🔄 Lookup sur |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
5.4.4. golden.element_constitutif
| Attribut | Source JSON | Règle |
|---|---|---|
|
|
✅ Direct, dédupliqué |
|
|
✅ Direct |
|
|
✅ Direct |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
5.4.5. golden.adresse_postale
| Attribut | Source JSON | Règle |
|---|---|---|
|
|
✅ FK vers |
|
|
🔄 Lookup sur |
|
— |
⚠️ Défaut : |
|
|
✅ Direct (50 premiers caractères, NOT NULL) |
|
— |
⚠️ Défaut : |
|
|
✅ Direct |
|
|
✅ Direct (NOT NULL) |
|
— |
⚠️ Défaut : |
|
|
✅ Direct (NOT NULL) |
|
— |
⚠️ Défaut : |
|
— |
❌ Non alimenté |
|
— |
❌ Non alimenté |
5.4.6. golden.coordonnees_contact
| Attribut | Source JSON | Règle |
|---|---|---|
|
|
✅ FK vers |
|
— |
⚠️ |
|
|
✅ Direct, 1 ligne par contact (NOT NULL) |
|
— |
⚠️ Défaut : |
|
— |
❌ Non alimenté |
|
— |
❌ Non alimenté |
5.4.7. golden.structure_organisationnelle
Hiérarchie à 2 niveaux depuis les données source :
-
Établissement :
data.denomination_de_l_etablissement_de_rattachement_* -
UFR/École :
data.denomination_de_l_ufr_*
| Attribut | Source JSON | Règle |
|---|---|---|
|
— |
⚠️ Généré : hash du libellé |
|
Champs hiérarchiques ci-dessus |
✅ Direct, dédupliqué (NOT NULL) |
|
— |
🔄 Extrait entre parenthèses, défaut libellé tronqué (NOT NULL) |
|
|
🔄 Lookup sur |
|
— |
🔄 Lookup sur structure parente |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
⚠️ Défaut : |
|
— |
❌ Non alimenté |
|
— |
❌ Non alimenté |
|
— |
⚠️ Défaut : |
| L’ordre d’insertion est important : établissements d’abord, puis UFR/écoles. |
5.5. Tables non migrées
Sur 21 tables golden, 7 sont alimentées par la migration. Les 14 suivantes ne sont pas migrées :
| Entité | Raison |
|---|---|
|
Redondante : données intégrées dans |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données (formation ≠ diplôme obtenu par l’enseignant) |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
|
Pas de données dans la source Drupal |
5.6. API Évaluation
5.6.1. POST /api/v1/folders/{folderId}/courses
| Attribut données | Attribut API | Commentaires |
|---|---|---|
|
|
✅ Direct |
|
|
✅ Direct (ID interne Drupal) |
— |
|
⚠️ Valeur fixe : |
|
|
🔄 Lookup |
|
❌ Manquant |
|
|
❌ Manquant |
|
|
❌ Manquant |
5.6.2. POST /api/v1/folders/{folderId}/articles
| Attribut données | Attribut API | Commentaires |
|---|---|---|
|
|
✅ Direct |
|
|
🔄 Lookup par dénomination (à travailler) |
|
|
✅ Direct |
— |
|
❌ Manquant (défaut : |
— |
|
❌ Manquant |
— |
|
❌ Manquant |
|
|
✅ Direct |
— |
|
⚠️ Valeur fixe : |
5.6.3. POST /api/v1/folders/{folderId}/reviews
| Attribut données | Attribut API | Commentaires |
|---|---|---|
|
|
✅ Direct |
|
|
✅ Direct |
|
|
✅ Direct |
— |
|
⚠️ Valeur fixe : |
5.6.4. POST /api/v1/folders/{folderId}/researches
| Attribut données | Attribut API | Commentaires |
|---|---|---|
|
|
✅ Direct |
— |
|
❌ Manquant |
|
|
✅ Direct |
|
|
✅ Direct |
— |
|
❌ Manquant |
|
|
✅ Direct |
— |
|
❌ Manquant (défaut : |
|
|
✅ Direct |
— |
|
❌ Manquant |
— |
|
❌ Manquant |
|
|
🔄 Parser le champ pages |
|
|
🔄 Parser le champ pages |
|
|
✅ Direct |
|
|
✅ Direct |
|
|
✅ Direct |
— |
|
⚠️ Valeur fixe : |
|
❌ Manquant |
|
|
❌ Manquant |
6. Remarques et questions ouvertes
6.1. Attributs manquants dans l’API
| Entité API | Attributs à ajouter |
|---|---|
|
|
|
|
|
|
|
|
6.2. Entités potentiellement requises
| Entité | Justification |
|---|---|
|
Gestion des corps de la fonction publique enseignante |
|
Types d’activités pédagogiques (Cours théorique, TD, TP, etc.) |
|
Titres des supports pédagogiques |
6.3. Questions de conception
| Question |
|---|
Pourquoi |
|
|
|
Renommer |
C’est quoi |
Le format de validation des contacts (email, téléphone) doit-il être dans |
C’est quoi |
7. Script de chargement MDM
Le chargement des données est orchestré par le script run_migration.py du projet bdes-migration.
7.1. Prérequis
-
Base de données
referentiel-serviceexistante -
Migrations Flyway V1 à V5 appliquées (schémas
staging,golden,reference,mdm) -
Fonctions
mdm.reconcile_*()disponibles -
Fichiers JSON des soumissions Drupal
7.2. Composants
| Composant | Description |
|---|---|
|
Orchestrateur principal, gère l’ordre de chargement |
|
Connexion PostgreSQL et exécution des requêtes |
|
Appels aux fonctions |
|
Gestion des triggers, utilitaires d’affichage |
|
Un loader par entité (extraction et transformation) |
|
Classe abstraite |
7.3. Flux d’exécution
JSON Drupal → Loader.extract() → staging.* (PENDING) → mdm.reconcile_*() → golden.*/reference.* (PROCESSED)
Documentation complète : bdes-migration/README.md
|
7.4. Statistiques d’extraction
| Onglet | Enregistrements | Description |
|---|---|---|
|
13 |
Grades uniques |
|
25 |
Domaines RESAO uniques |
|
443 |
Spécialités par domaine |
|
590 |
Enseignants uniques (par matricule) |
|
590 |
États civils |
|
590 |
Adresses postales |
|
1155 |
Emails + téléphones (2 lignes max/personne) |
|
590 |
Affectations établissements |
|
441 |
Formations uniques (par intitulé) |
|
1301 |
Unités d’enseignement uniques |
|
1511 |
Éléments constitutifs uniques |
|
169 |
Types de supports uniques |
|
5758 |
Enseignements (API évaluation) |
|
4378 |
Articles (API évaluation) |
|
1389 |
Rapports de performance (API évaluation) |
|
665 |
Travaux de recherche (API évaluation) |
|
9 |
Types de structure (Faculté, École, etc.) |
|
46 |
Structures hiérarchiques |
7.5. Statistiques MDM (dernière exécution)
| Table | Staging | Golden | Remarque |
|---|---|---|---|
|
12 |
12 |
✅ Complet |
|
15 |
15 |
✅ Complet |
|
25 |
21 |
⚠️ 4 PENDING (doublons ou invalides) |
|
166 |
157 |
⚠️ 9 PENDING |
|
65 |
65 |
✅ Complet |
|
795 |
715 |
⚠️ 80 PENDING (domaine_resao_code manquant) |
|
16 |
16 |
✅ Complet |
|
590 |
582 |
⚠️ 8 PENDING (données manquantes) |
|
572 |
522 |
⚠️ 50 PENDING (domaine_code ou type_diplome manquant) |
|
1331 |
1171 |
⚠️ 160 PENDING (formation_code manquant) |
|
1583 |
1405 |
⚠️ 178 PENDING (ue_code manquant) |
|
555 |
547 |
⚠️ 8 PENDING (personne_matricule manquant) |
|
1155 |
1139 |
⚠️ 16 PENDING (personne_matricule manquant) |
|
39 |
26 |
⚠️ 13 PENDING (type_structure_code manquant) |
| Les enregistrements PENDING n’ont pas été réconciliés car une FK est manquante ou invalide. Ils restent en staging pour correction manuelle ou enrichissement des tables de référence. |