ajout de script / modif d'enum et simplification du lancement en local

This commit is contained in:
951095 2025-09-19 10:22:34 +02:00
parent 4d402bb7cc
commit 80f24dce5a
25 changed files with 849 additions and 923 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.env .env
PtitsPas_CDC.pdf

View File

@ -29,18 +29,17 @@ Ce projet contient la **base de données** pour l'application PtitsPas, avec scr
Dans le terminal, depuis le dossier du projet: Dans le terminal, depuis le dossier du projet:
```bash ```bash
docker compose -f docker-compose.dev.yml up -d make demo
``` ```
Pour arrêter et supprimer les volumes: Pour arrêter et supprimer les volumes:
```bash ```bash
docker compose -f docker-compose.dev.yml down -v make stop
``` ```
--- ---
## Importation automatique des données de test ## Importation automatique des données de test
Les données de test (CSV) sont automatiquement importées dans la base au démarrage du conteneur Docker grâce aux scripts présents dans le dossier `migrations/`. Les données de test (CSV) sont automatiquement importées dans la base au démarrage du conteneur Docker grâce aux scripts présents dans le dossier `migrations/`.

View File

@ -1,3 +1,3 @@
"id_utilisateur","numero_agrement","nir_chiffre","nb_max_enfants","biographie","disponible","ville_residence","date_agrement","annee_experience","specialite","place_disponible" id_utilisateur,numero_agrement,nir_chiffre,nb_max_enfants,biographie,disponible,ville_residence,date_agrement,annee_experience,specialite,place_disponible
"a1f3d5c7-8b9a-4e2f-9c1d-3b2a4f6e7d8c","AGR5678",,3,"Agrément 3 enfants - Spécialité 1-3 ans - 1 place disponible",True,,"2010-09-01",14,"1-3 ans",1 a1f3d5c7-8b9a-4e2f-9c1d-3b2a4f6e7d8c,AGR5678,,3,Agrément 3 enfants - Spécialité 1-3 ans - 1 place disponible,True,,2010-09-01,14,1-3 ans,1
"d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f","AGR1234",,4,"Agrément 4 enfants - Spécialité bébés 0-18 mois - 2 places disponibles",True,,"2005-06-15",18,"Bébés 0-18 mois",2 d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f,AGR1234,,4,Agrément 4 enfants - Spécialité bébés 0-18 mois - 2 places disponibles,True,,2005-06-15,18,Bébés 0-18 mois,2

1 id_utilisateur numero_agrement nir_chiffre nb_max_enfants biographie disponible ville_residence date_agrement annee_experience specialite place_disponible
2 a1f3d5c7-8b9a-4e2f-9c1d-3b2a4f6e7d8c AGR5678 3 Agrément 3 enfants - Spécialité 1-3 ans - 1 place disponible True 2010-09-01 14 1-3 ans 1
3 d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f AGR1234 4 Agrément 4 enfants - Spécialité bébés 0-18 mois - 2 places disponibles True 2005-06-15 18 Bébés 0-18 mois 2

View File

@ -1,2 +1,2 @@
"id","id_dossier","planning","tarif_horaire","indemnites_repas","date_debut","statut","signe_parent","signe_am","finalise_le","cree_le","modifie_le" id,id_dossier,planning,tarif_horaire,indemnites_repas,date_debut,statut,signe_parent,signe_am,finalise_le,cree_le,modifie_le
"f09c6ffa-4627-4aa8-b20b-829c2c828f0d","bb9c30a0-60b4-4832-9947-8a7d2366673d","{""jours"": [""Lundi"", ""Mardi"", ""Mercredi""]}","10.50","4.50","2024-09-01","brouillon",True,False,,"2025-09-09 11:05:47.933418+00","2025-09-09 11:05:47.933418+00" f09c6ffa-4627-4aa8-b20b-829c2c828f0d,bb9c30a0-60b4-4832-9947-8a7d2366673d,"{""jours"": [""Lundi"", ""Mardi"", ""Mercredi""]}",10.50,4.50,2024-09-01,brouillon,True,False,,2025-09-09 11:05:47.933418+00,2025-09-09 11:05:47.933418+00

1 id id_dossier planning tarif_horaire indemnites_repas date_debut statut signe_parent signe_am finalise_le cree_le modifie_le
2 f09c6ffa-4627-4aa8-b20b-829c2c828f0d bb9c30a0-60b4-4832-9947-8a7d2366673d {"jours": ["Lundi", "Mardi", "Mercredi"]} 10.50 4.50 2024-09-01 brouillon True False 2025-09-09 11:05:47.933418+00 2025-09-09 11:05:47.933418+00

View File

@ -1,2 +1,2 @@
"id","id_parent","id_enfant","presentation","type_contrat","repas","budget","planning_souhaite","statut","cree_le","modifie_le" id,id_parent,id_enfant,presentation,type_contrat,repas,budget,planning_souhaite,statut,cree_le,modifie_le
"bb9c30a0-60b4-4832-9947-8a7d2366673d","f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b","5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf","Contrat test pour garde à temps plein","temps_plein",False,"1200.00",,"envoye","2025-09-09 10:58:28.718654+00","2025-09-09 10:58:28.718654+00" bb9c30a0-60b4-4832-9947-8a7d2366673d,f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b,5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf,Contrat test pour garde à temps plein,temps_plein,False,1200.00,,envoye,2025-09-09 10:58:28.718654+00,2025-09-09 10:58:28.718654+00

1 id id_parent id_enfant presentation type_contrat repas budget planning_souhaite statut cree_le modifie_le
2 bb9c30a0-60b4-4832-9947-8a7d2366673d f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b 5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf Contrat test pour garde à temps plein temps_plein False 1200.00 envoye 2025-09-09 10:58:28.718654+00 2025-09-09 10:58:28.718654+00

View File

@ -1,10 +1,10 @@
"id","statut","prenom","nom","genre","date_naissance","date_prevue_naissance","photo_url","consentement_photo","date_consentement_photo","est_multiple" id,statut,prenom,nom,genre,date_naissance,date_prevue_naissance,photo_url,consentement_photo,date_consentement_photo,est_multiple
"5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf","actif","Emma","Dupont","F","2020-06-01",,,False,,False 5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf,actif,Emma,Dupont,F,2020-06-01,,,False,,False
"a5c3268e-07eb-41a4-9f6c-2f9f16f37c3d","actif",,,,"2020-01-01","2025-01-01",,False,,False a5c3268e-07eb-41a4-9f6c-2f9f16f37c3d,actif,,,,2020-01-01,2025-01-01,,False,,False
"e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c","actif","Emma","Martin",,"2023-02-15",,,False,,False e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c,actif,Emma,Martin,,2023-02-15,,,False,,False
"e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d","actif","Noah","Martin",,"2023-02-15",,,False,,False e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d,actif,Noah,Martin,,2023-02-15,,,False,,False
"e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e","actif","Léa","Martin",,"2023-02-15",,,False,,False e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e,actif,Léa,Martin,,2023-02-15,,,False,,False
"e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f","actif","Chloé","Rousseau",,"2022-04-20",,,False,,False e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f,actif,Chloé,Rousseau,,2022-04-20,,,False,,False
"e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a","actif","Hugo","Rousseau",,"2024-03-10",,,False,,False e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a,actif,Hugo,Rousseau,,2024-03-10,,,False,,False
"e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b","actif","Maxime","Lecomte",,"2023-04-15",,,False,,False e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b,actif,Maxime,Lecomte,,2023-04-15,,,False,,False
"edd19cd1-bb67-4f14-8a37-c66b75c94537","scolarise","Lucas","Durand","H","2018-09-15",,,False,,False edd19cd1-bb67-4f14-8a37-c66b75c94537,scolarise,Lucas,Durand,H,2018-09-15,,,False,,False

1 id statut prenom nom genre date_naissance date_prevue_naissance photo_url consentement_photo date_consentement_photo est_multiple
2 5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf actif Emma Dupont F 2020-06-01 False False
3 a5c3268e-07eb-41a4-9f6c-2f9f16f37c3d actif 2020-01-01 2025-01-01 False False
4 e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c actif Emma Martin 2023-02-15 False False
5 e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d actif Noah Martin 2023-02-15 False False
6 e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e actif Léa Martin 2023-02-15 False False
7 e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f actif Chloé Rousseau 2022-04-20 False False
8 e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a actif Hugo Rousseau 2024-03-10 False False
9 e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b actif Maxime Lecomte 2023-04-15 False False
10 edd19cd1-bb67-4f14-8a37-c66b75c94537 scolarise Lucas Durand H 2018-09-15 False False

View File

@ -1,9 +1,9 @@
"id_parent","id_enfant" id_parent,id_enfant
"b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e","e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f" b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e,e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f
"b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e","e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a" b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e,e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a
"c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f","e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c" c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f,e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c
"c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f","e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d" c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f,e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d
"c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f","e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e" c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f,e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e
"d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a","e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b" d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a,e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b
"f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b","e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f" f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b,e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f
"f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b","e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a" f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b,e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a

1 id_parent id_enfant
2 b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f
3 b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a
4 c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c
5 c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d
6 c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e
7 d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b
8 f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f
9 f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a

View File

@ -1,2 +1,2 @@
"id","type","id_enfant","id_am","id_parent","cree_par","date_debut","date_fin","commentaires","statut","delai_grace","urgent","cree_le","modifie_le" id,type,id_enfant,id_am,id_parent,cree_par,date_debut,date_fin,commentaires,statut,delai_grace,urgent,cree_le,modifie_le
"9f09425c-a374-4c9f-b3b1-be7258b60cd3","absence_enfant","5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf","62de8e71-8082-4383-a3a2-4277bdd07516",,"bbcae75c-0e60-4b84-b281-079dba23b44e","2024-11-10 00:00:00+00","2024-11-11 00:00:00+00","Enfant malade","propose",,True,"2025-09-02 12:55:43.781467+00","2025-09-05 14:39:38.390126+00" 9f09425c-a374-4c9f-b3b1-be7258b60cd3,absence_enfant,5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf,62de8e71-8082-4383-a3a2-4277bdd07516,,bbcae75c-0e60-4b84-b281-079dba23b44e,2024-11-10 00:00:00+00,2024-11-11 00:00:00+00,Enfant malade,propose,,True,2025-09-02 12:55:43.781467+00,2025-09-05 14:39:38.390126+00

1 id type id_enfant id_am id_parent cree_par date_debut date_fin commentaires statut delai_grace urgent cree_le modifie_le
2 9f09425c-a374-4c9f-b3b1-be7258b60cd3 absence_enfant 5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf 62de8e71-8082-4383-a3a2-4277bdd07516 bbcae75c-0e60-4b84-b281-079dba23b44e 2024-11-10 00:00:00+00 2024-11-11 00:00:00+00 Enfant malade propose True 2025-09-02 12:55:43.781467+00 2025-09-05 14:39:38.390126+00

View File

@ -1,2 +1,2 @@
"id","id_utilisateur","contenu","lu","cree_le" id,id_utilisateur,contenu,lu,cree_le
"71e90c37-f2cb-4aff-ad34-1c728f620afb","bbcae75c-0e60-4b84-b281-079dba23b44e","Votre dossier a été accepté",False,"2025-09-02 12:57:42.845264+00" 71e90c37-f2cb-4aff-ad34-1c728f620afb,bbcae75c-0e60-4b84-b281-079dba23b44e,Votre dossier a été accepté,False,2025-09-02 12:57:42.845264+00

1 id id_utilisateur contenu lu cree_le
2 71e90c37-f2cb-4aff-ad34-1c728f620afb bbcae75c-0e60-4b84-b281-079dba23b44e Votre dossier a été accepté False 2025-09-02 12:57:42.845264+00

View File

@ -1,5 +1,5 @@
"id_utilisateur","id_co_parent" id_utilisateur,id_co_parent
"b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e","f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b" b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e,f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b
"c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f", c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f,
"d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a", d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a,
"f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b","b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e" f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b,b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e

1 id_utilisateur id_co_parent
2 b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b
3 c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f
4 d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a
5 f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e

View File

@ -1,2 +1,2 @@
"id","id_utilisateur","fichier_url","type","cree_le" id,id_utilisateur,fichier_url,type,cree_le
"db1eb36d-5f30-4027-b529-1d972b79180a","bbcae75c-0e60-4b84-b281-079dba23b44e","https://placeholder.local/file","image","2025-09-02 12:57:35.140078+00" db1eb36d-5f30-4027-b529-1d972b79180a,bbcae75c-0e60-4b84-b281-079dba23b44e,https://placeholder.local/file,image,2025-09-02 12:57:35.140078+00

1 id id_utilisateur fichier_url type cree_le
2 db1eb36d-5f30-4027-b529-1d972b79180a bbcae75c-0e60-4b84-b281-079dba23b44e https://placeholder.local/file image 2025-09-02 12:57:35.140078+00

