Aller au contenu principal

ENG-001.5J — Migration des infos pratiques vers Municipal Management

MissionENG-001.5J — Préparer la migration des infos pratiques
Rattaché àENG-001.5 — Extraction de Municipal Management ; ENG-001.5 — Recalibrage roadmap ; ENG-001.5I — Rapport d'implémentation
Dépôtdmv-docs
TypeSpécification documentaire — aucune implémentation
Code applicatifAucun changement
StatutPréparation prête — décision 13.C résolue en faveur de Municipal Management

Cette mission prépare ENG-001.5J sans modifier le code. Elle cartographie l'état réel de commune_infos, documente tous les chemins de lecture et d'écriture, et formalise la décision 13.C désormais résolue sur commune_info_sections.

1. Objectif

Définir le périmètre exact de la migration des infos pratiques vers Municipal Management, en préservant :

  • les routes existantes ;
  • les payloads ;
  • les validations observables ;
  • les réponses JSON ;
  • les comportements publics et workspace ;
  • le rafraîchissement SIRENE existant.

2. État réel observé

2.1 Données concernées

commune_infos

Table observée :

  • id
  • commune_id
  • section
  • label
  • valeur
  • sub
  • icon
  • icon_color
  • href
  • ordre
  • created_at

Aucune autre colonne métier confirmée n'a été trouvée dans le schéma actuel :

  • pas de colonne de visibilité ;
  • pas de updated_at ;
  • pas de lien SQL vers commune_info_sections.

commune_info_sections

Voir l'audit dédié : ENG-001.5J — Audit d'ownership de commune_info_sections.

2.2 Rôle métier constaté

  • commune_infos porte le contenu pratique par commune.
  • commune_info_sections porte un catalogue global de rubriques, consommé uniquement par Admin.
  • la lecture publique Territory enrichit la section mairie avec des données Actor synthétiques ; elle n'est donc pas une simple projection brute de commune_infos.

3. Chemins de lecture et d'écriture

3.1 Lectures de commune_infos

Mairie

  • MairieReadService::listInfos(string $communeId)
  • MairieCommuneController::indexInfos()
  • réponse : ['infos' => ...]

Admin

  • AdminCommuneInfoController::fullCommune()
  • lecture ordonnée par section, puis ordre
  • réponse agrégée contenant sections et infos_by_section

Territory / Public

  • TerritoryService::getCommuneInfos(string $communeId)
  • TerritoryController
  • lecture ordonnée par section, puis ordre
  • fusion avec des infos synthétiques Actor pour la section mairie

3.2 Écritures de commune_infos

Mairie

MairieWriteService :

  • createInfo()
  • updateInfo()
  • deleteInfo()

Caractéristiques observées :

  • écriture directe SQL/Eloquent sur commune_infos ;
  • aucune validation Laravel dédiée dans la façade Mairie ;
  • valeurs par défaut appliquées dans le service.

Admin

AdminCommuneInfoController :

  • storeInfo()
  • updateInfo()
  • destroyInfo()

Caractéristiques observées :

  • validation Laravel explicite ;
  • CRUD complet ;
  • lecture de retour immédiate par id.

Territory / SIRENE

CommuneMairieDataRefreshService :

  • refreshInfos()
  • upsertInfo()

Caractéristiques observées :

  • flux externe réel confirmé ;
  • périmètre limité à la section identite ;
  • matching par triplet commune_id + section + label ;
  • mise à jour limitée principalement à valeur.

3.3 Lectures de commune_info_sections

  • AdminCommuneInfoController::indexSections()
  • AdminCommuneInfoController::fullCommune()

3.4 Écritures de commune_info_sections

  • AdminCommuneInfoController::storeSection()
  • AdminCommuneInfoController::updateSection()
  • AdminCommuneInfoController::destroySection()

3.5 Chemins confirmés

Les trois chemins attendus sont bien présents :

  • Mairie
  • Admin
  • Territory / SIRENE

Aucun quatrième chemin n'a été confirmé dans les imports, jobs ou commandes.

4. Consommateurs

4.1 dmv-workspace

Consommateurs confirmés :

  • services/mairie/infos.ts
  • pages workspace mairie/commune liées aux infos pratiques

Comportement observé :

  • CRUD complet sur les endpoints Mairie ;
  • sections reconstruites à partir des items commune_infos ;
  • aucun usage direct de commune_info_sections.

4.2 dmv-public

Consommateurs confirmés :

  • app/components/VilleDrawer.tsx
  • app/[commune]/acteur/[slug]/ActorsClient.tsx
  • composants publics liés au drawer commune

