SPEC — Macroscope Rendering Templates

SPEC — Macroscope Rendering Templates

Status: Draft v0.1 Owner: Francois (Framework Specialist) Source request: MET-0008 Authority: TFD-0024 Reference impl: C:\Users\bockb\OneDrive - STM\agent-ea\clients\transgesco\DAE-0007-trangesco-evaluation-systemes\out\_publish\dae-0007\ Canonical taxonomy: C:\Users\bockb\OneDrive - STM\agent-ea\clients\transgesco\DAE-0007-trangesco-evaluation-systemes\MACROSCOPE-STRUCTURE.md


1. Purpose & Scope

Specify the rendering layer of the Macroscope framework — HTML templates + data binding + print/PDF behavior — so that every DAE (Dossier d'Architecture d'Entreprise) reuses the same structure instead of reinventing it.

In scope (this spec):

  • Common data contract (D1 → data.js)
  • Shared CSS tokens and layout primitives
  • Section schema (extensible per A### code)
  • A100+A280 jumeau mechanic
  • Print/PDF behavior

Out of scope (handled elsewhere):

  • D1 schema itself (lives in agent-ea v2, see memory ea-registre-architecture)
  • Content templates (markdown scaffolds, siblings under templates/)
  • Skill /toolkit:framework-publish (extracted after templates validated)
  • Word .docx export (lot 2)

1bis. Universal pattern — Landing → Registre → Detail (3 niveaux)

Note terminologique : on dit « Registre » (pas « Registreue ») pour la page intermédiaire, afin d'éviter la collision avec le Registreue d'objets EA (D1, voir memory ea-registre-architecture). Synonymes acceptables si contexte le justifie : Répertoire, Index, Liste. Jamais « Registreue ».

Règle transverse : tout livrable navigable suit le pattern à trois étages :

┌─────────────────────┐    ┌─────────────────────┐    ┌─────────────────────┐
│   LANDING PAGE      │    │   REGISTRE PAGE      │    │   DETAIL PAGE       │
│  (DAE home page)    │───▶│  (intermediate list)│───▶│  (single article)   │
├─────────────────────┤    ├─────────────────────┤    ├─────────────────────┤
│ • Présente le DAE   │    │ • Grille de tous    │    │ • Contenu complet   │
│ • Liens vers chaque │    │   les items d'UNE   │    │ • Chapter nav       │
│   registreue/article │    │   catégorie         │    │ • Toutes sections   │
│ • KPI / sommaire    │    │ • Recherche + filtres│   │ • Drawer / détails  │
│ • Carte du DAE      │    │ • Tri + compteur    │    │ • Prêt PDF/print    │
│ • Statut global     │    │ • Lien vers détail  │    │ • Retour vers       │
│                     │    │ • Retour vers       │    │   registreue         │
│                     │    │   landing           │    │                     │
└─────────────────────┘    └─────────────────────┘    └─────────────────────┘
       index.html             *-registreue.html             *-detail.html
                              (ou *-architecture.html)

Exemples appliqués DAE-0007 :

Niveau Page Rôle
Landing index.html Accueil DAE, présente le dossier et liens vers tous les registreues/livrables
Registre 230-orientations-architecture.html Liste de toutes les ORI avec recherche/filtres/tri
Detail 230-ori-001-yoffix.html Article complet d'une orientation (Yoffix)
Registre 14-processus-registreue.html Liste de tous les processus (FLOWS)
Detail 14-p01-fermeture-mensuelle.html Fiche complète d'un processus
Registre registreue-changements.html Liste des changements (CHG)
Detail fiche-changement.html?id=CHG-1 Détail d'une initiative
Registre 100-solution-globale.html Vue solution + sommaire (hybride A100/A280)

Capacités minimales d'une CATALOG page (vocabulaire fermé) :

  1. Recherche libre (input texte, filtre cartes par nm + desc + ctx)
  2. Filtres multi-critères (catégorie, statut, phase, direction — selon la donnée)
  3. Tri (par défaut sur ID ; alternatives : statut, phase, alphabétique)
  4. Compteur dynamique (X / Y affichés)
  5. État vide géré (placeholder si filtre vide ou data manquante)
  6. Lien vers detail sur chaque carte (si une page detail existe)
  7. Pas de mélange de catégories — un registre = UNE catégorie. Ne JAMAIS mêler CHG et ORI sur le même registre.
  8. Retour vers landing (breadcrumb ou lien ← Accueil)

Capacités minimales d'une LANDING page :

  1. Présente le DAE (titre, deck, métadonnées, statut global)
  2. Liens nommés vers chaque registre (Voir le registreue des orientations →)
  3. Aucune liste détaillée d'items individuels (c'est le rôle du registre)
  4. KPI/sommaire optionnel (nombre de changements, phases, etc.)

