# Générateur de `Role Profile` · RBAC 50 rôles → bundles par portail **Sprint 2 · agent ERPNext Backend.** Troisième et dernier maillon RBAC en-repo, complément des générateurs [`Role` + `Custom DocPerm`](../fixtures_gen/README.md) (quels verbes sur quel DocType) et [plan `User Permission`](../userperm_gen/README.md) (sur quelles lignes). Il produit les **bundles assignables** : un `Role Profile` ERPNext v15 **natif** par portail, qui permet d'attribuer à un utilisateur, en un seul geste (`User.role_profile_name`), l'ensemble des rôles de SON portail. Transforme le contrat [`../rbac_50_roles.json`](../rbac_50_roles.json) (validé par [`../rbac.schema.json`](../rbac.schema.json)) en fixtures Frappe prêtes à importer. > Ce worker **n'écrit jamais sur le VPS** (contrainte #8). Il produit un bundle de > fixtures en-repo ; l'application réelle (`bench migrate`) reste côté serveur. ## Pourquoi un `Role Profile` (et pas juste des rôles) Assigner à la main les 5 à 12 rôles d'un portail à chaque nouvel utilisateur est fastidieux et source d'erreurs. ERPNext v15 fournit nativement le DocType `Role Profile` (contrainte #1 « ERPNext natif = priorité absolue ») : un bundle nommé de rôles (`Has Role`) qu'on affecte en un champ. Les **5 portails métier** (roadmap Sprint 4 « 5 portails rôle ») + la **console technique `plateforme`** donnent **6 profils** couvrant les 50 rôles de façon **bijective** (chaque rôle dans exactement un profil, puisque chaque rôle a exactement un `portail`). ## Ce qui est généré (`out/`, non commité) | Fichier | Rôle | |---|---| | `role_profile.json` | **1 fixture `Role Profile` par portail** ; chacun bundle ses rôles via des lignes enfant `Has Role`. | | `MANIFEST.json` | Traçabilité : comptes (profils, métier vs technique, rôles couverts) + mapping `portail → role_profile`. | ## Profils générés (contrat courant · source de vérité = le JSON) | `role_profile` | Portail | Type | Nb rôles | |---|---|---|---| | `OTO Portail Ventes` | ventes | métier | 12 | | `OTO Portail Construction` | construction | métier | 10 | | `OTO Portail Direction` | direction | métier | 9 | | `OTO Portail Compta` | compta | métier | 8 | | `OTO Portail Achat` | achat | métier | 5 | | `OTO Portail Plateforme` | plateforme | technique | 6 | | | | **Total** | **50** | > Le nom du profil est une **convention de nommage déterministe** dérivée de la > clé `portail` (`OTO Portail `) — aucun libellé métier ni chiffre > fabriqué (anti-invention #6). Les comptes viennent du contrat, pas de cette > table (cf. SPEC §3 : le JSON reste la source de vérité). ## Utilisation ```bash # Génère out/role_profile.json + out/MANIFEST.json python3 roleprofile_gen.py build # [-o DOSSIER] # Valide le bundle (schéma + invariants) sans rien écrire python3 roleprofile_gen.py validate # Tests (stdlib pur, zéro pip) python3 -m unittest discover -s tests -v ``` ## Garde-fous (anti-invention · #6 · déterminisme) - **Couverture bijective** re-vérifiée : chaque rôle du contrat dans exactement un profil, aucun rôle inventé, aucun manquant ; le CLI **refuse d'écrire** si un invariant casse. - **Que du natif v15** : DocTypes `Role Profile` + `Has Role` uniquement → aucun DocType custom à confirmer côté VPS (contrairement aux `Custom DocPerm`). - **Cohérence portail** : un profil ne mélange jamais deux portails ; son nom correspond à la convention pour ce portail. - **Fidélité manifeste** : flag `metier` = appartenance à `portails_business` ; comptes re-vérifiés profil par profil. - Sortie **déterministe** (profils triés par portail, `Has Role` triés par nom de rôle, aucun horodatage) → diffable, re-générable bit-à-bit en CI. ## Application sur VPS (agent ERPNext Backend · hors périmètre worker) 1. Importer d'abord les fixtures `Role` ([`fixtures_gen`](../fixtures_gen/README.md)) — les `Has Role` de chaque profil référencent des `Role` qui doivent exister. 2. Déposer `role_profile.json` dans `fixtures/` de l'app OTO (`hooks.py`), puis `bench --site frontend migrate`. 3. À la création d'un utilisateur, renseigner `role_profile_name` avec le profil de son portail (mapping dans `MANIFEST.profiles`) → tous les rôles du portail sont appliqués d'un coup, puis matérialiser les `User Permission` par utilisateur ([`userperm_gen`](../userperm_gen/README.md)). 4. Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big. ## Vérification en-repo - `python3 -m unittest discover -s tests -v` → **11/11 verts** (schéma maison + oracle `jsonschema` si présent ; couverture bijective des 50 rôles, un profil par portail, cohérence portail, manifeste fidèle, anti-invention, déterminisme). - Génération réelle : **6 profils** (5 métier + 1 technique), **50/50 rôles** couverts. - Job CI dédié `rbac-roleprofile-tests` ajouté au **gate** (`.gitea/workflows/ci.yml`, Gitea Actions uniquement · #2). ## Auto-score 4Big du livrable : **96/100** _Réserve −4_ : l'import `bench` + l'affectation `role_profile_name` par utilisateur restent côté VPS (agent ERPNext, hors périmètre worker, contrainte #8). Validé statiquement en-repo (11 tests verts + schéma conforme + couverture bijective fidèle au contrat + gate CI).