47 lines
5.6 KiB
Markdown
47 lines
5.6 KiB
Markdown
# nyora-doc-api — Mode template : cause racine du non-restyle des runs + correctif proposé
|
||
|
||
**Date** : 08/07/2026 · **Statut** : IMPLÉMENTÉ ET DÉPLOYÉ le 08/07/2026 (commits a7380268/f7353419, image rebuildée, testé en prod)
|
||
|
||
## Contexte de la session
|
||
Objectif initial : rebuilder le correctif footer DOCX. **Constat : déjà déployé le 04/07** (image buildée 08:03 UTC, commit 3c0d20ff, code container == disque == Gitea, vérifié par `docker exec cat | diff`). Voir `common/nyora-doc-api-rebuild-footer-docx.md`. Session réorientée sur la limite connue du mode template.
|
||
|
||
## Vérification prod du footer (08/07, re-validée)
|
||
Mode data, titre long 140+ caractères + tableau totaux : footer1.xml contient liseré or B8862A, « · NYORA · », tagline, © 2026, champs PAGE/NUMPAGES. Corps intact, format FR `1 234 567,891` OK. **Aucune régression du correctif footer sur le mode data.**
|
||
|
||
## Cause racine — DOCX template (`generate_docx`, services.py:11)
|
||
1. `docxtpl.render()` remplace les tags Jinja **en héritant du rPr du run porteur du tag** (police/taille/couleur directes du template).
|
||
2. `apply_docx_theme(doc)` (formatting.py:139) ne modifie que les **définitions de styles** (Normal, Heading 1–4) + marges. Il ne touche jamais les runs.
|
||
3. Précédence OOXML : **formatage direct de run (rPr) > style de paragraphe > défauts**. Or Word écrit un rPr explicite dès que l'auteur choisit une police → dans un template réel, quasi tous les runs portent un rPr → le thème appliqué au style est invisible.
|
||
|
||
**Preuve empirique (08/07)** : template avec run Comic Sans MS 22pt rouge `{{name}}` → sortie : styles.xml bien rethémé Calibri, MAIS document.xml conserve Comic Sans/sz=44/FF0000. CQFD.
|
||
|
||
Angles morts supplémentaires : styles custom du template non couverts (seuls Normal/Heading 1–4 sont réécrits), headers/footers du template jamais parcourus, `font.name` de python-docx ne règle que `rFonts@ascii,hAnsi` (pas `cs` → texte arabe non restylé).
|
||
|
||
## Cause racine — PPTX template (`generate_pptx`, services.py:362)
|
||
Architectural : la branche template (`_replace_in_slide` → `validate_pptx_layout` → `save` → `return`) **sort avant toute lecture du thème**. `_replace_in_textframe` concentre le texte dans `runs[0]` qui garde son rPr d'origine. Aucun restyle n'est même tenté.
|
||
|
||
## Correctif proposé (design, à faire exécuter — brief prêt)
|
||
Option opt-in `options.restyle: "none" (défaut) | "full"` — défaut à `none` pour ne jamais détruire une mise en page de template voulue.
|
||
|
||
**DOCX (`restyle=full`)** : après `render()`, itérer TOUS les paragraphes (body + cellules de tables + header/footer de chaque section) ; pour chaque run : forcer `rFonts` ascii/hAnsi/**cs**/eastAsia (Calibri corps, Arial si style Heading 1–2), taille selon catégorie du style du paragraphe (mapping Typography), couleur charte ; **préserver bold/italic** (emphase sémantique de l'auteur). Générateur `_iter_all_paragraphs(doc)` ~15 lignes.
|
||
|
||
**PPTX (`restyle=full`)** : ne PAS restyler tout le deck (destructeur). Marquer dans `_replace_in_textframe` les paragraphes où une substitution a eu lieu et ne restyler que ceux-là (font family + couleur thème, taille conservée).
|
||
|
||
Estimation : ~60 lignes services.py + ~25 lignes formatting.py. Test de non-régression : le template Comic Sans ci-dessus avec restyle=none (inchangé) puis restyle=full (Calibri 11 navy).
|
||
|
||
## Leçon transverse (ajoutée à PROTOCOL-INFRA des 3 instances)
|
||
`/app` est **cuit dans l'image** (COPY du Dockerfile), pas bind-mounté. Avant tout rebuild « parce qu'un fix n'est pas actif » : vérifier d'abord `docker exec <ctn> cat <fichier> | diff - <fichier disque>` + date de build image (`docker images --format '{{.CreatedAt}}'`). Ici, le rebuild demandé était déjà fait — 10 min économisées, zéro interruption de service.
|
||
|
||
## Rappel usage pour les agents Hermes
|
||
Tant que `restyle=full` n'est pas implémenté : **mode data pour tout document devant porter la charte** (Nyora ou tt). Le mode template ne sert qu'à remplir un document dont on veut garder le design d'origine.
|
||
|
||
## Point d'attention branding (décision Nabil requise)
|
||
Le footer « · NYORA · » est ajouté à TOUT DOCX mode data, y compris pour des documents Zone Sud (le thème `tt` n'existe que pour XLSX/PPTX, pas DOCX). Un document officiel Direction Zone Sud portera donc le branding Nyora. Proposition : `options.theme=tt` sur DOCX → footer neutre (pagination seule) + éventuel thème navy/cyan. À trancher avant implémentation.
|
||
|
||
|
||
## Implémentation finale (08/07/2026, GO Nabil)
|
||
`options.restyle: "none" (défaut) | "full"`. DOCX full : `apply_docx_run_restyle()` (formatting.py) — corps + tables + headers/footers de section, rFonts ascii/hAnsi/cs/eastAsia (arabe couvert), tailles/couleurs charte par style (Heading 1-4/Title/Subtitle → Arial pour H1/H2/Title), bold/italic du corps préservés. PPTX full : `_restyle_touched_pptx()` — police+couleur charte sur les SEULS paragraphes substitués, taille conservée, le reste du deck intact.
|
||
|
||
**Décision complémentaire : plus AUCUN footer sur aucun document.** DOCX : bloc Nyora + pagination Page X/Y supprimés (fonction `_add_docx_page_number_footer` supprimée). PDF : `@bottom-center` retiré du CSS. Ceci règle aussi le point branding · NYORA · sur documents Zone Sud.
|
||
|
||
**Vérifié en prod** : data DOCX → zéro footer*.xml dans l'archive, corps/totaux intacts ; template restyle défaut → Comic Sans survit (rétro-compatible) ; restyle=full → Calibri 11 navy + cs="Calibri" + heading Arial ; PPTX restyle=full → paragraphe substitué Calibri (taille 28 conservée), paragraphe non substitué garde sa police d'origine ; PDF → « Page 1 / 1 » absent. |