# Coltura CRM/ERP. Monorepo Symfony 8 (API Platform 4) + Nuxt 4. **Architecture DDD (Domain-Driven Design).** ## Architecture DDD Le projet suit une architecture DDD cote backend ET frontend. Le code est organise par **domaine metier** (Bounded Context), pas par type technique. ### Backend — Organisation par domaine ``` src/ Domain/ # Couche domaine (logique metier pure, aucune dependance framework) {BoundedContext}/ # Ex: Customer, Sales, Catalog, Invoice... Entity/ # Entites et Aggregates du domaine ValueObject/ # Value Objects (Money, Address, Email...) Repository/ # Interfaces des repositories (ports) Service/ # Services domaine (logique metier) Event/ # Domain Events Exception/ # Exceptions metier Application/ # Couche application (cas d'usage, orchestration) {BoundedContext}/ Command/ # Commands (write) + Handlers Query/ # Queries (read) + Handlers DTO/ # Data Transfer Objects Infrastructure/ # Couche infrastructure (implementations techniques) {BoundedContext}/ Repository/ # Implementations Doctrine des repositories Persistence/ # Mapping Doctrine (si XML/YAML) Shared/ # Services techniques partages (mail, storage, etc.) Api/ # Couche API (exposition HTTP) {BoundedContext}/ Resource/ # ApiResource API Platform State/ # Providers & Processors API Platform ``` **Regles DDD backend :** - Le domaine (`Domain/`) ne depend de RIEN (pas de Doctrine, pas de Symfony, pas d'API Platform) - Les repositories dans `Domain/` sont des **interfaces** ; les implementations Doctrine sont dans `Infrastructure/` - Les entites API Platform (`Api/Resource/`) sont decouples des entites domaine si necessaire - Chaque Bounded Context est autonome — pas d'import croise entre contextes (communiquer via events ou services application) - `User` et `Auth` restent dans `src/` (hors DDD) car c'est du framework pur (Security Bundle) ### Frontend — Organisation par domaine ``` frontend/ domains/ # Modules metier {bounded-context}/ # Ex: customer, sales, catalog, invoice... components/ # Composants Vue specifiques au domaine composables/ # Composables specifiques au domaine services/ # Services API du domaine dto/ # Types TypeScript du domaine pages/ # Pages du domaine (optionnel, ou dans pages/) stores/ # Store Pinia du domaine (si necessaire) components/ # Composants UI partages (non lies a un domaine) composables/ # Composables partages (useApi, useAppVersion) stores/ # Stores globaux (auth, ui) services/ # Services partages ``` **Regles DDD frontend :** - Chaque domaine est un dossier autonome dans `frontend/domains/` - Un domaine ne doit pas importer depuis un autre domaine — utiliser les composables/stores partages - Les composants, services et types partages restent a la racine (`components/`, `composables/`, etc.) - Les pages peuvent etre dans `frontend/pages/` (routing Nuxt) et importer les composants du domaine ## Stack - **Backend** : PHP 8.4, Symfony 8.0, API Platform 4, Doctrine ORM, PostgreSQL 16 - **Frontend** : Nuxt 4 (SSR off / SPA), Vue 3, Pinia, Tailwind CSS, @malio/layer-ui, nuxt-toast, @nuxtjs/i18n, @nuxt/icon - **Auth** : JWT HTTP-only cookie (lexik/jwt-authentication-bundle), login a `/login_check`, cookie `BEARER` - **Docker** : PHP-FPM + Node 24, Nginx (port 8083), PostgreSQL (port 5436) ## Structure ``` src/ Domain/{Context}/Entity/ # Entites domaine Domain/{Context}/ValueObject/ # Value Objects Domain/{Context}/Repository/ # Interfaces repositories Domain/{Context}/Service/ # Services domaine Domain/{Context}/Event/ # Domain Events Application/{Context}/Command/ # Commands + Handlers Application/{Context}/Query/ # Queries + Handlers Application/{Context}/DTO/ # Data Transfer Objects Infrastructure/{Context}/Repository/ # Implementations Doctrine Api/{Context}/Resource/ # ApiResource API Platform Api/{Context}/State/ # Providers & Processors Entity/ # Entites framework (User) DataFixtures/ # Fixtures config/ # Config Symfony config/jwt/ # Cles JWT migrations/ # Migrations Doctrine infra/dev/ # Docker dev infra/prod/ # Docker prod (multi-stage) frontend/ domains/{context}/components/ # Composants du domaine domains/{context}/composables/ # Composables du domaine domains/{context}/services/ # Services API du domaine domains/{context}/dto/ # Types TS du domaine domains/{context}/stores/ # Store Pinia du domaine components/ # Composants UI partages composables/ # Composables partages (useApi, useAppVersion) stores/ # Stores globaux (auth, ui) pages/ # Pages (routing Nuxt) layouts/ # Layouts i18n/locales/ # Traductions ``` ## Commandes ```bash make start # Demarrer les containers make stop # Arreter les containers make restart # Redemarrer les containers make install # Install complet (composer, migrations, fixtures, build Nuxt) make reset # Tout supprimer et reinstaller (supprime la BDD) make dev-nuxt # Dev server Nuxt (hot reload, port 3003) make shell # Shell dans le container PHP make shell-root # Shell root dans le container PHP make cache-clear # Vider le cache Symfony make migration-migrate # Lancer les migrations make fixtures # Charger les fixtures make db-reset # Reset BDD + migrations + fixtures make test # PHPUnit make php-cs-fixer-allow-risky # Fix code style PHP make logs-dev # Tail logs Symfony ``` ## Conventions ### Commits Format : `() : ` (espace avant et apres `:`) Types autorises (minuscules) : `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test` Exemples : `feat : add login page`, `fix(auth) : prevent null token crash` ### Tags & Versioning - La version de l'app est dans `config/version.yaml` (parametre `app.version`) - A chaque creation de tag, **toujours** mettre a jour `config/version.yaml` avec la meme version - Faire un commit separe de bump : `chore : bump version to v` - Puis creer le tag et pusher : `git tag v && git push origin develop --tags` ### Backend - Toujours `declare(strict_types=1)` en haut des fichiers PHP - API Platform : utiliser ApiResource, Providers (`src/State/`), Processors — pas de controllers - Routes API prefixees `/api` (via `config/routes/api_platform.yaml`) - Le login (`/login_check`) est hors prefix `/api`, nginx reecrit `REQUEST_URI` vers `/login_check` - PHP CS Fixer : regles Symfony + PSR-12 + strict types - Roles : `ROLE_ADMIN`, `ROLE_USER` — hierarchie dans `security.yaml` - PostgreSQL : noms de colonnes toujours en **minuscules** dans le SQL brut - Controllers custom sous `/api/` : ajouter `priority: 1` sur `#[Route]` pour eviter le conflit avec API Platform `{id}` - Serialization : pour embarquer une relation (pas IRI), ajouter le groupe du parent aux proprietes de l'entite cible - Upload fichiers : utiliser `$file->getMimeType()` (pas `getClientMimeType()`) pour valider cote serveur ### Frontend - TypeScript strict - Composable `useApi()` pour tous les appels API (gere cookies, erreurs, toasts, i18n) - Stores Pinia : `useAuthStore` (auth), `useUiStore` (ui) - Middleware global `auth.global.ts` protege les routes - Traductions dans `frontend/i18n/locales/` - 4 espaces d'indentation ### Nginx - `/api/*` -> Symfony (via try_files + index.php) - `/api/login_check` -> location exact match, fastcgi direct avec REQUEST_URI reecrit en `/login_check` - `/` -> SPA frontend (`frontend/dist/`) ## Docker - Container PHP : `php-coltura-fpm` - Container Nginx : `nginx-coltura` - Container DB : PostgreSQL sur port **5436** (interne et externe) - Config Docker dev : `infra/dev/.env.docker` (override local : `infra/dev/.env.docker.local`) - Config Docker prod : `infra/prod/` (Dockerfile multi-stage, docker-compose.prod.yml) - Apres modif nginx : `docker restart nginx-coltura` ## Fixtures - User admin : `admin` / `admin` (ROLE_ADMIN) - Users internes : `alice` / `alice`, `bob` / `bob` (ROLE_USER)