ENG-001.2 — Introduction des contrats inter-contextes
| Epic | EPIC-001 — Restructuration de DMV Core |
| Mission | ENG-001.2 |
| Type | Implémentation |
| Priorité | P0 |
| PR cible | PR-001 |
| Dépendance | ENG-001.1 validé |
| Statut | Implémenté |
| Livrable | Rapport d'implémentation ENG-001.2 |
Objectif
Introduire les premiers contrats publics entre les Bounded Contexts sans modifier le comportement fonctionnel de l'application.
Cette mission constitue la fondation de toute la migration.
Aucune logique métier ne doit être modifiée.
Aucun comportement utilisateur ne doit changer.
Contexte
Le rapport ENG-001.1 montre que les modules communiquent principalement :
- par accès directs aux modèles ;
- par accès directs aux tables ;
- par appels de services internes ;
- sans frontière explicite.
Cette situation empêche :
- le respect de l'ownership ;
- l'introduction des événements métier ;
- le découplage des modules.
Objectifs techniques
Créer une première couche de contrats publics.
Chaque contexte devra progressivement exposer uniquement :
- Commands ;
- Queries ;
- Events, ultérieurement.
Les implémentations internes resteront inchangées.
Décisions d'architecture
ENG-001.2 n'a pas pour objectif de faire correspondre le code à un modèle théorique.
Le code réel et l'ownership effectif des Bounded Contexts priment toujours sur une abstraction souhaitée.
Certaines missions peuvent donc volontairement :
- reporter un contrat ;
- reporter une abstraction ;
- conserver provisoirement une dépendance directe ;
- utiliser un adaptateur transitoire explicitement nommé comme tel.
Ces choix sont autorisés lorsqu'ils évitent de figer une architecture provisoire.
Une abstraction ne doit jamais être créée uniquement pour satisfaire la documentation.
Un contrat public ne doit être créé que si :
- son contexte propriétaire existe clairement ;
- son ownership est établi ;
- sa signature n'expose pas Laravel, Eloquent, un Query Builder ou une table privée ;
- son implémentation actuelle peut être bindée sans changer le comportement.
Si l'une de ces conditions n'est pas remplie, le bon choix est de reporter le contrat ou de documenter un adaptateur temporaire.
Travail demandé
1. Définir l'organisation des contrats
Créer une convention unique pour tous les Bounded Contexts.
Exemple :
Modules/
Actor/
Contracts/
Publication/
Contracts/
Monetization/
Contracts/
Territory/
Contracts/
...
Aucun contrat métier ne doit vivre hors de son contexte.
2. Introduire les premières interfaces
Créer uniquement les interfaces.
Aucune logique.
Aucune implémentation.
Exemples :
Identity
IdentityReader
Contrat en lecture seule.
Identity fait explicitement partie de la première vague de PR-001.
Justification :
- Identity est aujourd'hui l'un des fournisseurs de lecture les plus consommés du backend ;
- plusieurs modules, Policies et services lisent directement les données Identity ;
- les profils, rôles globaux, informations de session et helpers comme
isAdmin()irriguent déjà la plupart des décisions d'accès ; - introduire
IdentityReaderdès PR-001 permettra de réduire progressivement ces dépendances directes sans modifier le comportement.
Ce contrat ne doit pas exposer le modèle Eloquent Profile.
Actor
ActorReaderActorWriter
Publication
PublicationReaderPublicationWriter
Monetization
SubscriptionManagerBoostManager
Territory
TerritoryReader
Municipal Management
MunicipalManagementReaderMunicipalManagementWriter
Ces noms sont des noms cibles, pas une obligation de création dans PR-001.
Nommage aligné sur celui déjà acté dans ADR-014, 28-dmv-core-bounded-context-map.md et
30-dmv-core-migration-roadmap.md — ne jamais raccourcir en « Municipal » dans le code ou la
documentation.
À la différence des autres contextes de cette liste, Municipal Management n'existe pas encore comme module.
Le rapport ENG-001.1 démontre que sa logique est aujourd'hui fragmentée entre :
Mairie, pour les alertes, services municipaux et certaines écritures brutes ;Territory, pour des modèles Eloquent liés aux élus, collectes et infos pratiques.
Il n'existe donc pas d'implémentation unique à laquelle lier MunicipalManagementReader ou MunicipalManagementWriter aujourd'hui.
Règles strictes pour PR-001 :
- aucun binding ne doit être créé vers un contexte inexistant ;
- aucun contrat ne doit figer l'architecture actuelle fragmentée ;
- aucun contrat Municipal Management ne doit être lié silencieusement à
MairieWriteService,MairieReadService,TerritoryServiceou à des modèles Territory ; - Codex ne doit jamais improviser une implémentation vers
MairieWriteServiceouTerritory.
Deux stratégies seulement sont autorisées :
Option A — adaptateur temporaire explicite.
Créer un adaptateur clairement nommé comme transitoire, documenté comme pont de migration et limité à une PR de transition.
Cette option doit expliquer précisément :
- pourquoi l'adaptateur existe ;
- quelles dépendances il encapsule provisoirement ;
- dans quelle mission il sera supprimé.
Option B — report du contrat.
Reporter la création des contrats Municipal Management à la mission de création effective du Bounded Context.
Cette option est préférée pour ENG-001.2, car elle évite de transformer la fragmentation actuelle Mairie / Territory en contrat public durable.
Si Option B est retenue, aucun fichier MunicipalManagementReader, MunicipalManagementWriter ou équivalent ne doit être créé dans PR-001.
La décision entre Option A et Option B doit être consciente, explicite et documentée dans le rapport d'implémentation.
Community
CommunityReader
CommunityWriter est volontairement absent de cette première vague.
Cette absence est une décision d'architecture.
Justification :
- le rapport ENG-001.1 identifie une violation autour de
contributors.can_publish; - cette donnée appartient au contexte Community ;
- l'écriture directe actuelle depuis Admin devra être supprimée plus tard ;
- créer un
CommunityWritermaintenant risquerait de figer trop tôt une capacité d'écriture qui doit être conçue avec l'ownership Community complet.
Le contrat CommunityWriter devra être introduit dans une mission ultérieure dédiée à la correction de cette violation, notamment pour remplacer l'écriture directe d'Admin dans contributors.can_publish.
Il ne doit pas être créé dans PR-001.
Rewards
RewardRecorder
3. Préparer l'injection de dépendances
Mettre en place les bindings nécessaires.
Les bindings ne sont autorisés que pour des contextes existants et des implémentations actuelles compatibles avec les contraintes de contrat public.
Un binding ne doit jamais être créé vers un contexte inexistant ou vers un service qui exposerait l'architecture fragmentée actuelle comme contrat durable.
Les implémentations actuelles continuent d'être utilisées.
Le comportement doit rester identique.
4. Aucun appel existant ne doit être supprimé
Cette PR prépare uniquement le terrain.
Les services continuent de fonctionner exactement comme aujourd'hui.
Hors périmètre
Ne pas :
- déplacer du code ;
- supprimer des dépendances ;
- introduire des Events ;
- modifier des tables ;
- modifier les contrôleurs.
Livrables
- Création de la couche
Contracts. - Bindings documentés.
- Contrats volontairement reportés documentés.
- Architecture prête pour les PR suivantes.
Critères d'acceptation
- Le projet compile.
- Aucun test ne casse.
- Aucun endpoint ne change.
- Aucun comportement fonctionnel ne change.
- Les interfaces sont documentées.
Définition de Done
Les Bounded Contexts possèdent désormais une couche de contrats publics.
Les futures PR pourront remplacer progressivement les appels directs par ces contrats, sans nouvelle restructuration.