espace-paie-odentas/ODENTAS_SIGN_INTERFACE.md
odentas b790faf12c feat: Implémentation complète du système Odentas Sign
- Remplacement de DocuSeal par solution souveraine Odentas Sign
- Système d'authentification OTP pour signataires (bcryptjs + JWT)
- 8 routes API: send-otp, verify-otp, sign, pdf-url, positions, status, webhook, signers
- Interface moderne avec canvas de signature et animations (framer-motion, confetti)
- Système de templates pour auto-détection des positions de signature (CDDU, RG, avenants)
- PDF viewer avec @react-pdf-viewer (compatible Next.js)
- Stockage S3: source/, signatures/, evidence/, signed/, certs/
- Tables Supabase: sign_requests, signers, sign_positions, sign_events, sign_assets
- Evidence bundle automatique (JSON metadata + timestamps)
- Templates emails: OTP et completion
- Scripts Lambda prêts: pades-sign (KMS seal) et tsaStamp (RFC3161)
- Mode test détecté automatiquement (emails whitelist)
- Tests complets avec PDF CDDU réel (2 signataires)
2025-10-27 19:03:07 +01:00

10 KiB
Raw Permalink Blame History

🎨 Odentas Sign - Interface de Signature (Phase 2)

📋 Vue d'ensemble

L'interface de signature Odentas Sign offre une expérience moderne et fluide pour la signature électronique de documents. Elle remplace complètement DocuSeal avec une solution souveraine et conforme eIDAS.

🎯 Fonctionnalités

Implémenté

  • Design moderne avec Tailwind CSS et Framer Motion
  • 🔐 Authentification OTP à 6 chiffres
  • ✍️ Canvas de signature HTML5 (souris, trackpad, tactile)
  • 📊 Barre de progression en temps réel
  • 🎉 Animation de célébration (confetti) après signature
  • 📱 Responsive mobile-first
  • 🔒 Vérification de consentement obligatoire
  • ⏱️ Countdown timer pour l'OTP (15 minutes)
  • 🚫 Limite de tentatives (3 maximum)
  • 📈 Affichage de la progression des signatures

🔄 À venir

  • 📄 Visualiseur PDF avec zones de signature surlignées
  • 📥 Téléchargement du document signé
  • 📧 Notifications email améliorées

🗂️ Structure des fichiers

app/signer/[requestId]/[signerId]/
├── page.tsx                              # Page principale avec routing
└── components/
    ├── ProgressBar.tsx                   # Barre de progression des étapes
    ├── OTPVerification.tsx               # Écran de vérification OTP
    ├── SignatureCapture.tsx              # Canvas de signature
    └── CompletionScreen.tsx              # Écran de confirmation

🎨 Flow utilisateur

1 Étape 1 : Vérification OTP

URL: /signer/[requestId]/[signerId]

Processus:

  1. L'utilisateur arrive sur la page avec son lien unique
  2. Affichage de son nom et email pré-remplis
  3. Clic sur "Recevoir le code"
  4. En mode test : OTP affiché dans les logs serveur
  5. En mode production : Email SES envoyé
  6. Saisie du code à 6 chiffres (auto-focus, auto-submit)
  7. Vérification du code → Génération d'un JWT (30min)
  8. Transition automatique vers l'étape signature

Sécurité:

  • Code valide 15 minutes
  • Maximum 3 tentatives
  • Rate limiting 60 secondes entre envois
  • JWT avec expiration

2 Étape 2 : Signature

Processus:

  1. Canvas de signature responsive
  2. Dessin avec souris/trackpad/doigt
  3. Bouton "Recommencer" pour effacer
  4. Checkbox de consentement obligatoire
  5. Validation → Upload de l'image PNG
  6. Enregistrement en base + S3
  7. Si tous ont signé → Déclenchement webhook
  8. Transition vers écran de confirmation