View File

@ -1,12 +1,12 @@
"id","email","password","prenom","nom","genre","role","statut","telephone","adresse","photo_url","consentement_photo","date_consentement_photo","changement_mdp_obligatoire","cree_le","modifie_le","ville","code_postal","mobile","telephone_fixe","profession","situation_familiale","date_naissance" id,email,password,prenom,nom,genre,role,statut,telephone,adresse,photo_url,consentement_photo,date_consentement_photo,changement_mdp_obligatoire,cree_le,modifie_le,ville,code_postal,mobile,telephone_fixe,profession,situation_familiale,date_naissance
"62de8e71-8082-4383-a3a2-4277bdd07516","am1@example.com","hash125","Claire","Martin","F","assistante_maternelle","actif","0609091011","5 place Bellecour",,False,,False,"2025-09-02 12:30:48.724463+00","2025-09-02 12:30:48.724463+00","Lyon","69002",,,,, 62de8e71-8082-4383-a3a2-4277bdd07516,am1@example.com,hash125,Claire,Martin,F,assistante_maternelle,actif,0609091011,5 place Bellecour,,False,,False,2025-09-02 12:30:48.724463+00,2025-09-02 12:30:48.724463+00,Lyon,69002,,,,,
"76c40571-5da6-4d27-8e07-303185875b36","gest1@example.com","hash126","Paul","Lemoine","H","gestionnaire","actif","0612131415","10 rue Victor Hugo",,False,,False,"2025-09-02 12:30:48.724463+00","2025-09-02 12:30:48.724463+00","Paris","75002",,,,, 76c40571-5da6-4d27-8e07-303185875b36,gest1@example.com,hash126,Paul,Lemoine,H,gestionnaire,actif,0612131415,10 rue Victor Hugo,,False,,False,2025-09-02 12:30:48.724463+00,2025-09-02 12:30:48.724463+00,Paris,75002,,,,,
"9bc30373-91a4-45ed-9c05-ffe1651ad906","coparent@example.com","hash124","Marc","Durand","H","parent","actif","0605060708","45 avenue de Lyon",,False,,False,"2025-09-02 12:30:48.724463+00","2025-09-02 12:30:48.724463+00","Lyon","69000",,,,, 9bc30373-91a4-45ed-9c05-ffe1651ad906,coparent@example.com,hash124,Marc,Durand,H,parent,actif,0605060708,45 avenue de Lyon,,False,,False,2025-09-02 12:30:48.724463+00,2025-09-02 12:30:48.724463+00,Lyon,69000,,,,,
"a1f3d5c7-8b9a-4e2f-9c1d-3b2a4f6e7d8c","fatima.elmansouri@ptits-pas.fr","password","Fatima","El Mansouri",,"assistante_maternelle","actif",,"17 Boulevard Aristide Briand",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 11:49:22.636003+00","Bezons","95870","06 75 45 67 89","01 39 98 78 90","Assistante maternelle","marie","1975-11-12" a1f3d5c7-8b9a-4e2f-9c1d-3b2a4f6e7d8c,fatima.elmansouri@ptits-pas.fr,password,Fatima,El Mansouri,,assistante_maternelle,actif,,17 Boulevard Aristide Briand,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 11:49:22.636003+00,Bezons,95870,06 75 45 67 89,01 39 98 78 90,Assistante maternelle,marie,1975-11-12
"b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e","julien.rousseau@ptits-pas.fr","password","Julien","Rousseau",,"parent","actif",,"14 Rue Pasteur",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 11:49:22.636003+00","Bezons","95870","06 56 67 78 89","01 39 98 01 23","Commercial","divorce","1985-08-29" b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e,julien.rousseau@ptits-pas.fr,password,Julien,Rousseau,,parent,actif,,14 Rue Pasteur,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 11:49:22.636003+00,Bezons,95870,06 56 67 78 89,01 39 98 01 23,Commercial,divorce,1985-08-29
"bbcae75c-0e60-4b84-b281-079dba23b44e","parent1@example.com","hash123","Alice","Dupont","F","parent","actif","0601020304","12 rue de Paris",,False,,False,"2025-09-02 12:30:48.724463+00","2025-09-02 12:30:48.724463+00","Paris","75001",,,,, bbcae75c-0e60-4b84-b281-079dba23b44e,parent1@example.com,hash123,Alice,Dupont,F,parent,actif,0601020304,12 rue de Paris,,False,,False,2025-09-02 12:30:48.724463+00,2025-09-02 12:30:48.724463+00,Paris,75001,,,,,
"c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f","claire.martin@ptits-pas.fr","password","Claire","Martin",,"parent","actif",,"5 Avenue du Général de Gaulle",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 11:49:22.636003+00","Bezons","95870","06 89 56 78 90","01 39 98 89 01","Infirmière","marie","1990-04-03" c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f,claire.martin@ptits-pas.fr,password,Claire,Martin,,parent,actif,,5 Avenue du Général de Gaulle,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 11:49:22.636003+00,Bezons,95870,06 89 56 78 90,01 39 98 89 01,Infirmière,marie,1990-04-03
"d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a","david.lecomte@ptits-pas.fr","password","David","Lecomte",,"parent","actif",,"31 Rue Émile Zola",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 11:49:22.636003+00","Bezons","95870","06 45 56 67 78","01 39 98 12 34","Développeur web","celibataire","1992-10-07" d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a,david.lecomte@ptits-pas.fr,password,David,Lecomte,,parent,actif,,31 Rue Émile Zola,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 11:49:22.636003+00,Bezons,95870,06 45 56 67 78,01 39 98 12 34,Développeur web,celibataire,1992-10-07
"d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f","marie.dubois@ptits-pas.fr","password","Marie","Dubois",,"assistante_maternelle","actif",,"25 Rue de la République",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 12:44:51.654512+00","Bezons","95870","06 96 34 56 78","01 39 98 67 89","Assistante maternelle","marie","1980-06-08" d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f,marie.dubois@ptits-pas.fr,password,Marie,Dubois,,assistante_maternelle,actif,,25 Rue de la République,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 12:44:51.654512+00,Bezons,95870,06 96 34 56 78,01 39 98 67 89,Assistante maternelle,marie,1980-06-08
"f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b","amelie.durand@ptits-pas.fr","password","Amélie","Durand",,"parent","actif",,"23 Rue Victor Hugo",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 11:49:22.636003+00","Bezons","95870","06 67 78 89 90","01 39 98 90 12","Comptable","divorce","1987-12-14" f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b,amelie.durand@ptits-pas.fr,password,Amélie,Durand,,parent,actif,,23 Rue Victor Hugo,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 11:49:22.636003+00,Bezons,95870,06 67 78 89 90,01 39 98 90 12,Comptable,divorce,1987-12-14
"f3b1a2d4-1c7e-4c2f-8b1a-9d3a8e2f5b6c","sophie.bernard@ptits-pas.fr","password","Sophie","Bernard",,"administrateur","actif",,"12 Avenue Gabriel Péri",,False,,False,"2025-09-04 11:49:22.636003+00","2025-09-04 11:49:22.636003+00","Bezons","95870","06 78 12 34 56","01 39 98 45 67","Responsable administrative","marie","1978-03-15" f3b1a2d4-1c7e-4c2f-8b1a-9d3a8e2f5b6c,sophie.bernard@ptits-pas.fr,password,Sophie,Bernard,,administrateur,actif,,12 Avenue Gabriel Péri,,False,,False,2025-09-04 11:49:22.636003+00,2025-09-04 11:49:22.636003+00,Bezons,95870,06 78 12 34 56,01 39 98 45 67,Responsable administrative,marie,1978-03-15

1 id email password prenom nom genre role statut telephone adresse photo_url consentement_photo date_consentement_photo changement_mdp_obligatoire cree_le modifie_le ville code_postal mobile telephone_fixe profession situation_familiale date_naissance
2 62de8e71-8082-4383-a3a2-4277bdd07516 am1@example.com hash125 Claire Martin F assistante_maternelle actif 0609091011 5 place Bellecour False False 2025-09-02 12:30:48.724463+00 2025-09-02 12:30:48.724463+00 Lyon 69002
3 76c40571-5da6-4d27-8e07-303185875b36 gest1@example.com hash126 Paul Lemoine H gestionnaire actif 0612131415 10 rue Victor Hugo False False 2025-09-02 12:30:48.724463+00 2025-09-02 12:30:48.724463+00 Paris 75002
4 9bc30373-91a4-45ed-9c05-ffe1651ad906 coparent@example.com hash124 Marc Durand H parent actif 0605060708 45 avenue de Lyon False False 2025-09-02 12:30:48.724463+00 2025-09-02 12:30:48.724463+00 Lyon 69000
5 a1f3d5c7-8b9a-4e2f-9c1d-3b2a4f6e7d8c fatima.elmansouri@ptits-pas.fr password Fatima El Mansouri assistante_maternelle actif 17 Boulevard Aristide Briand False False 2025-09-04 11:49:22.636003+00 2025-09-04 11:49:22.636003+00 Bezons 95870 06 75 45 67 89 01 39 98 78 90 Assistante maternelle marie 1975-11-12
6 b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e julien.rousseau@ptits-pas.fr password Julien Rousseau parent actif 14 Rue Pasteur False False 2025-09-04 11:49:22.636003+00 2025-09-04 11:49:22.636003+00 Bezons 95870 06 56 67 78 89 01 39 98 01 23 Commercial divorce 1985-08-29
7 bbcae75c-0e60-4b84-b281-079dba23b44e parent1@example.com hash123 Alice Dupont F parent actif 0601020304 12 rue de Paris False False 2025-09-02 12:30:48.724463+00 2025-09-02 12:30:48.724463+00 Paris 75001
8 c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f claire.martin@ptits-pas.fr password Claire Martin parent actif 5 Avenue du Général de Gaulle False False 2025-09-04 11:49:22.636003+00 2025-09-04 11:49:22.636003+00 Bezons 95870 06 89 56 78 90 01 39 98 89 01 Infirmière marie 1990-04-03
9 d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a david.lecomte@ptits-pas.fr password David Lecomte parent actif 31 Rue Émile Zola False False 2025-09-04 11:49:22.636003+00 2025-09-04 11:49:22.636003+00 Bezons 95870 06 45 56 67 78 01 39 98 12 34 Développeur web celibataire 1992-10-07
10 d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f marie.dubois@ptits-pas.fr password Marie Dubois assistante_maternelle actif 25 Rue de la République False False 2025-09-04 11:49:22.636003+00 2025-09-04 12:44:51.654512+00 Bezons 95870 06 96 34 56 78 01 39 98 67 89 Assistante maternelle marie 1980-06-08
11 f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b amelie.durand@ptits-pas.fr password Amélie Durand parent actif 23 Rue Victor Hugo False False 2025-09-04 11:49:22.636003+00 2025-09-04 11:49:22.636003+00 Bezons 95870 06 67 78 89 90 01 39 98 90 12 Comptable divorce 1987-12-14
12 f3b1a2d4-1c7e-4c2f-8b1a-9d3a8e2f5b6c sophie.bernard@ptits-pas.fr password Sophie Bernard administrateur actif 12 Avenue Gabriel Péri False False 2025-09-04 11:49:22.636003+00 2025-09-04 11:49:22.636003+00 Bezons 95870 06 78 12 34 56 01 39 98 45 67 Responsable administrative marie 1978-03-15

View File

@ -1,4 +1,4 @@
"id","id_utilisateur","type","statut","cree_le","modifie_le","valide_par","commentaire" id,id_utilisateur,type,statut,cree_le,modifie_le,valide_par,commentaire
"8ec99565-e8c2-469f-9641-01b99b8281eb","62de8e71-8082-4383-a3a2-4277bdd07516","identité","valide","2025-09-02 12:57:49.846424+00","2025-09-02 12:57:49.846424+00",, 8ec99565-e8c2-469f-9641-01b99b8281eb,62de8e71-8082-4383-a3a2-4277bdd07516,identité,valide,2025-09-02 12:57:49.846424+00,2025-09-02 12:57:49.846424+00,,
"be1c4779-341b-436d-b17e-8bc486d22ef8","62de8e71-8082-4383-a3a2-4277bdd07516",,"valide","2025-09-09 14:47:01.963573+00","2025-09-09 14:47:01.963573+00",,"Contrôle OK" be1c4779-341b-436d-b17e-8bc486d22ef8,62de8e71-8082-4383-a3a2-4277bdd07516,,valide,2025-09-09 14:47:01.963573+00,2025-09-09 14:47:01.963573+00,,Contrôle OK
"fcc45701-5708-4368-b467-b95ddb7e1580","d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f",,"valide","2025-09-09 14:52:47.339858+00","2025-09-09 14:52:47.339858+00","76c40571-5da6-4d27-8e07-303185875b36","Contrôle OK" fcc45701-5708-4368-b467-b95ddb7e1580,d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f,,valide,2025-09-09 14:52:47.339858+00,2025-09-09 14:52:47.339858+00,76c40571-5da6-4d27-8e07-303185875b36,Contrôle OK

