- Ajout helpers Handlebars pour remplacer filtres Liquid - Conversion template CDDU de Liquid vers Handlebars - Nouvelle API route /api/generate-contract-pdf pour Gotenberg - Configuration Docker Compose pour auto-héberger Gotenberg - Documentation complète de migration - Variables d'environnement exemple Note: Le bouton 'Créer PDF' utilise encore PDFMonkey. Pour activer Gotenberg, modifier l'appel dans ContractEditor.tsx
11 KiB
Migration PDFMonkey → Gotenberg
Contexte
Ce guide explique comment migrer la génération de PDF des contrats de travail de PDFMonkey (SaaS avec templates Liquid) vers Gotenberg (auto-hébergé).
Avantages de Gotenberg
- Auto-hébergé : contrôle total, pas de dépendance externe
- Gratuit et open-source
- Rapide et performant
- Supporte HTML/CSS nativement
- API simple et bien documentée
- Déployable sur Vercel, Railway, Coolify, etc.
Architecture de la Solution
┌─────────────────┐
│ Next.js App │
│ (Formulaire) │
└────────┬────────┘
│ 1. Envoie données JSON
↓
┌─────────────────────────┐
│ API Route Next.js │
│ /api/generate-contract │
│ │
│ - Compile template │
│ Handlebars │
│ - Génère HTML │
└────────┬────────────────┘
│ 2. Envoie HTML
↓
┌─────────────────────────┐
│ Gotenberg Service │
│ (Docker/Auto-hébergé) │
│ │
│ - Convertit HTML → PDF │
│ - Retourne le PDF │
└────────┬────────────────┘
│ 3. Reçoit PDF
↓
┌─────────────────────────┐
│ Supabase Storage │
│ (Stockage PDF) │
└─────────────────────────┘
Fichiers Créés
1. Helpers Handlebars
Fichier : lib/handlebars-helpers.ts
Remplace les filtres Liquid par des helpers Handlebars :
removeFirst: équivalent deremove_firstcontains: vérifier si une chaîne contient un patternsplit: diviser une chaîneeq,ne,gte,gt: comparaisonsisEmpty,isNotEmpty: vérifier les valeurs videsincludesAny: vérifier plusieurs valeurs (pour les CCN)
2. Template Handlebars
Fichier : templates-contrats/cddu-handlebars.html
Template HTML/Handlebars qui remplace le template Liquid PDFMonkey.
Principales conversions :
| Liquid | Handlebars |
|---|---|
{% if condition %} |
{{#if condition}} |
{% elsif %} |
{{else if}} |
{% assign var = value %} |
Variables pré-calculées en JS |
{{ var | filter }} |
{{helper var}} |
{% for item in array %} |
{{#each array}} |
3. API Route Gotenberg
Fichier : app/api/generate-contract-pdf/route.ts
Route API qui :
- Authentifie l'utilisateur
- Charge le template Handlebars
- Compile le template avec les données
- Envoie le HTML à Gotenberg
- Reçoit le PDF
- Upload sur Supabase Storage
- Retourne l'URL du PDF
4. Docker Compose
Fichier : docker-compose.gotenberg.yml
Configuration Docker pour auto-héberger Gotenberg.
Installation
Étape 1 : Installer les dépendances
npm install handlebars
npm install --save-dev @types/handlebars
Étape 2 : Configurer les variables d'environnement
Ajouter dans .env.local :
# URL de Gotenberg (local ou auto-hébergé)
GOTENBERG_URL=http://localhost:3001
# Ou en production (exemple avec Railway/Coolify)
# GOTENBERG_URL=https://gotenberg.votre-domaine.com
Étape 3 : Déployer Gotenberg localement
docker-compose -f docker-compose.gotenberg.yml up -d
Vérifier que Gotenberg fonctionne :
curl http://localhost:3001/health
Étape 4 : Tester l'API
Créer un fichier de test test-generate-pdf.ts :
const response = await fetch('/api/generate-contract-pdf', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
contractId: 'abc123',
contractType: 'cddu',
data: {
structure_name: 'Association Compagnie Lazara',
employee_firstname: 'Jean',
employee_lastname: 'GOLTIER',
// ... autres données
},
}),
});
const result = await response.json();
console.log('PDF généré:', result.pdfUrl);
Déploiement en Production
Option 1 : Railway (recommandé)
- Créer un nouveau service sur Railway
- Déployer l'image Docker :
gotenberg/gotenberg:8 - Exposer le port
3000 - Récupérer l'URL publique
- Mettre à jour
GOTENBERG_URLdans Vercel
Option 2 : Coolify
- Créer un nouveau service
- Source : Docker Image
- Image :
gotenberg/gotenberg:8 - Port :
3000 - Générer un domaine public
- Mettre à jour
GOTENBERG_URL
Option 3 : VPS auto-hébergé
# Sur le VPS
git clone <votre-repo>
cd Projet\ Nouvel\ Espace\ Paie
docker-compose -f docker-compose.gotenberg.yml up -d
# Configurer Nginx reverse proxy
sudo nano /etc/nginx/sites-available/gotenberg
# Contenu :
server {
listen 80;
server_name gotenberg.votre-domaine.com;
location / {
proxy_pass http://localhost:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Activer le site
sudo ln -s /etc/nginx/sites-available/gotenberg /etc/nginx/sites-enabled/
sudo systemctl reload nginx
Intégration dans le Code Existant
Modifier le formulaire de création de contrat
Dans app/staff/contrats/[id]/page.tsx ou le composant concerné :
const handleGeneratePDF = async () => {
setIsGenerating(true);
try {
const response = await fetch('/api/generate-contract-pdf', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
contractId: contract.id,
contractType: contract.regime === 'CDDU' ? 'cddu' : 'rg',
data: prepareContractData(contract),
}),
});
const result = await response.json();
if (result.success) {
toast.success('PDF généré avec succès');
// Ouvrir le PDF dans un nouvel onglet
window.open(result.pdfUrl, '_blank');
} else {
toast.error('Erreur lors de la génération du PDF');
}
} catch (error) {
console.error('Erreur:', error);
toast.error('Erreur lors de la génération du PDF');
} finally {
setIsGenerating(false);
}
};
// Fonction pour préparer les données
function prepareContractData(contract: Contract) {
return {
structure_name: contract.organization.name,
structure_adresse: contract.organization.address,
structure_cpville: contract.organization.postal_code,
structure_ville: contract.organization.city,
structure_siret: contract.organization.siret,
employee_firstname: contract.employee.first_name,
employee_lastname: contract.employee.last_name,
employee_dob: formatDate(contract.employee.birth_date),
// ... mapper toutes les données
imageUrl: contract.organization.logo_data_uri,
};
}
Différences avec PDFMonkey
| Aspect | PDFMonkey | Gotenberg |
|---|---|---|
| Hébergement | SaaS externe | Auto-hébergé |
| Coût | Payant (par document) | Gratuit |
| Template | Liquid (éditeur en ligne) | Handlebars (code local) |
| Latence | Variable (réseau externe) | Faible (interne) |
| Contrôle | Limité | Total |
| Maintenance | Aucune | Docker + monitoring |
Gestion des Templates
Modifier un template
- Éditer
templates-contrats/cddu-handlebars.html - Tester localement
- Commit + push
- Déploiement automatique via Vercel
Créer un nouveau template
- Dupliquer
cddu-handlebars.html - Adapter le contenu
- Ajouter le cas dans l'API route :
case 'nouveau-type':
templatePath = path.join(process.cwd(), 'templates-contrats', 'nouveau-type.html');
break;
Monitoring et Logs
Vérifier les logs Gotenberg
docker logs odentas-gotenberg --tail 100 -f
Health check
curl http://localhost:3001/health
Métriques de performance
Ajouter dans l'API route :
const startTime = Date.now();
// ... génération PDF
const duration = Date.now() - startTime;
console.log(`PDF généré en ${duration}ms`);
Troubleshooting
Erreur : Gotenberg inaccessible
Symptôme : fetch failed ou timeout
Solutions :
- Vérifier que Gotenberg est démarré :
docker ps - Vérifier le health check :
curl http://localhost:3001/health - Vérifier les logs :
docker logs odentas-gotenberg - Vérifier la variable
GOTENBERG_URL
Erreur : Template non trouvé
Symptôme : ENOENT: no such file or directory
Solutions :
- Vérifier le chemin du template
- Vérifier que le template existe bien dans
templates-contrats/ - En production Vercel, vérifier que les templates sont inclus dans le build
Erreur : Rendu incorrect du PDF
Symptôme : Mise en page cassée, polices manquantes
Solutions :
- Vérifier le CSS dans le template
- Utiliser des polices web-safe ou inclure les fonts en base64
- Tester le HTML seul dans un navigateur
- Ajuster les marges dans l'API route
Performance lente
Symptôme : Génération de PDF > 5 secondes
Solutions :
- Augmenter les ressources Docker
- Optimiser les images (compression, taille)
- Réduire la complexité du HTML/CSS
- Utiliser un cache pour les templates compilés
Checklist de Migration
- Installer les dépendances npm
- Créer les helpers Handlebars
- Convertir le template CDDU
- Créer l'API route
- Déployer Gotenberg localement
- Tester la génération de PDF en local
- Déployer Gotenberg en production
- Configurer la variable
GOTENBERG_URLsur Vercel - Intégrer dans le formulaire de contrat
- Tester en production
- Migrer les autres templates (RG, Avenants)
- Désactiver PDFMonkey
Rollback
Si besoin de revenir à PDFMonkey :
- Réactiver les appels à l'API PDFMonkey
- Commenter les appels à
/api/generate-contract-pdf - Garder le code Gotenberg en standby
Next Steps
Une fois la migration terminée :
- Migrer les autres templates : RG, Avenants, etc.
- Optimiser les performances : cache de templates, parallélisation
- Ajouter des analytics : temps de génération, taux de succès
- Backup automatique : sauvegarder les PDFs générés
- Versioning des templates : Git + tags pour suivre les changements
Support
En cas de problème, consulter :
- Documentation Gotenberg
- Documentation Handlebars
- Logs Docker :
docker logs odentas-gotenberg - Logs Next.js : Console Vercel
Auteur : Équipe Odentas Date : Décembre 2025 Version : 1.0