[DTP-Worker] Sprint 6 · Générateur Chat OTOIA embarqué par portail (Custom Block natif) (ERPNext Backend · roadmap L63)
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / Chat OTOIA · montage par portail (Custom Block) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / Chat OTOIA · montage par portail (Custom Block) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
Carrier natif ERPNext v15 (Custom Block) + config runtime par portail. Ancrage RBAC : roles_allowed/knowledge_scope = surface exacte du portail, synchronisés avec les Has Role des Workspaces. Endpoint OTOIA null (a_confirmer). Persona Amélie + capabilities + langues FR/EN/ES sourcés (anti-invention #6). 14 invariants · 31 tests · régression 408 tests verts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
"""Assemblage du bundle Chat OTOIA depuis (contrat RBAC + spec + portails + seo).
|
||||
|
||||
Sortie déterministe :
|
||||
- custom_block : 1 fixture Frappe `Custom Block` par portail (le carrier natif du
|
||||
chat, inséré dans le `content` du Workspace du portail côté VPS) ;
|
||||
- chat_mount : 1 config runtime par portail (persona, langues, rôles autorisés,
|
||||
portée de connaissance, capabilities, endpoint=null) — ce que le runtime OTOIA
|
||||
consomme ; données pures, diffables ;
|
||||
- manifest : traçabilité (comptes, résumé par portail, marque, hand-off VPS).
|
||||
|
||||
Anti-invention (#6), garanti ici + par les invariants du CLI :
|
||||
- portails = EXACTEMENT les portails métier (portails_spec / portails_business),
|
||||
la console technique `plateforme` étant exclue (comme les Workspaces) ;
|
||||
- `roles_allowed` / `knowledge_scope` viennent du CONTRAT (surface RBAC du portail),
|
||||
jamais de la spec — mêmes valeurs que les Has Role des Workspaces ;
|
||||
- `endpoint` reste null (a_confirmer · VPS) — jamais fabriqué ;
|
||||
- persona / capabilities / langues repris de sources sourcées (CLAUDE.md, seo_spec),
|
||||
jamais inventés ; aucun chiffre émis.
|
||||
|
||||
Déterminisme : portails dans l'ordre de la spec ; rôles + DocTypes triés → sortie
|
||||
reproductible bit-à-bit (aucun horodatage, aucun aléatoire).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from . import deps, frappe, knowledge
|
||||
|
||||
|
||||
def _portail_labels(portails_spec: dict) -> dict[str, str]:
|
||||
return {p["key"]: p["label"] for p in portails_spec["portails"]}
|
||||
|
||||
|
||||
def build_bundle(
|
||||
contract: dict,
|
||||
spec: dict,
|
||||
portails_spec: dict,
|
||||
langs: list[str],
|
||||
default_lang: str,
|
||||
) -> dict[str, Any]:
|
||||
"""Transforme les entrées en bundle {custom_block, chat_mount, manifest}."""
|
||||
labels = _portail_labels(portails_spec)
|
||||
keys = [p["key"] for p in portails_spec["portails"]] # ordre spec = déterminisme
|
||||
|
||||
mount_cfg = spec["mount"]
|
||||
id_prefix = mount_cfg["html_id_prefix"]
|
||||
css_class = mount_cfg["container_class"]
|
||||
bn_prefix = mount_cfg["block_name_prefix"]
|
||||
persona = {"nom": spec["persona"]["nom"], "voix": spec["persona"]["voix"]}
|
||||
capabilities = [c["module"] for c in spec["capabilities"]]
|
||||
ui_label = dict(spec["ui_label"])
|
||||
|
||||
custom_blocks: list[dict] = []
|
||||
mounts: list[dict] = []
|
||||
manifest_portails: list[dict] = []
|
||||
|
||||
for key in keys:
|
||||
label = labels[key]
|
||||
roles = knowledge.roles_for(contract, key)
|
||||
scope = knowledge.knowledge_scope_for(contract, key)
|
||||
html_id = f"{id_prefix}{key}"
|
||||
block_name = f"{bn_prefix}{label}"
|
||||
html = frappe.mount_html(html_id, key, persona["nom"], css_class)
|
||||
|
||||
custom_blocks.append(frappe.custom_block_fixture(block_name, html))
|
||||
|
||||
mounts.append({
|
||||
"portail": key,
|
||||
"workspace": label,
|
||||
"custom_block": block_name,
|
||||
"html_id": html_id,
|
||||
"persona": persona,
|
||||
"langues": list(langs),
|
||||
"lang_defaut": default_lang,
|
||||
"ui_label": ui_label,
|
||||
"roles_allowed": roles,
|
||||
"knowledge_scope": scope,
|
||||
"capabilities": list(capabilities),
|
||||
"endpoint": None,
|
||||
})
|
||||
|
||||
manifest_portails.append({
|
||||
"portail": key,
|
||||
"workspace": label,
|
||||
"custom_block": block_name,
|
||||
"nb_roles": len(roles),
|
||||
"nb_knowledge_doctypes": len(scope),
|
||||
})
|
||||
|
||||
knowledge_union = sorted({dt for m in mounts for dt in m["knowledge_scope"]})
|
||||
manifest = {
|
||||
"deliverable": spec["deliverable"],
|
||||
"sprint": spec["sprint"],
|
||||
"roadmap_ref": spec["roadmap_ref"],
|
||||
"generated_from": spec["generated_from"],
|
||||
"carrier": {
|
||||
"doctype": frappe.CUSTOM_BLOCK_DOCTYPE,
|
||||
"workspace_content_block_type": frappe.WORKSPACE_CONTENT_BLOCK_TYPE,
|
||||
"note": "Chaque Custom Block est inséré dans le `content` (editor.js) du "
|
||||
"Workspace de son portail via un bloc `custom_block` référençant "
|
||||
"`block_name`. La clé exacte du payload editor.js est a_confirmer "
|
||||
"selon le patch de version v15 — étape VPS (agent Frontend).",
|
||||
},
|
||||
"persona": persona,
|
||||
"langues": list(langs),
|
||||
"lang_defaut": default_lang,
|
||||
"capabilities": list(capabilities),
|
||||
"endpoint_statut": spec["endpoint"]["statut"],
|
||||
"counts": {
|
||||
"portails": len(mounts),
|
||||
"custom_blocks": len(custom_blocks),
|
||||
"mounts": len(mounts),
|
||||
"roles_couverts": sum(m["nb_roles"] for m in manifest_portails),
|
||||
"knowledge_doctypes_uniques": len(knowledge_union),
|
||||
},
|
||||
"portails": manifest_portails,
|
||||
"brand": {
|
||||
"fond": {"valeur": deps.branding.COLOR_BG, "source": "CLAUDE.md #4"},
|
||||
"accent": {"valeur": deps.branding.COLOR_ACCENT, "source": "CLAUDE.md #4"},
|
||||
"polices": [
|
||||
{"valeur": deps.branding.FONT_DISPLAY, "source": "CLAUDE.md #4"},
|
||||
{"valeur": deps.branding.FONT_BODY, "source": "CLAUDE.md #4"},
|
||||
],
|
||||
},
|
||||
"handoff_vps": [
|
||||
"Créer/confirmer le module propriétaire OTO côté app puis importer les "
|
||||
"fixtures `Custom Block` (bench).",
|
||||
"Insérer dans le `content` de chaque Workspace (frontend/portails/out/"
|
||||
"workspace.json) un bloc `custom_block` référençant `block_name` (payload "
|
||||
"editor.js a_confirmer selon version).",
|
||||
"Renseigner l'endpoint OTOIA (desk/bim-cloud) dans la config runtime + "
|
||||
"charger le web-component OTOIA via le thème desk (agent Frontend · #8).",
|
||||
"Appliquer les tokens de marque dark+doré (#4) au montage via le thème.",
|
||||
],
|
||||
}
|
||||
|
||||
return {"custom_block": custom_blocks, "chat_mount": mounts, "manifest": manifest}
|
||||
Reference in New Issue
Block a user