1 id id_utilisateur type statut cree_le modifie_le valide_par commentaire
2 8ec99565-e8c2-469f-9641-01b99b8281eb 62de8e71-8082-4383-a3a2-4277bdd07516 identité valide 2025-09-02 12:57:49.846424+00 2025-09-02 12:57:49.846424+00
3 be1c4779-341b-436d-b17e-8bc486d22ef8 62de8e71-8082-4383-a3a2-4277bdd07516 valide 2025-09-09 14:47:01.963573+00 2025-09-09 14:47:01.963573+00 Contrôle OK
4 fcc45701-5708-4368-b467-b95ddb7e1580 d9c2e3f4-5b6a-4c3d-9f1a-2e7b3c5d8a1f valide 2025-09-09 14:52:47.339858+00 2025-09-09 14:52:47.339858+00 76c40571-5da6-4d27-8e07-303185875b36 Contrôle OK

View File

@ -14,9 +14,19 @@ services:
ports: ports:
- "5433:5432" - "5433:5432"
volumes: volumes:
# Scripts de migration (ordre important → init, indexes, checks, triggers, import…)
- ./migrations/01_init.sql:/docker-entrypoint-initdb.d/01_init.sql - ./migrations/01_init.sql:/docker-entrypoint-initdb.d/01_init.sql
- ./migrations/02_indexes.sql:/docker-entrypoint-initdb.d/02_indexes.sql
- ./migrations/03_checks.sql:/docker-entrypoint-initdb.d/03_checks.sql
- ./migrations/05_triggers.sql:/docker-entrypoint-initdb.d/05_triggers.sql
- ./migrations/07_import.sql:/docker-entrypoint-initdb.d/07_import.sql - ./migrations/07_import.sql:/docker-entrypoint-initdb.d/07_import.sql
# Dossier de données de test (CSV, etc.)
- ./bdd/data_test:/bdd/data_test - ./bdd/data_test:/bdd/data_test
# Scripts de vérification
- ./tests/sql:/tests/sql
# Données persistées Postgres
- postgres_standalone_data:/var/lib/postgresql/data - postgres_standalone_data:/var/lib/postgresql/data
networks: networks:
- ptitspas_dev - ptitspas_dev

View File

@ -1,157 +1,146 @@
# ENUMS.md — Référentiel des valeurs énumérées
# ENUMS.md — Référentiel des valeurs énumérées (Sprint 1) Ce document recense **toutes les valeurs énumérées** utilisées dans la base **PtitsPas**, leur **sens fonctionnel**, et les **tables/colonnes concernées**.
Ce document recense **toutes les valeurs énumérées** utilisées dans la base PtitsPas, leur **sens fonctionnel**, les **colonnes concernées** et les **transitions** attendues côté métier / API. > Objectif : garantir la cohérence entre la **DB**, le **backend (NestJS)** et le **frontend (Flutter)**.
> Toute évolution doit être documentée ici **avant** migration DB.
> Objectif : garantir la **cohérence** entre la DB, le backend (NestJS) et le frontend (Flutter).
> Toute nouvelle valeur ou renommage **doit** être ajouté ici **avant** migration DB.
--- ---
## Conventions générales ## Conventions générales
- Les valeurs ENUM sont **en minuscules** et **sans espace** (snake_case si nécessaire). * Les valeurs ENUM sont **en minuscules** (snake\_case si nécessaire).
- Côté DB, elles sont implémentées via **types ENUM PostgreSQL** *ou* via `CHECK` (selon ce qui est en place dans `01_init.sql`). * Implémentées via `CREATE TYPE … AS ENUM` dans PostgreSQL.
- Côté API, ces valeurs sont **renvoyées telles quelles** et **documentées** dans lOpenAPI / DTO. * Les valeurs sont **renvoyées telles quelles** côté API.
--- ---
## 1) Rôle utilisateur — `role` ## 1) Rôle utilisateur — `role_type`
**Tables/colonnes** : `utilisateurs.role` **Tables/colonnes** : `utilisateurs.role`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | ----------------------- | ------------------------------------------------- |
| `super_admin` | Compte technique initial / administration globale |
| `gestionnaire` | Gestion / validation des comptes, supervision |
| `parent` | Parent ou co-parent | | `parent` | Parent ou co-parent |
| `am` | Assistante maternelle | | `gestionnaire` | Gestion/validation des comptes, supervision |
| `super_admin` | Compte technique initial / administration globale |
| `assistante_maternelle` | Profil professionnel dassistante maternelle |
| `administrateur` | Administration locale / restreinte |
--- ---
## 2) Statut utilisateur — `statut` ## 2) Genre utilisateur — `genre_type`
**Tables/colonnes** : `utilisateurs.genre`, `enfants.genre`
| Valeur | Description |
| ------- | ------------------- |
| `H` | Homme |
| `F` | Femme |
| `Autre` | Autre / non précisé |
---
## 3) Statut utilisateur — `statut_utilisateur_type`
**Tables/colonnes** : `utilisateurs.statut` **Tables/colonnes** : `utilisateurs.statut`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | ------------ | ------------------------------- |
| `en_attente` | Compte créé mais non validé | | `en_attente` | Compte créé mais non validé |
| `accepte` | Compte validé et actif | | `actif` | Compte validé et actif |
| `rejete` | Demande refusée (peut être recréée ultérieurement) | | `suspendu` | Compte temporairement désactivé |
--- ---
## 3) Statut enfant — `statut` ## 4) Statut enfant — `statut_enfant_type`
**Tables/colonnes** : `enfants.statut` **Tables/colonnes** : `enfants.statut`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | ----------- | ---------------------------------------------- |
| `a_naitre` | Enfant à naître (date prévue renseignée) | | `a_naitre` | Enfant à naître (date prévue) |
| `actif` | Enfant pris en charge / en cours de garde | | `actif` | Enfant pris en charge |
| `scolarise` | Enfant scolarisé, garde potentiellement périscolaire | | `scolarise` | Enfant scolarisé (garde périscolaire possible) |
**Contraintes associées** :
- `a_naitre`**`date_prevue_naissance` obligatoire**
- `actif`/`scolarise`**`date_naissance` obligatoire**
--- ---
## 4) Statut dossier — `statut` ## 5) Statut dossier — `statut_dossier_type`
**Tables/colonnes** : `dossiers.statut` **Tables/colonnes** : `dossiers.statut`
**Valeurs autorisées (MVP)** :
| Valeur | Description | | Valeur | Description |
|---|---| | --------- | ---------------------------- |
| `envoye` | Dossier soumis par le parent (état initial) | | `envoye` | Dossier soumis par le parent |
| `en_cours` | Échanges en cours entre parent et AM | | `accepte` | Dossier validé par lAM |
| `clos` | Dossier clôturé (contrat généré ou abandon) | | `refuse` | Dossier rejeté |
--- ---
## 5) Statut contrat — `statut` ## 6) Statut contrat — `statut_contrat_type`
**Tables/colonnes** : `contrats.statut` **Tables/colonnes** : `contrats.statut`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | ---------------------- | ----------------------------------------- |
| `brouillon` | Contrat en préparation | | `brouillon` | Contrat en préparation |
| `valide` | Contrat finalisé (signatures complètes) | | `en_attente_signature` | Contrat généré, en attente des signatures |
| `archive` | Contrat obsolète / terminé | | `valide` | Contrat signé et actif |
| `resilie` | Contrat résilié |
--- ---
## 6) Statut avenant — `statut` ## 7) Statut avenant — `statut_avenant_type`
**Tables/colonnes** : `avenants_contrats.statut` **Tables/colonnes** : `avenants_contrats.statut`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | --------- | --------------------------- |
| `propose` | Avenant proposé (en attente daccord) | | `propose` | Avenant proposé |
| `valide` | Avenant accepté et appliqué | | `accepte` | Avenant accepté et appliqué |
| `rejete` | Avenant refusé | | `refuse` | Avenant rejeté |
--- ---
## 7) Type dévénement — `type` ## 8) Type dévénement — `type_evenement_type`
**Tables/colonnes** : `evenements.type` **Tables/colonnes** : `evenements.type`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | ------------------ | -------------------------------- |
| `absence_enfant` | Enfant absent | | `absence_enfant` | Absence de lenfant |
| `conge_am` | Congé de lassistante maternelle | | `conge_am` | Congé de lassistante maternelle |
| `conge_parent` | Congé du parent | | `conge_parent` | Congé du parent |
| `arret_maladie_am` | Arrêt maladie AM | | `arret_maladie_am` | Arrêt maladie de lAM |
| `evenement_rpe` | Événement RPE | | `evenement_rpe` | Événement organisé par le RPE |
--- ---
## 8) Statut dévénement — `statut` ## 9) Statut dévénement — `statut_evenement_type`
**Tables/colonnes** : `evenements.statut` **Tables/colonnes** : `evenements.statut`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | --------- | ----------------- |
| `propose` | Événement proposé | | `propose` | Événement proposé |
| `valide` | Événement validé | | `valide` | Événement validé |
| `rejete` | Événement refusé | | `refuse` | Événement rejeté |
--- ---
## 9) Statut de validation compte — `statut` ## 10) Statut validation — `statut_validation_type`
**Tables/colonnes** : `validations.statut` **Tables/colonnes** : `validations.statut`
**Valeurs autorisées** :
| Valeur | Description | | Valeur | Description |
|---|---| | ------------ | ------------------------ |
| `accepte` | Compte validé | | `en_attente` | En attente de validation |
| `rejete` | Compte refusé | | `valide` | Validation acceptée |
| `refuse` | Validation refusée |
--- ---
## 10) Type de notification — `type` 📌 **Mainteneur** : Équipe BDD
📌 **Dernière mise à jour** : alignée sur `init.sql` (septembre 2025)
**Tables/colonnes** : `notifications.type`
**Valeurs proposées** :
| Valeur | Description |
|---|---|
| `nouveau_message` | Nouveau message sur un dossier |
| `validation_compte` | Résultat de la validation de compte |
| `maj_contrat` | Contrat mis à jour (avenant / signature) |
| `evenement_a_venir` | Rappel dun événement proche |
--- ---
**Mainteneur** : Équipe BDD
**Dernière mise à jour** : Sprint 1 — Ticket 9 (ENUMS)

View File

