Ce projet utilise une architecture Domain-Driven Design (DDD) avec des Bounded Contexts pour organiser le code selon les domaines métier.
src/
├── SharedKernel/ # Code partagé entre tous les contextes
│ ├── Domain/ # Concepts partagés du domaine
│ │ └── Security/ # Ex: SecurityEventTypeEnum
│ ├── Infrastructure/ # Couches techniques partagées
│ └── Presentation/
│ └── Web/
│ ├── Controller/ # Controllers transversaux (ex: LogReaderController)
│ └── Resources/views/ # Templates transversaux (layout, base.html.twig)
│
└── BoundedContext/ # Contextes métier délimités
└── User/ # Contexte de gestion des utilisateurs
├── Domain/
│ ├── Entity/ # Entités métier (User, SecurityEvent, Group)
│ └── Repository/ # Interfaces des repositories
├── Infrastructure/
│ ├── Doctrine/ # Implémentations Doctrine
│ │ └── Repository/ # Repositories concrets
│ └── Admin/
│ └── Extension/ # Extensions Sonata Admin
├── Application/
│ └── Service/ # Services applicatifs
└── Presentation/
├── Admin/ # Classes Admin Sonata
├── Api/
│ └── Controller/ # API Controllers
├── Web/
│ └── Controller/ # Web Controllers
└── Resources/
└── views/ # Templates spécifiques au contexte User
- User Context : Gestion des utilisateurs, groupes, événements de sécurité
- VideoGamesRecords.Igdb Context : Intégration avec l'API IGDB pour les données de jeux vidéo
- Autres contextes peuvent être ajoutés (Product, Order, etc.)
- Contient les concepts partagés entre contextes
- Fonctionnalités transversales (logs, layouts admin)
- Éviter les duplications entre contextes
- Domain : Logique métier pure, entités, value objects
- Application : Orchestration, services applicatifs
- Infrastructure : Persistence, APIs externes
- Presentation : Controllers, vues, APIs
// Domain Layer
src/BoundedContext/User/Domain/Entity/User.php
src/BoundedContext/User/Domain/Entity/SecurityEvent.php
// Infrastructure Layer
src/BoundedContext/User/Infrastructure/Doctrine/Repository/UserRepository.php
src/BoundedContext/User/Infrastructure/Admin/Extension/SecurityEventStatisticsExtension.php
// Application Layer
src/BoundedContext/User/Application/Service/UserRegistrationService.php
// Presentation Layer
src/BoundedContext/User/Presentation/Admin/UserAdmin.php
src/BoundedContext/User/Presentation/Web/Controller/Admin/SecurityEventStatisticsController.php
src/BoundedContext/User/Resources/views/admin/security_statistics.html.twig// Domaine partagé
src/SharedKernel/Domain/Security/SecurityEventTypeEnum.php
// Infrastructure partagée
src/SharedKernel/Presentation/Web/Controller/LogReaderController.php
src/SharedKernel/Resources/views/base.html.twig
src/SharedKernel/Resources/views/admin/layout.html.twig// Domain Layer - Entités métier IGDB
src/BoundedContext/VideoGamesRecords/Igdb/Domain/Entity/Game.php
src/BoundedContext/VideoGamesRecords/Igdb/Domain/Entity/Genre.php
src/BoundedContext/VideoGamesRecords/Igdb/Domain/Entity/Platform.php
src/BoundedContext/VideoGamesRecords/Igdb/Domain/Entity/PlatformType.php
src/BoundedContext/VideoGamesRecords/Igdb/Domain/Entity/PlatformLogo.php
// Application Layer - Services et commandes d'import
src/BoundedContext/VideoGamesRecords/Igdb/Application/Service/IgdbImportService.php
src/BoundedContext/VideoGamesRecords/Igdb/Application/Command/ImportGamesCommand.php
src/BoundedContext/VideoGamesRecords/Igdb/Application/Command/ImportGenresCommand.php
// Infrastructure Layer - Client IGDB et repositories
src/BoundedContext/VideoGamesRecords/Igdb/Infrastructure/Client/IgdbClient.php
src/BoundedContext/VideoGamesRecords/Igdb/Infrastructure/Doctrine/Repository/GameRepository.php
src/BoundedContext/VideoGamesRecords/Igdb/Infrastructure/Client/Endpoint/PlatformTypeEndpoint.php
// Presentation Layer - Interfaces admin (lecture seule)
src/BoundedContext/VideoGamesRecords/Igdb/Presentation/Admin/GameAdmin.php
src/BoundedContext/VideoGamesRecords/Igdb/Presentation/Admin/GenreAdmin.php
src/BoundedContext/VideoGamesRecords/Igdb/Presentation/Admin/PlatformAdmin.phpLes templates sont organisés par namespace :
# config/packages/twig.yaml
twig:
paths:
'%kernel.project_dir%/src/SharedKernel/Resources/views': 'SharedKernel'
'%kernel.project_dir%/src/BoundedContext/User/Resources/views': 'User'Utilisation :
{# Template SharedKernel #}
{% extends '@SharedKernel/admin/layout.html.twig' %}
{# Template User Context #}
{% include '@User/admin/security_statistics.html.twig' %}- Chaque contexte est autonome
- Pas de dépendances directes entre contextes
- Communication via events ou services partagés
- Domain ne dépend de rien
- Application dépend du Domain
- Infrastructure dépend de Application et Domain
- Presentation dépend de Application
- Contextes : PascalCase (User, Product, Order)
- Couches : PascalCase (Domain, Infrastructure, etc.)
- Entités : Suffixe explicite (UserAdmin, SecurityEvent)
- Templates métier dans leur contexte
- Templates transversaux dans SharedKernel
- Utiliser les namespaces Twig appropriés
Pour ajouter un nouveau contexte (ex: Product) :
src/BoundedContext/Product/
├── Domain/
│ ├── Entity/
│ │ └── Product.php
│ └── Repository/
│ └── ProductRepositoryInterface.php
├── Infrastructure/
│ └── Doctrine/
│ └── Repository/
│ └── ProductRepository.php
├── Application/
│ └── Service/
│ └── ProductCatalogService.php
└── Presentation/
├── Admin/
│ └── ProductAdmin.php
└── Resources/
└── views/
└── admin/
└── product_list.html.twig
Puis ajouter le namespace Twig :
# config/packages/twig.yaml
'%kernel.project_dir%/src/BoundedContext/Product/Resources/views': 'Product'Chaque bounded context peut avoir sa propre documentation CLAUDE.md :
| Contexte | Documentation |
|---|---|
| VideoGamesRecords.Core | src/BoundedContext/VideoGamesRecords/Core/CLAUDE.md |
| VideoGamesRecords.Igdb | src/BoundedContext/VideoGamesRecords/Igdb/CLAUDE.md |
Le projet utilise Bootstrap 5 comme framework CSS. Toutes les interfaces doivent être stylées en utilisant exclusivement les classes Bootstrap.
-
NE PAS ajouter de CSS inline dans les templates Twig
{# MAUVAIS #} <div style="color: red; margin: 20px;">Contenu</div>
-
NE PAS ajouter de balises
<style>dans les templates{# MAUVAIS #} {% block stylesheets %} <style> .my-class { color: blue; } </style> {% endblock %}
-
NE PAS créer de fichiers SCSS personnalisés pour des pages spécifiques (sauf exception validée)
// MAUVAIS - Éviter de créer des fichiers comme _register.scss, _login.scss, etc.
-
Utiliser les classes Bootstrap pour tous les besoins de styling
{# BON #} <div class="text-danger mt-4">Contenu</div>
-
Utiliser les composants Bootstrap (cards, forms, alerts, etc.)
{# BON #} <div class="card shadow-sm"> <div class="card-body p-4"> <h1 class="card-title text-center mb-4">Title</h1> </div> </div>
-
Utiliser les utilitaires Bootstrap pour le spacing, les couleurs, la typographie, etc.
{# BON #} <div class="container py-5"> <div class="row justify-content-center"> <div class="col-md-6 col-lg-5"> <!-- Contenu --> </div> </div> </div>
Si un besoin de styling personnalisé est vraiment nécessaire et ne peut pas être résolu avec Bootstrap :
- Consulter d'abord s'il existe une classe utilitaire Bootstrap
- Documenter la raison de l'exception
- Ajouter le CSS dans
assets/styles/app.scss(pas dans les templates) - Utiliser une classe sémantique réutilisable
assets/
├── styles/
│ ├── config/
│ │ └── _variables.scss # Variables personnalisées
│ ├── utilities/
│ │ └── _base.scss # Styles de base globaux
│ ├── views/
│ │ └── _home.scss # Styles spécifiques (si vraiment nécessaire)
│ └── app.scss # Point d'entrée principal
Les formulaires Symfony utilisent automatiquement les thèmes Bootstrap :
# config/packages/twig.yaml
twig:
form_themes:
- 'bootstrap_5_layout.html.twig'Cela signifie que tous les formulaires générés avec form_widget(), form_label(), etc. utilisent déjà les classes Bootstrap.