Comportement observé :

  • lecture publique /communes/{id}/infos ;
  • sections reconstruites côté frontend ;
  • filtres spécifiques pour éviter les doublons de données mairie déjà portées par Actor ;
  • aucun usage direct de commune_info_sections.

4.3 dmv-backoffice

Consommateur confirmé :

  • src/pages/Communes.jsx

Comportement observé :

  • consommation de sections + infos_by_section ;
  • CRUD complet sur /admin/communes/{id}/infos ;
  • CRUD complet sur /admin/commune-sections ;
  • mélange entre catalogue officiel et sections présentes dans les données.

5. Ownership de commune_infos

Constat

commune_infos relève du métier municipal :

  • données pratiques par commune ;
  • éditées par Mairie ;
  • éditées par Admin ;
  • partiellement réconciliées depuis une source externe dans Territory ;
  • lues publiquement via Territory.

Ownership cible

Municipal Management reste l'owner cible cohérent de commune_infos.

Conséquence

Mairie, Admin et Territory doivent devenir des adaptateurs :

  • Mairie pour la façade métier protégée ;
  • Admin pour la façade backoffice ;
  • Territory pour la réconciliation externe et la lecture publique.

6. Analyse de commune_info_sections

La décision 13.C est détaillée dans le document dédié : ENG-001.5J — Audit d'ownership de commune_info_sections.

Résumé opérationnel

  • ce n'est pas un simple détail frontend ;
  • ce n'est pas non plus une configuration transverse prouvée ;
  • c'est un référentiel global de rubriques des infos pratiques ;
  • il peut exister indépendamment de commune_infos ;
  • il est modifié uniquement par Admin ;
  • il n'est pas consommé directement par Workspace/Public.

7. Décision 13.C résolue

Question

Qui possède commune_info_sections ?

Options évaluées

  • A — Municipal Management
  • B — Settings / Platform Service
  • C — Séparation référentiel / affectation

Décision retenue

Option A — commune_info_sections appartient à Municipal Management, pour les raisons suivantes :

  • meilleure cohérence avec commune_infos ;
  • migration la plus simple et la plus réversible ;
  • aucun consommateur transverse réel observé ;
  • aucun besoin fonctionnel ne justifie un second contexte.

Effet sur ENG-001.5J

  • commune_info_sections entre dans le périmètre métier de Municipal Management ;
  • J1 couvre donc la lecture, les DTO et l'ownership de commune_infos et de commune_info_sections ;
  • J2 couvre les écritures Mairie/Admin des infos et des sections ;
  • J3 reste limité à la réconciliation Territory/SIRENE de commune_infos.

8. Contrats existants

MunicipalManagementReader

Capacité observée :

  • getInfos(string $communeId): Collection

État :

  • signature déjà présente ;
  • implémentation encore absente ou non active pour les infos pratiques dans l'état documenté préparatoire.

MunicipalManagementWriter

Capacités observées :

  • createInfo(string $communeId, array $data): MunicipalInfoDTO
  • updateInfo(string $communeId, string $infoId, array $data): MunicipalInfoDTO
  • deleteInfo(string $communeId, string $infoId): void

État :

  • signatures présentes ;
  • ne couvrent pas commune_info_sections ;
  • ne couvrent pas explicitement la réconciliation externe.

9. Contrats potentiellement manquants

9.1 Lecture des sections

Besoin :

Admin consomme un catalogue de sections distinct des infos.

Signature neutre proposée :

MunicipalManagementReader::getInfoSections(): Collection

Ownership visé :

  • Municipal Management si l'option A est retenue ;
  • sinon contexte à arbitrer.

9.2 Écriture des sections

Besoin :

Admin crée, modifie et supprime commune_info_sections.

Signatures neutres proposées :

MunicipalManagementWriter::createInfoSection(array $data): MunicipalInfoSectionDTO
MunicipalManagementWriter::updateInfoSection(string $sectionId, array $data): MunicipalInfoSectionDTO
MunicipalManagementWriter::deleteInfoSection(string $sectionId): void

Impact :

  • utile uniquement si l'option A est validée ;
  • sinon ces signatures n'appartiennent pas à Municipal Management.

9.3 Réconciliation externe des infos

Besoin :

Le flux SIRENE existe réellement pour la section identite.

Signature neutre proposée :

MunicipalManagementWriter::reconcileInfos(
string $communeId,
MunicipalInfosReconciliationDTO $data,
): MunicipalInfosReconciliationResultDTO

Ownership visé :

  • Municipal Management pour la logique de matching et de mise à jour ;
  • Territory conserve l'extraction externe et la construction du DTO.

9.4 Réordonnancement

Constat :

  • ordre existe sur commune_infos ;
  • aucun endpoint dédié de reorder n'est observé ;
  • l'ordre passe aujourd'hui par création/mise à jour standard.