@ -1,142 +1,144 @@
# FK\_POLICIES.md — Politiques de clés étrangères
# FK_POLICIES.md Ce document recense lensemble des **relations entre tables** dans la base **PtitsPas**, avec leurs **règles de suppression** et les implications fonctionnelles.
**Politique des clés étrangères (ON DELETE / ON UPDATE)** Sprint 1
## 🎯 Objectif > Objectif : assurer la cohérence entre la **DB**, le **backend** et le **fonctionnel métier**.
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 PtitsPas pour : > Toute nouvelle relation ou modification doit être ajoutée ici avant migration DB.
- 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 ## Conventions générales
- **CASCADE** quand la donnée fille **na pas de sens sans le parent** * Les FK sont définies en `REFERENCES ...`.
(ex. `dossiers` dun parent, `avenants` dun contrat). * Sauf précision, `ON UPDATE` est implicite = `NO ACTION`.
- **SET NULL** quand on veut **préserver lhistorique** mais que le référent peut disparaître * Les comportements documentés sont **côté PostgreSQL**.
(ex. auteur dun message supprimé, créateur dun événement).
- **RESTRICT/NO ACTION** non utilisé ici pour éviter des blocages au nettoyage.
--- ---
## 📚 Récapitulatif rapide (matrice) ## 1) Table `assistantes_maternelles`
| Table (colonne FK) → Référence | ON DELETE | Raison | * **FK** : `id_utilisateur → utilisateurs.id`
|---|---:|---| * **ON DELETE CASCADE**
| **assistantes_maternelles(id_utilisateur)**`utilisateurs(id)` | **CASCADE** | Profil AM supprimé avec son compte | * 🔎 Si un utilisateur AM est supprimé, son profil AM est supprimé automatiquement.
| **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 na pas de sens sans parent |
| **dossiers(id_enfant)**`enfants(id)` | **CASCADE** | Dossier na 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 lhistorique 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 lavenant sans bloquer |
| **evenements(id_enfant)**`enfants(id)` | **CASCADE** | Événements nont 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 lhistorique 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 lauteur |
| **notifications(id_utilisateur)**`utilisateurs(id)` | **CASCADE** | Notifications propres à lutilisateur |
| **validations(id_utilisateur)**`utilisateurs(id)` | **SET NULL** | Garder lhistorique de décision |
> **ON UPDATE** : **NO ACTION** partout (les UUID ne changent pas).
--- ---
## 🔎 Détail par domaine ## 2) Table `parents`
### Utilisateurs & extensions * **FK** : `id_utilisateur → utilisateurs.id`
- `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 * **ON DELETE CASCADE** → suppression dun parent entraîne suppression automatique du parent.
- `enfants_parents.id_parent`**CASCADE** * **FK** : `id_co_parent → utilisateurs.id`
- `enfants_parents.id_enfant` → **CASCADE**
### Dossiers & échanges * **ON DELETE NO ACTION** (par défaut) → suppression du co-parent interdite si référence active.
- `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) ## 3) Table `enfants_parents`
1. **Suppression dun parent** * **FK** : `id_parent → parents.id_utilisateur`
- Supprimer `utilisateurs(id=parentX)`
- Attendu : `parents` (CASCADE), ses `dossiers` (CASCADE), `messages` liés aux `dossiers` (CASCADE) sont supprimés.
2. **Suppression dun co-parent** * **ON DELETE CASCADE** → si le parent est supprimé, le lien avec lenfant disparaît.
- Supprimer `utilisateurs(id=coParentY)` * **FK** : `id_enfant → enfants.id`
- Attendu : `parents.id_co_parent` passe à **NULL**, aucun dossier supprimé.
3. **Suppression dun utilisateur auteur de messages** * **ON DELETE CASCADE** → si lenfant est supprimé, toutes ses associations avec des parents disparaissent.
- Supprimer `utilisateurs(id=uZ)`
- Attendu : les lignes `messages` **restent**, `id_expediteur` devient **NULL**.
4. **Suppression dun enfant**
- Supprimer `enfants(id=childA)`
- Attendu : `enfants_parents` (CASCADE), `dossiers` du childA (CASCADE), `evenements` du childA (CASCADE).
5. **Suppression dun utilisateur AM**
- Supprimer `utilisateurs(id=amB)`
- Attendu : `evenements.id_am` devient **NULL** (historique conservé).
--- ---
## 🛠 Migrations associées ## 4) Table `dossiers`
Les ajustements sont implémentés dans : * **FK** : `id_parent → parents.id_utilisateur`
- **`/bdd/migrations/04_fk_policies.sql`**
redéfinition des contraintes FK avec les bonnes politiques (**DROP puis ADD CONSTRAINT**), de façon idempotente. * **ON DELETE CASCADE** → si le parent est supprimé, ses dossiers disparaissent.
* **FK** : `id_enfant → enfants.id`
* **ON DELETE CASCADE** → si lenfant est supprimé, les dossiers liés disparaissent.
--- ---
## 📄 Notes & futures évolutions ## 5) Table `messages`
- **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). * **FK** : `id_dossier → dossiers.id`
- **Audit** : si vous voulez tracer les suppressions, ajoutez des triggers daudit (voir ticket Sprint 2 Audit log).
- **Performance** : chaque FK doit être **indexée côté enfant** (cf. `02_indexes.sql`). * **ON DELETE CASCADE** → si un dossier est supprimé, les messages disparaissent.
* **FK** : `id_expediteur → utilisateurs.id`
* **ON DELETE CASCADE** → si un utilisateur est supprimé, ses messages disparaissent.
--- ---
## ✅ Checklist de conformité ## 6) Table `contrats`
- [ ] Toutes les FK listées existent dans la base * **FK** : `id_dossier → dossiers.id`
- [ ] Politique **ON DELETE** conforme au tableau ci-dessus
- [ ] **ON UPDATE = NO ACTION** partout * **UNIQUE** + **ON DELETE CASCADE** → si un dossier est supprimé, le contrat disparaît.
- [ ] Tests de suppression réalisés sur une base seedée
- [ ] `04_fk_policies.sql` appliqué sans erreur
--- ---
**Mainteneur** : Équipe BDD ## 7) Table `avenants_contrats`
**Dernière mise à jour** : Sprint 1 Politique FK consolidée
* **FK** : `id_contrat → contrats.id`
* **ON DELETE CASCADE** → si un contrat est supprimé, ses avenants disparaissent.
* **FK** : `initie_par → utilisateurs.id`
* **ON DELETE NO ACTION** → suppression interdite tant que des avenants existent.
---
## 8) Table `evenements`
* **FK** : `id_enfant → enfants.id`
* **ON DELETE CASCADE** → si un enfant est supprimé, ses événements disparaissent.
* **FK** : `id_am → utilisateurs.id`
* **ON DELETE NO ACTION** → suppression interdite si des événements liés.
* **FK** : `id_parent → parents.id_utilisateur`
* **ON DELETE NO ACTION** → suppression interdite si des événements liés.
* **FK** : `cree_par → utilisateurs.id`
* **ON DELETE NO ACTION** → suppression interdite si référence encore utilisée.
---
## 9) Table `signalements_bugs`
* **FK** : `id_utilisateur → utilisateurs.id`
* **ON DELETE NO ACTION** → utilisateur non supprimable si bug référencé.
---
## 10) Table `uploads`
* **FK** : `id_utilisateur → utilisateurs.id`
* **ON DELETE SET NULL** → si un utilisateur est supprimé, ses fichiers restent, mais sans lien utilisateur.
---
## 11) Table `notifications`
* **FK** : `id_utilisateur → utilisateurs.id`
* **ON DELETE CASCADE** → si un utilisateur est supprimé, ses notifications disparaissent.
---
## 12) Table `validations`
* **FK** : `id_utilisateur → utilisateurs.id`
* **ON DELETE NO ACTION** → suppression interdite si validations liées.
* **FK** : `valide_par → utilisateurs.id`
* **ON DELETE NO ACTION** → suppression interdite si validations effectuées par lutilisateur.
---
📌 **Mainteneur** : Équipe BDD
📌 **Dernière mise à jour** : alignée sur `init.sql` (septembre 2025)
---

72
makefile Normal file
View File

@ -0,0 +1,72 @@
# ============================================================
# Makefile - Gestion de la base Ptits Pas (Postgres + pgAdmin)
# Compatible macOS, Linux, Windows (Git Bash)
# ============================================================
# Détection de l'OS
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin) # macOS
OPEN_CMD = open
else ifeq ($(UNAME_S),Linux) # Linux
OPEN_CMD = xdg-open
else # Windows (Git Bash / Cygwin)
OPEN_CMD = start
endif
# Paramètres
PG_CONTAINER = ptitspas-postgres-standalone
PG_USER = admin
PG_DB = ptitpas_db
VERIFY_SQL = /tests/sql/verify.sql
IMPORT_SQL = /docker-entrypoint-initdb.d/07_import.sql
# ============================================================
# Cibles principales
# ============================================================
reset:
@echo "🗑️ Réinitialisation de la base..."
docker compose -f docker-compose.dev.yml down -v
docker compose -f docker-compose.dev.yml up -d
@echo "✅ Base de données réinitialisée."
import:
@echo "⏳ Attente que Postgres démarre..."
@until docker exec -i $(PG_CONTAINER) pg_isready -U $(PG_USER) -d $(PG_DB); do \
sleep 2; \
done
@echo "📥 Import des données de démo..."
@docker exec -i $(PG_CONTAINER) psql -U $(PG_USER) -d $(PG_DB) -f $(IMPORT_SQL)
@echo "✅ Données importées."
verify:
@echo "⏳ Attente que Postgres démarre pour vérifier..."
@until docker exec -i $(PG_CONTAINER) pg_isready -U $(PG_USER) -d $(PG_DB); do \
sleep 2; \
done
@echo "🔎 Vérification des données..."
-@docker exec -i $(PG_CONTAINER) psql -U $(PG_USER) -d $(PG_DB) -f $(VERIFY_SQL) | tee verify.log
@if grep -q "ERROR" verify.log; then \
echo "❌ Des erreurs détectées (voir verify.log)"; \
else \
echo "✅ Vérification OK : pas d'erreurs détectées."; \
fi
demo: reset import verify
@echo "🌐 Ouverture de pgAdmin sur http://localhost:8081 ..."
@$(OPEN_CMD) http://localhost:8081
# ============================================================
# Utilitaires
# ============================================================
logs:
docker compose -f docker-compose.dev.yml logs -f
psql:
docker exec -it $(PG_CONTAINER) psql -U $(PG_USER) -d $(PG_DB)
stop:
docker compose -f docker-compose.dev.yml down
j

View File

@ -1,157 +1,57 @@
-- ============================================= -- ============================================================
-- 02_indexes.sql : Index FK + colonnes critiques -- 02_indexes.sql — Indexes pour améliorer les perfs
-- ============================================= -- ============================================================
-- Recommandation : exécuter après 01_init.sql -- ===========================================
-- Messages (par dossier + tri par date)
-- =========== -- Utilisé dans verify.sql (EXPLAIN + ORDER BY cree_le)
-- UTILISATEURS -- ===========================================
-- ===========
-- Recherche par email (insensibilité à la casse pour lookup)
CREATE INDEX IF NOT EXISTS idx_utilisateurs_lower_courriel
ON utilisateurs (LOWER(courriel));
-- ===========
-- ASSISTANTES_MATERNELLES
-- ===========
-- FK -> utilisateurs(id)
CREATE INDEX IF NOT EXISTS idx_am_id_utilisateur
ON assistantes_maternelles (id_utilisateur);
-- =======
-- PARENTS
-- =======
-- FK -> utilisateurs(id)
CREATE INDEX IF NOT EXISTS idx_parents_id_utilisateur
ON parents (id_utilisateur);
-- Co-parent (nullable)
CREATE INDEX IF NOT EXISTS idx_parents_id_co_parent
ON parents (id_co_parent);
-- =======
-- ENFANTS
-- =======
-- (souvent filtrés par statut / date_naissance ? à activer si besoin)
-- CREATE INDEX IF NOT EXISTS idx_enfants_statut ON enfants (statut);
-- CREATE INDEX IF NOT EXISTS idx_enfants_date_naissance ON enfants (date_naissance);
-- ================
-- ENFANTS_PARENTS (N:N)
-- ================
-- PK composite déjà en place (id_parent, id_enfant), ajouter index individuels si jointures unilatérales fréquentes
CREATE INDEX IF NOT EXISTS idx_enfants_parents_id_parent
ON enfants_parents (id_parent);
CREATE INDEX IF NOT EXISTS idx_enfants_parents_id_enfant
ON enfants_parents (id_enfant);
-- ========
-- DOSSIERS
-- ========
-- FK -> parent / enfant
CREATE INDEX IF NOT EXISTS idx_dossiers_id_parent
ON dossiers (id_parent);
CREATE INDEX IF NOT EXISTS idx_dossiers_id_enfant
ON dossiers (id_enfant);
-- Statut (filtrages "à traiter", "envoyé", etc.)
CREATE INDEX IF NOT EXISTS idx_dossiers_statut
ON dossiers (statut);
-- JSONB : si on fait des requêtes @> sur le planning souhaité
-- CREATE INDEX IF NOT EXISTS idx_dossiers_planning_souhaite_gin
-- ON dossiers USING GIN (planning_souhaite);
-- ========
-- MESSAGES
-- ========
-- Filtrage par dossier + tri chronologique
CREATE INDEX IF NOT EXISTS idx_messages_id_dossier_cree_le CREATE INDEX IF NOT EXISTS idx_messages_id_dossier_cree_le
ON messages (id_dossier, cree_le); ON messages (id_dossier, cree_le DESC);
-- Recherche par expéditeur -- ===========================================
CREATE INDEX IF NOT EXISTS idx_messages_id_expediteur_cree_le -- Evenements (filtrés par enfant + date)
ON messages (id_expediteur, cree_le); -- Utilisé dans verify.sql (WHERE id_enfant AND date_debut >= ...)
-- ===========================================
-- =========
-- CONTRATS
-- =========
-- UNIQUE(id_dossier) existe déjà -> index implicite
-- Tri / filtres fréquents
CREATE INDEX IF NOT EXISTS idx_contrats_statut
ON contrats (statut);
-- JSONB planning : activer si on requête par clé
-- CREATE INDEX IF NOT EXISTS idx_contrats_planning_gin
-- ON contrats USING GIN (planning);
-- ==================
-- AVENANTS_CONTRATS
-- ==================
CREATE INDEX IF NOT EXISTS idx_avenants_contrats_id_contrat_cree_le
ON avenants_contrats (id_contrat, cree_le);
CREATE INDEX IF NOT EXISTS idx_avenants_contrats_initie_par
ON avenants_contrats (initie_par);
CREATE INDEX IF NOT EXISTS idx_avenants_contrats_statut
ON avenants_contrats (statut);
-- =========
-- EVENEMENTS
-- =========
-- Accès par enfant + période
CREATE INDEX IF NOT EXISTS idx_evenements_id_enfant_date_debut CREATE INDEX IF NOT EXISTS idx_evenements_id_enfant_date_debut
ON evenements (id_enfant, date_debut); ON evenements (id_enfant, date_debut DESC);
-- Filtrage par auteur / AM / parent -- ===========================================
CREATE INDEX IF NOT EXISTS idx_evenements_cree_par -- Notifications (par utilisateur + lues/non lues + tri par date)
ON evenements (cree_par); -- Utilisé dans verify.sql (WHERE id_utilisateur AND lu=false ORDER BY cree_le DESC)
-- ===========================================
CREATE INDEX IF NOT EXISTS idx_evenements_id_am
ON evenements (id_am);
CREATE INDEX IF NOT EXISTS idx_evenements_id_parent
ON evenements (id_parent);
CREATE INDEX IF NOT EXISTS idx_evenements_type
ON evenements (type);
CREATE INDEX IF NOT EXISTS idx_evenements_statut
ON evenements (statut);
-- =================
-- SIGNALEMENTS_BUGS
-- =================
CREATE INDEX IF NOT EXISTS idx_signalements_bugs_id_utilisateur_cree_le
ON signalements_bugs (id_utilisateur, cree_le);
-- =======
-- UPLOADS
-- =======
CREATE INDEX IF NOT EXISTS idx_uploads_id_utilisateur_cree_le
ON uploads (id_utilisateur, cree_le);
-- =============
-- NOTIFICATIONS
-- =============
-- Requêtes fréquentes : non lues + ordre chrono
CREATE INDEX IF NOT EXISTS idx_notifications_user_lu_cree_le CREATE INDEX IF NOT EXISTS idx_notifications_user_lu_cree_le
ON notifications (id_utilisateur, lu, cree_le); ON notifications (id_utilisateur, lu, cree_le DESC);
-- Option : index partiel pour "non lues" -- ===========================================
-- CREATE INDEX IF NOT EXISTS idx_notifications_non_lues -- Dossiers (filtrés par parent + enfant + statut + tri par date)
-- ON notifications (id_utilisateur, cree_le) -- Utilisé dans verify.sql
-- WHERE lu = false; -- ===========================================
CREATE INDEX IF NOT EXISTS idx_dossiers_id_parent_enfant_statut_cree_le
ON dossiers (id_parent, id_enfant, statut, cree_le DESC);
-- =========== -- ===========================================
-- VALIDATIONS -- Contrats (lookup par dossier unique)
-- =========== -- ===========================================
-- Requêtes par utilisateur validé, par statut et par date CREATE UNIQUE INDEX IF NOT EXISTS idx_contrats_id_dossier
CREATE INDEX IF NOT EXISTS idx_validations_id_utilisateur_cree_le ON contrats (id_dossier);
ON validations (id_utilisateur, cree_le);
CREATE INDEX IF NOT EXISTS idx_validations_statut -- ===========================================
ON validations (statut); -- JSONB indexes (si filtres fréquents sur planning/planning_souhaite)
-- Exemple dans verify.sql : dossiers.planning_souhaite @> ...
-- ===========================================
CREATE INDEX IF NOT EXISTS idx_dossiers_planning_souhaite_gin
ON dossiers USING gin (planning_souhaite jsonb_path_ops);
CREATE INDEX IF NOT EXISTS idx_contrats_planning_gin
ON contrats USING gin (planning jsonb_path_ops);
-- ===========================================
-- Sanity check : validation des emails uniques
-- Déjà couvert par UNIQUE dans la table utilisateurs
-- ===========================================
-- ===========================================
-- Bonus : accélérer les jointures fréquentes
-- (utilisateurs.id, enfants.id, parents.id_utilisateur sont PK → déjà indexées automatiquement)
-- ===========================================

