From cc3e5aef0e49aad3f336ce04c48c5dff2f3fd625 Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Thu, 30 Jul 2026 02:05:54 +0000 Subject: [PATCH] =?UTF-8?q?[DTP-Worker]=20Sprint=202=20=C2=B7=20ERPNext=20?= =?UTF-8?q?RBAC=2050=20r=C3=B4les=20(sch=C3=A9ma=20+=20data=20+=20spec=20+?= =?UTF-8?q?=20gate)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Livrable Sprint 2 (roadmap §S2 l.38 « RBAC 50 rôles configuration », GAP_ANALYSIS §3.4). Seul deliverable S2 100% autorable en-repo — les clones Frontend/CRM dépendent des layouts LIVE (VPS). - rbac/rbac.schema.json — contrat JSON-Schema draft-07 (sous-ensemble validateur maison, zéro pip) : 50 rôles, DocPerm par DocType, scope User Permission. - rbac/rbac_50_roles.json — 50 rôles × 5 portails métier + console plateforme, mappés aux entités CLAUDE.md, ciblant des DocTypes ERPNext v15 natifs. - rbac/RBAC_50_ROLES_SPEC.md — design RBAC 3 niveaux + séparation des pouvoirs + procédure d'application VPS (fixtures bench, hors périmètre worker). - rbac/tests/test_rbac.py — 10 tests unittest (réutilise le validateur Publiciste, pas de doublon) : 50 rôles exacts, unicité, 5 portails, anti- élévation de privilège. Oracle jsonschema si présent. - ci.yml — job rbac-tests ajouté au gate (Gitea Actions uniquement). - GAP_ANALYSIS §3.4 + daily report 2026-07-30 (session 4) mis à jour. Anti-invention #6 : aucun plafond monétaire inventé ; DocTypes non natifs marqués custom → à confirmer VPS. Gate local vert (guard/json/docs + 10 tests RBAC + 23 tests Publiciste régression). Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitea/workflows/ci.yml | 17 +- 05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md | 6 +- .../daily_reports/2026-07-30.md | 46 + 05_deliverables_mvp/rbac/.gitignore | 5 + .../rbac/RBAC_50_ROLES_SPEC.md | 152 ++++ 05_deliverables_mvp/rbac/rbac.schema.json | 121 +++ 05_deliverables_mvp/rbac/rbac_50_roles.json | 832 ++++++++++++++++++ 05_deliverables_mvp/rbac/tests/test_rbac.py | 116 +++ 8 files changed, 1291 insertions(+), 4 deletions(-) create mode 100644 05_deliverables_mvp/rbac/.gitignore create mode 100644 05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md create mode 100644 05_deliverables_mvp/rbac/rbac.schema.json create mode 100644 05_deliverables_mvp/rbac/rbac_50_roles.json create mode 100644 05_deliverables_mvp/rbac/tests/test_rbac.py diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 2b551ca..3d8ef1c 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -59,10 +59,25 @@ jobs: - name: Tests unitaires Publiciste run: python3 -m unittest discover -s tests -v + # -------------------------------------------------------------------------- + # RBAC 50 rôles (Sprint 2 · ERPNext Backend) : contrat rbac_50_roles.json vs + # rbac.schema.json. Réutilise le validateur maison Publiciste (pas de pip). + # -------------------------------------------------------------------------- + rbac-tests: + name: RBAC · 50 rôles + schéma (unittest) + runs-on: ubuntu-latest + defaults: + run: + working-directory: 05_deliverables_mvp/rbac + steps: + - uses: actions/checkout@v4 + - name: Tests contrat RBAC + run: python3 -m unittest discover -s tests -v + gate: name: Gate qualité (agrégat) runs-on: ubuntu-latest - needs: [constraints-guard, validate-json, check-docs, publiciste-tests] + needs: [constraints-guard, validate-json, check-docs, publiciste-tests, rbac-tests] steps: - name: Résultat run: echo "✅ Gate qualité 4Big franchi — tous les checks verts." diff --git a/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md b/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md index 4dd871e..3886750 100644 --- a/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md +++ b/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md @@ -83,9 +83,9 @@ et la cible plancher **4-5 semaines**. ### 4 · ERPNext Backend Agent — 🟡 Refactor (gain ~35 %) - **Existe** : site `frontend` (`erpnext-backend-1`), apps `otov7_platform` + `otov7_construction` + `erpnext` v15.112 + `frappe` v15.112, modules `crm/ crm_native/ api/ config/ audit_console.py`. -- **Gap** : RBAC 50 rôles non configuré ; e-CF DGII (Compupar) non intégré ; commissions vendeurs auto absentes ; DocType « Faisabilité » (version + score) manquant. -- **À faire** : cartographie DocTypes (⚠ à confirmer VPS) → RBAC 50 rôles → e-CF → workflows. -- **Sprint** : S2 (RBAC) → S4 (e-CF + commissions). +- **Gap** : ~~RBAC 50 rôles non configuré~~ → **design livré S2** (`rbac/` : `rbac_50_roles.json` + `rbac.schema.json` + spec + 10 tests) ; application fixtures = VPS ; e-CF DGII (Compupar) non intégré ; commissions vendeurs auto absentes ; DocType « Faisabilité » (version + score) manquant. +- **À faire** : cartographie DocTypes (⚠ à confirmer VPS) → ✅ RBAC 50 rôles (design) → application fixtures VPS → e-CF → workflows. +- **Sprint** : S2 (RBAC ✅ design) → S4 (e-CF + commissions). ### 5 · Frontend Console Agent — 🟡 Refactor (gain ~55 %) - **Existe** : `portal/*.html`, pages Frappe `www/` (wag-home, waf-home, pole/, projets/), tokens luxury `#0a0a12`/`#f0b429` (Fraunces + Cormorant Garamond), 5 logos officiels. diff --git a/05_deliverables_mvp/daily_reports/2026-07-30.md b/05_deliverables_mvp/daily_reports/2026-07-30.md index 5f2ede3..918f00e 100644 --- a/05_deliverables_mvp/daily_reports/2026-07-30.md +++ b/05_deliverables_mvp/daily_reports/2026-07-30.md @@ -139,3 +139,49 @@ Rapport écrit dans `05_deliverables_mvp/daily_reports/` (chemin canonique fixé --- **Auto-score 4Big du livrable Publiciste (parser) : 95/100.** Réserve −5 : exécution contre `data_room/` réel différée (VPS) ; triggers/notifications/EN-ES = livrables Semaines 4-6 ; validé statiquement en-repo (23 tests verts + gate CI vert + schéma conforme). + +--- + +# Daily Report · 2026-07-30 · Claude Code DTP Worker (session 4) + +**Session** : `20260730_015634` + +## Tâche exécutée +**Sprint 2 · Livrable ERPNext Backend « RBAC 50 rôles »** +(roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` §Sprint 2 l.38 · `GAP_ANALYSIS_SPRINT1` §3.4 · suggérée par session 3). + +## Contexte / analyse +- Relu `CLAUDE.md`, `ROADMAP_8_WEEKS_OR_LESS.md`, `GAP_ANALYSIS_SPRINT1.md`, daily reports sessions 1-3, `AGENT.md` ERPNext Backend + Frontend Console, `AGENTS_EXISTING_ASSETS.md` §4-6, `projets_master.schema.json`, `validator.py`, `ci.yml`. +- **Sprint 1 bouclé côté repo** ; Sprint 2 : 3 deliverables. Frontend (clone 5 entités) + CRM (pipeline) dépendent des layouts LIVE `/waf-home` / `/crm.html` (VPS). **RBAC 50 rôles = seul deliverable S2 100 % autorable en-repo** comme spec de conception machine-lisible → priorité évidente. Dépendance amont des 5 portails rôle (S4) et du workflow vente. + +## Réalisé — module `05_deliverables_mvp/rbac/` +- `rbac.schema.json` — contrat JSON-Schema draft-07 (sous-ensemble supporté par le validateur maison, **zéro pip**) : 50 rôles, `id` kebab, `erpnext_role_name` préfixe `OTO `, `permissions_cibles[]` (DocType + verbes Frappe), `scope_donnees` (own/equipe/entite/groupe), `cible_rbac_roles` const 50. +- `rbac_50_roles.json` — **50 rôles** répartis sur 5 portails métier (roadmap S4) + 1 console technique (`plateforme`), mappés aux **entités CLAUDE.md** (WAF/WA SRL/AC Arias Cuevas/Consortium ECR DR/Helios RD/Ploutos/9060 QC/Groupe). Permissions ciblant des **DocTypes ERPNext v15 natifs** (Lead/Opportunity/Quotation/Sales Order/Purchase Order/Journal Entry/Salary Slip…) + DocTypes DTP marqués `custom: true` (à confirmer VPS). +- `RBAC_50_ROLES_SPEC.md` — design : modèle RBAC 3 niveaux (Role · DocPerm · User Permission), cartographie portails/familles/entités, conformité contraintes #1/#3/#6/#8, **séparation des pouvoirs** (`set_user_permissions` réservé au RBAC Admin), procédure d'application VPS (fixtures `bench`, hors périmètre worker). +- `tests/test_rbac.py` — **10 tests `unittest` (stdlib)** : **réutilise le validateur Publiciste** (pas de duplication · workflow #5) + oracle `jsonschema` si présent ; vérifie exactement 50 rôles, unicité `id`/nom Frappe, couverture des 5 portails, anti-élévation de privilège. +- **CI** : job `rbac-tests` ajouté au **gate** de `.gitea/workflows/ci.yml` (Gitea Actions uniquement · #2). +- `GAP_ANALYSIS_SPRINT1.md` §3.4 mis à jour (RBAC design livré S2). + +## Anti-invention (#6) appliqué +- **Aucun chiffre/plafond monétaire inventé** : seuls rôles, entités et DocTypes natifs. Plafonds d'approbation volontairement non chiffrés (à définir avec la Direction sur pièces). +- DocTypes non natifs marqués `custom: true` → **existence à confirmer VPS** avant application (respect de l'interdit « documenter code sans vérifier existence courante »). + +## Vérifications effectuées (en-repo, sans toucher au VPS) +- **10/10 tests RBAC verts** (schéma maison **+** oracle `jsonschema` installé → concordance draft-07 confirmée). +- **Gate CI local vert (exit 0)** : `guard_constraints.sh`, `validate_json.sh` (inclut `rbac_50_roles.json`), `check_docs.sh` (0 lien cassé ; spec RBAC porte son auto-score 4Big). +- **Régression** : 23/23 tests Publiciste toujours verts (réutilisation du validateur sans effet de bord). + +## Non fait (hors périmètre worker · touche au VPS) +- Génération + application des **fixtures `Role`/`Custom DocPerm`** sur `erpnext-backend-1` (`bench migrate`) → agent ERPNext Backend. +- Création des DocTypes DTP `custom` (`Faisabilité`, `Publiciste Log`, `CONFOTUR Application`, `API Access`) après confirmation VPS. +- Mapping `scope_donnees` → `User Permission` par utilisateur → VPS. +- Cartographie DocTypes réels `otov7_platform` (dernier critère S1) → ERPNext sur VPS. + +## Prochaine tâche suggérée +- ERPNext S2 : **générateur de fixtures** `rbac_50_roles.json → fixtures/` (même patron que le Publiciste, autorable en-repo). +- Ou Faisabilité S2 : générateur 4 volets auto consommant le template v1.0 (produit les `data_room/PXX/` consommés par le parser Publiciste). +- Ou Frontend/CRM S2 : nécessite les layouts LIVE (VPS) → hors périmètre worker. + +--- + +**Auto-score 4Big du livrable RBAC 50 rôles : 95/100.** Réserve −5 : application fixtures + DocTypes `custom` + `User Permission` = côté VPS (agent ERPNext, hors périmètre) ; plafonds monétaires non chiffrés (anti-invention #6). Validé statiquement en-repo (10 tests verts + schéma conforme + gate CI vert). diff --git a/05_deliverables_mvp/rbac/.gitignore b/05_deliverables_mvp/rbac/.gitignore new file mode 100644 index 0000000..f6faf9d --- /dev/null +++ b/05_deliverables_mvp/rbac/.gitignore @@ -0,0 +1,5 @@ +# Artefacts Python (jamais commit — reproductibles). +__pycache__/ +*.pyc +# Fixtures Frappe générées côté VPS (hors périmètre worker). +fixtures/ diff --git a/05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md b/05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md new file mode 100644 index 0000000..9239869 --- /dev/null +++ b/05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md @@ -0,0 +1,152 @@ +# Spec RBAC · 50 rôles · OTO Enterprise OS DTP + +> **Livrable Sprint 2 · ERPNext Backend** (roadmap +> [`../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md`](../../04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md) +> §Sprint 2 l.38 : _« ERPNext Backend : RBAC 50 rôles configuration »_ · +> [`../GAP_ANALYSIS_SPRINT1.md`](../GAP_ANALYSIS_SPRINT1.md) §3.4 gap ERPNext). +> +> **Date** : 2026-07-30 · **Auteur** : Claude Code DTP Worker · **Version** : 1.0.0 + +--- + +## 1. Objet + +Design **machine-lisible** des **50 rôles RBAC** (contrainte CLAUDE.md « RBAC 50 rôles ») +à créer nativement dans Frappe/ERPNext v15. Le contrat de données est +[`rbac.schema.json`](rbac.schema.json) ; les données sont +[`rbac_50_roles.json`](rbac_50_roles.json). Ce document ne touche **jamais la +production** : il définit la **cible** que l'agent ERPNext Backend appliquera sur +le VPS via `bench` / fixtures (voir §7). + +**Priorité ERPNext natif** (contrainte #1) : chaque rôle est un DocType `Role` +Frappe standard — **aucun** RBAC externe. +**CRM = ERPNext natif** (jamais EspoCRM ni HubSpot — contrainte #3). + +## 2. Modèle RBAC + +Le RBAC Frappe combine trois niveaux, tous couverts par le schéma : + +| Niveau Frappe | Champ du schéma | Rôle | +|---|---|---| +| **Role** (DocType) | `erpnext_role_name` | Un DocType `Role` par ligne, préfixe `OTO ` (anti-collision natif). | +| **Permissions par DocType** | `permissions_cibles[]` | Verbes Frappe (`read`/`write`/`create`/`submit`/`cancel`/`report`/…) par DocType. | +| **Row-level** (User Permission) | `scope_donnees` | `own` · `equipe` · `entite` (Company) · `groupe` (consolidé). | + +**Défense en profondeur** : le pouvoir `set_user_permissions` (gestion des +habilitations) est **réservé** au seul rôle `OTO Plateforme RBAC Admin` +(`scope_donnees = groupe`, `famille = plateforme`) — séparation des pouvoirs +vérifiée par test automatisé. + +## 3. Cartographie portails ↔ familles + +Les **5 portails métier** (roadmap Sprint 4 « 5 portails rôle ») + **1 console +technique transversale** (`plateforme`, hors du compte de 5) : + +| Portail | Familles rattachées | Nb rôles | +|---|---|---| +| **direction** | direction, finance (CFO), faisabilite (analyste), legal | 10 | +| **ventes** | ventes, marketing | 12 | +| **construction** | construction, faisabilite (rendu/IFC/économiste) | 10 | +| **achat** | achat | 5 | +| **compta** | finance | 8 | +| **plateforme** _(technique)_ | plateforme | 5 | +| | **Total** | **50** | + +> Répartition indicative issue de `rbac_50_roles.json` ; la source de vérité reste +> le JSON (le test impose exactement 50 rôles et la couverture des 5 portails). + +## 4. Cartographie rôles ↔ entités (CLAUDE.md §Entités) + +Chaque rôle porte une `entite_principale`. « Groupe » = périmètre consolidé +transversal (direction, contrôle de gestion, audit UAF, BI). + +| Entité | Exemples de rôles | +|---|---| +| **WAF** (holding) | Président, Directeur Juridique, Agent ONAPI | +| **WA SRL** | Contrats de vente, Achats, Comptable général, Fiscaliste e-CF, Analyste faisabilité | +| **AC Arias Cuevas** | Directeur/Chef de projet Construction, Ingénieur, Économiste, Magasinier | +| **Consortium ECR DR** (paymaster RH) | Gestionnaire Paie | +| **Helios RD** (marque publique) | Directeur des Ventes, Conseiller, Marketing, Comptable clients AR | +| **Ploutos** (patrimoine/monétaire) | Trésorier | +| **9060 QC** (World Activities Cdn.) | DevOps, RBAC Admin, QA, OTOIA, Mobile | +| **Groupe** (consolidé) | DG, CFO, COO, CCO, Conseil, Contrôle de gestion, Audit UAF, BI | + +## 5. Les 50 rôles (résumé) + +> Détail complet (permissions par DocType, modules, scope) dans +> [`rbac_50_roles.json`](rbac_50_roles.json). + +**Direction / Gouvernance (6)** — Président WAF · Directeur Général · CFO · COO · +CCO · Conseil d'Administration (lecture). + +**Ventes (8)** — Directeur des Ventes · Chef d'Équipe · Conseiller · Courtier +externe · Coordinateur Réservations · Gestionnaire Contrats · Coordinateur +CONFOTUR · Support Après-Vente. + +**Marketing (4)** — Directeur Marketing · Publiciste (agent) · SEO · Social. + +**Construction (7)** — Directeur · Chef de Projet · Ingénieur · Architecte · +QA/QC · Coordinateur BIM · Superviseur Sous-traitants. + +**Achat (5)** — Directeur · Acheteur · Gestionnaire Fournisseurs · Magasinier · +Contrôleur Réception. + +**Finance / Compta (8)** — Contrôleur de Gestion · Comptable Général · AP · AR · +Trésorier (Ploutos) · Paie (Consortium ECR DR) · Fiscaliste e-CF · Audit UAF. + +**Faisabilité / AEC (4)** — Analyste Faisabilité · Rendu 3D · IFC/Speckle · +Économiste de la Construction. + +**Legal (2)** — Directeur Juridique · Agent ONAPI. + +**Plateforme technique (6)** — DevOps · RBAC Admin · QA · OTOIA (système) · +Mobile · BI. + +_(6+8+4+7+5+8+4+2+6 = 50.)_ + +## 6. Conformité aux contraintes CLAUDE.md + +| # | Contrainte | Application ici | +|---|---|---| +| 1 | ERPNext natif prioritaire | 100 % DocType `Role` Frappe, aucun RBAC externe. | +| 3 | CRM = ERPNext natif | Rôles ventes → `Lead`/`Opportunity`/`Quotation`/`Customer` natifs. | +| 6 | Zéro invention | Aucun chiffre/plafond monétaire inventé ; seuls rôles, entités et DocTypes natifs (+ DocTypes DTP marqués `custom` à confirmer VPS). | +| 8 | VPS pour tous projets | Application des fixtures = VPS (§7), jamais local. | +| — | Séparation des pouvoirs | `set_user_permissions` réservé au RBAC Admin (test). | + +**DocTypes `custom: true`** (`Faisabilité`, `Publiciste Log`, `CONFOTUR +Application`, `API Access`) = DocTypes DTP **à créer** — existence **à confirmer +VPS** par l'agent ERPNext avant application (cohérent avec l'interdit « documenter +du code sans vérifier l'existence courante »). + +## 7. Application sur VPS (hors périmètre worker) + +Ce worker n'écrit **jamais** sur le VPS. L'agent ERPNext Backend appliquera la +cible côté serveur (`erpnext-backend-1`) : + +1. Générer les fixtures `Role` + `Custom DocPerm` depuis `rbac_50_roles.json`. +2. `bench --site frontend migrate` pour installer les rôles. +3. Créer les DocTypes DTP `custom` manquants (§6) **après** confirmation. +4. Mapper les `scope_donnees` en `User Permission` par utilisateur. +5. Vérification HTTP post-déploiement (workflow #3) + audit QA 4Big. + +> Un **générateur de fixtures** `rbac_50_roles.json → fixtures/` est le prochain +> incrément (branchable sur le même patron que le Publiciste) ; il reste autorable +> en-repo sans toucher au VPS. + +## 8. Vérification (en-repo, sans toucher au VPS) + +- `python3 -m unittest discover -s tests -v` → **10/10 verts** (schéma maison + + oracle `jsonschema`, 50 rôles, unicité, couverture 5 portails, séparation des + pouvoirs). +- `rbac_50_roles.json` : JSON strict valide (couvert par `ci/validate_json.sh`). +- Job CI dédié `rbac-tests` ajouté au **gate** (`.gitea/workflows/ci.yml`, + Gitea Actions uniquement · #2). + +## 9. Auto-score 4Big du livrable : **95/100** + +_Réserve −5_ : application des fixtures + création des DocTypes `custom` + +mapping `User Permission` = côté VPS (agent ERPNext, hors périmètre worker) ; +plafonds d'approbation monétaires par rôle volontairement **non chiffrés** ici +(anti-invention #6 — à définir avec la Direction sur pièces). Validé statiquement +en-repo (10 tests verts + schéma conforme + gate CI). diff --git a/05_deliverables_mvp/rbac/rbac.schema.json b/05_deliverables_mvp/rbac/rbac.schema.json new file mode 100644 index 0000000..68449af --- /dev/null +++ b/05_deliverables_mvp/rbac/rbac.schema.json @@ -0,0 +1,121 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://oto.dtp/schemas/rbac/rbac.schema.json", + "title": "Contrat RBAC · OTO Enterprise OS DTP (50 rôles)", + "description": "Design machine-lisible des 50 rôles RBAC (CLAUDE.md · roadmap Sprint 2 · ERPNext Backend). Chaque rôle cible un Role natif Frappe v15 + un jeu de permissions par DocType. Les bindings sont la CIBLE à appliquer sur le VPS par l'agent ERPNext (bench/fixtures) — ce document ne touche jamais la prod (contrainte worker).", + "type": "object", + "required": ["version", "generated_at", "cible_rbac_roles", "portails_business", "roles"], + "additionalProperties": false, + "properties": { + "version": { "type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$" }, + "generated_at": { "type": "string", "format": "date-time" }, + "cible_rbac_roles": { + "type": "integer", + "const": 50, + "description": "Cible non-négociable CLAUDE.md « RBAC 50 rôles ». La longueur de roles[] DOIT valoir 50 (contrôlé par le test)." + }, + "portails_business": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "uniqueItems": true, + "items": { "type": "string", "enum": ["ventes", "construction", "achat", "compta", "direction"] }, + "description": "Les 5 portails rôle métier de la roadmap Sprint 4. « plateforme » est une console technique transversale, hors de ce compte de 5." + }, + "roles": { + "type": "array", + "minItems": 50, + "maxItems": 50, + "items": { "$ref": "#/definitions/role" } + } + }, + "definitions": { + "role": { + "type": "object", + "required": [ + "id", "nom_fr", "famille", "portail", "entite_principale", + "niveau", "erpnext_role_name", "scope_donnees", "description", + "modules", "permissions_cibles" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", + "minLength": 3, + "description": "Identifiant kebab-case unique (unicité vérifiée par le test)." + }, + "nom_fr": { "type": "string", "minLength": 1 }, + "famille": { + "type": "string", + "enum": ["direction", "ventes", "marketing", "construction", "achat", "finance", "faisabilite", "legal", "plateforme"] + }, + "portail": { + "type": "string", + "enum": ["ventes", "construction", "achat", "compta", "direction", "plateforme"], + "description": "Console de rattachement. Les 5 premières = portails métier (roadmap S4) ; « plateforme » = console technique transversale." + }, + "entite_principale": { + "type": "string", + "enum": ["WAF", "WAG", "WA SRL", "AC Arias Cuevas", "Consortium ECR DR", "Helios RD", "Ploutos", "9060 QC", "Groupe"], + "description": "Entité juridique de rattachement principal (CLAUDE.md §Entités). « Groupe » = périmètre consolidé transversal." + }, + "niveau": { + "type": "integer", + "minimum": 1, + "maximum": 5, + "description": "Niveau hiérarchique/sensibilité : 1 externe/opérationnel → 5 direction/système." + }, + "erpnext_role_name": { + "type": "string", + "minLength": 4, + "pattern": "^OTO ", + "description": "Nom du DocType Role Frappe v15 à créer (préfixe « OTO » pour ne pas entrer en collision avec les rôles natifs). Unicité vérifiée par le test." + }, + "scope_donnees": { + "type": "string", + "enum": ["own", "equipe", "entite", "groupe"], + "description": "Row-level (User Permissions Frappe) : own=ses docs · equipe=son équipe · entite=sa Company · groupe=consolidé." + }, + "description": { "type": "string", "minLength": 1 }, + "modules": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 }, + "description": "Modules/Workspaces ERPNext visibles pour ce rôle." + }, + "permissions_cibles": { + "type": "array", + "minItems": 1, + "description": "Bindings CIBLES par DocType (à appliquer sur VPS via fixtures). Verbes = actions de permission Frappe v15.", + "items": { + "type": "object", + "required": ["doctype", "actions"], + "additionalProperties": false, + "properties": { + "doctype": { "type": "string", "minLength": 1 }, + "custom": { + "type": "boolean", + "description": "true = DocType OTOV7/DTP à créer (non natif ERPNext) — à confirmer VPS avant application." + }, + "actions": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string", + "enum": [ + "read", "write", "create", "delete", "submit", "cancel", + "amend", "print", "email", "export", "import", "report", + "share", "set_user_permissions" + ] + } + } + } + } + } + } + } + } +} diff --git a/05_deliverables_mvp/rbac/rbac_50_roles.json b/05_deliverables_mvp/rbac/rbac_50_roles.json new file mode 100644 index 0000000..d30128f --- /dev/null +++ b/05_deliverables_mvp/rbac/rbac_50_roles.json @@ -0,0 +1,832 @@ +{ + "version": "1.0.0", + "generated_at": "2026-07-30T00:00:00Z", + "cible_rbac_roles": 50, + "portails_business": ["ventes", "construction", "achat", "compta", "direction"], + "roles": [ + { + "id": "direction-president-waf", + "nom_fr": "Président · WAF (Holding)", + "famille": "direction", + "portail": "direction", + "entite_principale": "WAF", + "niveau": 5, + "erpnext_role_name": "OTO Direction Président", + "scope_donnees": "groupe", + "description": "Vue consolidée toutes entités ; approbations stratégiques et plafonds haut niveau. Lecture large, écriture limitée aux validations.", + "modules": ["Accounts", "CRM", "Selling", "Buying", "Projects", "OTOV7 Faisabilité"], + "permissions_cibles": [ + { "doctype": "Sales Invoice", "actions": ["read", "report", "print", "export"] }, + { "doctype": "Purchase Invoice", "actions": ["read", "report", "export"] }, + { "doctype": "Opportunity", "actions": ["read", "report"] }, + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "report"] } + ] + }, + { + "id": "direction-dg", + "nom_fr": "Directeur Général", + "famille": "direction", + "portail": "direction", + "entite_principale": "Groupe", + "niveau": 5, + "erpnext_role_name": "OTO Direction Générale", + "scope_donnees": "groupe", + "description": "Pilotage opérationnel du groupe ; approbation devis/commandes au-delà des plafonds directeurs.", + "modules": ["Accounts", "CRM", "Selling", "Buying", "Projects", "HR"], + "permissions_cibles": [ + { "doctype": "Quotation", "actions": ["read", "write", "submit", "cancel", "report"] }, + { "doctype": "Sales Order", "actions": ["read", "write", "submit", "cancel", "report"] }, + { "doctype": "Purchase Order", "actions": ["read", "write", "submit", "cancel", "report"] }, + { "doctype": "Project", "actions": ["read", "write", "report"] } + ] + }, + { + "id": "direction-cfo", + "nom_fr": "Directeur Financier (CFO)", + "famille": "finance", + "portail": "direction", + "entite_principale": "Groupe", + "niveau": 5, + "erpnext_role_name": "OTO Direction Financière", + "scope_donnees": "groupe", + "description": "Responsable comptabilité/trésorerie consolidées ; validation des écritures et des paiements.", + "modules": ["Accounts", "Buying", "Selling", "Report"], + "permissions_cibles": [ + { "doctype": "Journal Entry", "actions": ["read", "write", "create", "submit", "cancel", "report"] }, + { "doctype": "Payment Entry", "actions": ["read", "write", "submit", "cancel", "report"] }, + { "doctype": "Sales Invoice", "actions": ["read", "write", "submit", "cancel", "report", "export"] }, + { "doctype": "Purchase Invoice", "actions": ["read", "write", "submit", "cancel", "report", "export"] } + ] + }, + { + "id": "direction-coo", + "nom_fr": "Directeur des Opérations (COO)", + "famille": "direction", + "portail": "direction", + "entite_principale": "Groupe", + "niveau": 4, + "erpnext_role_name": "OTO Direction Opérations", + "scope_donnees": "groupe", + "description": "Coordination construction/achat/logistique multi-projets ; supervision des jalons.", + "modules": ["Projects", "Buying", "Stock", "Report"], + "permissions_cibles": [ + { "doctype": "Project", "actions": ["read", "write", "create", "report"] }, + { "doctype": "Task", "actions": ["read", "write", "create", "report"] }, + { "doctype": "Purchase Order", "actions": ["read", "report"] } + ] + }, + { + "id": "direction-cco", + "nom_fr": "Directeur Commercial (CCO)", + "famille": "direction", + "portail": "direction", + "entite_principale": "Groupe", + "niveau": 4, + "erpnext_role_name": "OTO Direction Commerciale", + "scope_donnees": "groupe", + "description": "Stratégie commerciale groupe ; supervision pipeline et marketing.", + "modules": ["CRM", "Selling", "Website", "Report"], + "permissions_cibles": [ + { "doctype": "Opportunity", "actions": ["read", "write", "report", "export"] }, + { "doctype": "Quotation", "actions": ["read", "write", "report"] }, + { "doctype": "Lead", "actions": ["read", "report"] } + ] + }, + { + "id": "direction-board", + "nom_fr": "Conseil d'Administration (lecture consolidée)", + "famille": "direction", + "portail": "direction", + "entite_principale": "Groupe", + "niveau": 5, + "erpnext_role_name": "OTO Conseil Administration", + "scope_donnees": "groupe", + "description": "Accès strictement lecture aux tableaux de bord consolidés et rapports 4Big (aucune écriture).", + "modules": ["Accounts", "Report", "OTOV7 Faisabilité"], + "permissions_cibles": [ + { "doctype": "Sales Invoice", "actions": ["read", "report"] }, + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "report"] } + ] + }, + + { + "id": "ventes-directeur", + "nom_fr": "Directeur des Ventes", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 4, + "erpnext_role_name": "OTO Ventes Directeur", + "scope_donnees": "entite", + "description": "Pilote le pipeline Helios RD ; approuve devis et remises ; assigne les leads aux équipes.", + "modules": ["CRM", "Selling", "Report"], + "permissions_cibles": [ + { "doctype": "Lead", "actions": ["read", "write", "create", "share", "report"] }, + { "doctype": "Opportunity", "actions": ["read", "write", "create", "report", "export"] }, + { "doctype": "Quotation", "actions": ["read", "write", "create", "submit", "cancel", "report"] }, + { "doctype": "Sales Order", "actions": ["read", "write", "submit", "report"] } + ] + }, + { + "id": "ventes-chef-equipe", + "nom_fr": "Chef d'Équipe Ventes", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 3, + "erpnext_role_name": "OTO Ventes Chef Équipe", + "scope_donnees": "equipe", + "description": "Supervise les conseillers de son équipe ; réaffecte leads et suit les objectifs.", + "modules": ["CRM", "Selling"], + "permissions_cibles": [ + { "doctype": "Lead", "actions": ["read", "write", "create", "report"] }, + { "doctype": "Opportunity", "actions": ["read", "write", "create", "report"] }, + { "doctype": "Quotation", "actions": ["read", "write", "create", "submit"] } + ] + }, + { + "id": "ventes-conseiller", + "nom_fr": "Conseiller Ventes", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 2, + "erpnext_role_name": "OTO Ventes Conseiller", + "scope_donnees": "own", + "description": "Gère ses propres leads/opportunités et produit des devis (soumis à approbation).", + "modules": ["CRM", "Selling"], + "permissions_cibles": [ + { "doctype": "Lead", "actions": ["read", "write", "create"] }, + { "doctype": "Opportunity", "actions": ["read", "write", "create"] }, + { "doctype": "Quotation", "actions": ["read", "write", "create", "print", "email"] } + ] + }, + { + "id": "ventes-courtier-externe", + "nom_fr": "Agent Externe / Courtier", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 1, + "erpnext_role_name": "OTO Ventes Courtier Externe", + "scope_donnees": "own", + "description": "Partenaire externe : soumet des leads et suit ses propres réservations/commissions, sans accès aux données internes.", + "modules": ["CRM"], + "permissions_cibles": [ + { "doctype": "Lead", "actions": ["read", "create"] }, + { "doctype": "Opportunity", "actions": ["read"] } + ] + }, + { + "id": "ventes-reservations", + "nom_fr": "Coordinateur Réservations", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 2, + "erpnext_role_name": "OTO Ventes Réservations", + "scope_donnees": "entite", + "description": "Enregistre les réservations/dépôts, gère la disponibilité des unités et l'agenda des visites.", + "modules": ["Selling", "CRM"], + "permissions_cibles": [ + { "doctype": "Sales Order", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Payment Entry", "actions": ["read", "create"] } + ] + }, + { + "id": "ventes-contrats", + "nom_fr": "Gestionnaire Contrats de Vente", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "WA SRL", + "niveau": 3, + "erpnext_role_name": "OTO Ventes Contrats", + "scope_donnees": "entite", + "description": "Établit et suit les contrats (promesse → contrat définitif) ; assure la cohérence avec le devis validé.", + "modules": ["Selling", "Accounts"], + "permissions_cibles": [ + { "doctype": "Sales Order", "actions": ["read", "write", "submit", "print", "email"] }, + { "doctype": "Sales Invoice", "actions": ["read", "create", "print"] } + ] + }, + { + "id": "ventes-confotur", + "nom_fr": "Coordinateur CONFOTUR (Ventes)", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "WA SRL", + "niveau": 3, + "erpnext_role_name": "OTO Ventes CONFOTUR", + "scope_donnees": "entite", + "description": "Monte les dossiers d'incitation CONFOTUR côté vente (pièces client, éligibilité) ; liaison avec l'agent ONAPI/Legal.", + "modules": ["Selling", "OTOV7 CONFOTUR"], + "permissions_cibles": [ + { "doctype": "CONFOTUR Application", "custom": true, "actions": ["read", "write", "create", "print"] }, + { "doctype": "Customer", "actions": ["read"] } + ] + }, + { + "id": "ventes-apres-vente", + "nom_fr": "Support Après-Vente", + "famille": "ventes", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 2, + "erpnext_role_name": "OTO Ventes Après-Vente", + "scope_donnees": "entite", + "description": "Traite les demandes clients post-signature (livraison, garanties) via les tickets et les tâches.", + "modules": ["CRM", "Support", "Projects"], + "permissions_cibles": [ + { "doctype": "Issue", "actions": ["read", "write", "create"] }, + { "doctype": "Customer", "actions": ["read"] } + ] + }, + + { + "id": "marketing-directeur", + "nom_fr": "Directeur Marketing", + "famille": "marketing", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 4, + "erpnext_role_name": "OTO Marketing Directeur", + "scope_donnees": "entite", + "description": "Pilote la marque publique Helios RD, les campagnes et la validation du contenu du site vente.otov7.com.", + "modules": ["CRM", "Website", "Report"], + "permissions_cibles": [ + { "doctype": "Web Page", "actions": ["read", "write", "create"] }, + { "doctype": "Publiciste Log", "custom": true, "actions": ["read", "report"] } + ] + }, + { + "id": "marketing-publiciste", + "nom_fr": "Éditeur Contenu / Publiciste", + "famille": "marketing", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 2, + "erpnext_role_name": "OTO Marketing Publiciste", + "scope_donnees": "entite", + "description": "Compte applicatif de l'agent Publiciste : publie le site public à partir des faisabilités validées (jamais d'invention de prix — CLAUDE.md #6).", + "modules": ["Website", "OTOV7 Publiciste"], + "permissions_cibles": [ + { "doctype": "Web Page", "actions": ["read", "write", "create"] }, + { "doctype": "Publiciste Log", "custom": true, "actions": ["read", "write", "create"] } + ] + }, + { + "id": "marketing-seo", + "nom_fr": "Spécialiste SEO", + "famille": "marketing", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 2, + "erpnext_role_name": "OTO Marketing SEO", + "scope_donnees": "entite", + "description": "Optimise l'indexation trilingue FR/EN/ES (hreflang, schema.org) ; suit Google Search Console.", + "modules": ["Website", "Report"], + "permissions_cibles": [ + { "doctype": "Web Page", "actions": ["read", "write"] } + ] + }, + { + "id": "marketing-social", + "nom_fr": "Community / Réseaux Sociaux", + "famille": "marketing", + "portail": "ventes", + "entite_principale": "Helios RD", + "niveau": 1, + "erpnext_role_name": "OTO Marketing Social", + "scope_donnees": "entite", + "description": "Gère les publications réseaux sociaux et remonte les leads sociaux dans le CRM.", + "modules": ["CRM", "Website"], + "permissions_cibles": [ + { "doctype": "Lead", "actions": ["read", "create"] } + ] + }, + + { + "id": "construction-directeur", + "nom_fr": "Directeur Construction", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 4, + "erpnext_role_name": "OTO Construction Directeur", + "scope_donnees": "entite", + "description": "Dirige AC Arias Cuevas ; approuve les projets, budgets travaux et jalons de chantier.", + "modules": ["Projects", "Buying", "Stock", "Report"], + "permissions_cibles": [ + { "doctype": "Project", "actions": ["read", "write", "create", "submit", "report"] }, + { "doctype": "Task", "actions": ["read", "write", "create", "report"] }, + { "doctype": "Purchase Order", "actions": ["read", "write", "submit"] } + ] + }, + { + "id": "construction-chef-projet", + "nom_fr": "Chef de Projet Construction", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 3, + "erpnext_role_name": "OTO Construction Chef Projet", + "scope_donnees": "equipe", + "description": "Pilote un projet : planning, tâches, avancement et demandes d'achat de chantier.", + "modules": ["Projects", "Buying"], + "permissions_cibles": [ + { "doctype": "Project", "actions": ["read", "write", "report"] }, + { "doctype": "Task", "actions": ["read", "write", "create"] }, + { "doctype": "Material Request", "actions": ["read", "write", "create", "submit"] } + ] + }, + { + "id": "construction-ingenieur", + "nom_fr": "Ingénieur de Chantier", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 2, + "erpnext_role_name": "OTO Construction Ingénieur", + "scope_donnees": "equipe", + "description": "Suit l'exécution technique sur site ; met à jour l'avancement des tâches et les feuilles de temps.", + "modules": ["Projects"], + "permissions_cibles": [ + { "doctype": "Task", "actions": ["read", "write"] }, + { "doctype": "Timesheet", "actions": ["read", "write", "create"] } + ] + }, + { + "id": "construction-architecte", + "nom_fr": "Architecte", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 3, + "erpnext_role_name": "OTO Construction Architecte", + "scope_donnees": "entite", + "description": "Produit le volet Architecture des faisabilités ; valide les plans et les modèles IFC.", + "modules": ["Projects", "OTOV7 Faisabilité"], + "permissions_cibles": [ + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "write", "create"] }, + { "doctype": "Project", "actions": ["read"] } + ] + }, + { + "id": "construction-qaqc", + "nom_fr": "Contrôleur Qualité Chantier (QA/QC)", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 2, + "erpnext_role_name": "OTO Construction QAQC", + "scope_donnees": "entite", + "description": "Contrôle la conformité qualité du chantier ; consigne inspections et non-conformités.", + "modules": ["Projects", "Quality"], + "permissions_cibles": [ + { "doctype": "Quality Inspection", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Task", "actions": ["read"] } + ] + }, + { + "id": "construction-bim", + "nom_fr": "Coordinateur BIM", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 3, + "erpnext_role_name": "OTO Construction BIM", + "scope_donnees": "entite", + "description": "Coordonne les maquettes BIM (Blender/Bonsai/IFC/Speckle) ; publie les modèles vers bim-cloud.otov7.com.", + "modules": ["Projects", "OTOV7 Faisabilité"], + "permissions_cibles": [ + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "write"] }, + { "doctype": "File", "actions": ["read", "write", "create"] } + ] + }, + { + "id": "construction-sous-traitants", + "nom_fr": "Superviseur Sous-traitants", + "famille": "construction", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 2, + "erpnext_role_name": "OTO Construction Sous-traitants", + "scope_donnees": "equipe", + "description": "Suit les sous-traitants et leurs livrables ; valide l'avancement pour paiement.", + "modules": ["Projects", "Buying"], + "permissions_cibles": [ + { "doctype": "Purchase Order", "actions": ["read", "report"] }, + { "doctype": "Task", "actions": ["read", "write"] } + ] + }, + + { + "id": "achat-directeur", + "nom_fr": "Directeur des Achats", + "famille": "achat", + "portail": "achat", + "entite_principale": "WA SRL", + "niveau": 4, + "erpnext_role_name": "OTO Achat Directeur", + "scope_donnees": "entite", + "description": "Pilote la fonction achats ; approuve commandes fournisseurs au-delà des plafonds acheteurs.", + "modules": ["Buying", "Stock", "Accounts", "Report"], + "permissions_cibles": [ + { "doctype": "Purchase Order", "actions": ["read", "write", "create", "submit", "cancel", "report"] }, + { "doctype": "Supplier", "actions": ["read", "write", "create"] }, + { "doctype": "Material Request", "actions": ["read", "write", "submit"] } + ] + }, + { + "id": "achat-acheteur", + "nom_fr": "Acheteur / Approvisionneur", + "famille": "achat", + "portail": "achat", + "entite_principale": "WA SRL", + "niveau": 2, + "erpnext_role_name": "OTO Achat Acheteur", + "scope_donnees": "entite", + "description": "Émet demandes de prix et commandes fournisseurs (soumises à approbation) ; suit les délais.", + "modules": ["Buying", "Stock"], + "permissions_cibles": [ + { "doctype": "Material Request", "actions": ["read", "write", "create"] }, + { "doctype": "Request for Quotation", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Purchase Order", "actions": ["read", "write", "create"] } + ] + }, + { + "id": "achat-fournisseurs", + "nom_fr": "Gestionnaire Fournisseurs", + "famille": "achat", + "portail": "achat", + "entite_principale": "WA SRL", + "niveau": 2, + "erpnext_role_name": "OTO Achat Fournisseurs", + "scope_donnees": "entite", + "description": "Tient à jour la base fournisseurs, les conditions et la conformité documentaire.", + "modules": ["Buying"], + "permissions_cibles": [ + { "doctype": "Supplier", "actions": ["read", "write", "create"] }, + { "doctype": "Contact", "actions": ["read", "write", "create"] } + ] + }, + { + "id": "achat-magasinier", + "nom_fr": "Magasinier / Inventaire", + "famille": "achat", + "portail": "achat", + "entite_principale": "AC Arias Cuevas", + "niveau": 2, + "erpnext_role_name": "OTO Achat Magasinier", + "scope_donnees": "entite", + "description": "Gère les stocks de chantier/dépôt : entrées, sorties et inventaires.", + "modules": ["Stock"], + "permissions_cibles": [ + { "doctype": "Stock Entry", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Item", "actions": ["read"] } + ] + }, + { + "id": "achat-reception", + "nom_fr": "Contrôleur Réception Matériaux", + "famille": "achat", + "portail": "achat", + "entite_principale": "AC Arias Cuevas", + "niveau": 2, + "erpnext_role_name": "OTO Achat Réception", + "scope_donnees": "entite", + "description": "Réceptionne et contrôle les livraisons ; établit les bons de réception.", + "modules": ["Stock", "Buying"], + "permissions_cibles": [ + { "doctype": "Purchase Receipt", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Purchase Order", "actions": ["read"] } + ] + }, + + { + "id": "compta-controleur-gestion", + "nom_fr": "Contrôleur de Gestion", + "famille": "finance", + "portail": "compta", + "entite_principale": "Groupe", + "niveau": 4, + "erpnext_role_name": "OTO Compta Contrôle Gestion", + "scope_donnees": "groupe", + "description": "Suit budgets, marges et point d'équilibre (52% pré-vente) ; produit les rapports de gestion consolidés.", + "modules": ["Accounts", "Report"], + "permissions_cibles": [ + { "doctype": "Budget", "actions": ["read", "write", "create", "report"] }, + { "doctype": "GL Entry", "actions": ["read", "report", "export"] }, + { "doctype": "Cost Center", "actions": ["read", "report"] } + ] + }, + { + "id": "compta-comptable-general", + "nom_fr": "Comptable Général", + "famille": "finance", + "portail": "compta", + "entite_principale": "WA SRL", + "niveau": 3, + "erpnext_role_name": "OTO Compta Général", + "scope_donnees": "entite", + "description": "Tient la comptabilité générale de l'entité ; saisit et rapproche les écritures.", + "modules": ["Accounts"], + "permissions_cibles": [ + { "doctype": "Journal Entry", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Account", "actions": ["read"] } + ] + }, + { + "id": "compta-fournisseurs-ap", + "nom_fr": "Comptable Fournisseurs (AP)", + "famille": "finance", + "portail": "compta", + "entite_principale": "WA SRL", + "niveau": 2, + "erpnext_role_name": "OTO Compta Fournisseurs AP", + "scope_donnees": "entite", + "description": "Traite les factures fournisseurs et prépare les paiements (soumis à approbation trésorier/CFO).", + "modules": ["Accounts", "Buying"], + "permissions_cibles": [ + { "doctype": "Purchase Invoice", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Payment Entry", "actions": ["read", "create"] } + ] + }, + { + "id": "compta-clients-ar", + "nom_fr": "Comptable Clients (AR)", + "famille": "finance", + "portail": "compta", + "entite_principale": "Helios RD", + "niveau": 2, + "erpnext_role_name": "OTO Compta Clients AR", + "scope_donnees": "entite", + "description": "Émet les factures clients et suit les encaissements (Cardnet · USD/DOP) et relances.", + "modules": ["Accounts", "Selling"], + "permissions_cibles": [ + { "doctype": "Sales Invoice", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Payment Entry", "actions": ["read", "create"] } + ] + }, + { + "id": "compta-tresorier", + "nom_fr": "Trésorier · Ploutos", + "famille": "finance", + "portail": "compta", + "entite_principale": "Ploutos", + "niveau": 3, + "erpnext_role_name": "OTO Compta Trésorier", + "scope_donnees": "entite", + "description": "Gère la trésorerie et le patrimoine monétaire (Ploutos) ; valide les décaissements.", + "modules": ["Accounts"], + "permissions_cibles": [ + { "doctype": "Payment Entry", "actions": ["read", "write", "submit", "cancel"] }, + { "doctype": "Bank Transaction", "actions": ["read", "write", "submit"] } + ] + }, + { + "id": "compta-paie", + "nom_fr": "Gestionnaire Paie · Consortium ECR DR", + "famille": "finance", + "portail": "compta", + "entite_principale": "Consortium ECR DR", + "niveau": 3, + "erpnext_role_name": "OTO Compta Paie", + "scope_donnees": "entite", + "description": "Traite la paie (paymaster RH Consortium ECR DR) ; établit et soumet les bulletins.", + "modules": ["Payroll", "HR"], + "permissions_cibles": [ + { "doctype": "Salary Slip", "actions": ["read", "write", "create", "submit"] }, + { "doctype": "Employee", "actions": ["read"] } + ] + }, + { + "id": "compta-fiscaliste-ecf", + "nom_fr": "Fiscaliste / e-CF DGII", + "famille": "finance", + "portail": "compta", + "entite_principale": "WA SRL", + "niveau": 3, + "erpnext_role_name": "OTO Compta Fiscaliste eCF", + "scope_donnees": "entite", + "description": "Gère la facturation électronique e-CF (Compupar/DGII) et la conformité fiscale RD.", + "modules": ["Accounts", "Report"], + "permissions_cibles": [ + { "doctype": "Sales Invoice", "actions": ["read", "write", "submit", "export"] }, + { "doctype": "Purchase Invoice", "actions": ["read", "export"] } + ] + }, + { + "id": "compta-audit-uaf", + "nom_fr": "Auditeur Interne / Conformité UAF", + "famille": "finance", + "portail": "compta", + "entite_principale": "Groupe", + "niveau": 4, + "erpnext_role_name": "OTO Compta Audit UAF", + "scope_donnees": "groupe", + "description": "Audit interne et conformité anti-blanchiment (UAF) ; accès lecture/rapport étendu, aucune écriture comptable.", + "modules": ["Accounts", "Report"], + "permissions_cibles": [ + { "doctype": "GL Entry", "actions": ["read", "report", "export"] }, + { "doctype": "Payment Entry", "actions": ["read", "report"] }, + { "doctype": "Sales Invoice", "actions": ["read", "report"] } + ] + }, + + { + "id": "faisabilite-analyste", + "nom_fr": "Analyste Faisabilité", + "famille": "faisabilite", + "portail": "direction", + "entite_principale": "WA SRL", + "niveau": 3, + "erpnext_role_name": "OTO Faisabilité Analyste", + "scope_donnees": "entite", + "description": "Produit les faisabilités 4 volets (Masterplan/Architecture/Paysage/Ingénierie) niveau 4Big ; versionne et score.", + "modules": ["OTOV7 Faisabilité", "Projects", "Report"], + "permissions_cibles": [ + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "write", "create", "submit", "report"] }, + { "doctype": "Project", "actions": ["read"] } + ] + }, + { + "id": "faisabilite-rendu-3d", + "nom_fr": "Spécialiste Rendu 3D", + "famille": "faisabilite", + "portail": "construction", + "entite_principale": "WA SRL", + "niveau": 2, + "erpnext_role_name": "OTO Faisabilité Rendu 3D", + "scope_donnees": "entite", + "description": "Génère les rendus Flux liés au projet réel (❌ IA générique interdite — CLAUDE.md) ; 6 vues/projet.", + "modules": ["OTOV7 Faisabilité"], + "permissions_cibles": [ + { "doctype": "File", "actions": ["read", "write", "create"] }, + { "doctype": "Faisabilité", "custom": true, "actions": ["read"] } + ] + }, + { + "id": "faisabilite-ifc-speckle", + "nom_fr": "Gestionnaire IFC / Speckle", + "famille": "faisabilite", + "portail": "construction", + "entite_principale": "WA SRL", + "niveau": 2, + "erpnext_role_name": "OTO Faisabilité IFC Speckle", + "scope_donnees": "entite", + "description": "Exporte IFC→GLB et publie les modèles sur bim-cloud.otov7.com pour le viewer console.", + "modules": ["OTOV7 Faisabilité"], + "permissions_cibles": [ + { "doctype": "File", "actions": ["read", "write", "create"] }, + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "write"] } + ] + }, + { + "id": "faisabilite-economiste", + "nom_fr": "Économiste de la Construction (métrés)", + "famille": "faisabilite", + "portail": "construction", + "entite_principale": "AC Arias Cuevas", + "niveau": 3, + "erpnext_role_name": "OTO Faisabilité Économiste", + "scope_donnees": "entite", + "description": "Produit métrés et quantitatifs (BIM compras) pour le volet Ingénierie ; chiffre les coûts travaux.", + "modules": ["OTOV7 Faisabilité", "Buying", "Stock"], + "permissions_cibles": [ + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "write"] }, + { "doctype": "Item", "actions": ["read"] } + ] + }, + + { + "id": "legal-directeur", + "nom_fr": "Directeur Juridique", + "famille": "legal", + "portail": "direction", + "entite_principale": "WAF", + "niveau": 4, + "erpnext_role_name": "OTO Legal Directeur", + "scope_donnees": "groupe", + "description": "Supervise les contrats, la conformité et les dépôts légaux du groupe ; valide les documents à portée juridique.", + "modules": ["OTOV7 CONFOTUR", "Accounts", "Report"], + "permissions_cibles": [ + { "doctype": "CONFOTUR Application", "custom": true, "actions": ["read", "write", "submit", "report"] }, + { "doctype": "Contract", "actions": ["read", "write", "create", "submit"] } + ] + }, + { + "id": "legal-onapi", + "nom_fr": "Agent ONAPI / Propriété Intellectuelle", + "famille": "legal", + "portail": "direction", + "entite_principale": "WAF", + "niveau": 2, + "erpnext_role_name": "OTO Legal ONAPI", + "scope_donnees": "groupe", + "description": "Prépare et suit les dépôts ONAPI (marques, Classes 36/37/43) et les dossiers CONFOTUR (P05/P07).", + "modules": ["OTOV7 CONFOTUR"], + "permissions_cibles": [ + { "doctype": "CONFOTUR Application", "custom": true, "actions": ["read", "write", "create"] } + ] + }, + + { + "id": "plateforme-devops", + "nom_fr": "Administrateur Système (DevOps)", + "famille": "plateforme", + "portail": "plateforme", + "entite_principale": "9060 QC", + "niveau": 5, + "erpnext_role_name": "OTO Plateforme DevOps", + "scope_donnees": "groupe", + "description": "Administre l'infrastructure (Docker, Gitea, systemd, nginx) et les déploiements. Aucune plateforme git hors Gitea (CLAUDE.md #2).", + "modules": ["Core", "Website", "Report"], + "permissions_cibles": [ + { "doctype": "Scheduled Job Type", "actions": ["read", "write"] }, + { "doctype": "Server Script", "actions": ["read", "write", "create"] } + ] + }, + { + "id": "plateforme-rbac-admin", + "nom_fr": "Administrateur RBAC / Sécurité", + "famille": "plateforme", + "portail": "plateforme", + "entite_principale": "9060 QC", + "niveau": 5, + "erpnext_role_name": "OTO Plateforme RBAC Admin", + "scope_donnees": "groupe", + "description": "Gère utilisateurs, rôles et User Permissions ; seul habilité à modifier les habilitations (séparation des pouvoirs).", + "modules": ["Users and Permissions", "Core"], + "permissions_cibles": [ + { "doctype": "User", "actions": ["read", "write", "create", "set_user_permissions"] }, + { "doctype": "Role", "actions": ["read", "write", "create"] }, + { "doctype": "Role Profile", "actions": ["read", "write", "create"] }, + { "doctype": "User Permission", "actions": ["read", "write", "create", "delete"] } + ] + }, + { + "id": "plateforme-qa", + "nom_fr": "Ingénieur QA Plateforme", + "famille": "plateforme", + "portail": "plateforme", + "entite_principale": "9060 QC", + "niveau": 3, + "erpnext_role_name": "OTO Plateforme QA", + "scope_donnees": "groupe", + "description": "Exécute les audits qualité 4Big (Playwright, night-audit) ; accès lecture large + rapports, aucune écriture métier.", + "modules": ["Report", "Core"], + "permissions_cibles": [ + { "doctype": "Report", "actions": ["read", "report", "export"] }, + { "doctype": "Error Log", "actions": ["read"] } + ] + }, + { + "id": "plateforme-otoia", + "nom_fr": "Orchestrateur OTOIA (compte système)", + "famille": "plateforme", + "portail": "plateforme", + "entite_principale": "9060 QC", + "niveau": 4, + "erpnext_role_name": "OTO Plateforme OTOIA", + "scope_donnees": "groupe", + "description": "Compte de service de l'agent OTOIA (AEC + RAG + prompt engine). Écrit faisabilités et logs via API ; périmètre limité aux DocTypes DTP.", + "modules": ["OTOV7 Faisabilité", "OTOV7 Publiciste", "Core"], + "permissions_cibles": [ + { "doctype": "Faisabilité", "custom": true, "actions": ["read", "write", "create"] }, + { "doctype": "Publiciste Log", "custom": true, "actions": ["read", "write", "create"] } + ] + }, + { + "id": "plateforme-mobile", + "nom_fr": "Développeur Mobile", + "famille": "plateforme", + "portail": "plateforme", + "entite_principale": "9060 QC", + "niveau": 2, + "erpnext_role_name": "OTO Plateforme Mobile", + "scope_donnees": "groupe", + "description": "Maintient l'app Expo/React Native et l'API mobile ; gère les builds EAS et les soumissions stores.", + "modules": ["Core", "Website"], + "permissions_cibles": [ + { "doctype": "API Access", "custom": true, "actions": ["read", "write"] } + ] + }, + { + "id": "plateforme-bi", + "nom_fr": "Analyste Données / BI", + "famille": "plateforme", + "portail": "plateforme", + "entite_principale": "Groupe", + "niveau": 3, + "erpnext_role_name": "OTO Plateforme BI", + "scope_donnees": "groupe", + "description": "Construit tableaux de bord et rapports consolidés (lecture seule) pour la direction ; aucune écriture transactionnelle.", + "modules": ["Report", "Accounts", "CRM"], + "permissions_cibles": [ + { "doctype": "Dashboard", "actions": ["read", "write", "create"] }, + { "doctype": "Report", "actions": ["read", "write", "create", "export"] } + ] + } + ] +} diff --git a/05_deliverables_mvp/rbac/tests/test_rbac.py b/05_deliverables_mvp/rbac/tests/test_rbac.py new file mode 100644 index 0000000..ace81a0 --- /dev/null +++ b/05_deliverables_mvp/rbac/tests/test_rbac.py @@ -0,0 +1,116 @@ +"""Tests RBAC 50 rôles — stdlib pur (unittest), zéro dépendance pip. + +Réutilise le validateur JSON-Schema du module Publiciste (Sprint 2) plutôt que +d'en dupliquer un (CLAUDE.md · workflow #5 « éliminer le vieux / ne pas +accumuler de doublons »). L'oracle `jsonschema` est utilisé s'il est présent. + +Invariants vérifiés : + 1. `rbac_50_roles.json` valide contre `rbac.schema.json`. + 2. EXACTEMENT 50 rôles (cible non-négociable CLAUDE.md « RBAC 50 rôles »). + 3. `id` et `erpnext_role_name` uniques (pas de collision de rôle Frappe). + 4. Les 5 portails métier de la roadmap S4 sont tous couverts par ≥1 rôle. + 5. Cohérence interne (portail déclaré ⊆ portails connus, cible=50). + 6. Anti-invention (#6) : aucun rôle « own/equipe » n'a le pouvoir + `set_user_permissions` (élévation de privilège) — réservé au RBAC Admin. +""" + +import json +import os +import unittest + +# --- localisation des fichiers ------------------------------------------------- +HERE = os.path.dirname(os.path.abspath(__file__)) +RBAC_DIR = os.path.dirname(HERE) +DELIVERABLES = os.path.dirname(RBAC_DIR) + +DATA_PATH = os.path.join(RBAC_DIR, "rbac_50_roles.json") +SCHEMA_PATH = os.path.join(RBAC_DIR, "rbac.schema.json") + +# --- réutilisation du validateur Publiciste (pas de duplication) --------------- +import sys +sys.path.insert(0, os.path.join(DELIVERABLES, "publiciste")) +from lib import validator as maison # noqa: E402 + + +def _load(path): + with open(path, encoding="utf-8") as fh: + return json.load(fh) + + +class RbacContractTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.data = _load(DATA_PATH) + cls.schema = _load(SCHEMA_PATH) + cls.roles = cls.data["roles"] + + # 1 · conformité au schéma (validateur maison) + def test_valide_contre_schema_maison(self): + errors = maison.validate(self.data, self.schema) + self.assertEqual(errors, [], f"Erreurs de schéma (maison) : {errors}") + + # 1bis · oracle jsonschema si disponible + def test_valide_contre_oracle_jsonschema_si_present(self): + try: + import jsonschema + except ImportError: + self.skipTest("jsonschema non installé (validateur maison fait foi)") + jsonschema.validate(self.data, self.schema) + + # 2 · cible non-négociable = 50 + def test_exactement_50_roles(self): + self.assertEqual(self.data["cible_rbac_roles"], 50) + self.assertEqual(len(self.roles), 50, "La cible CLAUDE.md « RBAC 50 rôles » exige exactement 50 rôles.") + + # 3 · unicité des identifiants et des noms de rôle Frappe + def test_ids_uniques(self): + ids = [r["id"] for r in self.roles] + self.assertEqual(len(ids), len(set(ids)), "id de rôle dupliqué.") + + def test_noms_erpnext_uniques(self): + names = [r["erpnext_role_name"] for r in self.roles] + self.assertEqual(len(names), len(set(names)), "erpnext_role_name dupliqué (collision Frappe).") + + def test_noms_erpnext_prefixes_oto(self): + for r in self.roles: + self.assertTrue( + r["erpnext_role_name"].startswith("OTO "), + f"{r['id']}: le rôle Frappe doit être préfixé « OTO » pour éviter la collision avec les rôles natifs.", + ) + + # 4 · les 5 portails métier de la roadmap S4 sont tous couverts + def test_cinq_portails_business_couverts(self): + portails_declares = set(self.data["portails_business"]) + self.assertEqual(portails_declares, {"ventes", "construction", "achat", "compta", "direction"}) + portails_utilises = {r["portail"] for r in self.roles} + for p in portails_declares: + self.assertIn(p, portails_utilises, f"Portail métier « {p} » sans aucun rôle rattaché.") + + # 5 · cohérence portail + def test_portail_connu(self): + connus = {"ventes", "construction", "achat", "compta", "direction", "plateforme"} + for r in self.roles: + self.assertIn(r["portail"], connus, f"{r['id']}: portail inconnu {r['portail']!r}") + + # 6 · anti-élévation de privilège : set_user_permissions réservé au groupe + def test_set_user_permissions_reserve_admin(self): + for r in self.roles: + verbs = {a for p in r["permissions_cibles"] for a in p["actions"]} + if "set_user_permissions" in verbs: + self.assertEqual( + r["scope_donnees"], "groupe", + f"{r['id']}: 'set_user_permissions' exige un scope 'groupe' (séparation des pouvoirs).", + ) + self.assertEqual( + r["famille"], "plateforme", + f"{r['id']}: seul un rôle 'plateforme' peut porter 'set_user_permissions'.", + ) + + # 7 · chaque rôle a au moins un binding de permission + def test_chaque_role_a_des_permissions(self): + for r in self.roles: + self.assertGreaterEqual(len(r["permissions_cibles"]), 1, f"{r['id']}: aucun binding de permission.") + + +if __name__ == "__main__": + unittest.main(verbosity=2)