ediverse Explorer la plateforme

À la une PEPPOL BIS Billing 3.0 L’obligation européenne d’e-invoicing arrive : France sept 2026, Belgique janv 2026, Allemagne 2025.

Claim Check

Comme à la consigne de gare : on dépose la valise (le payload), on récupère un ticket (la référence), et c'est le ticket qui voyage — pas la valise. Le pattern indispensable dès que les messages EDI pèsent plus de quelques centaines de kilo-octets.

Problème

Les queues de messagerie (RabbitMQ, SQS, Kafka, Service Bus) sont dimensionnées pour des messages de quelques kilo-octets — pas pour des INVOIC EDIFACT de 50 MB ou des DESADV X12 multi-livraisons de 200 MB. Passer ces gros payloads dans la queue : (a) sature la bande passante du broker, (b) ralentit tous les autres messages, (c) atteint les limites natives (SQS plafonne à 256 KB, Service Bus standard à 256 KB, EventBridge à 256 KB), (d) gonfle les coûts de stockage de la file. Mais on ne peut pas non plus se passer du contenu — on doit le conserver et l'audit-clore.

Forces

  • Asymétrie des coûts. Un object store (S3, Azure Blob, GCS) coûte ~10× moins cher au giga-octet qu'un broker, et tient des téra-octets sans souci. Un broker n'est pas un stockage.
  • Asymétrie des accès. Le pipeline a souvent besoin d'un sous-ensemble du payload (l'en-tête, quelques champs) pour router, valider, dédupliquer. Charger 100 MB pour lire 200 octets est gaspilleur.
  • Rétention longue. Les obligations légales EDI (5-10 ans en France pour les factures) imposent un stockage long qu'un broker n'est pas conçu pour fournir.
  • Audit-closeness. Le payload original doit être archivable avec hash, horodatage, scellement — toutes choses que les object stores font nativement.

Solution

EIP §358 (Hohpe & Woolf, 2003), sous le nom Store In Library ou Claim Check. Le producteur dépose le payload complet dans un object store (avec chiffrement at-rest, calcul SHA-256, archivage versionné), puis publie dans la queue un message court qui contient : métadonnées d'enveloppe, hash, taille, et l'URI du payload. Le consommateur lit le message court ; s'il a besoin du payload, il fait un GET sur l'object store. Le message reste léger à transiter ; le payload reste indexable et archivable.

plaintext topology.txt
Producer                    Consumer
   ────────                    ────────

   payload 100MB


   ┌─────────────┐
   │  store(    │ ──▶ s3://archive/2026/05/14/inv-001.edi
   │  payload)  │              (full payload archived)
   └─────────────┘

        ▼ ref = "s3://archive/2026/05/14/inv-001.edi"
   ┌─────────────────────────────────────────────┐
   │  small message {  +metadata, +ref  }        │ ──▶ queue
   └─────────────────────────────────────────────┘


                                          consumer reads small msg


                                          if needs payload, fetch
                                          s3://archive/...

Topologie

Deux variantes :

  • Mandatory Claim Check. Tous les messages passent par l'object store, indépendamment de leur taille. Simple, uniforme.
  • Threshold-based. Seuls les messages au-delà d'un seuil (par exemple 64 KB) sont externalisés. Sous le seuil, le payload reste inline. Plus efficient pour les petits messages mais plus complexe à maintenir.

Implémentation EDI

Pour un INVOIC EDIFACT de 100 MB :

  1. Le transport (AS2 / AS4 / SFTP) reçoit le payload, calcule son hash SHA-256.
  2. Le payload est stocké en object store sous une clé canonique s3://ediverse-archive/<year>/<month>/<day>/<interchangeRef>.edi.
  3. Le message court suivant est publié dans la queue :
json claim-check-msg.json
{
  "claimCheckVersion": "1",
  "type": "INVOIC",
  "interchangeRef": "INV202605140001",
  "from": "BUYER_GLN",
  "to": "SUPPLIER_GLN",
  "sizeBytes": 105374208,
  "sha256": "9a4b1c2def8b6a5e8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b",
  "claimCheck": {
    "uri": "s3://ediverse-archive/2026/05/14/inv-202605140001.edi",
    "expiresAt": "2031-05-14T00:00:00Z",
    "encryption": "AES256",
    "contentType": "application/edifact"
  }
}

Le consommateur (Normalizer, validateur) lit ce message. Pour la plupart des opérations en amont, il n'a même pas besoin du payload complet — l'en-tête, les métadonnées de routage et le hash suffisent. Quand il a besoin du payload (parse, traduction), il fait GET s3://... avec une plage si possible (lecture partielle de l'en-tête pour le sniffer, puis lecture complète pour la traduction).

Lifecycle du blob

Trois questions à trancher :

  • Durée de rétention. Les obligations légales varient selon le type de message : 5 à 10 ans pour les factures (article L102B du Code général des impôts en France, 6 ans US IRS). Les ORDERS et DESADV ont des obligations plus courtes (3-5 ans). Configurer un cycle de vie S3 par préfixe.
  • Tiers de stockage. Au-delà de 90 jours, basculer en stockage froid (S3 Glacier, Azure Cool Blob). Coût × 10 inférieur, latence d'accès en heures — acceptable pour de l'audit ponctuel.
  • Chiffrement et scellement. Activer le chiffrement at-rest par défaut (SSE-KMS). Pour les flux financiers, ajouter une signature détachée (CMS / PKCS#7) horodatée pour rendre le blob inattaquable juridiquement.

Anti-patterns

  • Suppression précoce du blob. Si la rétention du blob est inférieure à la fenêtre d'investigation possible, on perd la traçabilité. La rétention du blob doit être ≥ rétention de toutes les références qui le pointent.
  • Pas de hash. Sans hash dans le message court, on ne peut pas vérifier que le blob téléchargé est bien celui annoncé par le producteur. Risque d'altération non détectée.
  • URI couplée au protocole. Une URI file:///mnt/edi/... n'est pas portable au cloud. Préférer une URI abstraite que le runtime traduit en accès concret (factory pattern).
  • Pas de gestion de l'orphan. Si le pipeline crashe entre le upload du blob et la publication du message, on a un blob orphelin. Prévoir un nettoyage périodique des blobs sans référence connue (avec sécurité : marquer pour suppression, attendre 30 jours, supprimer).
  • Claim check pour tout. Pour un CONTRL de 500 octets, externaliser dans S3 ajoute de la latence sans bénéfice. Garder l'option threshold-based.

Patterns liés

  • Dead Letter Channel — utilise le claim check pour le payload archivé en DLQ.
  • Normalizer — lit le payload via le claim check pour traduire.
  • Aggregator — stocke les enfants via claim check pour ne pas saturer la mémoire pendant la fenêtre.

Sources