View File

@ -1,140 +1,74 @@
-- ============================================= -- ============================================================
-- 03_checks.sql : Contraintes CHECK & NOT NULL -- 03_checks.sql — Contraintes d'intégrité métier
-- A exécuter après 01_init.sql (et 02_indexes.sql) -- ============================================================
-- =============================================
-- ============== -- ===========================================
-- UTILISATEURS -- UTILISATEURS
-- ============== -- ===========================================
-- (Regex email déjà présente dans 01_init.sql)
-- Optionnel : forcer prenom/nom non vides si fournis -- Email déjà couvert par UNIQUE + regex dans le schéma
-- Vérifier que mobile et téléphone fixe ne sont pas identiques
ALTER TABLE utilisateurs ALTER TABLE utilisateurs
ADD CONSTRAINT chk_utilisateurs_prenom_non_vide ADD CONSTRAINT chk_telephone_diff CHECK (
CHECK (prenom IS NULL OR btrim(prenom) <> ''), mobile IS NULL OR telephone_fixe IS NULL OR mobile <> telephone_fixe
ADD CONSTRAINT chk_utilisateurs_nom_non_vide
CHECK (nom IS NULL OR btrim(nom) <> '');
-- =========================
-- ASSISTANTES_MATERNELLES
-- =========================
-- NIR : aujourdhui en 15 chiffres (Sprint 2 : chiffrement)
ALTER TABLE assistantes_maternelles
ADD CONSTRAINT chk_am_nir_format
CHECK (nir_chiffre IS NULL OR nir_chiffre ~ '^[0-9]{15}$'),
ADD CONSTRAINT chk_am_nb_max_enfants
CHECK (nb_max_enfants IS NULL OR nb_max_enfants BETWEEN 0 AND 10),
ADD CONSTRAINT chk_am_ville_non_vide
CHECK (ville_residence IS NULL OR btrim(ville_residence) <> '');
-- =========
-- PARENTS
-- =========
-- Interdiction dêtre co-parent de soi-même
ALTER TABLE parents
ADD CONSTRAINT chk_parents_co_parent_diff
CHECK (id_co_parent IS NULL OR id_co_parent <> id_utilisateur);
-- =========
-- ENFANTS
-- =========
-- Cohérence statut / dates de naissance
ALTER TABLE enfants
ADD CONSTRAINT chk_enfants_dates_exclusives
CHECK (NOT (date_naissance IS NOT NULL AND date_prevue_naissance IS NOT NULL)),
ADD CONSTRAINT chk_enfants_statut_dates
CHECK (
-- a_naitre => date_prevue_naissance requise
(statut = 'a_naitre' AND date_prevue_naissance IS NOT NULL)
OR
-- actif/scolarise => date_naissance requise
(statut IN ('actif','scolarise') AND date_naissance IS NOT NULL)
OR statut IS NULL -- si statut non encore fixé
),
ADD CONSTRAINT chk_enfants_consentement_coherent
CHECK (
(consentement_photo = true AND date_consentement_photo IS NOT NULL)
OR
(consentement_photo = false AND date_consentement_photo IS NULL)
); );
-- ================= -- ===========================================
-- ENFANTS_PARENTS -- ENFANTS
-- ================= -- ===========================================
-- (PK composite déjà en place, rien à ajouter ici)
-- ======== -- Si lenfant est "a_naitre", la date_prevue_naissance doit être renseignée
ALTER TABLE enfants
ADD CONSTRAINT chk_enfant_date_prevue
CHECK (
(statut = 'a_naitre' AND date_prevue_naissance IS NOT NULL)
OR (statut <> 'a_naitre')
);
-- Si lenfant est déjà né, sa date_naissance doit être renseignée
ALTER TABLE enfants
ADD CONSTRAINT chk_enfant_date_naissance
CHECK (
(statut IN ('actif','scolarise') AND date_naissance IS NOT NULL)
OR (statut = 'a_naitre')
);
-- ===========================================
-- DOSSIERS -- DOSSIERS
-- ======== -- ===========================================
-- Budget positif si renseigné
ALTER TABLE dossiers ALTER TABLE dossiers
ADD CONSTRAINT chk_dossiers_budget_nonneg ADD CONSTRAINT chk_dossier_budget_pos CHECK (budget IS NULL OR budget > 0);
CHECK (budget IS NULL OR budget >= 0),
ADD CONSTRAINT chk_dossiers_type_contrat_non_vide
CHECK (type_contrat IS NULL OR btrim(type_contrat) <> ''),
ADD CONSTRAINT chk_dossiers_planning_json
CHECK (planning_souhaite IS NULL OR jsonb_typeof(planning_souhaite) = 'object');
-- ======== -- ===========================================
-- MESSAGES
-- ========
-- Contenu obligatoire, non vide
ALTER TABLE messages
ALTER COLUMN contenu SET NOT NULL;
ALTER TABLE messages
ADD CONSTRAINT chk_messages_contenu_non_vide
CHECK (btrim(contenu) <> '');
-- =========
-- CONTRATS -- CONTRATS
-- ========= -- ===========================================
-- Cohérence des dates : date_debut obligatoire pour un contrat signé
ALTER TABLE contrats ALTER TABLE contrats
ADD CONSTRAINT chk_contrats_tarif_nonneg ADD CONSTRAINT chk_contrat_date_debut
CHECK (tarif_horaire IS NULL OR tarif_horaire >= 0), CHECK (
ADD CONSTRAINT chk_contrats_indemnites_nonneg (statut = 'brouillon' OR date_debut IS NOT NULL)
CHECK (indemnites_repas IS NULL OR indemnites_repas >= 0); );
-- ================== -- ===========================================
-- AVENANTS_CONTRATS
-- ==================
-- Rien de spécifique (statut enum déjà en place)
-- =========
-- EVENEMENTS -- EVENEMENTS
-- ========= -- ===========================================
-- Cohérence des dates : début < fin
ALTER TABLE evenements ALTER TABLE evenements
ADD CONSTRAINT chk_evenements_dates_coherentes ADD CONSTRAINT chk_evenement_dates
CHECK (date_fin IS NULL OR date_debut IS NULL OR date_fin >= date_debut); CHECK (date_fin IS NULL OR date_debut <= date_fin);
-- ================= -- ===========================================
-- SIGNALEMENTS_BUGS
-- =================
-- Description obligatoire, non vide
ALTER TABLE signalements_bugs
ALTER COLUMN description SET NOT NULL;
ALTER TABLE signalements_bugs
ADD CONSTRAINT chk_bugs_description_non_vide
CHECK (btrim(description) <> '');
-- =======
-- UPLOADS
-- =======
-- URL obligatoire + format basique (chemin absolu ou http(s))
ALTER TABLE uploads
ALTER COLUMN fichier_url SET NOT NULL;
ALTER TABLE uploads
ADD CONSTRAINT chk_uploads_url_format
CHECK (fichier_url ~ '^(https?://.+|/[^\\s]+)$');
-- =============
-- NOTIFICATIONS
-- =============
-- Contenu obligatoire, non vide
ALTER TABLE notifications
ALTER COLUMN contenu SET NOT NULL;
ALTER TABLE notifications
ADD CONSTRAINT chk_notifications_contenu_non_vide
CHECK (btrim(contenu) <> '');
-- ===========
-- VALIDATIONS -- VALIDATIONS
-- =========== -- ===========================================
-- Rien de plus ici (Sprint 1 Ticket 8 enrichira la table)
-- Si statut = 'valide', alors modifie_le doit être >= cree_le
ALTER TABLE validations
ADD CONSTRAINT chk_validation_modif
CHECK (
(statut <> 'valide')
OR (modifie_le IS NULL OR modifie_le >= cree_le)
);

View File

