Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Backend: Domain/Application/Infrastructure/Api layers per bounded context.
Frontend: domains/{context}/ modules with isolated components/services/stores.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8.8 KiB
8.8 KiB
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 dansInfrastructure/ - 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)
UseretAuthrestent danssrc/(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, cookieBEARER - 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
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 : <type>(<scope optionnel>) : <message> (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(parametreapp.version) - A chaque creation de tag, toujours mettre a jour
config/version.yamlavec la meme version - Faire un commit separe de bump :
chore : bump version to v<X.Y.Z> - Puis creer le tag et pusher :
git tag v<X.Y.Z> && 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(viaconfig/routes/api_platform.yaml) - Le login (
/login_check) est hors prefix/api, nginx reecritREQUEST_URIvers/login_check - PHP CS Fixer : regles Symfony + PSR-12 + strict types
- Roles :
ROLE_ADMIN,ROLE_USER— hierarchie danssecurity.yaml - PostgreSQL : noms de colonnes toujours en minuscules dans le SQL brut
- Controllers custom sous
/api/: ajouterpriority: 1sur#[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()(pasgetClientMimeType()) 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.tsprotege 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)