# Starseed CRM/ERP en architecture **modular monolith DDD** — Symfony 8 (API Platform 4) + Nuxt 4. Le backend est la **source de vérité unique** : il décide des modules actifs et de l'organisation de la sidebar. Le frontend scanne `frontend/modules/*/` comme layers Nuxt et consomme l'API pour la navigation. --- ## Sommaire - [Stack](#stack) - [Prérequis](#prérequis) - [Démarrage rapide](#démarrage-rapide) - [Dev local : avec ou sans données de seed](#dev-local--avec-ou-sans-données-de-seed) - [Comptes (dev)](#comptes-dev) - [Bases de données : dev et test](#bases-de-données--dev-et-test) - [Tests](#tests) - [Déploiement : seed RBAC en recette / prod](#déploiement--seed-rbac-en-recette--prod) - [Commandes make](#commandes-make) - [Architecture](#architecture) - [Structure du dépôt](#structure-du-dépôt) - [CI/CD](#cicd) - [Conventions](#conventions) --- ## Stack - **Backend** : PHP 8.4, Symfony 8, API Platform 4, Doctrine ORM, PostgreSQL 16 - **Frontend** : Nuxt 4 (SPA, SSR off), Vue 3, Pinia, Tailwind CSS, @malio/layer-ui, @nuxtjs/i18n - **Auth** : JWT HTTP-only cookie (Lexik), login sur `/login_check` - **Infra** : Docker Compose (dev + prod multi-stage) - **CI/CD** : Gitea Actions (auto-tag + build Docker) | Service | Port | |---------------|------| | API (Nginx) | 8083 | | Frontend dev | 3004 | | PostgreSQL | 5437 | --- ## Prérequis - Docker + Docker Compose - `make` - `nvm` (la version de Node est fixée par `.nvmrc`, voir `make node-use`) Toutes les commandes `make` s'exécutent dans le container PHP (`php-starseed-fpm`) ; rien n'est requis sur l'hôte hormis Docker — **sauf les tests E2E**, qui tournent sur l'hôte (navigateur réel, voir [Tests](#tests)). --- ## Démarrage rapide ```bash make start # Démarre les containers Docker make install # Composer + clés JWT + migrations + permissions + BDD de test make dev-nuxt # Serveur Nuxt avec hot reload (http://localhost:3004) ``` `make install` prépare une base de dev **vierge** (schéma + RBAC structurel, sans données de démo) et la base de **test**. Pour obtenir des comptes et des données de démo prêtes à l'emploi, lis la section suivante. > Override local possible : `make` lit `infra/dev/.env.docker`, surchargé par > `infra/dev/.env.docker.local` s'il existe (créé automatiquement par `make env-init`). --- ## Dev local : avec ou sans données de seed Le projet distingue deux états de base de données de dev. Les **fixtures Doctrine sont en `require-dev`** : elles n'existent qu'en dev, jamais dans le build de prod. ### Sans données de seed (base vierge) C'est ce que produit `make install`. La base contient : - le **schéma** complet (toutes les migrations jouées) ; - les **rôles système** `admin` / `user` (seedés en SQL par la migration RBAC) ; - le **catalogue de permissions** synchronisé (`app:sync-permissions`). Mais **aucun compte utilisateur ni donnée métier**. Pour pouvoir te connecter, crée toi-même un compte : ```bash make shell php bin/console app:create-user admin monMotDePasse --admin # compte ROLE_ADMIN ``` Optionnel — provisionner les **rôles métier** (bureau / compta / commerciale / usine + matrice RBAC § 2.7) sans comptes de démo : ```bash php bin/console app:seed-rbac ``` Cet état est utile pour repartir d'une base propre, reproduire un bug sur données minimales, ou tester un parcours d'onboarding réel. ### Avec données de seed (base de démo) `make db-reset` (ou `make fixtures` après un `make install`) recharge la base de dev avec un jeu complet de données de démonstration, **idempotent** : ```bash make db-reset # ATTENTION : drop + recrée la base de dev, puis charge tout le seed ``` Ce que les fixtures posent : - **3 utilisateurs système** : `admin` (ROLE_ADMIN), `alice`, `bob` (ROLE_USER), rattachés à des sites distincts ; - **3 sites** : Chatellerault, Saint-Jean, Pommevic ; - **les comptes de démo RBAC métier** (`bureau`, `compta`, `commerciale`, `usine`, mot de passe `demo`) avec la matrice § 2.7 attachée ; - les **référentiels et données métier** des modules (catégories, clients de démo, référentiels comptables…). Toutes les fixtures sont rejouables sans effet de bord (lookup par clé naturelle, aucun doublon). > Différence avec `make install` : `install` ne charge **pas** les fixtures sur la base > de dev (il alimente uniquement la base de test). Utilise `make db-reset` ou > `make fixtures` quand tu veux des données de démo en dev. --- ## Comptes (dev) Disponibles uniquement après `make db-reset` / `make fixtures` (état « avec seed ») : | Username | Password | Rôle | RBAC métier | |---------------|----------|------------|---------------------------------------------------------------| | `admin` | `admin` | ROLE_ADMIN | bypass complet (`is_admin`) | | `alice` | `alice` | ROLE_USER | — | | `bob` | `bob` | ROLE_USER | — | | `bureau` | `demo` | ROLE_USER | clients : view + manage | | `compta` | `demo` | ROLE_USER | clients : view + accounting.view / manage | | `commerciale` | `demo` | ROLE_USER | clients : view + manage (Information obligatoire — RG-1.04) | | `usine` | `demo` | ROLE_USER | aucun accès clients | --- ## Bases de données : dev et test Deux bases distinctes vivent dans le **même container PostgreSQL** (port 5437) : | Base | Environnement | Construite par | Usage | |------------|---------------|--------------------------------------|--------------------------------| | `` | `dev` | `make install` / `make db-reset` | développement manuel, dev-nuxt | | `_test` | `test` | `make test-db-setup` | PHPUnit (jamais touchée à la main) | Le suffixe `_test` est appliqué **automatiquement** par Doctrine quand `APP_ENV=test` (config `when@test` dans `config/packages/doctrine.yaml`). La base de test est donc totalement **isolée** de la base de dev : lancer `make test` ne touche jamais tes données de dev. `make test-db-setup` fait davantage que jouer les migrations, car certaines structures ne sont pas portées par des migrations « métier » : 1. `doctrine:migrations:migrate` — schéma métier réel ; 2. `doctrine:schema:update --force` — crée les tables mappées en `when@test` uniquement (entités de test) ; 3. `app:apply-column-comments` — réapplique les `COMMENT ON COLUMN` que `schema:update` efface sur les tables managées par l'ORM (garde-fou `ColumnsHaveSqlCommentTest`) ; 4. `fixtures:load` → `sync-permissions` → `seed-rbac` — dans cet ordre précis (le purger des fixtures vide la table `permission`, donc la sync passe après) ; 5. recréation des **index partiels uniques** (`LOWER(...) WHERE ...`) non exprimables en attributs ORM, indispensables aux tests d'unicité (RG-1.07, RG-1.16, RG-1.03/1.29). `make install` et `make db-reset` appellent déjà `test-db-setup` : tu n'as à le relancer à la main que si la base de test diverge (nouvelle migration, nouvelle permission) sans vouloir reseed la base de dev. --- ## Tests | Suite | Commande | Outil | Où | |-------------------|------------------|----------------------|-----------------------------------| | Back | `make test` | PHPUnit | container PHP, base `_test` | | Front unitaire | `make nuxt-test` | Vitest (happy-dom) | container Node, < 30 s | | Front E2E | `make test-e2e` | Playwright | **hôte** (navigateur réel requis) | | Tout (back+front) | `make test-all` | PHPUnit + Vitest | — | ### Tests back (PHPUnit) ```bash make test # toute la suite make test FILES=tests/Module/Commercial # un dossier / fichier ciblé ``` PHPUnit force `APP_ENV=test` (`phpunit.dist.xml`) : les tests tournent **toujours** sur la base `_test`, jamais sur la base de dev. Prérequis : que la base de test existe — c'est le cas après `make install`. Si elle a divergé, rejoue `make test-db-setup` (cf. [Bases de données](#bases-de-données--dev-et-test)). ### Tests front unitaires (Vitest) ```bash make nuxt-test # composables, utils, stores — rapide et stable ``` C'est la **place par défaut** pour étendre la couverture (cf. règle d'or ci-dessous). ### Tests E2E (Playwright) Suite volontairement minimaliste (login + matrice RBAC sidebar). **Règle d'or : un nouveau test E2E ne s'ajoute que si un bug critique est passé en prod** — sinon, préférer un test Vitest ou étendre un persona existant. Bootstrap (une fois par poste) : ```bash make install-e2e-deps # télécharge Chromium + libs système (apt/dnf, sudo) ``` Workflow : ```bash # Terminal 1 — containers, seed des personas, serveur dev make start && make seed-e2e && make dev-nuxt # Terminal 2 — tests make test-e2e # headless make test-e2e-ui # UI interactive (debug) ``` > Toute permission testable touche **3 miroirs** à garder alignés : `config/sidebar.php`, > `frontend/tests/e2e/_fixtures/personas.ts`, `SeedE2ECommand.php`. --- ## Déploiement : seed RBAC en recette / prod Les fixtures Doctrine étant en `require-dev`, elles sont **absentes du build de prod**. Le RBAC métier (rôles `bureau` / `compta` / `commerciale` / `usine` + matrice § 2.7) est seedé par une **commande applicative idempotente**, jouée dans l'étape de release, **après** les migrations et la synchronisation des permissions : ```bash php bin/console doctrine:migrations:migrate --no-interaction php bin/console app:sync-permissions # pose les permissions (commercial.clients.*, …) php bin/console app:seed-rbac # PROD : rôles + matrice § 2.7 (sans comptes démo) ``` En **recette / staging**, ajouter le flag pour disposer de logins de test. Le mot de passe est fourni **explicitement** (jamais en dur, jamais committé) : ```bash php bin/console app:seed-rbac --with-demo-users --password='' # ou via la variable d'environnement RBAC_DEMO_PASSWORD ``` La commande est rejouable sans effet de bord (aucun doublon de rôle, de lien ou de compte). Pour créer un premier administrateur en prod : ```bash php bin/console app:create-user --admin ``` --- ## Commandes make `make` (sans argument) ou `make help` affiche l'aide colorée. Les principales : | Commande | Description | |--------------------------------|----------------------------------------------------------| | `make start` / `stop` / `restart` | Cycle de vie des containers | | `make install` | Install complet (base dev vierge + base de test) | | `make reset` | Tout supprimer et réinstaller (**drop la BDD**) | | `make dev-nuxt` | Serveur Nuxt hot reload (port 3004) | | `make shell` / `shell-root` | Shell bash dans le container PHP | | `make migration-migrate` | Jouer les migrations Doctrine | | `make fixtures` | Charger les fixtures (données de démo dev) | | `make sync-permissions` | Synchroniser le catalogue RBAC | | `make seed-rbac` | Seed RBAC métier (rôles + matrice § 2.7) | | `make db-reset` | Reset base dev : drop + migrate + fixtures + RBAC | | `make test-db-setup` | (Re)construire la base de test | | `make test` | PHPUnit (back) | | `make nuxt-test` | Vitest (front unitaire) | | `make test-all` | PHPUnit + Vitest | | `make test-e2e` / `test-e2e-ui`| Playwright (E2E, sur l'hôte) | | `make seed-e2e` | Seed des 6 personas E2E | | `make php-cs-fixer-allow-risky`| Fix du code style PHP | | `make php-cs-fixer-check` | Dry-run du fixer (CI / avant push) | | `make logs-dev` | Tail des logs Symfony | --- ## Architecture **Modular Monolith DDD** : chaque module est un bounded context autonome, activable / désactivable par tenant. Le backend est la seule source de vérité pour l'activation des modules et l'organisation de la sidebar. - `config/modules.php` — liste des modules actifs - `config/sidebar.php` — structure de la sidebar (sections + items avec module owner) - `GET /api/modules` — IDs des modules actifs (public) - `GET /api/sidebar` — sections filtrées par modules actifs + routes désactivées (public) **Désactiver un module** : commenter sa ligne dans `config/modules.php`, vider le cache. Ses items de sidebar disparaissent et ses routes sont bloquées par le middleware front. Le code reste dans le bundle (layer auto-détecté) → réactivation instantanée. **Réorganiser la sidebar** : éditer `config/sidebar.php` uniquement — le code des modules n'est pas touché. **Communication inter-modules** : jamais d'import direct d'un module à l'autre. Passer par `Shared/Domain/Contract/` (interfaces) ou des domain events. --- ## Structure du dépôt ``` src/ # Backend Symfony Shared/ # Noyau technique partagé (Domain/, Application/Bus/, Infrastructure/ApiPlatform/) Module/ Core/ # Module obligatoire (auth, users, RBAC) CoreModule.php # Déclaration (ID, LABEL, REQUIRED, permissions()) Domain/ Application/ Infrastructure/ Commercial/ Catalog/ Sites/ # Modules métier config/ modules.php # Source de vérité : activation sidebar.php # Source de vérité : navigation packages/ # Config Symfony (doctrine, api_platform, security…) migrations/ # Migrations d'initialisation (namespace racine : setup, RBAC, seed de base) frontend/ # App Nuxt 4 (SPA) app/ # Shell : layouts, middlewares (auth.global, modules.global) shared/ # Code inter-modules (composables, stores, utils, types) modules/ # Layers Nuxt auto-détectés (core/, commercial/…) i18n/locales/ # Traductions (sidebar.*, audit.entity.*, …) infra/ dev/ # Docker dev (Dockerfile, nginx, php.ini, xdebug, .env.docker) prod/ # Docker prod (multi-stage, nginx, php-prod.ini) .gitea/workflows/ # CI Gitea (auto-tag, build Docker) ``` --- ## CI/CD - **Auto Tag** : push sur `develop` → bump `config/version.yaml` → tag `vX.Y.Z` - **Build Docker** : push tag `v*` → build image multi-stage → push Gitea Registry Secrets requis dans Gitea : - `RELEASE_TOKEN` — PAT avec droits `write:repository` - `REGISTRY_TOKEN` — token pour le registry Docker --- ## Conventions ### Commits ``` () : ``` Espaces obligatoires autour du `:`. Types : `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`. ### Langue - UI et communication : **français** - Code (classes, méthodes, variables) : **anglais** - Commentaires (PHP, TS, Vue) : **français** > Règles détaillées : `CLAUDE.md` et `.claude/rules/`.