@ -1,150 +1,103 @@
-- ============================================= -- ============================================================
-- 05_triggers.sql : Timestamps automatiques -- 05_triggers.sql — Triggers métier et maintenance
-- - Ajoute (si absent) cree_le DEFAULT now() et modifie_le DEFAULT now() -- ============================================================
-- - Crée un trigger BEFORE UPDATE pour mettre à jour modifie_le
-- - Idempotent (DROP TRIGGER IF EXISTS / IF NOT EXISTS)
-- A exécuter après 01_init.sql, 02_indexes.sql, 03_checks.sql
-- =============================================
-- 1) Fonction unique de mise à jour du timestamp -- ===========================================
-- 1. Mettre à jour automatiquement modifie_le
-- ===========================================
CREATE OR REPLACE FUNCTION set_modifie_le() CREATE OR REPLACE FUNCTION set_modifie_le()
RETURNS TRIGGER AS $$ RETURNS TRIGGER AS $$
BEGIN BEGIN
NEW.modifie_le := NOW(); NEW.modifie_le := now();
RETURN NEW; RETURN NEW;
END; END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
-- Helper macro-like: pour chaque table, s'assurer des colonnes & trigger -- Appliquer sur les tables qui ont modifie_le
-- (on ne peut pas faire de macro, donc on répète pour chaque table) CREATE TRIGGER trg_update_modifie_le_utilisateurs
-- Liste des tables concernées :
-- utilisateurs, assistantes_maternelles, parents, enfants, enfants_parents,
-- dossiers, messages, contrats, avenants_contrats, evenements,
-- signalements_bugs, uploads, notifications, validations
-- ========== UTILISATEURS
ALTER TABLE utilisateurs
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_utilisateurs_set_modifie_le ON utilisateurs;
CREATE TRIGGER trg_utilisateurs_set_modifie_le
BEFORE UPDATE ON utilisateurs BEFORE UPDATE ON utilisateurs
FOR EACH ROW EXECUTE FUNCTION set_modifie_le(); FOR EACH ROW
EXECUTE FUNCTION set_modifie_le();
-- ========== ASSISTANTES_MATERNELLES CREATE TRIGGER trg_update_modifie_le_dossiers
ALTER TABLE assistantes_maternelles
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_am_set_modifie_le ON assistantes_maternelles;
CREATE TRIGGER trg_am_set_modifie_le
BEFORE UPDATE ON assistantes_maternelles
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== PARENTS
ALTER TABLE parents
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_parents_set_modifie_le ON parents;
CREATE TRIGGER trg_parents_set_modifie_le
BEFORE UPDATE ON parents
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== ENFANTS
ALTER TABLE enfants
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_enfants_set_modifie_le ON enfants;
CREATE TRIGGER trg_enfants_set_modifie_le
BEFORE UPDATE ON enfants
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== ENFANTS_PARENTS (table de liaison)
ALTER TABLE enfants_parents
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_enfants_parents_set_modifie_le ON enfants_parents;
CREATE TRIGGER trg_enfants_parents_set_modifie_le
BEFORE UPDATE ON enfants_parents
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== DOSSIERS
ALTER TABLE dossiers
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_dossiers_set_modifie_le ON dossiers;
CREATE TRIGGER trg_dossiers_set_modifie_le
BEFORE UPDATE ON dossiers BEFORE UPDATE ON dossiers
FOR EACH ROW EXECUTE FUNCTION set_modifie_le(); FOR EACH ROW
EXECUTE FUNCTION set_modifie_le();
-- ========== MESSAGES CREATE TRIGGER trg_update_modifie_le_contrats
ALTER TABLE messages
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_messages_set_modifie_le ON messages;
CREATE TRIGGER trg_messages_set_modifie_le
BEFORE UPDATE ON messages
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== CONTRATS
ALTER TABLE contrats
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_contrats_set_modifie_le ON contrats;
CREATE TRIGGER trg_contrats_set_modifie_le
BEFORE UPDATE ON contrats BEFORE UPDATE ON contrats
FOR EACH ROW EXECUTE FUNCTION set_modifie_le(); FOR EACH ROW
EXECUTE FUNCTION set_modifie_le();
-- ========== AVENANTS_CONTRATS CREATE TRIGGER trg_update_modifie_le_avenants
ALTER TABLE avenants_contrats
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_avenants_contrats_set_modifie_le ON avenants_contrats;
CREATE TRIGGER trg_avenants_contrats_set_modifie_le
BEFORE UPDATE ON avenants_contrats BEFORE UPDATE ON avenants_contrats
FOR EACH ROW EXECUTE FUNCTION set_modifie_le(); FOR EACH ROW
EXECUTE FUNCTION set_modifie_le();
-- ========== EVENEMENTS CREATE TRIGGER trg_update_modifie_le_evenements
ALTER TABLE evenements
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_evenements_set_modifie_le ON evenements;
CREATE TRIGGER trg_evenements_set_modifie_le
BEFORE UPDATE ON evenements BEFORE UPDATE ON evenements
FOR EACH ROW EXECUTE FUNCTION set_modifie_le(); FOR EACH ROW
EXECUTE FUNCTION set_modifie_le();
-- ========== SIGNALEMENTS_BUGS CREATE TRIGGER trg_update_modifie_le_validations
ALTER TABLE signalements_bugs
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_signalements_bugs_set_modifie_le ON signalements_bugs;
CREATE TRIGGER trg_signalements_bugs_set_modifie_le
BEFORE UPDATE ON signalements_bugs
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== UPLOADS
ALTER TABLE uploads
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_uploads_set_modifie_le ON uploads;
CREATE TRIGGER trg_uploads_set_modifie_le
BEFORE UPDATE ON uploads
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== NOTIFICATIONS
ALTER TABLE notifications
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_notifications_set_modifie_le ON notifications;
CREATE TRIGGER trg_notifications_set_modifie_le
BEFORE UPDATE ON notifications
FOR EACH ROW EXECUTE FUNCTION set_modifie_le();
-- ========== VALIDATIONS
ALTER TABLE validations
ADD COLUMN IF NOT EXISTS cree_le TIMESTAMP DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS modifie_le TIMESTAMP DEFAULT NOW();
DROP TRIGGER IF EXISTS trg_validations_set_modifie_le ON validations;
CREATE TRIGGER trg_validations_set_modifie_le
BEFORE UPDATE ON validations BEFORE UPDATE ON validations
FOR EACH ROW EXECUTE FUNCTION set_modifie_le(); FOR EACH ROW
EXECUTE FUNCTION set_modifie_le();
-- ===========================================
-- 2. Empêcher plusieurs contrats actifs par dossier
-- ===========================================
CREATE OR REPLACE FUNCTION prevent_multiple_active_contrats()
RETURNS TRIGGER AS $$
DECLARE
nb_actifs INT;
BEGIN
IF NEW.statut IN ('en_attente_signature','valide') THEN
SELECT COUNT(*) INTO nb_actifs
FROM contrats
WHERE id_dossier = NEW.id_dossier
AND statut IN ('en_attente_signature','valide')
AND id <> COALESCE(NEW.id, gen_random_uuid());
IF nb_actifs > 0 THEN
RAISE EXCEPTION 'Un contrat actif existe déjà pour ce dossier (%).', NEW.id_dossier;
END IF;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_one_active_contrat_per_dossier
BEFORE INSERT OR UPDATE ON contrats
FOR EACH ROW
EXECUTE FUNCTION prevent_multiple_active_contrats();
-- ===========================================
-- 3. Empêcher événements incohérents
-- - Pas de chevauchement de congés pour le même AM
-- ===========================================
CREATE OR REPLACE FUNCTION prevent_overlapping_events()
RETURNS TRIGGER AS $$
DECLARE
nb_overlap INT;
BEGIN
IF NEW.id_am IS NOT NULL AND NEW.date_debut IS NOT NULL AND NEW.date_fin IS NOT NULL THEN
SELECT COUNT(*) INTO nb_overlap
FROM evenements ev
WHERE ev.id_am = NEW.id_am
AND ev.id <> COALESCE(NEW.id, gen_random_uuid())
AND ev.date_fin >= NEW.date_debut
AND ev.date_debut <= NEW.date_fin;
IF nb_overlap > 0 THEN
RAISE EXCEPTION 'Conflit d''événements : chevauchement détecté pour AM %', NEW.id_am;
END IF;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_no_overlapping_am_events
BEFORE INSERT OR UPDATE ON evenements
FOR EACH ROW
EXECUTE FUNCTION prevent_overlapping_events();

59
scripts/clean_csv.py Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
import csv
import sys
from pathlib import Path
def clean_csv_file(file_path: Path):
"""
Nettoie un CSV directement en place :
- remplace "NULL" par ""
- supprime les espaces parasites
- force le même nombre de colonnes que l'en-tête
"""
cleaned_rows = []
with open(file_path, "r", encoding="utf-8-sig", newline="") as infile:
reader = csv.reader(infile)
try:
header = next(reader)
except StopIteration:
print(f"[⚠️] Fichier vide : {file_path}")
return
nb_cols = len(header)
cleaned_rows.append([h.strip() for h in header])
for i, row in enumerate(reader, start=2):
# Ajuste le nombre de colonnes
if len(row) < nb_cols:
row.extend([""] * (nb_cols - len(row)))
elif len(row) > nb_cols:
row = row[:nb_cols]
# Nettoyage cellule par cellule
row = [cell.strip().replace("NULL", "") for cell in row]
cleaned_rows.append(row)
# Réécriture dans le même fichier
with open(file_path, "w", encoding="utf-8", newline="") as outfile:
writer = csv.writer(outfile)
writer.writerows(cleaned_rows)
print(f"[✔] Nettoyé : {file_path}")
def main():
if len(sys.argv) > 1:
base_dir = Path(sys.argv[1])
else:
base_dir = Path("bdd/data_test")
print(f"🔎 Nettoyage des CSV dans : {base_dir}")
for file_path in base_dir.glob("*.csv"):
clean_csv_file(file_path)
print(f"✅ Terminé. Les fichiers CSV ont été écrasés (nettoyés en place).")
if __name__ == "__main__":
main()

64
scripts/verify_data.sql Normal file
View File

@ -0,0 +1,64 @@
-- ==============================================
-- Script de vérification d'intégrité des données
-- ==============================================
-- 1) Vérifier unicité des emails
SELECT email, COUNT(*) AS doublons
FROM utilisateurs
GROUP BY email
HAVING COUNT(*) > 1;
-- 2) Vérifier utilisateurs sans rôle
SELECT id, email
FROM utilisateurs
WHERE role IS NULL OR role = '';
-- 3) Vérifier cohérence enfants → parents
SELECT e.id AS enfant_id, e.nom, e.prenom
FROM enfants e
LEFT JOIN enfants_parents ep ON e.id = ep.enfant_id
WHERE ep.parent_id IS NULL;
-- 4) Vérifier cohérence enfants_parents → parents existants
SELECT ep.enfant_id, ep.parent_id
FROM enfants_parents ep
LEFT JOIN parents p ON ep.parent_id = p.id
WHERE p.id IS NULL;
-- 5) Vérifier cohérence dossiers → utilisateurs
SELECT d.id, d.parent_id
FROM dossiers d
LEFT JOIN parents p ON d.parent_id = p.id
WHERE p.id IS NULL;
-- 6) Vérifier cohérence contrats → utilisateurs et assistantes
SELECT c.id, c.parent_id, c.assistante_id
FROM contrats c
LEFT JOIN parents p ON c.parent_id = p.id
LEFT JOIN assistantes_maternelles am ON c.assistante_id = am.id
WHERE p.id IS NULL OR am.id IS NULL;
-- 7) Vérifier cohérence validations → utilisateurs
SELECT v.id, v.valide_par
FROM validations v
LEFT JOIN utilisateurs u ON v.valide_par = u.id
WHERE u.id IS NULL;
-- 8) Vérifier cohérence dates enfants
SELECT id, nom, prenom, date_naissance
FROM enfants
WHERE date_naissance > CURRENT_DATE;
-- 9) Vérifier cohérence date agrément assistantes
SELECT id, nom, prenom, date_agrement
FROM assistantes_maternelles
WHERE date_agrement > CURRENT_DATE;
-- 10) Vérifier NULL obligatoires (ex: NIR des assistantes)
SELECT id, nom, prenom
FROM assistantes_maternelles
WHERE nir IS NULL OR nir = '';
-- ==============================================
-- Fin du script
-- ==============================================

View File

