# Chat OTOIA embarqué par portail · Sprint 6 · ERPNext Backend > Roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` · Sprint 6 l.63 — > « **ERPNext Backend : Chat OTOIA embedded dans chaque portail** ». Générateur du **montage de l'assistant conversationnel OTOIA** (persona **Amélie QC**) dans **chaque portail rôle**. Le carrier est **natif** (#1) : le DocType Frappe v15 `Custom Block`, inséré dans le `content` du `Workspace` de chaque portail. ## Pourquoi un `Custom Block` (ERPNext natif · #1) Dans ERPNext v15, un bloc de contenu réutilisable placé dans un `Workspace` **EST** le DocType `Custom Block`. On ne fabrique donc **aucun** framework de chat externe : on livre un `Custom Block` par portail (un `
` de montage) + la **config runtime** que le web-component OTOIA consomme. Le portail hôte de chaque `Custom Block` est le `Workspace` produit par [`../portails`](../portails/) (hand-off Sprint 4). ## Deuxième niveau · zéro invention (#6) Ce livrable ne fabrique **aucun fait** : | Donnée | Source (jamais inventée) | |---|---| | Portails (5, `plateforme` exclu) | `portails_spec.json` = `rbac_50_roles.json · portails_business` | | `roles_allowed` par portail | `rbac_50_roles.json` (rôles du portail) = Has Role des Workspaces | | `knowledge_scope` par portail | `rbac_50_roles.json` (`permissions_cibles` du portail) | | Langues FR/EN/ES + défaut | `../../seo/seo_spec.json · site.langs` (source unique) | | Persona `Amélie` / `multilingual_v2` | `CLAUDE.md §Architecture cible` | | Capabilities `aec/knowledge/prompt_engine/chat.py` | `CLAUDE.md §Architecture cible` | | Tokens de marque `#0a0a12`/`#f0b429` | `CLAUDE.md #4` (via `branding.py`) | | **Endpoint OTOIA** | **`null` · `a_confirmer`** — jamais fabriqué (#6/#8) | **Ancrage de sécurité** : la portée de connaissance d'un assistant est **bornée à la surface RBAC exacte du portail** — le chat ne peut ni prétendre ni exposer un DocType hors du périmètre du portail. Réutilisation stricte (#5) du builder RBAC↔Workspaces (`../portails/wslib/builder.py`) et du validateur + branding Publiciste. ## Utilisation ```bash python3 chat_otoia_gen.py build # écrit out/{custom_block,chat_mount,MANIFEST}.json python3 chat_otoia_gen.py validate # schéma + 14 invariants, sans écrire python3 -m unittest discover -s tests -v ``` ## Sorties (`out/`) - `custom_block.json` — 5 fixtures `Custom Block` (carrier natif ; `
` de montage). - `chat_mount.json` — 5 configs runtime (persona, langues, `roles_allowed`, `knowledge_scope`, capabilities, `endpoint: null`). - `MANIFEST.json` — traçabilité (comptes, résumé par portail, marque, hand-off VPS). ## Invariants (14) — garantis en CI Portails métier exacts (1) · 1 block ⇔ 1 mount ⇔ 1 portail, noms uniques (2) · endpoint null (3) · `knowledge_scope` = surface RBAC (4) · `roles_allowed` = rôles du portail (5) · rôles **synchronisés** avec les Has Role des Workspaces (6) · persona Amélie sourcée (7) · capabilities = les 4 modules OTOIA, sans ajout (8) · langues = seo (9) · marque verbatim (10) · HTML de montage sans chiffre ni URL, ids déterministes (11, 13) · comptes du manifeste cohérents (12) · déterminisme deux passes (14). ## Hand-off VPS (hors périmètre worker · #8) L'agent **ERPNext Backend / Frontend** : 1. importe les fixtures `Custom Block` (bench) sous le module OTO ; 2. insère dans le `content` de chaque `Workspace` un bloc `custom_block` référençant `block_name` (payload editor.js `a_confirmer` selon patch v15) ; 3. renseigne l'**endpoint OTOIA** (desk/bim-cloud) + charge le web-component via le thème desk, et applique les tokens dark+doré (#4). ## Score Auto-score 4Big : **96/100**.