Aller au contenu

Lot 0 bis, séquence L0-3 — Manifestes et gardes des modules

02/10/2026. Mise en œuvre de la séquence L0-3 du plan d’alignement, d’après la note d’amendement (AM-05). Décisions : EC-092 (précisé), EC-095 (en partie), EC-096, EC-097.

  • Chaque module a un manifeste dans le code : ses permissions, ses commandes, ses routes d’API et ses écrans. Chaque élément appartient à exactement un module, et les tests le vérifient.
  • Un module désactivé passe en lecture seule. L’API laisse lire ses données et refuse toute écriture (409 module_inactif).
  • Un fait du terrain n’est jamais rejeté. Une commande d’un module inactif à sa date d’opération est conservée et mise en contrôle module_inactif, sans écriture métier.
  • Le back-office masque les écrans d’un module jamais activé et marque « Lecture seule » ceux d’un module désactivé.
  • La synchronisation filtrée par module est faite en L1-5 (page).

packages/domain/src/modules/manifestes.ts est la source de vérité. Les tables app.module, app.module_dependance et app.module_activite la reflètent ; un test d’intégration compare les deux.

Module Permissions Commandes Routes et écrans
noyau utilisateurs, appareils, ensembles, paramétrage, modules.manage, review.resolve, dashboard.view – Synchronisation, identité, campagnes, produits, numérotation, certificats, conformité, contrats, activités et modules, file de contrôle
membres_foncier producer.*, plot.*, capacity.approve producteur.*, parcelle.* Groupements, producteurs (avec fusion), parcelles (avec polygone), capacités (avec validations)
collecte (requiert membres_foncier) collection.*, receipt.reprint, delivery.issue_note collecte.*, recu.reimprimer, livraison.etablir_bon –
sci (requiert membres_foncier) inspection.record, nonconformity.report, harvest.estimate inspection.enregistrer, non_conformite.constater, recolte.estimer –
intrants_avances input.issue intrant.remettre –
paiements (requiert collecte), planification, reception, preparation, commercialisation, eudr – – –

Les identifiants de permission restent en anglais : leur préfixe désigne un domaine, pas le code du module (EC-092 précisé).

GardeModule (apps/api/src/auth/module.ts) se place après la garde de permission, sur les contrôleurs du back-office et de l’identité.

  • La route est retrouvée dans le registre par sa méthode et son gabarit, puis rattachée à son module par le manifeste. Une route hors registre ou hors manifeste est une erreur de programmation.
  • GET est toujours permis. Une écriture sur un module inactif reçoit 409 { erreur: "module_inactif", details: { module } }, avant tout autre contrôle du service.
  • Le noyau n’est jamais gardé.
  • Au traitement d’une commande, après le contrôle des droits (étape 9), le serveur lit l’état du module à la date d’opération (app.module_actif_a).
  • Module inactif : motif module_inactif, rangé parmi les motifs sans écriture. La commande est conservée, la séquence avance, aucune entité n’est créée.
  • Levée : reprise_manuelle, par le support ou le RSCI, comme donnees_illisibles.
  • Un type de commande hors catalogue (le type technique de test) relève du noyau. Un gestionnaire ne peut pas changer le module d’un type du catalogue.
  • GET /v1/moi rend modules : les modules actifs, noyau compris, et ceux qui ont été désactivés (lecture_seule). Un module jamais activé est absent.
  • navigationVisible(permissions, modules) masque les écrans d’un module absent et marque « Lecture seule » ceux d’un module désactivé.
  • GET /v1/permissions rend aussi par_module, avec l’état de chaque module. Les ensembles par défaut ne changent pas : une organisation neuve n’a aucun module actif, et l’on ne vide pas ses ensembles.

db/migrations/20261002110000_lot0bis_l03_gardes.sql :

  • dépendance collecte → membres_foncier, refusée si une organisation a collecte actif sans membres_foncier ;
  • fonction app.module_actif_a(organisation, module, instant) ;
  • motif module_inactif dans la contrainte de sync.controle. La descente est refusée si un tel contrôle existe.

Contrat d’API 1.11.0 : modules dans Moi, par_module dans le catalogue des permissions, 409 module_inactif sur les écritures de Membres et foncier.

Test Ce qu’il vérifie
packages/domain/src/modules/manifestes.test.ts Chaque permission et chaque type de commande dans exactement un module ; codes uniques ; dépendances existantes et sans cycle ; rattachements EC-095 et EC-097
VT-MOD-016 à 021, VT-CTRL-018 et 019 Rattachements ; décision et effet bloquant de module_inactif
apps/api/src/openapi.test.ts Chaque route du registre appartient à un manifeste, et chaque route d’un manifeste existe
db/tests/l0bis-3.sql Dépendance collecte → membres_foncier appliquée par la base ; motif module_inactif accepté
apps/api/test/gardes-modules.test.ts Concordance des tables et des manifestes ; lecture permise et écriture refusée sur un module inactif ; moi et par_module ; commande en contrôle module_inactif sans écriture ; état apprécié à la date d’opération ; commande du noyau non concernée
apps/backoffice/src/mise-en-page/navigation.test.ts Écrans masqués sans module, visibles en lecture seule après désactivation

Le monde de test de l’API active Membres et foncier par défaut, comme le supposent les tests des producteurs, parcelles et capacités ; creerMonde({ modules: [] }) donne une organisation sans module.

Non vérifié dans le navigateur : la connexion au back-office de bout en bout n’est pas encore montée (aucun compte de développement dans Keycloak, réserve du journal).