@ -1,221 +0,0 @@
-- ============================================================
-- 02_seed.sql : Données de test réalistes (Sprint 1)
-- A exécuter après :
-- 01_init.sql (création des tables)
-- 02_indexes.sql
-- 03_checks.sql
-- 04_fk_policies.sql
-- 05_triggers.sql
-- ============================================================
BEGIN;
-- ------------------------------------------------------------
-- Utilisateurs (super_admin, gestionnaire, 2 parents + co-parent, 1 AM)
-- ------------------------------------------------------------
-- UUIDs fixes pour faciliter les tests / jointures
-- super_admin
INSERT INTO utilisateurs (id, courriel, mot_de_passe_hash, prenom, nom, role, statut)
VALUES ('11111111-1111-1111-1111-111111111111', 'admin@ptits-pas.fr', '$2y$10$hashAdminIci', 'Super', 'Admin', 'super_admin', 'accepte')
ON CONFLICT (id) DO NOTHING;
-- gestionnaire
INSERT INTO utilisateurs (id, courriel, mot_de_passe_hash, prenom, nom, role, statut)
VALUES ('22222222-2222-2222-2222-222222222222', 'gestion@ptits-pas.fr', '$2y$10$hashGestionIci', 'Gina', 'Gestion', 'gestionnaire', 'accepte')
ON CONFLICT (id) DO NOTHING;
-- parent #1
INSERT INTO utilisateurs (id, courriel, mot_de_passe_hash, prenom, nom, role, statut)
VALUES ('33333333-3333-3333-3333-333333333333', 'parent1@example.com', '$2y$10$hashParent1', 'Paul', 'Parent', 'parent', 'accepte')
ON CONFLICT (id) DO NOTHING;
-- co-parent du parent #1
INSERT INTO utilisateurs (id, courriel, mot_de_passe_hash, prenom, nom, role, statut)
VALUES ('44444444-4444-4444-4444-444444444444', 'coparent1@example.com', '$2y$10$hashCoParent1', 'Clara', 'CoParent', 'parent', 'accepte')
ON CONFLICT (id) DO NOTHING;
-- parent #2
INSERT INTO utilisateurs (id, courriel, mot_de_passe_hash, prenom, nom, role, statut)
VALUES ('55555555-5555-5555-5555-555555555555', 'parent2@example.com', '$2y$10$hashParent2', 'Nora', 'Parent', 'parent', 'accepte')
ON CONFLICT (id) DO NOTHING;
-- assistante maternelle #1
INSERT INTO utilisateurs (id, courriel, mot_de_passe_hash, prenom, nom, role, statut)
VALUES ('66666666-6666-6666-6666-666666666666', 'am1@example.com', '$2y$10$hashAM1', 'Alice', 'AM', 'am', 'accepte')
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Extensions de rôles (parents / AM)
-- ------------------------------------------------------------
-- parents (id_co_parent nullable)
INSERT INTO parents (id_utilisateur, id_co_parent)
VALUES ('33333333-3333-3333-3333-333333333333', '44444444-4444-4444-4444-444444444444') -- parent1 avec co-parent
ON CONFLICT (id_utilisateur) DO NOTHING;
INSERT INTO parents (id_utilisateur, id_co_parent)
VALUES ('55555555-5555-5555-5555-555555555555', NULL) -- parent2 sans co-parent
ON CONFLICT (id_utilisateur) DO NOTHING;
-- assistantes_maternelles
INSERT INTO assistantes_maternelles (id_utilisateur, numero_agrement, nb_max_enfants, disponible, ville_residence)
VALUES ('66666666-6666-6666-6666-666666666666', 'AGR-2025-0001', 3, true, 'Lille')
ON CONFLICT (id_utilisateur) DO NOTHING;
-- ------------------------------------------------------------
-- Enfants
-- - child A : déjà né (statut = 'actif' et date_naissance requise)
-- - child B : à naître (statut = 'a_naitre' et date_prevue_naissance requise)
-- ------------------------------------------------------------
INSERT INTO enfants (id, prenom, nom, statut, date_naissance, jumeau_multiple)
VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'Léo', 'Parent', 'actif', '2022-04-12', false)
ON CONFLICT (id) DO NOTHING;
INSERT INTO enfants (id, prenom, nom, statut, date_prevue_naissance, jumeau_multiple)
VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 'Mila', 'Parent', 'a_naitre', '2026-02-15', false)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Liaison N:N parents_enfants
-- - parent1 + co-parent ↔ enfant A & B
-- - parent2 ↔ enfant B
-- ------------------------------------------------------------
-- parent1 ↔ enfant A
INSERT INTO enfants_parents (id_parent, id_enfant)
VALUES ('33333333-3333-3333-3333-333333333333', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')
ON CONFLICT DO NOTHING;
-- co-parent1 ↔ enfant A
INSERT INTO enfants_parents (id_parent, id_enfant)
VALUES ('44444444-4444-4444-4444-444444444444', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')
ON CONFLICT DO NOTHING;
-- parent1 ↔ enfant B
INSERT INTO enfants_parents (id_parent, id_enfant)
VALUES ('33333333-3333-3333-3333-333333333333', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb')
ON CONFLICT DO NOTHING;
-- parent2 ↔ enfant B
INSERT INTO enfants_parents (id_parent, id_enfant)
VALUES ('55555555-5555-5555-5555-555555555555', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb')
ON CONFLICT DO NOTHING;
-- ------------------------------------------------------------
-- Dossier (parent1 ↔ enfant A)
-- ------------------------------------------------------------
INSERT INTO dossiers (id, id_parent, id_enfant, presentation, type_contrat, repas, budget, planning_souhaite)
VALUES (
'dddddddd-dddd-dddd-dddd-dddddddddddd',
'33333333-3333-3333-3333-333333333333',
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
'Besoin garde périscolaire lundi/mardi/jeudi/vendredi.',
'mensuel',
true,
600.00,
'{"lun_ven":{"matin":false,"midi":true,"soir":true}}'::jsonb
)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Messages (sur le dossier)
-- ------------------------------------------------------------
INSERT INTO messages (id, id_dossier, id_expediteur, contenu)
VALUES ('m0000000-0000-0000-0000-000000000001', 'dddddddd-dddd-dddd-dddd-dddddddddddd', '33333333-3333-3333-3333-333333333333', 'Bonjour, nous cherchons une garde périscolaire.')
ON CONFLICT (id) DO NOTHING;
INSERT INTO messages (id, id_dossier, id_expediteur, contenu)
VALUES ('m0000000-0000-0000-0000-000000000002', 'dddddddd-dddd-dddd-dddd-dddddddddddd', '66666666-6666-6666-6666-666666666666', 'Bonjour, je suis disponible les soirs. Discutons du contrat.')
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Contrat (1:1 avec le dossier)
-- ------------------------------------------------------------
INSERT INTO contrats (id, id_dossier, planning, tarif_horaire, indemnites_repas, date_debut, statut, signe_parent, signe_am)
VALUES (
'cccccccc-cccc-cccc-cccc-cccccccccccc',
'dddddddd-dddd-dddd-dddd-dddddddddddd',
'{"lun_ven":{"17h-19h":true}}'::jsonb,
12.50,
3.50,
'2025-09-01',
'brouillon',
false,
false
)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Avenant de contrat
-- ------------------------------------------------------------
INSERT INTO avenants_contrats (id, id_contrat, modifications, initie_par, statut)
VALUES (
'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
'cccccccc-cccc-cccc-cccc-cccccccccccc',
'{"changement_horaire":{"vendredi":{"17h-20h":true}}}'::jsonb,
'33333333-3333-3333-3333-333333333333',
'propose'
)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Événement (absence enfant)
-- ------------------------------------------------------------
INSERT INTO evenements (id, type, id_enfant, id_am, id_parent, cree_par, date_debut, date_fin, commentaires, statut, urgence)
VALUES (
'e0000000-0000-0000-0000-000000000001',
'absence_enfant',
'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
'66666666-6666-6666-6666-666666666666',
'33333333-3333-3333-3333-333333333333',
'33333333-3333-3333-3333-333333333333',
'2025-09-12',
'2025-09-12',
'Enfant malade (rhume).',
'propose',
false
)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Upload (justificatif lié au dossier)
-- ------------------------------------------------------------
INSERT INTO uploads (id, id_utilisateur, id_dossier_lie, fichier_url, type_fichier)
VALUES (
'u0000000-0000-0000-0000-000000000001',
'33333333-3333-3333-3333-333333333333',
'dddddddd-dddd-dddd-dddd-dddddddddddd',
'/uploads/justificatifs/dossier_dddddddd_attestation.pdf',
'application/pdf'
)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Notification (pour le parent1)
-- ------------------------------------------------------------
INSERT INTO notifications (id, id_utilisateur, type, contenu, lu)
VALUES (
'n0000000-0000-0000-0000-000000000001',
'33333333-3333-3333-3333-333333333333',
'nouveau_message',
'Vous avez un nouveau message sur le dossier #dddd…',
false
)
ON CONFLICT (id) DO NOTHING;
-- ------------------------------------------------------------
-- Validation (compte de lAM validé par le gestionnaire)
-- ------------------------------------------------------------
INSERT INTO validations (id, id_utilisateur, statut, commentaire, cree_le)
VALUES (
'v0000000-0000-0000-0000-000000000001',
'66666666-6666-6666-6666-666666666666',
'accepte',
'Dossier AM vérifié par gestionnaire.',
NOW()
)
ON CONFLICT (id) DO NOTHING;
COMMIT;

View File

@ -1,23 +1,5 @@
-- ============================================================ -- ============================================================
-- verify.sql — Jeux de requêtes de vérification (Sprint 1) -- verify.sql — Jeux de requêtes de vérification (Sprint 1)
-- Objectifs :
-- 1) Vérifier l'intégrité fonctionnelle (joins, données seedées)
-- 2) Détecter rapidement des problèmes d'index/perf (EXPLAIN)
-- 3) Servir de référence pour le back/front (requêtes typiques)
--
-- Usage (Docker) :
-- docker compose exec -T postgres \
-- psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} \
-- -f /docker-entrypoint-initdb.d/tests/verify.sql
--
-- Pré-requis :
-- - 01_init.sql
-- - 02_indexes.sql
-- - 03_checks.sql
-- - 04_fk_policies.sql
-- - 05_triggers.sql
-- - 02_seed.sql (pour résultats non vides)
-- ============================================================ -- ============================================================
\echo '=== 0) Version & horodatage ====================================' \echo '=== 0) Version & horodatage ===================================='
@ -38,9 +20,9 @@ ORDER BY nb DESC;
\echo '=== 3) Parents avec co-parents (NULL si pas de co-parent) ======' \echo '=== 3) Parents avec co-parents (NULL si pas de co-parent) ======'
SELECT p.id_utilisateur AS parent_id, SELECT p.id_utilisateur AS parent_id,
u.courriel AS parent_email, u.email AS parent_email,
p.id_co_parent, p.id_co_parent,
uc.courriel AS co_parent_email uc.email AS co_parent_email
FROM parents p FROM parents p
JOIN utilisateurs u ON u.id = p.id_utilisateur JOIN utilisateurs u ON u.id = p.id_utilisateur
LEFT JOIN utilisateurs uc ON uc.id = p.id_co_parent LEFT JOIN utilisateurs uc ON uc.id = p.id_co_parent
@ -52,21 +34,21 @@ FROM enfants
ORDER BY nom, prenom; ORDER BY nom, prenom;
\echo '=== 5) Liaison N:N parents_enfants =============================' \echo '=== 5) Liaison N:N parents_enfants ============================='
SELECT ep.id_parent, up.courriel AS parent_email, ep.id_enfant, e.prenom AS enfant SELECT ep.id_parent, up.email AS parent_email, ep.id_enfant, e.prenom AS enfant
FROM enfants_parents ep FROM enfants_parents ep
JOIN utilisateurs up ON up.id = ep.id_parent JOIN utilisateurs up ON up.id = ep.id_parent
JOIN enfants e ON e.id = ep.id_enfant JOIN enfants e ON e.id = ep.id_enfant
ORDER BY parent_email, enfant; ORDER BY parent_email, enfant;
\echo '=== 6) Dossiers (parent, enfant, statut) =======================' \echo '=== 6) Dossiers (parent, enfant, statut) ======================='
SELECT d.id, up.courriel AS parent_email, e.prenom AS enfant, d.statut, d.budget SELECT d.id, up.email AS parent_email, e.prenom AS enfant, d.statut, d.budget
FROM dossiers d FROM dossiers d
JOIN utilisateurs up ON up.id = d.id_parent JOIN utilisateurs up ON up.id = d.id_parent
JOIN enfants e ON e.id = d.id_enfant JOIN enfants e ON e.id = d.id_enfant
ORDER BY d.cree_le DESC; ORDER BY d.cree_le DESC;
\echo '=== 7) Messages par dossier (ordre chronologique) ==============' \echo '=== 7) Messages par dossier (ordre chronologique) =============='
SELECT m.id, m.id_dossier, m.id_expediteur, ue.courriel AS expediteur_email, m.contenu, m.cree_le SELECT m.id, m.id_dossier, m.id_expediteur, ue.email AS expediteur_email, m.contenu, m.cree_le
FROM messages m FROM messages m
LEFT JOIN utilisateurs ue ON ue.id = m.id_expediteur LEFT JOIN utilisateurs ue ON ue.id = m.id_expediteur
ORDER BY m.id_dossier, m.cree_le; ORDER BY m.id_dossier, m.cree_le;
@ -87,22 +69,20 @@ WHERE ev.date_debut >= (NOW()::date - INTERVAL '30 days')
ORDER BY ev.date_debut DESC; ORDER BY ev.date_debut DESC;
\echo '=== 10) Uploads & notifications récentes =======================' \echo '=== 10) Uploads & notifications récentes ======================='
SELECT u.courriel, up.fichier_url, up.type_fichier, up.cree_le SELECT u.email, up.fichier_url, up.type AS fichier_type, up.cree_le
FROM uploads up FROM uploads up
LEFT JOIN utilisateurs u ON u.id = up.id_utilisateur LEFT JOIN utilisateurs u ON u.id = up.id_utilisateur
ORDER BY up.cree_le DESC; ORDER BY up.cree_le DESC;
SELECT u.courriel, n.type, n.contenu, n.lu, n.cree_le SELECT u.email, n.contenu, n.lu, n.cree_le
FROM notifications n FROM notifications n
LEFT JOIN utilisateurs u ON u.id = n.id_utilisateur LEFT JOIN utilisateurs u ON u.id = n.id_utilisateur
ORDER BY n.cree_le DESC; ORDER BY n.cree_le DESC;
\echo '=== 11) Validations (qui a validé quoi) ========================' \echo '=== 11) Validations (qui a validé quoi) ========================'
SELECT v.id, uu.courriel AS utilisateur_valide, SELECT v.id, u.email AS utilisateur_email, v.type, v.statut, v.cree_le
uv.courriel AS valide_par, v.statut, v.commentaire, v.cree_le
FROM validations v FROM validations v
LEFT JOIN utilisateurs uu ON uu.id = v.id_utilisateur LEFT JOIN utilisateurs u ON u.id = v.id_utilisateur
LEFT JOIN utilisateurs uv ON uv.id = v.valide_par
ORDER BY v.cree_le DESC; ORDER BY v.cree_le DESC;
-- ============================================================ -- ============================================================
@ -176,19 +156,15 @@ WHERE d.id_parent = '33333333-3333-3333-3333-333333333333'
ORDER BY d.cree_le DESC; ORDER BY d.cree_le DESC;
\echo '=== 14) JSONB : exemples de filtrage ===========================' \echo '=== 14) JSONB : exemples de filtrage ==========================='
-- Recherche de dossiers où planning_souhaite contient midi=true un jour ouvré
-- (Index GIN recommandé si usage intensif : cf. 02_indexes.sql)
SELECT d.id, d.planning_souhaite SELECT d.id, d.planning_souhaite
FROM dossiers d FROM dossiers d
WHERE d.planning_souhaite @> '{"lun_ven":{"midi":true}}'; WHERE d.planning_souhaite @> '{"lun_ven":{"midi":true}}';
-- Contrats : présence dun créneau donné
SELECT c.id, c.planning SELECT c.id, c.planning
FROM contrats c FROM contrats c
WHERE c.planning @> '{"lun_ven":{"17h-19h":true}}'; WHERE c.planning @> '{"lun_ven":{"17h-19h":true}}';
\echo '=== 15) Sanity check final ====================================' \echo '=== 15) Sanity check final ===================================='
-- Quelques totaux utiles
SELECT SELECT
(SELECT COUNT(*) FROM utilisateurs) AS nb_utilisateurs, (SELECT COUNT(*) FROM utilisateurs) AS nb_utilisateurs,
(SELECT COUNT(*) FROM parents) AS nb_parents, (SELECT COUNT(*) FROM parents) AS nb_parents,