Capacités minimales d'une DETAIL page :

  1. Contenu complet d'UN seul item
  2. Breadcrumb : Landing → Registre → Detail
  3. Lien ← Registre en mast
  4. Optimisée pour PDF/print (single-document focus)

Anti-patterns explicites :

  • ✗ Page qui mélange "orientations" + "changements" + "projets" sur une seule grille
  • ✗ Detail page accessible uniquement par URL directe (toujours partir du registre)
  • ✗ Filtres absents sur un registre dépassant ~5 items
  • ✗ Registre page sans lien vers landing
  • ✗ Landing page qui détaille individuellement les items (c'est le rôle du registre)

Le skill /toolkit:framework-publish enforce ce pattern à 3 étages lors du scaffold de toute nouvelle catégorie de livrables.


2. Architecture overview

D1 (per-client EA DB)
    │  export
    ▼
data.js  ──┐ (single source of truth, per DAE)
           │
           ▼
HTML template (rendering layer, this spec)
    │
    ├─ Screen view (interactive: filters, drawers, tabs)
    └─ Print view (_print.css: expanded, paginated)
            │
            ▼
       PDF (Playwright headless, _shared/exporters/html-to-pdf.js)

Invariants:

  • A template never contains client data — only structure + binding.
  • All client data flows through data.js (loaded via <script src="data.js">).
  • A template is identified by one or more Macroscope A### codes (a "jumeau" template carries 2+).
  • Two templates referencing the same A### code = error (single home per code, see MACROSCOPE-STRUCTURE.md §"une seule maison").

3. Data contract

3.1 Top-level objects in data.js

Borrowed from DAE-0007 (proven), extensible. All optional except META.

Object Shape Used by Notes
META {client, dae, publishedDate, basePath} all required, drives footer + crumbs
MAP [{l1, nom, caps:[{nm, sub, dec, decL, crit, critL, pro[], org, role[], app[], cmp[], vendor, op, opStm, opex, vol, src, change_type?, change_desc?}]}] A100, A280, A219, A200, A250 LeanIX v4 (Capacité→Processus→App→Composant→Opérateur). Optional change_type + change_desc populate A280 overlay.
SVC [{nm, dec, decL, crit, cov, cons, opex, dec2}] A100, A280, A400 services partenaires/STM
PROJ [{id, nm, cap, org, st, stL, capex, opexD, fund, why, type, impact, impactDesc, change, owner, deadline, depends, sow?}] A100, A280, A270 projets, CapEx, change détaillé
CHG [{id, code, nm, dir, desc, ph, phEnd, projets[]}] A100 sommaire, A310-A360 initiatives (regroupe ≥1 PROJ)
PHASES, PHWIN, JALONS timeline A100, A270 feuille de route
DATA {subjects:[{id, nm, dom, apps[], own, d}], rel[], flows[]} A100 (vues données/flot), A150 modèle conceptuel + flux
FLOWS {<process-id>:{...}} A251, A100 (process refs) processus, SIPOC, BPMN
PROC_LINKS {<process-name>: <url>} cross-page links navigation processus
ORI [{id, nm, cat, catL, st, stL, q, ctx, href?, phase?}] A230, A100 (orient. transverses) Orientations d'architecture. catcollab|infra|fin|gov. stcours|att|diff. Schéma DAE-0007 canonique.

3.2 The change_type / change_desc overlay (A280 mechanic)

Any object that participates in an A280 view exposes optional fields:

Field Type Values Meaning
change_type enum NEW, MOD, EXIST, OUT Nature du changement de l'objet entre AS-IS et cible
change_desc string text Description courte (≤200 char), affichée en tooltip/drawer
change_phase enum 0, 1, 2, x Phase de livraison (filtre Macroscope, optionnel)
change_chg string CHG-N id Rattache l'objet à une initiative (filtre, optionnel)

Règle : un objet sans change_type est traité comme EXIST par défaut. Aucune donnée client n'est jamais codée en dur dans le template.

3.3 D1 → data.js binding

Le mapping D1 → data.js est porté par le pipeline existant (memory d1-datajs-html-pipeline). Cette spec contraint uniquement la forme de data.js, pas comment il est produit. Aligné TFD-0010 (interface contract).


4. CSS tokens & layout primitives

Source canonique : _jct-editorial.css + _jct-harmonize.css + _print.css (DAE-0007). Copiés dans templates/rendering/_shared-css/.

4.1 Color tokens

:root{
  /* STM/Transgesco navy (override per client via META) */
  --navy:#002B5C; --navy-700:#003D7A; --navy-50:#EAF0F8;
  --green:#009A44; --green-700:#007A35; --green-50:#E8F7EE;
  --yellow:#FFE400; --yellow-700:#8A7600; --yellow-50:#FFFBE6;
  --blue:#009EE0; --blue-50:#E0F5FC; --teal:#007489;
  --red:#B91C1C; --red-50:#FEE2E2;

  /* Editorial ink scale */
  --ink:#0B1220; --ink-2:#1F2937; --ink-3:#4B5563; --ink-4:#6B7280;

  /* Paper (cream) — editorial signature */
  --paper:#F7F4EC; --paper-2:#FBF8F0; --white:#fff;
  --rule:#B8B19E; --rule-2:#E5E0D1;

  /* Change-type swatches (A280) */
  --chg-new:#0066CC; --chg-mod:#D4A800; --chg-exist:#5A9B6A; --chg-out:#999;

  /* Typography */
  --serif:"Fraunces","Cormorant Garamond",Georgia,serif;
  --sans:"Inter","Söhne","Segoe UI",system-ui,sans-serif;
  --mono:"JetBrains Mono",Consolas,monospace;
}

4.2 Layout primitives

Class Purpose
header.mast + .stripe Masthead navy → green gradient + yellow/green/blue stripe
.container (max-width:1280px) Page container
.crumb Breadcrumb (mono, small)
h1 (serif, italic accent en <em> jaune) Page title
.deck Subtitle (serif italic, light navy)
h2.sec Section heading (serif, navy, underline)
.intro-text Section intro paragraph
.callout Highlighted box (green left-border)
.grid Card grid (auto-fill min 380px)
.chg-card, .chg-head, .chg-body Change card (used in A100 sommaire et A230)
.chg-status + .st-actif/.st-cond/.st-out/.st-phase Status pills
.diag-tab, .diag-pane, .diag-bar, .diag-stage Interactive diagram framing
.tg-card (variants [data-impact="..."]) Object cards in diagrams, colored by change_type
.diag-drawer + .scrim Side drawer for object detail

4.3 Print rules (_print.css)

  • All interactive panes expanded.
  • Drawers inlined as appendix sections.
  • Tabs collapsed to sequential sections (each pane visible).
  • Page breaks before each h2.sec.
  • Color preserved (-webkit-print-color-adjust: exact).

5. Section schema (extensible registre)

Each A### code declares its rendering recipe. Registre format:

// templates/rendering/_registre.js (generated alongside the templates)
const CATALOG = {
  "LANDING": {
    title: "Accueil DAE (landing)",
    crumbLabel: "00 · Accueil",
    twinned: false,
    file: "index.html",
    sections: [
      { id:"masthead", h:"Masthead", kind:"prose", binding:"LANDING.{badge,rule,title,sub,meta}" },
      { id:"intro",    h:"Intro éditoriale", kind:"prose", binding:"LANDING.intro" },
      { id:"sections", h:"Ledger sections (cartes vers registres)", kind:"card-grid",
        binding:"LANDING.sections[].tiles[]",
        // LOI : un tile.href pointe TOUJOURS un registre ou un detail. Jamais un item enumeré ici.
        contract:"no item enumeration on landing — point to registers only" }
    ]
  },
  "A100+A280": {
    title: "Solution d'entreprise & analyse d'impact",
    crumbLabel: "01 · A100 · A280",
    twinned: true,
    file: "A100-A280-solution-impacts.html",
    sections: [
      { id:"archi-cible", h:"Architecture cible — 4 vues",
        kind:"interactive-tabs",
        tabs:[
          {id:"logi",  label:"Logicielle · A219", binding:"MAP+app/cmp"},
          {id:"data",  label:"Données · A150",   binding:"DATA.subjects+rel"},
          {id:"flot",  label:"Flot de données",  binding:"DATA.flows"},
          {id:"infra", label:"Infrastructure · A370", binding:"MAP+infra"}
        ],
        filters:["phase","chg","impact"],
        drawer:"object-detail"
      },
      { id:"sommaire-chg", h:"Sommaire des changements",
        kind:"card-grid",
        binding:"CHG",
        linkPattern:"fiche-changement.html?id={id}"
      },
      { id:"orientations", h:"Orientations transverses à valider",
        kind:"card-grid",
        binding:"ORIENT (filtered by CHG=CHG-1)"
      }
    ]
  },
  "A230": {
    title: "Orientations d'architecture",
    crumbLabel: "02 · A230",
    twinned: false,
    file: "A230-orientations-architecture.html",
    sections: [
      { id:"orient-list", h:"Orientations", kind:"card-grid",
        binding:"ORIENT", linkPattern:"230-ori-{id}.html" }
    ]
  }
  // Future codes (A140, A200, A251, ...) plug in here via /toolkit:framework-publish
};

Section kinds (vocabulaire fermé, étendre seulement si besoin réel) :

  • interactive-tabs — pane tabs + filters + drawer (A100, A219, A150)

  • card-grid — grid of .chg-card (sommaire, orientations)

  • static-mermaid — Mermaid diagram block (A251, A270)

  • data-table — sortable/filterable table (registreues, inventaires)

  • prose — h2 + intro-text + body sections (A140, A230 detail pages)

  • impact-matrix — matrice couche × option avec changements typés (A230-ORI detail).

    Définitions canoniques des couches (LOI : ne jamais mélanger ces couches, chaque objet va dans UNE couche unique) :

    Couche Définition stricte Exemples d'objets NE PAS mettre ici
    Stratégie / orientations Principes directeurs et choix de cap. Pas des objets concrets. « Orientation SaaS-first », « Cloud-only », « Multi-fournisseur autorisé » Apps, rôles, processus
    Organisation Structure organisationnelle : directions, départements, équipes, comités. Entités collectives nommées dans l'organigramme. « Direction Finance », « Comité de gérance SEC », « Équipe TI Transgesco » Rôles individuels (→ Rôles), processus (→ Processus)
    Processus d'affaires Flux de travail métier, séquences d'activités, procédures opérationnelles. « Fermeture mensuelle », « Démarche de marché », « Réservation de poste » Apps qui supportent le processus (→ Applications), rôles qui l'exécutent (→ Rôles)
    Rôles et compétences Fonctions individuelles : postes nommés, profils de compétences, rôles dans l'organigramme. C'est ici que vivent « administrateur X », « gestionnaire Y », « analyste Z ». « Comptable principale », « Administrateur M365 », « Administrateur Yoffix » Départements (→ Organisation), équipes (→ Organisation)
    Applications Logiciels métiers identifiables : apps SaaS, modules ERP, plateformes. Un nom commercial unique. « Sage Vision33 », « CaseWare », « Yoffix », « Microsoft Teams » Composantes techniques sous-jacentes (→ Composante TI), hébergement (→ Composante TI)
    Composante TI Infrastructure et services techniques : connecteurs, intégrations, stockage, identité, réseau, hébergement. « Tenant M365 », « Connexion SSO SAML », « Provisionnement SCIM », « Hébergement EU Yoffix » Apps (→ Applications)

    Tests de la couche (à appliquer mentalement avant d'écrire un objet dans le matrix) :

    • Si je peux le pointer dans un organigramme et c'est une boîte avec ≥2 personnes → Organisation
    • Si je peux le pointer dans un organigramme et c'est une fonction individuelle → Rôles
    • Si c'est un nom commercial de logiciel → Applications
    • Si c'est un câble, un protocole, un stockage, une intégration → Composante TI
    • Si c'est un verbe d'action métier (« faire X ») → Processus
    • Si c'est un principe de cap → Stratégie

    Format canonique :

// In data.js for a A230-ORI detail page
const ORI_DETAIL = {
  ref:"A230-ORI-001",
  title:"Plateforme de gestion des espaces de bureau",
  deck:"Yoffix · Microsoft Places · M365 natif",
  meta:[ /* metadata bar rows */ ],

  options:[
    { id:"A", label:"Yoffix",            color:"opt-a" },
    { id:"B", label:"Microsoft Places",  color:"opt-b" },
    { id:"C", label:"M365 natif",        color:"opt-c", recommended:true }
  ],

  // Layers — vocabulaire LeanIX v4 étendu (Stratégie + Org + Rôles ajoutés)
  layers:[
    { id:"strat", nm:"Stratégie / orientations" },
    { id:"org",   nm:"Organisation" },
    { id:"proc",  nm:"Processus d'affaires" },
    { id:"role",  nm:"Rôles et compétences" },
    { id:"app",   nm:"Applications" },
    { id:"cmp",   nm:"Composante TI" },
    { id:"data",  nm:"Données" },           // optionnel
    { id:"sec",   nm:"Sécurité & conformité" } // optionnel
  ],

  // Matrix indexed by "<layer>.<option>" → structured cell
  matrix:{
    "strat.A":{ level:"NONE", objects:[],
      rationale:"Aligné orientation SaaS-first. Pas de tension stratégique." },
    "org.A":  { level:"NEW",  objects:[
        {type:"NEW", nm:"Rôle administrateur Yoffix", desc:"Cumulé avec admin M365"}],
      rationale:"Pas d'embauche. Admin Yoffix = admin M365 (PRJ-08)." },
    "app.A":  { level:"NEW",  objects:[
        {type:"NEW", nm:"Yoffix (SaaS)", desc:"Add-in Teams + portail"}],
      rationale:"Nouveau fournisseur SaaS, intégration Teams native." },
    // ... etc pour chaque combinaison couche×option
  }
};

Vocabulaire fermé :

  • levelNEW | MOD | OUT | NONE (jamais autre chose). NONE = aucun impact sur cette couche pour cette option.
  • objects[].typeNEW | MOD | OUT. Pas de type NONE au niveau objet — un objet sans changement n'est simplement pas listé.
  • level doit être la synthèse cohérente des objects[] : si tout est NONElevel:"NONE" et objects:[]. Si ≥1 NEW et ≥1 MOD ⇒ level:"NEW" (priorité décroissante NEW > MOD > OUT > NONE).

Rendu visuel (cellule) :

┌──────────────────────────────────────┐
│ [pill NEW]                           │  ← level pill (color-coded)
│                                      │
│ • [NEW] Yoffix (SaaS)               │  ← objects with type badges
│   Add-in Teams + portail            │
│                                      │
│ Nouveau fournisseur SaaS,           │  ← rationale (italic, ink-3)
│ intégration Teams native.           │
└──────────────────────────────────────┘

Colonne option recommandée (recommended:true) : fond --paper-2 + bordure verte gauche.

5.1 A100+A280 jumeau mechanic

Une seule page HTML, mode toggle en haut (sticky, mono-font pill) :

[ Cible · A100 ]  [ Impacts · A280 ]  [ Tableau sommaire ]
  • Mode "Cible" : tg-cards rendues sans data-impact attribute → bordure neutre, légende impact masquée.
  • Mode "Impacts" : tg-cards rendues avec data-impact={change_type} → bordure colorée + légende visible + filtre change_type actif.
  • Tableau sommaire : remplace le stage diag par une data-table (objets × change_type × change_desc × change_phase × change_chg). Tri/filtre côté client. Pas d'overlay visuel — c'est la version "exécutive" du A280.

Impl note : un seul <main>, trois <section data-mode="..."> masquées/affichées par aria-hidden. Pas de re-render — toggle de classe sur <body>.

5.2 PDF rendering du jumeau (résout R2 du request)

À l'impression, les 3 modes sont rendus séquentiellement : Cible → Impacts → Tableau. Page break entre chaque. Le toggle est masqué (@media print { .mode-toggle{display:none} }). Aucun choix utilisateur à l'impression — un PDF unique contient tout.


6. File layout (canonical)

production-lines/digital-talent/frameworks/
  enterprise-architecture/
    macroscope/
      framework-guide.md          (existing, content layer doc)
      overview.md                 (existing, content layer doc)
      templates/                  (Francois owns)
        enterprise-solution-template.md          (existing, content scaffold)
        enterprise-context-template.md           (existing)
        architecture-orientation-template.md     (existing)
        architecture-evaluation-template.md      (existing)
        rendering/                               (THIS SPEC)
          SPEC.md                                (← this file)
          README.md                              (usage for Remy/Elena)
          _registre.js                            (section registre, extensible)
          _shared-css/
            _jct-editorial.css
            _jct-harmonize.css
            _print.css
          index.html                             (LANDING gabarit, niveau 1 du 3-tier)
          index-data.example.js                  (DAE-0007 echo for regression)
          A100-A280-solution-impacts.html
          A100-A280-data.example.js              (skeleton + DAE-0007 echo for regression)
          A230-orientations-architecture.html
          A230-data.example.js
          A230-ORI-detail.html
          A230-ORI-detail-data.example.js
  _shared/
    exporters/
      html-to-pdf.js              (Playwright, all frameworks)
      README.md

7. Validation criteria

A template is "ready" when:

  1. Renders cleanly with empty data (skeleton navigable, no JS errors).
  2. Renders cleanly with DAE-0007 echo (A100-A280-data.example.js reuses DAE-0007 data.js as a regression fixture).
  3. PDF export reproduces screen layout, all interactive content expanded, clean page breaks.
  4. Cloneable to a new DAE in ≤5 min (copy folder + swap data.js + adjust META + done).
  5. No client data hardcoded in HTML — every visible string in templates is a placeholder or comes from data.js.

8. Open questions for board review

  • OQ-1 — Tokens client-specific (navy override per client) : currently hardcoded in :root. Move to META.theme = {primary, accent} and apply via CSS variables? Reco : oui, mais lot 2 — pour DAE-0007 le navy STM reste bon.
  • OQ-2CATALOG extensible : doit-il être 1 fichier global ou 1 fichier par framework ? Reco : 1 par framework (_registre.js sous chaque framework folder), agrégé par le skill /toolkit:framework-publish.
  • OQ-3 — Mermaid (utilisé par A251 dans DAE-0007) : on garde le bundle mermaid.min.js shared ou per-template ? Reco : _shared/lib/mermaid.min.js à côté des exporteurs.
  • OQ-4 — A140 (Contexte d'entreprise), A270 (Stratégie de livraison) — pas dans MET-0008 mais à scaffolder via skill plus tard. Section kinds prose + data-table suffisent ? À valider quand on les fera.

9. Next steps (post-spec approval)

  1. Board review spec (this file) → ajustements
  2. Implement A100-A280-solution-impacts.html + A230-orientations-architecture.html (task #3)
  3. Copy DAE-0007 data.js as *-data.example.js fixtures (regression)
  4. Build html-to-pdf.js Playwright (task #4)
  5. Regression test : régénérer DAE-0007 A100 + A230 depuis les gabarits
  6. Extract /toolkit:framework-publish skill du pattern (task #5)
  7. Notif Pablo (N-023a) + Ada (N-050) à la publication