ajout de script / modif d'enum et simplification du lancement en local
This commit is contained in:
parent
4d402bb7cc
commit
80f24dce5a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
.env
|
.env
|
||||||
|
PtitsPas_CDC.pdf
|
||||||
@ -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/`.
|
||||||
|
|||||||
@ -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,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,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,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,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,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,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,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,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,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,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
|
||||||
|
|||||||
|
@ -14,10 +14,20 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5433:5432"
|
- "5433:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- ./migrations/01_init.sql:/docker-entrypoint-initdb.d/01_init.sql
|
# Scripts de migration (ordre important → init, indexes, checks, triggers, import…)
|
||||||
- ./migrations/07_import.sql:/docker-entrypoint-initdb.d/07_import.sql
|
- ./migrations/01_init.sql:/docker-entrypoint-initdb.d/01_init.sql
|
||||||
- ./bdd/data_test:/bdd/data_test
|
- ./migrations/02_indexes.sql:/docker-entrypoint-initdb.d/02_indexes.sql
|
||||||
- postgres_standalone_data:/var/lib/postgresql/data
|
- ./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
|
||||||
|
# Dossier de données de test (CSV, etc.)
|
||||||
|
- ./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
|
||||||
networks:
|
networks:
|
||||||
- ptitspas_dev
|
- ptitspas_dev
|
||||||
|
|
||||||
|
|||||||
169
docs/ENUMS.md
169
docs/ENUMS.md
@ -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 **P’titsPas**, leur **sens fonctionnel**, et les **tables/colonnes concernées**.
|
||||||
|
|
||||||
Ce document recense **toutes les valeurs énumérées** utilisées dans la base P’titsPas, 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 l’OpenAPI / 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 |
|
| `parent` | Parent ou co-parent |
|
||||||
| `gestionnaire` | Gestion / validation des comptes, supervision |
|
| `gestionnaire` | Gestion/validation des comptes, supervision |
|
||||||
| `parent` | Parent ou co-parent |
|
| `super_admin` | Compte technique initial / administration globale |
|
||||||
| `am` | Assistante maternelle |
|
| `assistante_maternelle` | Profil professionnel d’assistante 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 l’AM |
|
||||||
| `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 d’accord) |
|
| `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 l’enfant |
|
||||||
| `conge_am` | Congé de l’assistante maternelle |
|
| `conge_am` | Congé de l’assistante 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 l’AM |
|
||||||
| `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 d’un événement proche |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Mainteneur** : Équipe BDD
|
|
||||||
**Dernière mise à jour** : Sprint 1 — Ticket 9 (ENUMS)
|
|
||||||
|
|||||||
@ -1,142 +1,144 @@
|
|||||||
|
# FK\_POLICIES.md — Politiques de clés étrangères
|
||||||
|
|
||||||
# FK_POLICIES.md
|
Ce document recense l’ensemble des **relations entre tables** dans la base **P’titsPas**, 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 P’titsPas 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 **n’a pas de sens sans le parent**
|
* Les FK sont définies en `REFERENCES ...`.
|
||||||
(ex. `dossiers` d’un parent, `avenants` d’un contrat).
|
* Sauf précision, `ON UPDATE` est implicite = `NO ACTION`.
|
||||||
- **SET NULL** quand on veut **préserver l’historique** mais que le référent peut disparaître
|
* Les comportements documentés sont **côté PostgreSQL**.
|
||||||
(ex. auteur d’un message supprimé, créateur d’un événement).
|
|
||||||
- **RESTRICT/NO ACTION** non utilisé ici pour éviter des blocages au nettoyage.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📚 Récapitulatif rapide (matrice)
|
## 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 n’a pas de sens sans parent |
|
|
||||||
| **dossiers(id_enfant)** → `enfants(id)` | **CASCADE** | Dossier n’a pas de sens sans enfant |
|
|
||||||
| **messages(id_dossier)** → `dossiers(id)` | **CASCADE** | Messages détruits avec le dossier |
|
|
||||||
| **messages(id_expediteur)** → `utilisateurs(id)` | **SET NULL** | Garder l’historique des échanges |
|
|
||||||
| **contrats(id_dossier)** → `dossiers(id)` | **CASCADE** | 1:1, contrat détruit si dossier supprimé |
|
|
||||||
| **avenants_contrats(id_contrat)** → `contrats(id)` | **CASCADE** | Avenants détruits avec le contrat |
|
|
||||||
| **avenants_contrats(initie_par)** → `utilisateurs(id)` | **SET NULL** | Historiser l’avenant sans bloquer |
|
|
||||||
| **evenements(id_enfant)** → `enfants(id)` | **CASCADE** | Événements n’ont plus de sens |
|
|
||||||
| **evenements(id_am)** → `utilisateurs(id)` | **SET NULL** | Garder la trace même si AM supprimée |
|
|
||||||
| **evenements(id_parent)** → `parents(id_utilisateur)` | **SET NULL** | Garder la trace si parent supprimé |
|
|
||||||
| **evenements(cree_par)** → `utilisateurs(id)` | **SET NULL** | Conserver l’historique de création |
|
|
||||||
| **signalements_bugs(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Conserver le ticket même si compte supprimé |
|
|
||||||
| **uploads(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Fichier reste référencé sans l’auteur |
|
|
||||||
| **notifications(id_utilisateur)** → `utilisateurs(id)` | **CASCADE** | Notifications propres à l’utilisateur |
|
|
||||||
| **validations(id_utilisateur)** → `utilisateurs(id)` | **SET NULL** | Garder l’historique de décision |
|
|
||||||
|
|
||||||
> **ON UPDATE** : **NO ACTION** partout (les UUID ne changent pas).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔎 Détail par domaine
|
## 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 d’un 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 d’un 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 d’un co-parent**
|
* **ON DELETE CASCADE** → si le parent est supprimé, le lien avec l’enfant disparaît.
|
||||||
- Supprimer `utilisateurs(id=coParentY)`
|
* **FK** : `id_enfant → enfants.id`
|
||||||
- Attendu : `parents.id_co_parent` passe à **NULL**, aucun dossier supprimé.
|
|
||||||
|
|
||||||
3. **Suppression d’un utilisateur auteur de messages**
|
* **ON DELETE CASCADE** → si l’enfant est supprimé, toutes ses associations avec des parents disparaissent.
|
||||||
- Supprimer `utilisateurs(id=uZ)`
|
|
||||||
- Attendu : les lignes `messages` **restent**, `id_expediteur` devient **NULL**.
|
|
||||||
|
|
||||||
4. **Suppression d’un enfant**
|
|
||||||
- Supprimer `enfants(id=childA)`
|
|
||||||
- Attendu : `enfants_parents` (CASCADE), `dossiers` du childA (CASCADE), `evenements` du childA (CASCADE).
|
|
||||||
|
|
||||||
5. **Suppression d’un utilisateur AM**
|
|
||||||
- Supprimer `utilisateurs(id=amB)`
|
|
||||||
- Attendu : `evenements.id_am` devient **NULL** (historique conservé).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠 Migrations associées
|
## 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 l’enfant 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 d’audit (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 l’utilisateur.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
📌 **Mainteneur** : Équipe BDD
|
||||||
|
📌 **Dernière mise à jour** : alignée sur `init.sql` (septembre 2025)
|
||||||
|
|
||||||
|
---
|
||||||
|
|||||||
72
makefile
Normal file
72
makefile
Normal 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
|
||||||
@ -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)
|
||||||
|
-- ===========================================
|
||||||
|
|||||||
@ -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 : aujourd’hui 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 l’enfant 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 l’enfant 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)
|
||||||
|
);
|
||||||
|
|||||||
@ -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
59
scripts/clean_csv.py
Executable 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
64
scripts/verify_data.sql
Normal 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
|
||||||
|
-- ==============================================
|
||||||
221
seed/02_seed.sql
221
seed/02_seed.sql
@ -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 l’AM 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;
|
|
||||||
@ -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 d’un 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
188
verify.log
Normal 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)
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user