## Objectif
Seeder le RBAC métier de façon **rejouable et disponible en recette/prod** (commande applicative, pas fixture `require-dev`), durcir RG-1.04, et écrire le test de matrice (rôles enfin existants).
## A. `RbacSeeder` (Core) — source unique anti-drift
4 rôles (`bureau`/`compta`/`commerciale`/`usine`, isSystem=false), matrice § 2.7 (rôle → permissions) et comptes démo, définis en **un seul endroit**. Méthodes idempotentes `ensureRoles` / `attachMatrix` / `ensureDemoUsers`. `commerciale` référence `BusinessRoles::COMMERCIALE` (déjà consommé par RG-1.04).
## B. Commande `app:seed-rbac` (présente en build prod, idempotente, non destructive)
- Sans option : rôles + matrice § 2.7.
- `--with-demo-users` + `--password=<…>` ou env `RBAC_DEMO_PASSWORD` : 1 compte démo/rôle. **Aucun mot de passe en dur** côté serveur.
- Garde-fou : exit non-zéro + invite à lancer `app:sync-permissions` si les codes `commercial.clients.*` manquent.
## C. Fixture dev/test `RbacDemoFixtures` (DRY)
Appelle le **même seeder** (`ensureRoles` + `ensureDemoUsers`). La matrice est attachée juste après par l'étape `app:seed-rbac` du makefile (la table `permission` est purgée au moment du `fixtures:load`, donc `attachMatrix` ne peut pas tourner pendant le load). `make db-reset` / `test-db-setup` reproduisent l'état de recette.
## Déploiement (documenté README)
Après `migration-migrate` + `app:sync-permissions` : `app:seed-rbac` (prod) ; `app:seed-rbac --with-demo-users --password=…` (recette).
## D. Durcissement RG-1.04
Pour une Commerciale, complétude de l'onglet Information exigée sur **POST + tout PATCH** (suppression de la condition d'intersection). Conséquence : POST Commerciale → 422 (le POST n'expose pas le groupe Information), Admin → 201. Spec § 7 amendée.
## Compta ↔ onglet Comptabilité (§ 2.7)
Pour que `compta PATCH accounting → 200` (exigé par la matrice), la security du `Patch /clients/{id}` est élargie à `manage` **OU** `accounting.manage`, et un nouveau **`guardManage`** (mode strict RG-1.28) interdit à un porteur non-`manage` de modifier les onglets principal/Information (→ 403). Approche validée : élargir la security + guard in-processor (pas de nouvel endpoint).
## E. `ClientRBACMatrixTest`
Matrice § 2.7 complète via les comptes démo seedés (`app:seed-rbac --with-demo-users`) : bureau / compta / commerciale / usine (200/403 par verbe et par onglet) + RG-1.04 (POST Commerciale 422 / Admin 201).
## Tests
`make php-cs-fixer-allow-risky` OK ; `make test` **429 tests verts**. Idempotence vérifiée (rejeu de la commande : 0 rôle / 0 lien / 0 user). `test-db-setup` exécute la nouvelle étape `app:seed-rbac` sans erreur.
Cible : `develop`. Squash merge.
---------
Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #40
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
6.0 KiB
Starseed
Contexte
CRM/ERP en architecture modular monolith DDD. Le backend est la source de verite unique (modules actifs, sidebar). Le frontend scanne frontend/modules/*/ comme layers Nuxt et consomme l'API pour la navigation. Multi-tenant : chaque module est activable/desactivable.
Doc humaine : README.md — Spec audit : doc/audit-log.md (à lire à la demande, non chargés en permanence).
Stack
- Backend : PHP 8.4, Symfony 8, API Platform 4, Doctrine ORM, PostgreSQL 16 (port 5437)
- Frontend : Nuxt 4 (SPA), Vue 3, Pinia, Tailwind, @malio/layer-ui, @nuxtjs/i18n
- Auth : JWT HTTP-only cookie (Lexik), login a
/login_check - Containers :
php-starseed-fpm,nginx-starseed(port 8083), dev Nuxt port 3004
Regles ABSOLUES
- Ne jamais importer d'un module a un autre — passer par
Shared/Domain/Contract/(interfaces) ou domain events. - Toujours
declare(strict_types=1);en tete de tout fichier PHP. - Toujours annoter
#[Auditable]les entites metier ;#[AuditIgnore]sur champs sensibles (password, token, secret). - Toujours utiliser
useApi()pour les appels API cote front — jamais$fetch/ofetchdirect. - Toujours utiliser les composants
Malio*(@malio/layer-ui) pour formulaires/filtres ;MalioDataTablepour listes paginees. - Jamais persister l'etat de tableau dans l'URL (filtres, pagination, tri, selection) — state local uniquement.
- Jamais ajouter un test E2E sauf si un bug critique est passe en prod ; preferer un test Vitest.
- Toujours mettre a jour les 3 sources RBAC ensemble :
config/sidebar.php,frontend/tests/e2e/_fixtures/personas.ts,src/Module/Core/Infrastructure/Console/SeedE2ECommand.php. - Jamais commit sans demande explicite de l'utilisateur ; jamais force push sans confirmation.
- Jamais mentionner Claude, Anthropic ou une IA dans un commit (message, titre, body, footer, trailer) ou une PR (titre, description). Pas de
Co-Authored-By: Claude, pas deGenerated with Claude Code, pas de🤖, pas d'emoji robot, rien. Les commits sont signes par l'utilisateur uniquement. - Migrations d'initialisation au namespace racine
DoctrineMigrationsdansmigrations/(setup user, RBAC, seed de base). Les migrations modulaires (src/Module/*/Infrastructure/Doctrine/Migrations/) sont reservees aux evolutions post-schema (ajout de colonnes, index) — cf. @.claude/rules/architecture.md pour la raison. - Toujours documenter chaque colonne BDD via
COMMENT ON COLUMNdans la migration qui la cree ou la modifie. Description en francais, courte (≤ 200 caracteres), explique la semantique metier + contraintes implicites (unicite partielle, FK importante, lien RG). Garde-fou :tests/Architecture/ColumnsHaveSqlCommentTestechoue si une colonnepublicn'a pas de description (col_description IS NULL). Details et exemples : @.claude/rules/backend.md § Migrations Doctrine. - Toujours paginer toute collection exposee par l'API. Aucun retour de collection complete (pas de provider qui retourne un array brut). Standard pose dans
config/packages/api_platform.yaml: 10 items par defaut, max 50, le client peut basculer entre 10/25/50 et peut envoyer?pagination=falsepour alimenter un select. Garde-fou :tests/Architecture/CollectionsArePaginatedTestechoue si uneGetCollectiondesactive la pagination sans whitelist. Details et exemples : @.claude/rules/backend.md § Pagination. symfony.lockest versionne (au meme titre quecomposer.lock) — ne JAMAIS le.gitignore. C'est le registre des recipes Flex appliquees : sans lui, chaquecomposer requirerejoue toutes les recipes et repollue.env,config/bundles.php,docker-compose.ymlet recree du scaffolding parasite (src/Entity/,src/Controller/...). Le regenerer si besoin viacomposer recipes:install --force.
Conventions
@.claude/rules/architecture.md @.claude/rules/backend.md @.claude/rules/frontend.md @.claude/rules/testing.md @.claude/rules/naming.md @.claude/rules/git.md @.claude/rules/workflow.md
Commandes (liste complete dans README.md)
- Demarrer :
make start - Dev front (hot reload) :
make dev-nuxt(port 3004) - Shell PHP :
make shell - Tests back :
make test - Tests front unitaires :
make nuxt-test - Tests E2E :
make test-e2e(prerequis :make seed-e2e && make dev-nuxt) - Reset BDD :
make db-reset - Lint PHP :
make php-cs-fixer-allow-risky
Activer / desactiver un module
Editer uniquement config/modules.php (commenter la ligne). Cascade automatique via /api/modules, /api/sidebar, middleware front modules.global.ts. Details : @.claude/rules/architecture.md
A NE PAS faire
- Pas de controller Symfony custom sous
/api/sanspriority: 1sur#[Route](conflit API Platform{id}). - Pas de provider API Platform qui retourne un array brut sur une
GetCollection— court-circuite la pagination Hydra (totalItems/viewabsents). UtiliserApiPlatform\Doctrine\Orm\Paginator(ORM) ou un paginator implementantPaginatorInterface(DBAL — cf.DbalPaginator). - Pas de
getClientMimeType()pour valider un upload — utiliser$file->getMimeType()(serveur). - Pas de hardcode de la sidebar cote front, pas de
modules-loader.tsni.module.ts. - Pas d'edition manuelle de
extendsdansfrontend/nuxt.config.ts— les layers sont scannes automatiquement. - Pas de commentaires en anglais dans le code — commentaires en francais, code (noms) en anglais.
- Pas d'
<input>/<select>/<table>bruts quand un composant@malio/layer-uiexiste (exceptions documentees dans @.claude/rules/frontend.md). - Pas de modification de la config git.
Skills projet
create-module— scaffolder un nouveau module back+front et wirer la sidebar.
Credentials (dev)
admin / admin (ROLE_ADMIN) ; alice / alice, bob / bob (ROLE_USER).
Comptes demo des roles metier (seedes par RbacDemoFixtures / app:seed-rbac --with-demo-users, mot de passe demo) : bureau / demo, compta / demo, commerciale / demo, usine / demo. Matrice RBAC § 2.7 (M1 Clients) attachee aux roles correspondants.