Mise en service des règles métier
Observer les droits, corriger, armer module par module ; poser des règles avec condition et gravité ; déclarer les champs sensibles ; lire les signaux de risque ; s’appuyer sur le copilote.
Cette page décrit la procédure de mise en service des règles métier et des droits sur un nouveau locataire, dans l’ordre où un consultant la suit : observer avant de bloquer, paramétrer condition et gravité plutôt que multiplier les types, déclarer ce qui doit être tracé, lire ce que le moteur de risque sait déjà, et laisser le copilote expliquer un refus dans le langage de l’utilisateur.
Droits : observer, corriger, armer
Deux réglages contrôlent l’application des droits : AUTH_GUARD_MODE pour les actions d’écriture et AUTH_GUARD_READ_MODE pour la lecture, chacun sur trois valeurs : off (aucun contrôle), observe (le refus est journalisé mais laissé passer) et enforce (le refus bloque réellement). Les deux valent off par défaut.
Étape 1 — observer : passer AUTH_GUARD_MODE=observe sur une période représentative et lire GET /api/v1/admin/auth-guard/observations, qui renvoie le mode courant, le mode lecture, les modules déjà armés, et un compte des refus qui seraient survenus, par module et par action.
Étape 2 — corriger : pour chaque refus qui apparaît, décider s’il s’agit d’un manque légitime (un rôle sans un droit qu’il devrait avoir) et corriger le rôle, ou d’un refus que le locataire veut réellement une fois armé.
Étape 3 — armer, module par module, via AUTH_GUARD_ENFORCE_MODULES, une liste partagée entre écriture et lecture — jamais tout d’un coup. Le volume de lecture observée est échantillonné (AUTH_GUARD_READ_LOG_SAMPLE, 100 par défaut) pour ne pas saturer les journaux.
Une fois armé, un refus de droit répond 403 avec le code droit_insuffisant — actionnable, contrairement à une simple erreur générique. Un module hors abonnement répond 404 : l’utilisateur ne sait même pas qu’il existe.
Les droits disent qui peut agir sur ce module ; une fois armés, un profil de statuts peut aller plus loin et dire qui peut faire passer ce document précis de tel statut à tel autre — en restreignant un graphe de transitions déjà codé, jamais en l’élargissant.
Condition et gravité
Restreindre une règle : la condition d’application
Toute règle, de tout type, peut porter une condition d’application, générique au niveau du registre — aucun type de règle n’a à la recoder. Une condition est { champ, op, valeur } ; plusieurs conditions se combinent par ET, sous la forme d’un objet condition unique ou d’une liste conditions dans params. Sans condition, la règle s’applique toujours dans sa portée.
La condition est évaluée sur l’état après écriture, complétée par une relecture de la ligne courante quand un champ de la condition manque au corps envoyé — un champ que le client n’a pas envoyé n’est pas forcément un champ vide. Quand la condition n’est pas remplie, la règle n’est même pas appelée : l’écriture passe.
Les opérateurs
| Opérateur | Signifie |
|---|---|
eq | est égal à |
ne | est différent de |
gt | est supérieur à |
gte | est supérieur ou égal à |
lt | est inférieur à |
lte | est inférieur ou égal à |
in | est parmi |
not_in | n’est pas parmi |
empty | est vide |
not_empty | n’est pas vide |
contains | contient |
Avertir puis bloquer : la gravité
Tout type de règle lit aussi un paramètre générique mode : bloquer (le défaut) ou avertir. En mode avertir, un refus est appliqué après l’appel de la règle — il est journalisé et compté, puis effacé : l’écriture passe quand même.
bloquer | Bloquer (refuse l’écriture) |
avertir | Avertir (journalise et laisse passer) |
Les avertissements sont comptés par règle (clé regle/<code>), lus aux côtés des observations de droits sur GET /api/v1/admin/auth-guard/observations — le même instrument, la même discipline : observer le compteur avant de durcir une règle d’avertir à bloquer.
{
"rule_type": "approbation_montant",
"scope_type": "tenant",
"params": {
"table": "purchase_orders",
"paliers": ["10000:2", "100000:3"],
"mode": "avertir",
"conditions": [
{ "champ": "warehouse_id", "op": "eq", "valeur": "WH-EST" }
]
}
}Champs sensibles
Chaque changement sur un champ déclaré sensible est journalisé : champ, ancienne valeur, nouvelle valeur, auteur et date. Le mécanisme s’appuie sur une table de déclaration (sensitive_fields) et une table de journal (field_changes), alimentées par un déclencheur générique — un champ nouvellement déclaré est journalisé sans code applicatif supplémentaire.
Un consultant déclare un champ additionnel à journaliser via la ressource sensitive-fields, sur l’écran Champs journalisés, à côté de Règles métier dans Paramètres → Système : choisir la table (fournisseurs, clients, articles, employés, profils, droits utilisateur) et le champ. Les valeurs bancaires (RIB, IBAN) restent masquées sauf les 4 derniers caractères. Un champ déclaré peut être désactivé sans perdre l’historique déjà écrit ; la lecture se fait dans l’onglet Historique de la fiche fournisseur, client ou article.
Signaux de risque
Un moteur dédié (internal/risk) calcule douze indicateurs — fiabilité fournisseur, délai article, disponibilité et pannes de poste, retards transporteur — chacun sur une fenêtre par défaut de 90 jours, paramétrable. Les seuils ne sont pas des constantes : le type couche 2 seuil_risque les paramètre par indicateur (attention, critique, fenetre_jours, echantillon_min), en portée locataire, fournisseur, article ou poste. Sans règle paramétrée, des seuils par défaut s’appliquent, et la réponse indique quelle source a répondu (seuil_source: defaut|tenant|…).
| Indicateur | Entité | Signifie |
|---|---|---|
supplier.otd | Fournisseur | réceptions à l’heure / réceptions totales |
supplier.retard_moyen_j | Fournisseur | retard moyen des réceptions en retard, en jours |
supplier.taux_nc | Fournisseur | non-conformités / réceptions |
supplier.note | Fournisseur | dernière note d’évaluation et son ancienneté |
article.delai_reel_vs_annonce | Article | écart entre délai réel et délai annoncé |
workstation.couverture_qualif | Poste | part des opérateurs affectés qualifiés au niveau requis |
employee.qualif_poste | Employé × poste | affecté, niveau requis, certification à jour ? |
workstation.pannes_90j | Poste | nombre de pannes sur la fenêtre |
workstation.mtbf_h | Poste | temps moyen entre pannes, en heures |
workstation.disponibilite | Poste | disponibilité moyenne du poste sur la fenêtre |
carrier.retard | Transporteur | part des livraisons en retard |
article.taux_nc | Article | non-conformités / ordres de fabrication terminés |
Chaque signal rend { code, valeur, unite, fenetre_j, n_echantillon, preuve[] } — la preuve est constituée de 3 à 5 documents à l’appui (numéro, date, écart), jamais un simple score. Un échantillon en dessous d’echantillon_min répond insuffisant, jamais un faux vert.
Points d’entrée : GET /api/v1/risks/{entite}/{id}?fenetre=90 pour une entité seule ; POST /api/v1/risks/evaluate pour une liste de nœuds du flow-designer avant sauvegarde ; GET /api/v1/risks/flow/{flowId}, /manufacturing-order/{id} et /affair/{id} pour la même évaluation sur un flux enregistré, un OF ou une affaire — qui renvoient les cinq problèmes les plus probables, triés critique d’abord. Mis en cache 15 minutes par (locataire, entité, identifiant, fenêtre).
Le copilote
Le copilote lit le même refus structuré ({ code, params, message }) qu’une règle produit, pour l’expliquer en langage courant et guider l’utilisateur vers la correction — changer la quantité reçue, choisir une autre période, demander une approbation. Le prompt le restreint à uniquement le contexte fourni : le copilote explique, il ne calcule pas ses propres chiffres.
Sur le flow-designer et sur une page d’affaire, la même liste d’alertes que calcule le moteur de risque est injectée dans le contexte du copilote — le même JSON que celui affiché par le panneau, rien de recalculé côté IA. Lui demander « pourquoi ce nœud est rouge » et il lit l’indicateur, le seuil franchi, et les documents à l’appui déjà renvoyés par le moteur.
La page dédiée au copilote va plus loin : « Pourquoi le dernier refus ? » sur n’importe quel écran, « Guide-moi » pour les trois procédures de bout en bout avec un stepper et « Faire pour moi », et ce que le copilote ne fait jamais.
← Retour à Règles métier et contrôle
Voir aussi : Catalogue des types · Packs par métier · Copilote · Profils de statuts