# Spec — Multi-Association

> Statut : `done`

## Intention

Permettre à plusieurs associations d'utiliser la même instance de Récré, chacune avec ses propres données isolées. Un super-admin gère la création des associations et désigne leurs admins.

## Contraintes

- Toute donnée métier (produits, caisses, sessions, ventes, stock) est scopée à une `Association`.
- Un utilisateur appartient à une seule association (sauf super-admin qui est hors asso).
- L'isolation des données doit être garantie au niveau Doctrine (filtre automatique).

## Comportement attendu

1. Le super-admin se connecte au back-office.
2. Il crée une association (nom, slug).
3. Il crée un compte admin pour cette association.
4. L'admin de l'asso peut ensuite créer ses vendeurs, produits, caisses.
5. Chaque utilisateur ne voit que les données de son association.

## Critères de « fait »

- [x] Entité `Association` créée avec nom et slug.
- [x] `User` lié à une `Association` (nullable pour super-admin).
- [x] Toutes les entités métier ont une FK vers `Association`.
- [x] Doctrine Filter actif pour filtrer par asso automatiquement.
- [x] Le super-admin peut créer/éditer des associations dans EasyAdmin.
- [x] Le super-admin peut créer un admin pour une asso.
- [x] Un admin ne voit que les données de son asso dans EasyAdmin.
- [x] Un vendeur ne voit que les données de son asso sur le front.
- [x] La création de compte n'est pas en libre-service : demande d'accès, puis ouverture à la main par le super-admin.

## Notes

Le critère « un admin ne voit que les données de son asso dans EasyAdmin » n'a été réellement
satisfait qu'avec l'ajout des gardes `ROLE_SUPER_ADMIN` sur `AssociationCrudController` et
`UserCrudController`. Le filtre Doctrine ne protège pas `Association` : il filtre *par*
association, il ne peut pas se filtrer lui-même. L'isolation de cet écran est portée par les
contrôleurs, et couverte par `tests/Controller/MonAssociationCrudControllerTest.php`.

Le super-admin est créé via une commande console au déploiement initial.

**Correction du 2026-08-21.** La route `/inscription` contredisait cette spec : elle créait une association **et** son compte administrateur, sans aucun contrôle, pour qui trouvait l'URL. Elle est remplacée par une **demande d'accès** — un formulaire public qui enregistre la demande, que seul le super-admin lit, et à partir de laquelle il ouvre l'association à la main. C'est ce que la spec décrivait depuis le début.

L'entité `DemandeAcces` est la **seule qui n'appartient à aucune association**, et ce n'est pas un oubli : elle existe avant qu'il y en ait une. Le filtre Doctrine ne s'y applique donc pas, et son isolation est portée par une garde `ROLE_SUPER_ADMIN`, comme pour `AssociationCrudController`.

**Mise à jour du 2026-08-25** ([mail.md](mail.md)) : deux messages partent désormais, mais **après** l'enregistrement et sans jamais pouvoir le faire échouer — la notification au super-admin, et l'accusé de réception au demandeur. La trace reste la demande en base : un formulaire dont le contenu dépendrait de la disponibilité d'un service tiers serait pire que pas de formulaire du tout.
