Aller au contenu principal

ENG-001.2 — Introduction des contrats inter-contextes

EpicEPIC-001 — Restructuration de DMV Core
MissionENG-001.2
TypeImplémentation
PrioritéP0
PR ciblePR-001
DépendanceENG-001.1 validé
StatutImplémenté
LivrableRapport 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 IdentityReader dè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

  • ActorReader
  • ActorWriter

Publication

  • PublicationReader
  • PublicationWriter

Monetization

  • SubscriptionManager
  • BoostManager

Territory

  • TerritoryReader

Municipal Management

  • MunicipalManagementReader
  • MunicipalManagementWriter

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, TerritoryService ou à des modèles Territory ;
  • Codex ne doit jamais improviser une implémentation vers MairieWriteService ou Territory.

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 CommunityWriter maintenant 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.