- Structure complète: utilisateurs, parents, assmat, enfants, contrats - Migrations SQL avec enums et contraintes - Seed: 1 super_admin (admin@ptits-pas.fr) - Mot de passe: 4dm1n1strateur (hash bcrypt)
6.4 KiB
6.4 KiB
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.dossiersd’un parent,avenantsd’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→ CASCADEparents.id_utilisateur→ CASCADEparents.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→ CASCADEenfants_parents.id_enfant→ CASCADE
Dossiers & échanges
dossiers.id_parent→ CASCADEdossiers.id_enfant→ CASCADEmessages.id_dossier→ CASCADEmessages.id_expediteur→ SET NULL
Contrats & avenants
contrats.id_dossier→ CASCADE (unique 1:1)avenants_contrats.id_contrat→ CASCADEavenants_contrats.initie_par→ SET NULL
Événements
evenements.id_enfant→ CASCADEevenements.id_am→ SET NULLevenements.id_parent→ SET NULLevenements.cree_par→ SET NULL
Divers
signalements_bugs.id_utilisateur→ SET NULLuploads.id_utilisateur→ SET NULLnotifications.id_utilisateur→ CASCADEvalidations.id_utilisateur→ SET NULL
🧪 Scénarios de test (exemples)
-
Suppression d’un parent
- Supprimer
utilisateurs(id=parentX) - Attendu :
parents(CASCADE), sesdossiers(CASCADE),messagesliés auxdossiers(CASCADE) sont supprimés.
- Supprimer
-
Suppression d’un co-parent
- Supprimer
utilisateurs(id=coParentY) - Attendu :
parents.id_co_parentpasse à NULL, aucun dossier supprimé.
- Supprimer
-
Suppression d’un utilisateur auteur de messages
- Supprimer
utilisateurs(id=uZ) - Attendu : les lignes
messagesrestent,id_expediteurdevient NULL.
- Supprimer
-
Suppression d’un enfant
- Supprimer
enfants(id=childA) - Attendu :
enfants_parents(CASCADE),dossiersdu childA (CASCADE),evenementsdu childA (CASCADE).
- Supprimer
-
Suppression d’un utilisateur AM
- Supprimer
utilisateurs(id=amB) - Attendu :
evenements.id_amdevient NULL (historique conservé).
- Supprimer
🛠 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.sqlappliqué sans erreur
Mainteneur : Équipe BDD
Dernière mise à jour : Sprint 1 – Politique FK consolidée