# Sprint 02 - SchoolContext et securite multi-ecole

Date : 2026-05-09

## Resume

Ce sprint centralise la recuperation de la madrassa courante et les controles d'appartenance multi-ecole dans un service dedie. L'objectif etait de reduire la duplication des methodes `currentEcole()` et `assertSameSchool()` dans les controleurs `/school`, sans modifier les regles metier ni supprimer les filtres repository existants.

## Service cree

- `src/Service/School/SchoolContext.php`

Methodes principales :

- `getUser(): User`
- `getEcole(): Ecole`
- `getEcoleOrNull(): ?Ecole`
- `isSameSchool(?object $subject): bool`
- `assertSameSchool(?object $subject): void`

Le service utilise l'utilisateur authentifie via Symfony Security. Il conserve le comportement actuel de l'espace `/school` : un utilisateur sans ecole associee est refuse avec une exception d'acces clair. Pour le cas super-admin, aucun comportement nouveau n'a ete invente dans ce sprint : si un super-admin n'a pas d'ecole associee et entre dans `/school`, il reste refuse comme avant.

## Controleurs refactorises

Les 11 controleurs de `src/Controller/School` injectent maintenant `SchoolContext` et utilisent `$this->schoolContext->getEcole()` :

- `AnneeScolaireController`
- `ClasseController`
- `ConfigurationController`
- `DashboardController`
- `DepenseController`
- `EtudiantController`
- `FinanceController`
- `InscriptionController`
- `NiveauController`
- `PaiementController`
- `SectionController`

Les controles d'isolation utilisent maintenant `$this->schoolContext->assertSameSchool(...)` dans les controleurs concernes.

## Methodes supprimees ou conservees

Methodes supprimees :

- Toutes les methodes privees `currentEcole()` des controleurs `/school`.
- Toutes les methodes privees `assertSameSchool()` des controleurs `/school`.

Methodes conservees :

- Aucune methode privee `currentEcole()` ou `assertSameSchool()` n'est conservee dans `src/Controller/School`.
- Les filtres repository par ecole sont conserves. Le service centralise l'acces courant, mais ne remplace pas les clauses `ecole = :ecole`.

## Fichiers modifies ou crees

- `src/Service/School/SchoolContext.php`
- `src/Controller/School/AnneeScolaireController.php`
- `src/Controller/School/ClasseController.php`
- `src/Controller/School/ConfigurationController.php`
- `src/Controller/School/DashboardController.php`
- `src/Controller/School/DepenseController.php`
- `src/Controller/School/EtudiantController.php`
- `src/Controller/School/FinanceController.php`
- `src/Controller/School/InscriptionController.php`
- `src/Controller/School/NiveauController.php`
- `src/Controller/School/PaiementController.php`
- `src/Controller/School/SectionController.php`
- `composer.json`
- `composer.lock`
- `docs/sprints/sprint-02-school-context.md`

## Tests

Aucun test automatise n'a ete ajoute, car le projet ne contient pas encore de structure `tests/` ni de dependance PHPUnit installee. Les cas a couvrir en priorite au sprint suivant :

- `SchoolContext::getEcole()` retourne l'ecole de l'admin connecte.
- `SchoolContext::getEcole()` refuse un utilisateur non connecte.
- `SchoolContext::getEcole()` refuse un utilisateur sans ecole dans l'espace school.
- `SchoolContext::assertSameSchool()` accepte une entite de la meme ecole.
- `SchoolContext::assertSameSchool()` refuse une entite d'une autre ecole.

## Commandes executees

- `php8.4 -l src/Service/School/SchoolContext.php` : OK.
- `php8.4 -l` sur tous les controleurs `src/Controller/School/*.php` : OK.
- `composer validate` : OK.
- `composer update --lock` : le lock a ete reecrit, mais le script Composer `cache:clear` a echoue car la commande `composer` locale utilise PHP 8.1 alors que le projet exige PHP 8.4.
- `php8.4 bin/console cache:clear` : OK.
- `php8.4 bin/console lint:twig templates` : OK.
- `php8.4 bin/console lint:yaml config` : OK.
- `php8.4 bin/console lint:container` : OK.
- `php8.4 bin/console debug:router` : OK.
- `php8.4 bin/console doctrine:schema:validate` : OK.

Verifications HTTP locales :

- Non authentifie :
  - `GET /school` : 302 vers login.
  - `GET /school/inscriptions` : 302 vers login.
  - `GET /school/etudiants` : 302 vers login.
  - `GET /school/classes` : 302 vers login.
  - `GET /school/paiements` : 302 vers login.
- Authentifie avec `adminsahaba@salsabilmadrassas.local` :
  - `GET /school` : 200.
  - `GET /school/inscriptions` : 200.
  - `GET /school/etudiants` : 200.
  - `GET /school/classes` : 200.
  - `GET /school/paiements` : 200.
- Public :
  - `GET /madrassas/qamar` : 200.
  - `GET /madrassas/daroulilm` : 200.
  - `GET /madrassas/sahaba` : 200.

## Points a verifier manuellement

- Verifier dans le navigateur que les menus `/school` restent fluides pour les admins Qamar et Daroul-Ilm, pas seulement Sahaba.
- Tester une action POST sensible par module : creation classe, affectation inscription, validation paiement, depense.
- Tester un acces croise manuel en modifiant un ID dans l'URL pour verifier que `assertSameSchool()` bloque bien la ressource d'une autre ecole.
- Configurer la commande `composer` locale pour utiliser PHP 8.4 afin d'eviter l'echec des auto-scripts Composer.

## Points encore a refactoriser

- Centraliser plus tard les petites comparaisons manuelles `getEcole()?->getId() === $ecole->getId()` dans certains filtres internes de controleurs, seulement si cela reste lisible.
- Envisager un `SchoolAccessGuard` separe uniquement si les regles d'acces deviennent plus complexes.

## Recommandations sprint suivant

- Ajouter une base de tests PHPUnit/WebTestCase et couvrir `SchoolContext`.
- Ajouter un test fonctionnel par admin ecole pour valider que Qamar, Daroul-Ilm et Sahaba ne voient que leurs propres donnees.
- Factoriser les helpers de filtres annee/categorie lorsque les pages finance et depenses evoluent.
