---
description: 
globs: *.php,src/*
alwaysApply: false
---
# 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
}
```