[DTP-Worker 20260731_023000] Auto exec · session 20260731_023000
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 / Reproductibilité des artefacts out/ (build == commité) (push) Has been cancelled
CI / Fraîcheur matrice de régression (run == commité) (push) Has been cancelled
CI / Intégrité du câblage CI (gate agrège tout · gates statiques verrouillés) (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 / QA · Audit 4Big (95+/100 sur 100% deliverables) (push) Has been cancelled
CI / Démo · Scénarios (run-sheet P07 banquier / P05 client) (push) Has been cancelled
CI / QA · Matrice de régression exhaustive (Sprint 8) (push) Has been cancelled
CI / DevOps · Run-book de déploiement VPS unifié (Sprint 8) (push) Has been cancelled
CI / QA · Matrice d'acceptation / traçabilité MVP (Sprint 8) (push) Has been cancelled
CI / Mobile · config app Expo/EAS (navigation par rôle) (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 / Reproductibilité des artefacts out/ (build == commité) (push) Has been cancelled
CI / Fraîcheur matrice de régression (run == commité) (push) Has been cancelled
CI / Intégrité du câblage CI (gate agrège tout · gates statiques verrouillés) (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 / QA · Audit 4Big (95+/100 sur 100% deliverables) (push) Has been cancelled
CI / Démo · Scénarios (run-sheet P07 banquier / P05 client) (push) Has been cancelled
CI / QA · Matrice de régression exhaustive (Sprint 8) (push) Has been cancelled
CI / DevOps · Run-book de déploiement VPS unifié (Sprint 8) (push) Has been cancelled
CI / QA · Matrice d'acceptation / traçabilité MVP (Sprint 8) (push) Has been cancelled
CI / Mobile · config app Expo/EAS (navigation par rôle) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
"""Bibliothèque du générateur de config app mobile (Sprint 5 · Mobile).
|
||||
|
||||
Modules :
|
||||
- deps : dépendances partagées (validateur + branding Publiciste ; résolution
|
||||
RBAC → rôles par portail via le builder des Workspaces · réutilisation #5).
|
||||
- builder : construction déterministe du bundle (app_config Expo + eas.json +
|
||||
navigation par rôle + manifeste) depuis les sources committées.
|
||||
"""
|
||||
@@ -0,0 +1,184 @@
|
||||
"""Construction du bundle de config app mobile depuis les sources committées.
|
||||
|
||||
Entrées :
|
||||
- contract : rbac_50_roles.json (portails_business + rôles · source de vérité
|
||||
des ONGLETS et de leurs rôles autorisés).
|
||||
- spec : mobile_spec.json (choix de config : nom/slug/scheme, profils EAS,
|
||||
ordre des onglets, liste des champs `a_confirmer`).
|
||||
- portails_spec : labels + icônes des 5 portails (mise en page · même source que les
|
||||
Workspaces).
|
||||
- langs : langues FR/EN/ES + défaut (seo_spec · source unique).
|
||||
|
||||
Sortie : bundle déterministe (tri stable, aucun horodatage) :
|
||||
- app_config -> objet Expo `app.config` (thème dark+doré #4, locales seo,
|
||||
identifiants de store `null` · a_confirmer).
|
||||
- eas_build -> objet `eas.json` (profils de build + submit, credentials `null`).
|
||||
- role_navigation -> 1 onglet par portail métier, gated par la surface RBAC exacte.
|
||||
- manifest -> traçabilité (comptes, résumé par portail, marque, a_confirmer).
|
||||
|
||||
Anti-invention (#6) : aucun identifiant de store/build fabriqué (tous `null`) ; rôles =
|
||||
surface RBAC exacte du portail (mêmes valeurs que les Has Role des Workspaces) ; tokens
|
||||
de marque + devises + langues repris verbatim de leurs sources uniques.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from . import deps
|
||||
|
||||
|
||||
def _labels_icons(portails_spec: dict) -> tuple[dict, dict]:
|
||||
labels = {p["key"]: p["label"] for p in portails_spec["portails"]}
|
||||
icons = {p["key"]: p["icon"] for p in portails_spec["portails"]}
|
||||
return labels, icons
|
||||
|
||||
|
||||
def build_app_config(spec: dict, langs: list[str], default_lang: str) -> dict[str, Any]:
|
||||
"""Objet Expo `app.config`. Thème #4 ; identifiants de store `null` (#6/#8)."""
|
||||
app = spec["app"]
|
||||
b = deps.branding
|
||||
return {
|
||||
"expo": {
|
||||
"name": app["name"],
|
||||
"slug": app["slug"],
|
||||
"scheme": app["scheme"],
|
||||
"version": None,
|
||||
"orientation": app["orientation"],
|
||||
"userInterfaceStyle": app["user_interface_style"],
|
||||
"backgroundColor": b.COLOR_BG,
|
||||
"primaryColor": b.COLOR_ACCENT,
|
||||
"icon": None,
|
||||
"splash": {
|
||||
"backgroundColor": b.COLOR_BG,
|
||||
"resizeMode": "contain",
|
||||
"image": None,
|
||||
},
|
||||
"locales": {lang: None for lang in langs},
|
||||
"ios": {
|
||||
"bundleIdentifier": None,
|
||||
"buildNumber": None,
|
||||
"supportsTablet": True,
|
||||
},
|
||||
"android": {
|
||||
"package": None,
|
||||
"versionCode": None,
|
||||
},
|
||||
"extra": {
|
||||
"expoSdkMajor": app["expo_sdk_major"],
|
||||
"defaultLocale": default_lang,
|
||||
"devises": [b.DEVISE_PRIMAIRE, b.DEVISE_SECONDAIRE],
|
||||
"eas": {"projectId": None},
|
||||
},
|
||||
"plugins": [],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def build_eas(spec: dict) -> dict[str, Any]:
|
||||
"""Objet `eas.json` : profils de build + submit ; credentials `null` (#6/#8)."""
|
||||
return {
|
||||
"cli": {"version": None, "appVersionSource": spec["eas"]["app_version_source"]},
|
||||
"build": {
|
||||
"development": {
|
||||
"developmentClient": True,
|
||||
"distribution": "internal",
|
||||
"channel": "development",
|
||||
},
|
||||
"preview": {"distribution": "internal", "channel": "preview"},
|
||||
"production": {"channel": "production", "autoIncrement": True},
|
||||
},
|
||||
"submit": {
|
||||
"production": {
|
||||
"ios": {"appleId": None, "ascAppId": None, "appleTeamId": None},
|
||||
"android": {"serviceAccountKeyPath": None, "track": "internal"},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def build_navigation(contract: dict, spec: dict, portails_spec: dict) -> list[dict[str, Any]]:
|
||||
"""1 onglet par portail métier, dans l'ordre de la spec ; rôles = surface RBAC exacte."""
|
||||
roles_map = deps.roles_by_portail(contract)
|
||||
labels, icons = _labels_icons(portails_spec)
|
||||
nav: list[dict[str, Any]] = []
|
||||
for key in spec["portail_order"]:
|
||||
roles = sorted(roles_map.get(key, []))
|
||||
nav.append(
|
||||
{
|
||||
"portail": key,
|
||||
"label": labels[key],
|
||||
"icon": icons[key],
|
||||
"route": f"/{key}",
|
||||
"roles_allowed": roles,
|
||||
"n_roles": len(roles),
|
||||
}
|
||||
)
|
||||
return nav
|
||||
|
||||
|
||||
def build_bundle(contract: dict, spec: dict, portails_spec: dict, langs: list[str], default_lang: str) -> dict[str, Any]:
|
||||
app_config = build_app_config(spec, langs, default_lang)
|
||||
eas_build = build_eas(spec)
|
||||
nav = build_navigation(contract, spec, portails_spec)
|
||||
b = deps.branding
|
||||
|
||||
portails_meta = [
|
||||
{
|
||||
"portail": n["portail"],
|
||||
"label": n["label"],
|
||||
"icon": n["icon"],
|
||||
"nb_roles": n["n_roles"],
|
||||
}
|
||||
for n in nav
|
||||
]
|
||||
|
||||
manifest = {
|
||||
"generated_from": spec["generated_from"],
|
||||
"spec_version": spec["version"],
|
||||
"source_version": contract["version"],
|
||||
"roadmap_ref": spec["roadmap_ref"],
|
||||
"app": {
|
||||
"name": spec["app"]["name"],
|
||||
"slug": spec["app"]["slug"],
|
||||
"scheme": spec["app"]["scheme"],
|
||||
"expo_sdk_major": spec["app"]["expo_sdk_major"],
|
||||
},
|
||||
"counts": {
|
||||
"onglets": len(nav),
|
||||
"portails": len(nav),
|
||||
"roles_couverts": sum(n["n_roles"] for n in nav),
|
||||
"langues": len(langs),
|
||||
"identifiants_a_confirmer": len(spec["a_confirmer"]),
|
||||
},
|
||||
"brand": {
|
||||
"fond": {"valeur": b.COLOR_BG, "source": "CLAUDE.md #4"},
|
||||
"accent": {"valeur": b.COLOR_ACCENT, "source": "CLAUDE.md #4"},
|
||||
},
|
||||
"devises": {
|
||||
"primaire": b.DEVISE_PRIMAIRE,
|
||||
"secondaire": b.DEVISE_SECONDAIRE,
|
||||
"source": "CLAUDE.md #10",
|
||||
},
|
||||
"langues": {
|
||||
"liste": list(langs),
|
||||
"defaut": default_lang,
|
||||
"source": "seo/seo_spec.json · site.langs",
|
||||
},
|
||||
"a_confirmer": spec["a_confirmer"],
|
||||
"identifiants_statut": "a_confirmer",
|
||||
"portails": portails_meta,
|
||||
"hand_off": (
|
||||
"Build Expo 54 + submit App Store #32 / Play Store exécutés hors de ce "
|
||||
"worker (agent Mobile · #8) : ce livrable ne produit que la config "
|
||||
"versionnable. Les identifiants/credentials `null` sont renseignés au "
|
||||
"build sur le poste/CI Mobile, jamais fabriqués ici (#6)."
|
||||
),
|
||||
}
|
||||
|
||||
return {
|
||||
"app_config": app_config,
|
||||
"eas_build": eas_build,
|
||||
"role_navigation": nav,
|
||||
"manifest": manifest,
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
"""Dépendances partagées du générateur de config app mobile · réutilisation stricte (#5).
|
||||
|
||||
On NE réimplémente rien qui existe déjà dans le mandat :
|
||||
- `validator` (validateur JSON-Schema draft-07 maison) et `branding` (tokens de
|
||||
marque #4 + devises #10) sont importés du livrable Publiciste, source unique.
|
||||
- la résolution RBAC → rôles par portail est importée du builder des Workspaces
|
||||
(`frontend/portails/wslib/builder.py`) : l'app mobile s'ancre sur EXACTEMENT la
|
||||
même surface RBAC que les Workspaces et le Chat OTOIA — aucune logique dupliquée.
|
||||
|
||||
Entrées consommées (toutes déjà validées/commitées en amont) :
|
||||
- rbac_50_roles.json (contrat RBAC · portails_business + rôles)
|
||||
- frontend/portails/portails_spec.json (labels + icônes des 5 portails · mise en page)
|
||||
- seo/seo_spec.json (langues trilingues FR/EN/ES · source unique)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
_MOBILE = os.path.dirname(_HERE) # mobile/app_config/
|
||||
_MOBILE_ROOT = os.path.normpath(os.path.join(_MOBILE, "..")) # mobile/
|
||||
_DELIVERABLES = os.path.normpath(os.path.join(_MOBILE_ROOT, "..")) # 05_deliverables_mvp/
|
||||
_PUBLICISTE = os.path.join(_DELIVERABLES, "publiciste")
|
||||
_PORTAILS = os.path.join(_DELIVERABLES, "frontend", "portails")
|
||||
_RBAC_DIR = os.path.join(_DELIVERABLES, "rbac")
|
||||
_SEO = os.path.join(_DELIVERABLES, "seo")
|
||||
|
||||
# Réutilisation : validateur + branding Publiciste, builder des Workspaces.
|
||||
for _p in (_PUBLICISTE, _PORTAILS):
|
||||
if _p not in sys.path:
|
||||
sys.path.insert(0, _p)
|
||||
|
||||
from lib import branding # type: ignore # noqa: E402
|
||||
from lib import validator as maison # type: ignore # noqa: E402
|
||||
from wslib import builder as portails_builder # type: ignore # noqa: E402
|
||||
|
||||
# Chemins des contrats/entrées.
|
||||
SPEC_PATH = os.path.join(_MOBILE, "mobile_spec.json")
|
||||
SCHEMA_PATH = os.path.join(_MOBILE, "mobile.schema.json")
|
||||
CONTRACT_PATH = os.path.join(_RBAC_DIR, "rbac_50_roles.json")
|
||||
PORTAILS_SPEC_PATH = os.path.join(_PORTAILS, "portails_spec.json")
|
||||
SEO_SPEC_PATH = os.path.join(_SEO, "seo_spec.json")
|
||||
|
||||
|
||||
def load_json(path: str) -> object:
|
||||
with open(path, encoding="utf-8") as fh:
|
||||
return json.load(fh)
|
||||
|
||||
|
||||
def load_spec() -> dict:
|
||||
return load_json(SPEC_PATH)
|
||||
|
||||
|
||||
def load_contract() -> dict:
|
||||
return load_json(CONTRACT_PATH)
|
||||
|
||||
|
||||
def load_portails_spec() -> dict:
|
||||
return load_json(PORTAILS_SPEC_PATH)
|
||||
|
||||
|
||||
def load_langs() -> tuple[list[str], str]:
|
||||
"""Langues + langue par défaut DÉRIVÉES du seo_spec (source unique · #5)."""
|
||||
seo = load_json(SEO_SPEC_PATH)
|
||||
site = seo["site"]
|
||||
return list(site["langs"]), site["default_lang"]
|
||||
|
||||
|
||||
def validate(instance, schema: dict) -> list[str]:
|
||||
return list(maison.validate(instance, schema))
|
||||
|
||||
|
||||
# Réexport : surface RBAC des rôles par portail = celle des Workspaces (source unique).
|
||||
roles_by_portail = portails_builder.roles_by_portail
|
||||
|
||||
__all__ = [
|
||||
"branding",
|
||||
"load_json",
|
||||
"load_spec",
|
||||
"load_contract",
|
||||
"load_portails_spec",
|
||||
"load_langs",
|
||||
"validate",
|
||||
"roles_by_portail",
|
||||
"SPEC_PATH",
|
||||
"SCHEMA_PATH",
|
||||
"CONTRACT_PATH",
|
||||
"PORTAILS_SPEC_PATH",
|
||||
"SEO_SPEC_PATH",
|
||||
]
|
||||
Reference in New Issue
Block a user