Conclusion :

Pas de contrat de reorder dédié requis tant que le comportement observable reste inchangé.

10. Périmètre inclus

Si ENG-001.5J est lancée après arbitrage :

  • lecture commune_infos ;
  • écriture commune_infos depuis Mairie ;
  • écriture commune_infos depuis Admin ;
  • lecture publique conservée via Territory ;
  • réconciliation SIRENE des infos ;
  • commune_info_sections, la décision 13.C étant désormais validée en faveur de Municipal Management.

11. Hors périmètre

Restent explicitement hors périmètre :

  • communes.description
  • communes.image_url
  • communes.site_web
  • communes.email_contact
  • communes.telephone
  • tout changement frontend
  • toute migration SQL non strictement nécessaire à une future implémentation validée
  • toute modification d'ADR ou de RFC
  • toute fonctionnalité nouvelle sur les infos pratiques

12. Découpage proposé

Recommandation

Découper ENG-001.5J en trois PR logiques, plus sûres qu'une seule PR massive.

J1 — Fondation et lecture

  • confirmer l'ownership retenu ;
  • compléter DTO/contrats nécessaires ;
  • implémenter lecture commune_infos ;
  • implémenter lecture commune_info_sections seulement si l'option A est validée ;
  • brancher Mairie/Admin en lecture sans changer les réponses.

J2 — Écritures Mairie et Admin

  • création ;
  • modification ;
  • suppression ;
  • conservation de ordre ;
  • délégation Mairie et Admin vers le contrat.

J3 — Réconciliation Territory / SIRENE

  • déplacer la logique de matching/upsert de refreshInfos() ;
  • conserver Territory comme adaptateur d'entrée externe ;
  • garder les compteurs et le comportement historiques si des compteurs sont introduits.

Pourquoi ce découpage

  • chaque PR reste indépendante ;
  • chaque PR est testable ;
  • chaque PR est réversible ;
  • la décision 13.C est déjà levée avant les écritures ;
  • le flux externe SIRENE est isolé dans la PR la plus risquée.

13. Risques

  • divergence actuelle de validation entre Mairie, Admin et Territory ;
  • lecture publique enrichie par Actor sur la section mairie ;
  • absence de lien SQL fort entre commune_infos.section et commune_info_sections.slug ;
  • risque de sur-architecture si 13.C est envoyée vers Settings sans besoin prouvé ;
  • risque de régression backoffice si le catalogue de sections n'est pas migré avec son vrai owner.

14. Tests attendus

Une future implémentation devra au minimum couvrir :

  • lecture Mairie inchangée ;
  • lecture Admin fullCommune() inchangée ;
  • lecture publique Territory inchangée ;
  • CRUD Mairie inchangé ;
  • CRUD Admin inchangé ;
  • isolation inter-communes ;
  • ordre conservé ;
  • section conservée ;
  • compatibilité catalogue sections + infos_by_section ;
  • réconciliation SIRENE idempotente sur la section identite ;
  • garde-fous architecturaux empêchant toute écriture directe restante hors Municipal Management.

15. Critères d'acceptation

Pour considérer ENG-001.5J implémentée plus tard :

  • un seul owner applicatif de commune_infos ;
  • zéro écriture directe restante depuis Mairie, Admin ou Territory ;
  • réponses API inchangées ;
  • routes inchangées ;
  • payloads et validations observables inchangés ;
  • aucun frontend à modifier ;
  • décision 13.C reflétée explicitement dans l'ownership et les contrats.

16. Définition de Done

ENG-001.5J sera considérée terminée quand :

  • la décision 13.C restera appliquée explicitement ;
  • l'ownership choisi sera reflété dans les contrats et services ;
  • tous les chemins d'écriture auront été unifiés ;
  • les tests locaux et CI seront verts ;
  • les garde-fous d'architecture empêcheront toute régression ;
  • aucune modification hors périmètre n'aura été introduite.

17. Divergences et décisions requises

Divergences observées

  • Mairie n'applique pas la même validation qu'Admin ;
  • Territory écrit seulement une sous-partie (identite) avec une logique d'upsert spécifique ;
  • Public ne consomme pas le catalogue de sections ;
  • Admin consomme à la fois le catalogue et les sections réelles présentes dans les données.

Décisions requises

  1. Faut-il introduire un contrat de lecture/écriture des sections, l'ownership Municipal Management étant désormais acté ?
  2. Faut-il isoler la réconciliation SIRENE des infos dans une PR dédiée (recommandation : oui) ?
  3. Quelle règle de validation historique doit faire foi après unification quand Mairie et Admin divergent ?