From 2075ff33797a1e9258f9572768cf0ba8dd8b0187 Mon Sep 17 00:00:00 2001 From: vdorge Date: Mon, 25 Aug 2025 11:14:27 +0000 Subject: [PATCH] =?UTF-8?q?T=C3=A9l=C3=A9verser=20les=20fichiers=20vers=20?= =?UTF-8?q?"docs"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/FK_POLICIES.md | 142 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 docs/FK_POLICIES.md diff --git a/docs/FK_POLICIES.md b/docs/FK_POLICIES.md new file mode 100644 index 0000000..3be63b3 --- /dev/null +++ b/docs/FK_POLICIES.md @@ -0,0 +1,142 @@ + +# FK_POLICIES.md +**Politique des clés étrangères (ON DELETE / ON UPDATE)** – Sprint 1 + +## 🎯 Objectif +Documenter, de façon unique et partagée, les règles de suppression/mise à jour appliquées aux **clés étrangères** de la base P’titsPas pour : +- préserver l’**intégrité référentielle** ; +- conserver l’**historique** utile (messages, événements…) ; +- respecter les exigences **RGPD** (suppression en cascade lorsque pertinent). + +> Par défaut, **ON UPDATE = NO ACTION** (UUID immuables). +> Ce document couvre **ON DELETE** table par table. + +--- + +## 🧭 Principes généraux + +- **CASCADE** quand la donnée fille **n’a pas de sens sans le parent** + (ex. `dossiers` d’un parent, `avenants` d’un contrat). +- **SET NULL** quand on veut **préserver l’historique** mais que le référent peut disparaître + (ex. auteur d’un message supprimé, créateur d’un événement). +- **RESTRICT/NO ACTION** non utilisé ici pour éviter des blocages au nettoyage. + +--- + +## 📚 Récapitulatif rapide (matrice) + +| Table (colonne FK) → Référence | ON DELETE | Raison | +|---|---:|---| +| **assistantes_maternelles(id_utilisateur)** → `utilisateurs(id)` | **CASCADE** | Profil AM supprimé avec son compte | +| **parents(id_utilisateur)** → `utilisateurs(id)` | **CASCADE** | Extension parent supprimée avec son compte | +| **parents(id_co_parent)** → `utilisateurs(id)` | **SET NULL** | Conserver le parent principal si co-parent disparaît | +| **enfants_parents(id_parent)** → `parents(id_utilisateur)` | **CASCADE** | Nettoyage liaisons N:N | +| **enfants_parents(id_enfant)** → `enfants(id)` | **CASCADE** | Idem | +| **dossiers(id_parent)** → `parents(id_utilisateur)` | **CASCADE** | Dossier n’a pas de sens sans parent | +| **dossiers(id_enfant)** → `enfants(id)` | **CASCADE** | Dossier n’a pas de sens sans enfant | +| **messages(id_dossier)** → `dossiers(id)` | **CASCADE** | Messages détruits avec le dossier | +| **messages(id_expediteur)** → `utilisateurs(id)` | **SET NULL** | Garder l’historique des échanges | +| **contrats(id_dossier)** → `dossiers(id)` | **CASCADE** | 1:1, contrat détruit si dossier supprimé | +| **avenants_contrats(id_contrat)** → `contrats(id)` | **CASCADE** | Avenants détruits avec le contrat | +| **avenants_contrats(initie_par)** → `utilisateurs(id)` | **SET NULL** | Historiser l’avenant sans bloquer | +| **evenements(id_enfant)** → `enfants(id)` | **CASCADE** | Événements n’ont plus de sens | +| **evenements(id_am)** → `utilisateurs(id)` | **SET NULL** | Garder la trace même si AM supprimée | +| **evenements(id_parent)** → `parents(id_utilisateur)` | **SET NULL** | Garder la trace si parent supprimé | +| **evenements(cree_par)** → `utilisateurs(id)` | **SET NULL** | Conserver l’historique de création | +| **signalements_bugs(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Conserver le ticket même si compte supprimé | +| **uploads(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Fichier reste référencé sans l’auteur | +| **notifications(id_utilisateur)** → `utilisateurs(id)` | **CASCADE** | Notifications propres à l’utilisateur | +| **validations(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Garder l’historique de décision | + +> **ON UPDATE** : **NO ACTION** partout (les UUID ne changent pas). + +--- + +## 🔎 Détail par domaine + +### Utilisateurs & extensions +- `assistantes_maternelles.id_utilisateur` → **CASCADE** +- `parents.id_utilisateur` → **CASCADE** +- `parents.id_co_parent` → **SET NULL** (interdit d’être co-parent de soi-même via CHECK déjà posé) + +### Enfants & liaisons +- `enfants_parents.id_parent` → **CASCADE** +- `enfants_parents.id_enfant` → **CASCADE** + +### Dossiers & échanges +- `dossiers.id_parent` → **CASCADE** +- `dossiers.id_enfant` → **CASCADE** +- `messages.id_dossier` → **CASCADE** +- `messages.id_expediteur` → **SET NULL** + +### Contrats & avenants +- `contrats.id_dossier` → **CASCADE** (unique 1:1) +- `avenants_contrats.id_contrat` → **CASCADE** +- `avenants_contrats.initie_par` → **SET NULL** + +### Événements +- `evenements.id_enfant` → **CASCADE** +- `evenements.id_am` → **SET NULL** +- `evenements.id_parent` → **SET NULL** +- `evenements.cree_par` → **SET NULL** + +### Divers +- `signalements_bugs.id_utilisateur` → **SET NULL** +- `uploads.id_utilisateur` → **SET NULL** +- `notifications.id_utilisateur` → **CASCADE** +- `validations.id_utilisateur` → **SET NULL** + +--- + +## 🧪 Scénarios de test (exemples) + +1. **Suppression d’un parent** + - Supprimer `utilisateurs(id=parentX)` + - Attendu : `parents` (CASCADE), ses `dossiers` (CASCADE), `messages` liés aux `dossiers` (CASCADE) sont supprimés. + +2. **Suppression d’un co-parent** + - Supprimer `utilisateurs(id=coParentY)` + - Attendu : `parents.id_co_parent` passe à **NULL**, aucun dossier supprimé. + +3. **Suppression d’un utilisateur auteur de messages** + - Supprimer `utilisateurs(id=uZ)` + - Attendu : les lignes `messages` **restent**, `id_expediteur` devient **NULL**. + +4. **Suppression d’un enfant** + - Supprimer `enfants(id=childA)` + - Attendu : `enfants_parents` (CASCADE), `dossiers` du childA (CASCADE), `evenements` du childA (CASCADE). + +5. **Suppression d’un utilisateur AM** + - Supprimer `utilisateurs(id=amB)` + - Attendu : `evenements.id_am` devient **NULL** (historique conservé). + +--- + +## 🛠 Migrations associées + +Les ajustements sont implémentés dans : +- **`/bdd/migrations/04_fk_policies.sql`** + – redéfinition des contraintes FK avec les bonnes politiques (**DROP puis ADD CONSTRAINT**), de façon idempotente. + +--- + +## 📄 Notes & futures évolutions + +- **RGPD (Sprint 2)** : si vous activez le **soft delete** (`deleted_at`) côté tables métier, ces politiques restent valides (les suppressions logiques se gèrent au niveau applicatif). +- **Audit** : si vous voulez tracer les suppressions, ajoutez des triggers d’audit (voir ticket Sprint 2 – Audit log). +- **Performance** : chaque FK doit être **indexée côté enfant** (cf. `02_indexes.sql`). + +--- + +## ✅ Checklist de conformité + +- [ ] Toutes les FK listées existent dans la base +- [ ] Politique **ON DELETE** conforme au tableau ci-dessus +- [ ] **ON UPDATE = NO ACTION** partout +- [ ] Tests de suppression réalisés sur une base seedée +- [ ] `04_fk_policies.sql` appliqué sans erreur + +--- + +**Mainteneur** : Équipe BDD +**Dernière mise à jour** : Sprint 1 – Politique FK consolidée