Project

General

Profile

Actions

Feature #377

closed
RA

Feature #82: Améliorer la génération de PDF pour les contrats avec design professionnel et signatures configurables

Refonte du rendu PDF contrat : HTML → Chromium (Playwright) + Paged.js (mise en page A4 pro multi-page)

Feature #377: Refonte du rendu PDF contrat : HTML → Chromium (Playwright) + Paged.js (mise en page A4 pro multi-page)

Added by Redmine Admin about 2 months ago. Updated about 1 month ago.

Status:
Shipped
Priority:
Normal
Assignee:
-
Start date:
06/15/2026
Due date:
% Done:

0%

Estimated time:
spec_ref:
build_status:
build_number:
ci_run_url:
scan_status:
scan_report_url:
deploy_status:
deployed
preprod_url:
deployed_at:
06/23/2026
branch:
feat/377-contract-pdf-chromium
pr_url:
security_key:
severity:
paused:

Description

**Suivi #82/#90.** Le moteur pdf-lib hand-rolled (#90) produit une mise en page cassée sur les contrats multi-pages : texte qui se chevauche/duplique aux sauts de page, signatures/logo par-dessus le texte, formatage HTML perdu (gras/listes/tableaux). pdf-lib n'a pas de moteur de flux/pagination.

**Solution retenue (B) :** rendre le contrat HTML via **Chromium headless (Playwright) + Paged.js**, embarqué dans l'image api.

### Architecture (hexagonale)
- `domain/ports/pdf-renderer.port.ts` : `PdfRendererPort.renderHtmlToPdf(html, opts): Promise<Buffer>`.
- `infrastructure/pdf/chromium-pdf.renderer.ts` : adaptateur Playwright (navigateur singleton, `--no-sandbox`), `setContent` + injection Paged.js + `page.pdf({format:'A4', printBackground:true})`. Échec → `DependencyUnavailableError(503)`.
- `application/functions/contract-html.builder.ts` : fonction **pure** qui assemble le document HTML complet + le CSS d'impression (testable sans navigateur).
- `contract-pdf.use-cases.ts` : recâblé (résout réglages/logo/signatures comme #91/#92 → builder → PdfRendererPort → stockage). **Contrat public `generateContractPdf` inchangé** (file_url + data-URI).
- `app.module.ts` : bind `PDF_RENDERER → ChromiumPdfRenderer`.
- `server/Dockerfile` : installer Chromium Playwright + libs système.

### Mise en page (Paged.js + print CSS)
- `@page { size:A4; margin:2cm }` ; éléments courants Paged.js : logo en en-tête sur **chaque** page, pied de page « page X / Y » + numéro de contrat.
- Corps = HTML **préservé** (gras/listes/tableaux) ; flux + sauts de page **automatiques** (plus de chevauchement).
- Bloc signatures = ligne HTML (emplacement left/right/side_by_side selon réglages), image signature + nom + « Signé par … le … », `break-inside: avoid` (jamais coupé, jamais par-dessus le texte). Les signatures sont dans le HTML → le **PDF signé** est corrigé de la même façon (plus de stamping pdf-lib).

## Acceptance criteria
- [ ] Contrat multi-pages : aucun chevauchement/duplication aux sauts de page.
- [ ] Logo en-tête + filet sur chaque page ; marges 2 cm ; numéro de contrat + pagination en pied.
- [ ] Formatage HTML (gras/listes/tableaux) préservé.
- [ ] Signatures (émetteur/destinataire) aux 3 emplacements, mentions, jamais par-dessus le texte ; PDF signé OK.
- [ ] `generateContractPdf` garde son contrat de retour ; flux de signature/contre-signature OK.
- [ ] Tests : builder HTML (unit, sans navigateur) + un rendu e2e (Chromium) ; lint/typecheck/build verts ; Dockerfile installe Chromium.
- [ ] Doc de conception : docs/superpowers/specs/2026-06-15-contract-pdf-chromium-design.md.

RA Updated by Redmine Admin about 2 months ago Actions #1

  • Status changed from Submitted to In development
  • branch set to feat/377-contract-pdf-chromium

Dev démarré (worktree sur `origin/dev`). Submitted → In development. Refonte rendu PDF contrat via Chromium + Paged.js (design approuvé par l'utilisateur).

RA Updated by Redmine Admin about 2 months ago Actions #2

  • Status changed from In development to QA

**Déployé en préprod (build #16, api OK) + vérifié visuellement → QA.** Contrat 68 Ko régénéré via le nouveau moteur Chromium : **PDF A4 7 pages**, géométrie A4 (595×842 pt), marges 2 cm.
- **Chevauchement/duplication aux sauts de page : CORRIGÉ** (flux propre, filet d'en-tête sur chaque page, pied « page X / 7 » + numéro CONTRAT-2026-001).
- **Signatures : CORRIGÉ** — bloc deux colonnes (structure / production) avec images + « Signé par … le … », sous le texte, plus de chevauchement (break-inside:avoid OK).
- **Formatage HTML préservé** (gras, articles).

**Suivi (hors mise en page de base) :**
1. Le **logo** intégré dans le corps déborde de la marge droite → cap CSS `img{max-width:100%}` à ajouter (correctif rapide en cours).
2. Tags non substitués sur ce modèle : `{{production.company_name}}`, `<<column_firstrow:…>>`, `{{signature}}` littéral → problème de **substitution** (syntaxe de tags du modèle), distinct de la mise en page — à traiter à part.

RA Updated by Redmine Admin about 2 months ago Actions #3

  • Status changed from QA to Preprod

Déployé et vérifié en préprod (build #19, https://preprod-scobby.omdev.tech) : contrat multi-pages sans chevauchement/duplication, logo en-tête, numéro + pagination, HTML préservé, signatures aux bons emplacements, PDF signé OK. Tous les chemins (téléchargement éditeur, téléchargement public, signature) passent par Chromium/Paged.js. Passage QA → Preprod.

RA Updated by Redmine Admin about 1 month ago Actions #4

  • Status changed from Preprod to Ready to ship

Livré sur master (dev = preprod = master). Commits `149c2eaf` (PR #29) — rendu PDF via Chromium (Playwright) + Paged.js, `289e0f38` (PR #34) — cible Prisma debian-openssl-3.0.x runtime Playwright, `9183e4e0` (PR #39) — substitution complète des tags + cap logo. Passage en **Ready to ship** — *Shipped* après confirmation du gate prod manuel (Jenkins) sur scobby.fr.

RA Updated by Redmine Admin about 1 month ago Actions #5

  • Status changed from Ready to ship to Shipped
  • deploy_status set to deployed
  • deployed_at set to 06/23/2026

Déploiement PROD confirmé live sur scobby.fr (gate manuel Jenkins approuvé le 2026-06-23). Passage en **Shipped**.

Actions

Also available in: PDF Atom