188
verify.log Normal file
View File

@ -0,0 +1,188 @@
=== 0) Version & horodatage ====================================
version
--------------------------------------------------------------------------------------------------------------------
PostgreSQL 17.6 (Debian 17.6-1.pgdg13+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
(1 row)
executed_at
-------------------------------
2025-09-19 08:16:02.305781+00
(1 row)
=== 1) Comptes & répartition par rôle ==========================
role | nb
-----------------------+----
parent | 6
assistante_maternelle | 3
administrateur | 1
gestionnaire | 1
super_admin | 1
(5 rows)
=== 2) Utilisateurs en attente / acceptés / rejetés ============
statut | nb
--------+----
actif | 12
(1 row)
=== 3) Parents avec co-parents (NULL si pas de co-parent) ======
parent_id | parent_email | id_co_parent | co_parent_email
--------------------------------------+------------------------------+--------------------------------------+------------------------------
f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b | amelie.durand@ptits-pas.fr | b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e | julien.rousseau@ptits-pas.fr
c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f | claire.martin@ptits-pas.fr | |
d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a | david.lecomte@ptits-pas.fr | |
b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e | julien.rousseau@ptits-pas.fr | f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b | amelie.durand@ptits-pas.fr
(4 rows)
=== 4) Enfants (statut, dates cohérentes) ======================
id | prenom | nom | statut | date_naissance | date_prevue_naissance
--------------------------------------+--------+----------+-----------+----------------+-----------------------
5e8574b7-63e6-4d48-9af3-8d3bf7a6a6cf | Emma | Dupont | actif | 2020-06-01 |
edd19cd1-bb67-4f14-8a37-c66b75c94537 | Lucas | Durand | scolarise | 2018-09-15 |
e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b | Maxime | Lecomte | actif | 2023-04-15 |
e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c | Emma | Martin | actif | 2023-02-15 |
e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e | Léa | Martin | actif | 2023-02-15 |
e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d | Noah | Martin | actif | 2023-02-15 |
e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f | Chloé | Rousseau | actif | 2022-04-20 |
e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a | Hugo | Rousseau | actif | 2024-03-10 |
a5c3268e-07eb-41a4-9f6c-2f9f16f37c3d | | | actif | 2020-01-01 | 2025-01-01
(9 rows)
=== 5) Liaison N:N parents_enfants =============================
id_parent | parent_email | id_enfant | enfant
--------------------------------------+------------------------------+--------------------------------------+--------
f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b | amelie.durand@ptits-pas.fr | e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f | Chloé
f1d3c5b7-8a9e-4f2d-9c1b-3e7a5d8c2f1b | amelie.durand@ptits-pas.fr | e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a | Hugo
c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f | claire.martin@ptits-pas.fr | e1a2b3c4-d5e6-4f7a-8b9c-1d2e3f4a5b6c | Emma
c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f | claire.martin@ptits-pas.fr | e3c4d5e6-f7a8-4b9c-1d2e-3f4a5b6c7d8e | Léa
c4e2d1f5-6b7a-4c3d-8f2a-1e9c3b5a7d6f | claire.martin@ptits-pas.fr | e2b3c4d5-e6f7-4a8b-9c1d-2e3f4a5b6c7d | Noah
d3e5f7a9-1c2b-4d6e-8f3a-2b4c6d8e9f1a | david.lecomte@ptits-pas.fr | e6f7a8b9-c1d2-4e3f-5a6b-7c8d9e0f1a2b | Maxime
b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e | julien.rousseau@ptits-pas.fr | e4d5e6f7-a8b9-4c1d-2e3f-4a5b6c7d8e9f | Chloé
b6c4d2e3-5f7a-4b8c-9d1e-2a3c5f7b8d9e | julien.rousseau@ptits-pas.fr | e5e6f7a8-b9c1-4d2e-3f4a-5b6c7d8e9f1a | Hugo
(8 rows)
=== 6) Dossiers (parent, enfant, statut) =======================
id | parent_email | enfant | statut | budget
--------------------------------------+----------------------------+--------+--------+---------
bb9c30a0-60b4-4832-9947-8a7d2366673d | amelie.durand@ptits-pas.fr | Emma | envoye | 1200.00
(1 row)
=== 7) Messages par dossier (ordre chronologique) ==============
id | id_dossier | id_expediteur | expediteur_email | contenu | cree_le
----+------------+---------------+------------------+---------+---------
(0 rows)
=== 8) Contrats 1:1 avec dossier + avenants ====================
contrat_id | id_dossier | statut | nb_avenants
--------------------------------------+--------------------------------------+-----------+-------------
f09c6ffa-4627-4aa8-b20b-829c2c828f0d | bb9c30a0-60b4-4832-9947-8a7d2366673d | brouillon | 0
(1 row)
=== 9) Evénements par enfant (30 derniers jours) ==============
id | type | id_enfant | enfant | date_debut | date_fin | statut
----+------+-----------+--------+------------+----------+--------
(0 rows)
=== 10) Uploads & notifications récentes =======================
email | fichier_url | fichier_type | cree_le
---------------------+--------------------------------+--------------+-------------------------------
parent1@example.com | https://placeholder.local/file | image | 2025-09-02 12:57:35.140078+00
(1 row)
email | contenu | lu | cree_le
---------------------+-----------------------------+----+-------------------------------
parent1@example.com | Votre dossier a été accepté | f | 2025-09-02 12:57:42.845264+00
(1 row)
=== 11) Validations (qui a validé quoi) ========================
id | utilisateur_email | type | statut | cree_le
--------------------------------------+---------------------------+----------+--------+-------------------------------
fcc45701-5708-4368-b467-b95ddb7e1580 | marie.dubois@ptits-pas.fr | | valide | 2025-09-09 14:52:47.339858+00
be1c4779-341b-436d-b17e-8bc486d22ef8 | am1@example.com | | valide | 2025-09-09 14:47:01.963573+00
8ec99565-e8c2-469f-9641-01b99b8281eb | am1@example.com | identité | valide | 2025-09-02 12:57:49.846424+00
(3 rows)
=== 12) Orphelins potentiels (doivent renvoyer 0 ligne) =======
id | id_dossier | id_expediteur | contenu | re_redige_par_ia | cree_le
----+------------+---------------+---------+------------------+---------
(0 rows)
id_parent | id_enfant
-----------+-----------
(0 rows)
id | id_dossier | planning | tarif_horaire | indemnites_repas | date_debut | statut | signe_parent | signe_am | finalise_le | cree_le | modifie_le
----+------------+----------+---------------+------------------+------------+--------+--------------+----------+-------------+---------+------------
(0 rows)
id | id_contrat | modifications | initie_par | statut | cree_le | modifie_le
----+------------+---------------+------------+--------+---------+------------
(0 rows)
id | type | id_enfant | id_am | id_parent | cree_par | date_debut | date_fin | commentaires | statut | delai_grace | urgent | cree_le | modifie_le
----+------+-----------+-------+-----------+----------+------------+----------+--------------+--------+-------------+--------+---------+------------
(0 rows)
=== 13) Performance : EXPLAIN sur requêtes clés ===============
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=11.31..11.31 rows=3 width=89) (actual time=0.027..0.029 rows=0 loops=1)
-> Sort (cost=11.31..11.31 rows=3 width=89) (actual time=0.026..0.027 rows=0 loops=1)
Sort Key: cree_le DESC
Sort Method: quicksort Memory: 25kB
-> Bitmap Heap Scan on messages m (cost=4.17..11.28 rows=3 width=89) (actual time=0.021..0.021 rows=0 loops=1)
Recheck Cond: (id_dossier = 'dddddddd-dddd-dddd-dddd-dddddddddddd'::uuid)
-> Bitmap Index Scan on idx_messages_id_dossier_cree_le (cost=0.00..4.17 rows=3 width=0) (actual time=0.011..0.011 rows=0 loops=1)
Index Cond: (id_dossier = 'dddddddd-dddd-dddd-dddd-dddddddddddd'::uuid)
Planning Time: 0.837 ms
Execution Time: 0.079 ms
(10 rows)
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using idx_evenements_id_enfant_date_debut on evenements ev (cost=0.15..8.17 rows=1 width=161) (actual time=0.006..0.007 rows=0 loops=1)
Index Cond: ((id_enfant = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'::uuid) AND (date_debut >= '2025-01-01 00:00:00+00'::timestamp with time zone))
Planning Time: 0.107 ms
Execution Time: 0.099 ms
(4 rows)
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=9.52..9.53 rows=2 width=73) (actual time=0.020..0.021 rows=0 loops=1)
-> Sort (cost=9.52..9.53 rows=2 width=73) (actual time=0.019..0.020 rows=0 loops=1)
Sort Key: cree_le DESC
Sort Method: quicksort Memory: 25kB
-> Bitmap Heap Scan on notifications n (cost=4.17..9.51 rows=2 width=73) (actual time=0.014..0.014 rows=0 loops=1)
Recheck Cond: ((id_utilisateur = '33333333-3333-3333-3333-333333333333'::uuid) AND (NOT lu))
-> Bitmap Index Scan on idx_notifications_user_lu_cree_le (cost=0.00..4.17 rows=2 width=0) (actual time=0.008..0.008 rows=0 loops=1)
Index Cond: ((id_utilisateur = '33333333-3333-3333-3333-333333333333'::uuid) AND (lu = false))
Planning Time: 0.122 ms
Execution Time: 0.043 ms
(10 rows)
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Sort (cost=8.18..8.18 rows=1 width=267) (actual time=0.429..0.431 rows=0 loops=1)
Sort Key: cree_le DESC
Sort Method: quicksort Memory: 25kB
-> Index Scan using idx_dossiers_id_parent_enfant_statut_cree_le on dossiers d (cost=0.15..8.17 rows=1 width=267) (actual time=0.419..0.419 rows=0 loops=1)
Index Cond: ((id_parent = '33333333-3333-3333-3333-333333333333'::uuid) AND (id_enfant = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'::uuid))
Planning Time: 1.115 ms
Execution Time: 0.476 ms
(7 rows)
=== 14) JSONB : exemples de filtrage ===========================
id | planning_souhaite
----+-------------------
(0 rows)
id | planning
----+----------
(0 rows)
=== 15) Sanity check final ====================================
nb_utilisateurs | nb_parents | nb_am | nb_enfants | nb_liens_parent_enfant | nb_dossiers | nb_messages | nb_contrats | nb_avenants | nb_evenements | nb_uploads | nb_notifications | nb_validations
-----------------+------------+-------+------------+------------------------+-------------+-------------+-------------+-------------+---------------+------------+------------------+----------------
12 | 4 | 2 | 9 | 8 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 3
(1 row)