diff --git a/migrations/01_init.sql b/migrations/01_init.sql index ea4fe18..6b4d43b 100644 --- a/migrations/01_init.sql +++ b/migrations/01_init.sql @@ -1,215 +1,265 @@ --- ============================================================ --- 02_seed.sql : Données de test réalistes (conformes à 01_init.sql) --- - Idempotent : ON CONFLICT DO NOTHING --- - Utilise des UUID fixes pour faciliter les tests --- ============================================================ +CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -BEGIN; +-- ========================================================== +-- ENUMS +-- ========================================================== +DO $$ BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'role_type') THEN + CREATE TYPE role_type AS ENUM ('parent', 'gestionnaire', 'super_admin', 'assistante_maternelle'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'genre_type') THEN + CREATE TYPE genre_type AS ENUM ('H', 'F', 'Autre'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_utilisateur_type') THEN + CREATE TYPE statut_utilisateur_type AS ENUM ('en_attente','actif','suspendu'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_enfant_type') THEN + CREATE TYPE statut_enfant_type AS ENUM ('a_naitre','actif','scolarise'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_dossier_type') THEN + CREATE TYPE statut_dossier_type AS ENUM ('envoye','accepte','refuse'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_contrat_type') THEN + CREATE TYPE statut_contrat_type AS ENUM ('brouillon','en_attente_signature','valide','resilie'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_avenant_type') THEN + CREATE TYPE statut_avenant_type AS ENUM ('propose','accepte','refuse'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'type_evenement_type') THEN + CREATE TYPE type_evenement_type AS ENUM ('absence_enfant','conge_am','conge_parent','arret_maladie_am','evenement_rpe'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_evenement_type') THEN + CREATE TYPE statut_evenement_type AS ENUM ('propose','valide','refuse'); + END IF; + IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'statut_validation_type') THEN + CREATE TYPE statut_validation_type AS ENUM ('en_attente','valide','refuse'); + END IF; +END $$; --- ============================== --- Utilisateurs (rôles & statuts) --- ============================== --- 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; +-- ========================================================== +-- Table : utilisateurs +-- ========================================================== +CREATE TABLE utilisateurs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + courriel VARCHAR(255) NOT NULL UNIQUE, + CHECK (courriel ~* '^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$'), + mot_de_passe_hash TEXT NOT NULL, + prenom VARCHAR(100), + nom VARCHAR(100), + genre genre_type, + role role_type NOT NULL, + statut statut_utilisateur_type DEFAULT 'en_attente', + telephone VARCHAR(20), + adresse TEXT, + photo_url TEXT, + consentement_photo BOOLEAN DEFAULT false, + date_consentement_photo TIMESTAMPTZ, + changement_mdp_obligatoire BOOLEAN DEFAULT false, + cree_le TIMESTAMPTZ DEFAULT now(), + modifie_le TIMESTAMPTZ DEFAULT now(), + ville VARCHAR(150), + code_postal VARCHAR(10) +); --- 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; +-- ========================================================== +-- Table : assistantes_maternelles +-- ========================================================== +CREATE TABLE assistantes_maternelles ( + id_utilisateur UUID PRIMARY KEY REFERENCES utilisateurs(id) ON DELETE CASCADE, + numero_agrement VARCHAR(50), + date_naissance DATE, + ville_naissance VARCHAR(100), + pays_naissance CHAR(2), + nir_chiffre CHAR(15), + nb_max_enfants INT, + biographie TEXT, + disponible BOOLEAN DEFAULT true, + ville_residence VARCHAR(100) +); --- 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; +-- ========================================================== +-- Table : parents +-- ========================================================== +CREATE TABLE parents ( + id_utilisateur UUID PRIMARY KEY REFERENCES utilisateurs(id) ON DELETE CASCADE, + id_co_parent UUID REFERENCES utilisateurs(id) +); --- 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; +-- ========================================================== +-- Table : enfants +-- ========================================================== +CREATE TABLE enfants ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + statut statut_enfant_type, + prenom VARCHAR(100), + nom VARCHAR(100), + genre genre_type, + date_naissance DATE, + date_prevue_naissance DATE, + photo_url TEXT, + consentement_photo BOOLEAN DEFAULT false, + date_consentement_photo TIMESTAMPTZ, + est_multiple BOOLEAN DEFAULT false +); --- 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', 'en_attente') -ON CONFLICT (id) DO NOTHING; +-- ========================================================== +-- Table : enfants_parents +-- ========================================================== +CREATE TABLE enfants_parents ( + id_parent UUID REFERENCES parents(id_utilisateur) ON DELETE CASCADE, + id_enfant UUID REFERENCES enfants(id) ON DELETE CASCADE, + PRIMARY KEY (id_parent, id_enfant) +); --- assistante maternelle -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; +-- ========================================================== +-- Table : dossiers +-- ========================================================== +CREATE TABLE dossiers ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_parent UUID REFERENCES parents(id_utilisateur) ON DELETE CASCADE, + id_enfant UUID REFERENCES enfants(id) ON DELETE CASCADE, + presentation TEXT, + type_contrat VARCHAR(50), + repas BOOLEAN DEFAULT false, + budget NUMERIC(10,2), + planning_souhaite JSONB, + statut statut_dossier_type DEFAULT 'envoye', + cree_le TIMESTAMPTZ DEFAULT now(), + modifie_le TIMESTAMPTZ DEFAULT now() +); --- ============================== --- Parents & co-parents (extensions) --- ============================== -INSERT INTO parents (id_utilisateur, id_co_parent) -VALUES - ('33333333-3333-3333-3333-333333333333', '44444444-4444-4444-4444-444444444444'), -- parent1 avec co-parent - ('55555555-5555-5555-5555-555555555555', NULL) -- parent2 seul -ON CONFLICT (id_utilisateur) DO NOTHING; +-- ========================================================== +-- Table : messages +-- ========================================================== +CREATE TABLE messages ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_dossier UUID REFERENCES dossiers(id) ON DELETE CASCADE, + id_expediteur UUID REFERENCES utilisateurs(id) ON DELETE CASCADE, + contenu TEXT, + re_redige_par_ia BOOLEAN DEFAULT false, + cree_le TIMESTAMPTZ DEFAULT now() +); --- ============================== --- Assistantes maternelles (extension) --- ============================== -INSERT INTO assistantes_maternelles (id_utilisateur, numero_agrement, nb_max_enfants, disponible, ville_residence, nir_chiffre) -VALUES ('66666666-6666-6666-6666-666666666666', 'AGR-2025-0001', 3, true, 'Lille', '000000000000000') -ON CONFLICT (id_utilisateur) DO NOTHING; +-- ========================================================== +-- Table : contrats +-- ========================================================== +CREATE TABLE contrats ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_dossier UUID UNIQUE REFERENCES dossiers(id) ON DELETE CASCADE, + planning JSONB, + tarif_horaire NUMERIC(6,2), + indemnites_repas NUMERIC(6,2), + date_debut DATE, + statut statut_contrat_type DEFAULT 'brouillon', + signe_parent BOOLEAN DEFAULT false, + signe_am BOOLEAN DEFAULT false, + finalise_le TIMESTAMPTZ, + cree_le TIMESTAMPTZ DEFAULT now(), + modifie_le TIMESTAMPTZ DEFAULT now() +); --- ============================== --- Enfants --- ============================== --- Enfant A : déjà né (statut actif) -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; +-- ========================================================== +-- Table : avenants_contrats +-- ========================================================== +CREATE TABLE avenants_contrats ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_contrat UUID REFERENCES contrats(id) ON DELETE CASCADE, + modifications JSONB, + initie_par UUID REFERENCES utilisateurs(id), + statut statut_avenant_type DEFAULT 'propose', + cree_le TIMESTAMPTZ DEFAULT now(), + modifie_le TIMESTAMPTZ DEFAULT now() +); --- Enfant B : à naître (statut a_naitre) -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; +-- ========================================================== +-- Table : evenements +-- ========================================================== +CREATE TABLE evenements ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + type type_evenement_type, + id_enfant UUID REFERENCES enfants(id) ON DELETE CASCADE, + id_am UUID REFERENCES utilisateurs(id), + id_parent UUID REFERENCES parents(id_utilisateur), + cree_par UUID REFERENCES utilisateurs(id), + date_debut TIMESTAMPTZ, + date_fin TIMESTAMPTZ, + commentaires TEXT, + statut statut_evenement_type DEFAULT 'propose', + delai_grace TIMESTAMPTZ, + urgent BOOLEAN DEFAULT false, + cree_le TIMESTAMPTZ DEFAULT now(), + modifie_le TIMESTAMPTZ DEFAULT now() +); --- ============================== --- Liaison N:N parents ↔ enfants --- ============================== --- parent1 & co-parent ↔ enfant A -INSERT INTO enfants_parents (id_parent, id_enfant) -VALUES - ('33333333-3333-3333-3333-333333333333', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'), - ('44444444-4444-4444-4444-444444444444', 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa') -ON CONFLICT DO NOTHING; +-- ========================================================== +-- Table : signalements_bugs +-- ========================================================== +CREATE TABLE signalements_bugs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_utilisateur UUID REFERENCES utilisateurs(id), + description TEXT, + cree_le TIMESTAMPTZ DEFAULT now() +); --- parent1 & parent2 ↔ enfant B -INSERT INTO enfants_parents (id_parent, id_enfant) -VALUES - ('33333333-3333-3333-3333-333333333333', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'), - ('55555555-5555-5555-5555-555555555555', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb') -ON CONFLICT DO NOTHING; +-- ========================================================== +-- Table : uploads +-- ========================================================== +CREATE TABLE uploads ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_utilisateur UUID REFERENCES utilisateurs(id) ON DELETE SET NULL, + fichier_url TEXT NOT NULL, + type VARCHAR(50), + cree_le TIMESTAMPTZ DEFAULT now() +); --- ============================== --- Dossier (parent1 ↔ enfant A) --- ============================== -INSERT INTO dossiers (id, id_parent, id_enfant, presentation, type_contrat, repas, budget, planning_souhaite, statut) -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":{"midi":true,"soir":true}}'::jsonb, - 'envoye' +-- ========================================================== +-- Table : notifications +-- ========================================================== +CREATE TABLE notifications ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_utilisateur UUID REFERENCES utilisateurs(id) ON DELETE CASCADE, + contenu TEXT, + lu BOOLEAN DEFAULT false, + cree_le TIMESTAMPTZ DEFAULT now() +); + +-- ========================================================== +-- Table : validations +-- ========================================================== +CREATE TABLE validations ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + id_utilisateur UUID REFERENCES utilisateurs(id), + type VARCHAR(50), + statut statut_validation_type DEFAULT 'en_attente', + cree_le TIMESTAMPTZ DEFAULT now(), + modifie_le TIMESTAMPTZ DEFAULT now() +); + + +-- ========================================================== +-- Initialisation d'un administrateur par défaut +-- ========================================================== + +INSERT INTO utilisateurs ( + id, + courriel, + mot_de_passe_hash, + prenom, + nom, + role, + statut, + cree_le, + modifie_le ) -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.'), - ('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 + gen_random_uuid(), + 'admin@ptitspas.com', + 'motdepasse_hashé', -- ⚠️ à remplacer par le hash réel du mot de passe + 'Admin', + 'PtitsPas', + 'super_admin', + 'actif', + now(), + now() ) -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, delai_grace, 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', - '2025-09-15', - 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é) --- ============================== -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; - --- ============================== --- Signalement de bug --- ============================== -INSERT INTO signalements_bugs (id, id_utilisateur, description, cree_le) -VALUES ( - 'b0000000-0000-0000-0000-000000000001', - '33333333-3333-3333-3333-333333333333', - 'Impossible d’envoyer un message quand le fichier est trop lourd.', - NOW() -) -ON CONFLICT (id) DO NOTHING; - -COMMIT; +ON CONFLICT (courriel) DO NOTHING;