Canvas:

  • Taille adaptative (devicePixelRatio)
  • Ligne fluide (lineCap: round)
  • Couleur noire (#1e293b)
  • Export PNG avec transparence
  • Support touch events

3 Étape 3 : Confirmation

Processus:

  1. 🎉 Animation de confetti
  2. Affichage des détails (date, référence)
  3. Progression des signatures (X/Y signé)
  4. Message différent selon statut:
    • Tous signés → "Document finalisé"
    • En attente → "Attente des autres"
  5. Boutons (téléchargement désactivé pour l'instant)

🧪 Test de l'interface

Prérequis

# 1. Créer une demande de test
node test-odentas-sign.js

# 2. Lancer le serveur Next.js en dev
npm run dev

# 3. Utiliser le script de test interactif
./test-interface-signature.sh

Script de test

Le script test-interface-signature.sh offre:

  1. Ouvrir l'interface Employeur → Ouvre automatiquement le navigateur
  2. Ouvrir l'interface Salarié → Ouvre automatiquement le navigateur
  3. Afficher l'OTP Employeur → Trigger l'envoi + instructions pour logs
  4. Afficher l'OTP Salarié → Trigger l'envoi + instructions pour logs
  5. Vérifier le statut → Affiche qui a signé, progression
  6. Quitter

Mode test vs Production

Aspect Mode Test Mode Production
Détection Ref commence par TEST- Ref normale
OTP Logs serveur Email SES
Scellement Sauté PAdES + TSA
Archive Sautée S3 Object Lock 10 ans

🎨 Design System

Couleurs

/* Gradients principaux */
from-indigo-600 to-purple-600  /* Header vérification */
from-green-500 to-teal-500     /* Confirmation success */
from-slate-50 via-blue-50       /* Background page */

/* Boutons */
bg-indigo-600 hover:bg-indigo-700  /* Primary action */
bg-slate-100 text-slate-400        /* Disabled */
border-slate-200                    /* Secondary */

Animations

// Transitions de page
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}

// Progress bar fill
initial={{ width: 0 }}
animate={{ width: `${percentage}%` }}
transition={{ duration: 1, ease: 'easeOut' }}

// Confetti celebration
confetti({
  particleCount: 50,
  startVelocity: 30,
  spread: 360,
  colors: ['#6366f1', '#8b5cf6', '#ec4899']
})

Composants réutilisables

  • ProgressBar : Étapes avec cercles et connecteurs
  • Icons de Lucide : Shield, Check, Clock, Users, PenTool
  • Modales animées avec AnimatePresence

🔐 Sécurité

JWT Session Token

{
  signerId: string,
  requestId: string,
  role: string,
  iat: number,  // Issued at
  exp: number,  // Expiration (30 minutes)
  iss: 'odentas-sign'
}

Utilisation:

  • Généré après validation OTP
  • Stocké dans state React (pas de localStorage)
  • Envoyé dans header Authorization: Bearer <token>
  • Vérifié côté serveur pour /sign

Protection CSRF

  • Origin checking dans les API routes
  • Rate limiting sur /send-otp
  • Validation des inputs (OTP digits only)

Données personnelles

  • Email affiché mais non modifiable
  • IP et User-Agent enregistrés dans sign_events
  • Consentement explicite requis
  • Archivage 10 ans conforme RGPD (base légale: contrat)

📊 Tracking des événements

Tous les événements sont loggés dans sign_events:

  1. request_created → Création demande
  2. otp_sent → Envoi code
  3. otp_verified → Code validé
  4. otp_verification_failed → Code invalide
  5. signed → Signature enregistrée
  6. request_completed → Tous ont signé
  7. pdf_sealed → PAdES appliqué
  8. document_timestamped → TSA horodatage
  9. archived → Archive S3

🌐 URLs

Signature

/signer/[requestId]/[signerId]

Exemple:

/signer/75b4408d-1bbd-464f-a9ea-2b4e5075a817/95c4ccdc-1a26-4426-a56f-653758159b54

API Endpoints utilisés

POST /api/odentas-sign/signers/[id]/send-otp
POST /api/odentas-sign/signers/[id]/verify-otp
POST /api/odentas-sign/signers/[id]/sign
GET  /api/odentas-sign/signers/[id]/status

📱 Responsive Design

Breakpoints

sm: 640px   /* Tablettes portrait */
md: 768px   /* Tablettes landscape */
lg: 1024px  /* Desktop */
xl: 1280px  /* Large screens */

Canvas tactile

// Disable browser touch gestures
style={{ touchAction: 'none' }}

// Support touch events
onTouchStart={startDrawing}
onTouchMove={draw}
onTouchEnd={stopDrawing}

🎯 Prochaines étapes

PDF Viewer intégration

npm install react-pdf pdfjs-dist

Fonctionnalités:

  • Afficher le PDF dans SignatureCapture
  • Overlay semi-transparent sur zones de signature
  • Scroll automatique vers la zone du signataire
  • Zoom responsive

Email notifications

Templates à créer:

  • signature-completed.html → Envoyé au signataire après sa signature
  • all-signatures-completed.html → Envoyé à tous quand finalisé
  • Avec lien de téléchargement du PDF signé

Download du document

async function downloadSignedDocument() {
  const response = await fetch(`/api/odentas-sign/requests/${requestId}/download`);
  const blob = await response.blob();
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `${documentRef}-signed.pdf`;
  a.click();
}

🐛 Debugging

Logs serveur

npm run dev

Chercher dans les logs:

⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
        MODE TEST - Code OTP
⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

Console navigateur

// État du composant
React DevTools  SignerPage  state

// Erreurs réseau
Network tab  Filter: "odentas-sign"

// JWT decode
JSON.parse(atob(token.split('.')[1]))

Base de données

-- Derniers événements
SELECT * FROM sign_events 
ORDER BY created_at DESC 
LIMIT 20;

-- Statut des signataires
SELECT 
  sr.ref,
  s.name,
  s.role,
  s.has_signed,
  s.signed_at
FROM signers s
JOIN sign_requests sr ON s.request_id = sr.id
ORDER BY sr.created_at DESC;

🎉 Migration depuis DocuSeal

Coexistence

Les anciennes pages DocuSeal restent actives:

  • /signatures-electroniques → DocuSeal (employeur)
  • /signature-salarie → DocuSeal (salarié)

Nouvelles pages Odentas Sign:

  • /signer/[requestId]/[signerId] → Odentas Sign (tous rôles)

Migration progressive

  1. Phase 1 : Nouveaux contrats → Odentas Sign
  2. Phase 2 : Anciens contrats → Continuer DocuSeal
  3. Phase 3 : Quand tous migrés → Supprimer DocuSeal

Détection automatique

// Dans le code de création de contrat
const useOdentasSign = process.env.NEXT_PUBLIC_USE_ODENTAS_SIGN === 'true';

if (useOdentasSign) {
  // Créer via /api/odentas-sign/requests/create
  // Envoyer liens /signer/[requestId]/[signerId]
} else {
  // Créer via DocuSeal
  // Envoyer liens DocuSeal
}

📚 Ressources

Checklist de production

Avant mise en production:

  • Tester sur mobile (iOS Safari, Android Chrome)
  • Vérifier accessibilité (contraste, keyboard navigation)
  • Intégrer PDF viewer
  • Ajouter templates email de notification
  • Activer vraie signature PAdES (retirer test mode bypass)
  • Configurer monitoring (Sentry, logs CloudWatch)
  • Load testing (Artillery, k6)
  • Documentation utilisateur finale
  • Formation équipe support
  • Plan de rollback DocuSeal

Créé le: $(date +%Y-%m-%d)
Version: 2.0.0
Auteur: GitHub Copilot
Statut: Phase 2 Complète