feat: ajout de rules pour cursor
This commit is contained in:
parent
fe92e53be7
commit
19a697c712
210
.cursor/rules/architecture.mdc
Normal file
210
.cursor/rules/architecture.mdc
Normal file
@@ -0,0 +1,210 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
# Architecture Hexagonale de Mangarr
|
||||
|
||||
## Structure Générale
|
||||
L'application suit une architecture hexagonale (ports & adapters) avec une séparation claire des responsabilités. Le code métier est organisé en domaines distincts dans le dossier `src/Domain/`.
|
||||
|
||||
```
|
||||
src/
|
||||
└── Domain/
|
||||
├── Shared/ # Code partagé entre les domaines
|
||||
├── Manga/ # Domaine de gestion des mangas
|
||||
├── Reader/ # Domaine de lecture
|
||||
└── Scraping/ # Domaine de scraping
|
||||
```
|
||||
|
||||
## Organisation des Domaines
|
||||
Chaque domaine suit la même structure hexagonale :
|
||||
|
||||
```
|
||||
Domain/Manga/
|
||||
├── Domain/ # Cœur métier
|
||||
│ ├── Entity/ # Entités du domaine
|
||||
│ ├── ValueObject/ # Objets de valeur
|
||||
│ ├── Event/ # Événements du domaine
|
||||
│ └── Exception/ # Exceptions métier
|
||||
├── Application/ # Cas d'utilisation
|
||||
│ ├── Command/ # Commandes (DTO)
|
||||
│ ├── CommandHandler/# Gestionnaires de commandes
|
||||
│ ├── Query/ # Requêtes (DTO)
|
||||
│ ├── QueryHandler/ # Gestionnaires de requêtes
|
||||
│ └── Response/ # Objets de réponse (DTO)
|
||||
└── Infrastructure/ # Adaptateurs
|
||||
├── Repository/ # Implémentation des repositories
|
||||
├── Service/ # Services techniques
|
||||
└── Persistence/ # Persistence des données
|
||||
```
|
||||
|
||||
## Règles d'Architecture
|
||||
|
||||
### 1. Règles Générales
|
||||
- Tout le code métier doit résider dans le namespace `App\Domain`
|
||||
- Les dépendances externes doivent être limitées et explicitement autorisées
|
||||
- Les exceptions standards et utilitaires autorisés :
|
||||
- `DateTimeImmutable`
|
||||
- `RuntimeException`
|
||||
- `Exception`
|
||||
- `DomainException`
|
||||
- `Symfony\Component\HttpKernel\Exception`
|
||||
- `InvalidArgumentException`
|
||||
|
||||
### 2. Domaine Shared
|
||||
- Le domaine `Shared` ne doit dépendre d'aucun autre domaine
|
||||
- Il contient les contrats et les types partagés entre les domaines
|
||||
- Exemple : `App\Domain\Shared\Contract\UuidInterface`
|
||||
|
||||
### 3. Couche Domain
|
||||
- Ne doit dépendre que d'elle-même et du domaine Shared
|
||||
- Contient la logique métier pure
|
||||
- Ne doit pas avoir de dépendances externes
|
||||
- Structure des composants :
|
||||
- Les `Entity` sont les objets métier principaux
|
||||
- Les `ValueObject` sont immuables et s'auto-valident
|
||||
- Les `Event` représentent les changements d'état du domaine
|
||||
- Les `Exception` définissent les erreurs métier spécifiques
|
||||
|
||||
### 4. Couche Application
|
||||
- Peut dépendre de son propre domaine et du domaine Shared
|
||||
- Peut utiliser les dépendances externes autorisées :
|
||||
- `Symfony\Component\Messenger`
|
||||
- `Ramsey\Uuid`
|
||||
- Ne doit JAMAIS dépendre de la couche Infrastructure
|
||||
- Structure des composants :
|
||||
- Les `Query` sont des DTO (Data Transfer Objects) en lecture seule
|
||||
- Les `Command` sont des DTO pour les modifications
|
||||
- Les `QueryHandler` doivent :
|
||||
- Implémenter `QueryHandlerInterface`
|
||||
- Prendre une seule `Query` en paramètre
|
||||
- Retourner une `Response`
|
||||
- Les `CommandHandler` doivent :
|
||||
- Implémenter `CommandHandlerInterface`
|
||||
- Prendre une seule `Command` en paramètre
|
||||
- Ne pas retourner de valeur (void)
|
||||
- Les `Response` sont des DTO immuables pour les résultats de requêtes
|
||||
|
||||
### 5. Couche Infrastructure
|
||||
- Implémente les interfaces définies dans le domaine
|
||||
- Peut dépendre de toutes les couches de son domaine
|
||||
- Contient les adaptateurs pour les services externes
|
||||
- Structure des composants :
|
||||
- Les `Repository` implémentent les interfaces du domaine
|
||||
- Les `Service` fournissent des fonctionnalités techniques
|
||||
- La `Persistence` gère le stockage des données
|
||||
|
||||
## Flux de Dépendances
|
||||
```
|
||||
Infrastructure → Application → Domain
|
||||
↓ ↓ ↓
|
||||
External Shared Shared
|
||||
```
|
||||
|
||||
## Validation
|
||||
Les règles d'architecture sont validées par phparkitect. Les violations de ces règles entraîneront une erreur lors de la validation.
|
||||
|
||||
## Exemples de Code
|
||||
|
||||
### Domain Layer
|
||||
```php
|
||||
namespace App\Domain\Manga\Domain\Entity;
|
||||
|
||||
class Manga
|
||||
{
|
||||
private MangaId $id;
|
||||
private Title $title;
|
||||
private Description $description;
|
||||
|
||||
public function __construct(MangaId $id, Title $title)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->title = $title;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Application Layer
|
||||
```php
|
||||
namespace App\Domain\Manga\Application\Query;
|
||||
|
||||
readonly class GetMangaByIdQuery
|
||||
{
|
||||
public function __construct(
|
||||
public string $id
|
||||
) {}
|
||||
}
|
||||
|
||||
namespace App\Domain\Manga\Application\QueryHandler;
|
||||
|
||||
class GetMangaByIdQueryHandler implements QueryHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MangaRepositoryInterface $mangaRepository
|
||||
) {}
|
||||
|
||||
public function __invoke(GetMangaByIdQuery $query): MangaResponse
|
||||
{
|
||||
$manga = $this->mangaRepository->get($query->id);
|
||||
return new MangaResponse($manga);
|
||||
}
|
||||
}
|
||||
|
||||
namespace App\Domain\Manga\Application\Command;
|
||||
|
||||
readonly class CreateMangaCommand
|
||||
{
|
||||
public function __construct(
|
||||
public string $title,
|
||||
public ?string $description = null,
|
||||
) {}
|
||||
}
|
||||
|
||||
namespace App\Domain\Manga\Application\CommandHandler;
|
||||
|
||||
class CreateMangaCommandHandler implements CommandHandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private MangaRepositoryInterface $mangaRepository
|
||||
) {}
|
||||
|
||||
public function __invoke(CreateMangaCommand $command): void
|
||||
{
|
||||
$manga = Manga::create($command->title, $command->description);
|
||||
$this->mangaRepository->save($manga);
|
||||
}
|
||||
}
|
||||
|
||||
namespace App\Domain\Manga\Application\Response;
|
||||
|
||||
readonly class MangaResponse
|
||||
{
|
||||
public function __construct(
|
||||
public string $id,
|
||||
public string $title,
|
||||
public ?string $description
|
||||
) {}
|
||||
|
||||
public static function fromEntity(Manga $manga): self
|
||||
{
|
||||
return new self(
|
||||
$manga->getId()->toString(),
|
||||
$manga->getTitle()->value(),
|
||||
$manga->getDescription()?->value()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Infrastructure Layer
|
||||
```php
|
||||
namespace App\Domain\Manga\Infrastructure\Repository;
|
||||
|
||||
use App\Domain\Manga\Domain\Repository\MangaRepositoryInterface;
|
||||
|
||||
class DoctrineMangaRepository implements MangaRepositoryInterface
|
||||
{
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user