feat: Provisionner automatiquement un nouvel établissement
Lorsqu'un super-admin crée un établissement via l'interface, le système doit automatiquement créer la base tenant, exécuter les migrations, créer le premier utilisateur admin et envoyer l'invitation — le tout de manière asynchrone pour ne pas bloquer la réponse HTTP. Ce mécanisme rend chaque établissement opérationnel dès sa création sans intervention manuelle sur l'infrastructure.
This commit is contained in:
181
backend/seed-story-6.9.sql
Normal file
181
backend/seed-story-6.9.sql
Normal file
@@ -0,0 +1,181 @@
|
||||
-- =============================================================================
|
||||
-- Jeu de données local — Story 6.9 : GradeVoter & accès notes
|
||||
-- =============================================================================
|
||||
-- Prérequis : avoir lancé `make generate-demo` sur un tenant (ecole-beta par défaut)
|
||||
-- Usage :
|
||||
-- docker compose exec -T php php bin/console dbal:run-sql "$(cat backend/seed-story-6.9.sql)"
|
||||
--
|
||||
-- Mot de passe de tous les comptes démo : DemoPassword123!
|
||||
-- URL : http://ecole-beta.classeo.local:5174/login
|
||||
--
|
||||
-- ┌──────────────────────────────────────────────────────────────────────────┐
|
||||
-- │ Scénarios à tester │
|
||||
-- │ │
|
||||
-- │ AC1 — GradeVoter │
|
||||
-- │ ✅ Amina Benali (prof maths, affectée 6A) → peut saisir notes │
|
||||
-- │ ❌ Sophie Lambert (prof SVT, pas affectée 6A en maths) → bloquée │
|
||||
-- │ ✅ David Nguyen (remplaçant actif maths 6A) → peut saisir notes │
|
||||
-- │ │
|
||||
-- │ AC2 — Retrait d'affectation │
|
||||
-- │ ❌ Julie Caron (prof français, affectation retirée 6A) │
|
||||
-- │ → peut voir les notes existantes, ne peut plus en saisir │
|
||||
-- │ │
|
||||
-- │ AC3 — Badge "Remplaçant" │
|
||||
-- │ → Se connecter avec David Nguyen, saisir une note │
|
||||
-- │ → Le badge violet "Remplaçant" apparaît sur la ligne │
|
||||
-- │ │
|
||||
-- │ AC4 — Parent StudentVoter │
|
||||
-- │ ✅ Nadia Martin → voit les notes de Lina Martin (6A) │
|
||||
-- │ ❌ Claire Bernard → ne voit PAS les notes de Lina Martin │
|
||||
-- └──────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
v_tenant_id UUID;
|
||||
v_class_6a_id UUID;
|
||||
v_subject_math_id UUID;
|
||||
v_subject_fr_id UUID;
|
||||
v_teacher_amina_id UUID; -- prof maths, affectée
|
||||
v_teacher_julie_id UUID; -- prof français, affectation retirée
|
||||
v_teacher_david_id UUID; -- prof anglais, utilisé comme remplaçant
|
||||
v_student_lina_id UUID;
|
||||
v_student_chloe_id UUID;
|
||||
v_student_hugo_id UUID;
|
||||
v_student_zoe_id UUID;
|
||||
v_eval_math_id UUID;
|
||||
v_eval_fr_id UUID;
|
||||
v_subdomain TEXT := 'ecole-beta';
|
||||
BEGIN
|
||||
-- Résoudre le tenant via les utilisateurs démo
|
||||
SELECT tenant_id INTO v_tenant_id
|
||||
FROM users WHERE email = 'prof.amina.benali.' || v_subdomain || '@classeo.test' LIMIT 1;
|
||||
|
||||
IF v_tenant_id IS NULL THEN
|
||||
RAISE EXCEPTION 'Aucun compte démo trouvé pour %. Lancez `make generate-demo` d''abord.', v_subdomain;
|
||||
END IF;
|
||||
|
||||
-- Résoudre les entités de démo existantes
|
||||
SELECT id INTO v_class_6a_id FROM school_classes WHERE tenant_id = v_tenant_id AND name = '6A';
|
||||
SELECT id INTO v_subject_math_id FROM subjects WHERE tenant_id = v_tenant_id AND code = 'MATH';
|
||||
SELECT id INTO v_subject_fr_id FROM subjects WHERE tenant_id = v_tenant_id AND code = 'FR';
|
||||
|
||||
SELECT id INTO v_teacher_amina_id FROM users WHERE tenant_id = v_tenant_id AND email = 'prof.amina.benali.' || v_subdomain || '@classeo.test';
|
||||
SELECT id INTO v_teacher_julie_id FROM users WHERE tenant_id = v_tenant_id AND email = 'prof.julie.caron.' || v_subdomain || '@classeo.test';
|
||||
SELECT id INTO v_teacher_david_id FROM users WHERE tenant_id = v_tenant_id AND email = 'prof.david.nguyen.' || v_subdomain || '@classeo.test';
|
||||
|
||||
SELECT id INTO v_student_lina_id FROM users WHERE tenant_id = v_tenant_id AND email = 'eleve.lina.martin.' || v_subdomain || '@classeo.test';
|
||||
SELECT id INTO v_student_chloe_id FROM users WHERE tenant_id = v_tenant_id AND email = 'eleve.chloe.lopez.' || v_subdomain || '@classeo.test';
|
||||
SELECT id INTO v_student_hugo_id FROM users WHERE tenant_id = v_tenant_id AND email = 'eleve.hugo.lopez.' || v_subdomain || '@classeo.test';
|
||||
SELECT id INTO v_student_zoe_id FROM users WHERE tenant_id = v_tenant_id AND email = 'eleve.zoe.moreau.' || v_subdomain || '@classeo.test';
|
||||
|
||||
-- Vérifications
|
||||
IF v_class_6a_id IS NULL THEN RAISE EXCEPTION 'Classe 6A introuvable.'; END IF;
|
||||
IF v_subject_math_id IS NULL THEN RAISE EXCEPTION 'Matière MATH introuvable.'; END IF;
|
||||
IF v_teacher_amina_id IS NULL THEN RAISE EXCEPTION 'Prof Amina introuvable.'; END IF;
|
||||
IF v_teacher_david_id IS NULL THEN RAISE EXCEPTION 'Prof David introuvable.'; END IF;
|
||||
IF v_student_lina_id IS NULL THEN RAISE EXCEPTION 'Élève Lina introuvable.'; END IF;
|
||||
|
||||
-- =========================================================================
|
||||
-- 1. Évaluation de maths en 6A (propriétaire = Amina, affectée)
|
||||
-- =========================================================================
|
||||
v_eval_math_id := gen_random_uuid();
|
||||
|
||||
INSERT INTO evaluations (id, tenant_id, class_id, subject_id, teacher_id, title, description, evaluation_date, grade_scale, coefficient, status, created_at, updated_at, grades_published_at)
|
||||
VALUES (v_eval_math_id, v_tenant_id, v_class_6a_id, v_subject_math_id, v_teacher_amina_id,
|
||||
'Contrôle — Fractions', 'Chapitre 4 : fractions et décimaux',
|
||||
CURRENT_DATE - INTERVAL '3 days', 20, 1.0, 'published', NOW(), NOW(),
|
||||
NOW() - INTERVAL '2 days');
|
||||
|
||||
-- Notes pour les 4 élèves de 6A
|
||||
-- Lina et Hugo : saisies par David (remplaçant) → badge "Remplaçant" visible
|
||||
-- Chloe et Zoe : saisies par Amina (titulaire) → pas de badge
|
||||
INSERT INTO grades (id, tenant_id, evaluation_id, student_id, value, status, created_by, created_at, updated_at)
|
||||
VALUES
|
||||
(gen_random_uuid(), v_tenant_id, v_eval_math_id, v_student_lina_id, 16.5, 'graded', v_teacher_david_id, NOW(), NOW()),
|
||||
(gen_random_uuid(), v_tenant_id, v_eval_math_id, v_student_chloe_id, 12.0, 'graded', v_teacher_amina_id, NOW(), NOW()),
|
||||
(gen_random_uuid(), v_tenant_id, v_eval_math_id, v_student_hugo_id, NULL, 'absent', v_teacher_david_id, NOW(), NOW()),
|
||||
(gen_random_uuid(), v_tenant_id, v_eval_math_id, v_student_zoe_id, 18.0, 'graded', v_teacher_amina_id, NOW(), NOW());
|
||||
|
||||
-- Statistiques
|
||||
INSERT INTO evaluation_statistics (evaluation_id, average, min_grade, max_grade, median_grade, graded_count, updated_at)
|
||||
VALUES (v_eval_math_id, 15.5, 12.0, 18.0, 16.5, 3, NOW())
|
||||
ON CONFLICT (evaluation_id) DO NOTHING;
|
||||
|
||||
-- =========================================================================
|
||||
-- 2. Évaluation de français en 6A (propriétaire = Julie)
|
||||
-- Julie aura son affectation RETIRÉE → AC2
|
||||
-- =========================================================================
|
||||
v_eval_fr_id := gen_random_uuid();
|
||||
|
||||
INSERT INTO evaluations (id, tenant_id, class_id, subject_id, teacher_id, title, description, evaluation_date, grade_scale, coefficient, status, created_at, updated_at, grades_published_at)
|
||||
VALUES (v_eval_fr_id, v_tenant_id, v_class_6a_id, v_subject_fr_id, v_teacher_julie_id,
|
||||
'Dictée — Les Misérables', NULL,
|
||||
CURRENT_DATE - INTERVAL '5 days', 20, 1.0, 'published', NOW(), NOW(),
|
||||
NOW() - INTERVAL '4 days');
|
||||
|
||||
INSERT INTO grades (id, tenant_id, evaluation_id, student_id, value, status, created_by, created_at, updated_at)
|
||||
VALUES
|
||||
(gen_random_uuid(), v_tenant_id, v_eval_fr_id, v_student_lina_id, 14.0, 'graded', v_teacher_julie_id, NOW(), NOW()),
|
||||
(gen_random_uuid(), v_tenant_id, v_eval_fr_id, v_student_chloe_id, 17.5, 'graded', v_teacher_julie_id, NOW(), NOW());
|
||||
|
||||
INSERT INTO evaluation_statistics (evaluation_id, average, min_grade, max_grade, median_grade, graded_count, updated_at)
|
||||
VALUES (v_eval_fr_id, 15.75, 14.0, 17.5, 15.75, 2, NOW())
|
||||
ON CONFLICT (evaluation_id) DO NOTHING;
|
||||
|
||||
-- Retirer l'affectation français 6A de Julie → AC2
|
||||
UPDATE teacher_assignments
|
||||
SET status = 'removed', end_date = NOW(), updated_at = NOW()
|
||||
WHERE tenant_id = v_tenant_id
|
||||
AND teacher_id = v_teacher_julie_id
|
||||
AND school_class_id = v_class_6a_id
|
||||
AND subject_id = v_subject_fr_id;
|
||||
|
||||
-- =========================================================================
|
||||
-- 3. Remplacement actif : David Nguyen remplace Amina en maths 6A → AC1/AC3
|
||||
-- =========================================================================
|
||||
INSERT INTO teacher_replacements (id, tenant_id, replaced_teacher_id, replacement_teacher_id, start_date, end_date, status, reason, created_by, created_at, updated_at)
|
||||
VALUES (gen_random_uuid(), v_tenant_id, v_teacher_amina_id, v_teacher_david_id,
|
||||
CURRENT_DATE - INTERVAL '1 day', CURRENT_DATE + INTERVAL '14 days',
|
||||
'active', 'Formation continue — 2 semaines',
|
||||
v_teacher_amina_id, NOW(), NOW());
|
||||
|
||||
-- Lier le remplacement à la classe/matière maths 6A
|
||||
INSERT INTO replacement_classes (replacement_id, class_id, subject_id)
|
||||
SELECT tr.id, v_class_6a_id, v_subject_math_id
|
||||
FROM teacher_replacements tr
|
||||
WHERE tr.tenant_id = v_tenant_id
|
||||
AND tr.replacement_teacher_id = v_teacher_david_id
|
||||
AND tr.replaced_teacher_id = v_teacher_amina_id
|
||||
AND tr.status = 'active';
|
||||
|
||||
-- =========================================================================
|
||||
-- Résumé
|
||||
-- =========================================================================
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE '══════════════════════════════════════════════════════════════';
|
||||
RAISE NOTICE ' Story 6.9 — Jeu de données créé !';
|
||||
RAISE NOTICE '══════════════════════════════════════════════════════════════';
|
||||
RAISE NOTICE ' URL : http://ecole-beta.classeo.local:5174/login';
|
||||
RAISE NOTICE ' Mot de passe : DemoPassword123!';
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE ' AC1 — Enseignant affecté :';
|
||||
RAISE NOTICE ' prof.amina.benali.ecole-beta@classeo.test → saisie maths 6A ✅';
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE ' AC1 — Enseignant non affecté :';
|
||||
RAISE NOTICE ' prof.sophie.lambert.ecole-beta@classeo.test';
|
||||
RAISE NOTICE ' → /dashboard/teacher/evaluations/%/grades → bloqué ❌', v_eval_math_id;
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE ' AC1/AC3 — Remplaçant actif + badge :';
|
||||
RAISE NOTICE ' prof.david.nguyen.ecole-beta@classeo.test';
|
||||
RAISE NOTICE ' → /dashboard/teacher/evaluations/%/grades → saisie ✅ + badge', v_eval_math_id;
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE ' AC2 — Affectation retirée (lecture seule) :';
|
||||
RAISE NOTICE ' prof.julie.caron.ecole-beta@classeo.test';
|
||||
RAISE NOTICE ' → /dashboard/teacher/evaluations/%/grades → lecture ✅ saisie ❌', v_eval_fr_id;
|
||||
RAISE NOTICE '';
|
||||
RAISE NOTICE ' AC4 — Parent lié / non lié :';
|
||||
RAISE NOTICE ' parent.nadia.martin.ecole-beta@classeo.test → notes Lina ✅';
|
||||
RAISE NOTICE ' parent.claire.bernard.ecole-beta@classeo.test → pas Lina ❌';
|
||||
RAISE NOTICE '══════════════════════════════════════════════════════════════';
|
||||
|
||||
END $$;
|
||||
Reference in New Issue
Block a user