Provider de lecture (liste paginée Hydra filtrée + item) :
- exclut les produits soft-deleted (RG-6.09), tri name ASC ;
- filtres ?search (code+name), ?categoryId/?categoryCode, ?state (JSONB @>), ?siteId[] (EXISTS) ;
- Get item : 404 sur soft-deleted (non exposé au M6, § 2.7) ;
- pagination obligatoire via Paginator ORM (règle n°13), échappatoire ?pagination=false.
Processor d'écriture (POST/PATCH) :
- normalisation serveur code trim+UPPER, name trim (RG-6.07, ProductFieldNormalizer) ;
- RG-6.03 : manufactured/containsMolasses forcés false si states sans SALE ;
- RG-6.01 : unicité globale du code parmi les actifs -> 409 (pré-check + filet anti-race index partiel), propertyPath code côté front.
Entité Product : Assert\Callback RG-6.05 (catégorie de type PRODUIT) et RG-6.06
(types de stockage disponibles sur au moins un site choisi), atPath pour mapping
inline 422 ; constantes d'états.
Repository : createListQueryBuilder (filtres + eager-load category/sites/storageTypes)
+ existsActiveByCode déjà en place.
make test vert (873 tests), php-cs-fixer OK.