Workflows : automatisations et livraisons gouvernées

Ce qui sort d’un espace est déclaré, classé, journalisé

Un workflow est un graphe versionné de nœuds typés où circulent des lots d’éléments : une source, des transformations, un fichier produit en route, une destination. Une exécution dure des secondes ou des minutes. Ce n’est pas le moteur des parcours — qui suit un contact pendant des semaines — mais il s’appuie sur les mêmes briques. Et ce qui le distingue d’un orchestrateur générique tient en une phrase : un nœud Missivia sait quelle donnée il manipule, et ce qu’elle a le droit de devenir.

SOURCETRANSFORMATIONFICHIERSegmentprojection expliciteProjectionréférence · e-mail · villeMise en formeCSV · chiffré PGPDépôt SFTPdestination déclarée · piiclé d’hôte épingléee-mail (pii) → cible techrefusé à la compilationEntrepôt HTTPdestination déclarée · techrien ne partJournal : noms de champs · compte · empreinte du fichier — jamais une valeur
Le lot suit la seule branche autorisée. L’autre est refusée avant d’exister : la classe d’une colonne et la classe d’une destination se comparent à la compilation.

Un graphe, des lots, des versions

Des nœuds typés, des ports typés, et une compilation qui refuse avant d’exécuter.

  • Une définition tient en trois listes : des déclencheurs, des nœuds à identifiant stable, des arêtes. Le graphe est acyclique ; les ports sont typés — éléments, fichier, rien — et le compilateur refuse une connexion qui ne concorde pas.
  • Un brouillon s’enregistre sans compiler : un éditeur sauve un travail en cours. Une version publiée a compilé : les règles de gouvernance s’appliquent au moment où l’on décide que ce graphe tournera, pas la nuit où il tourne.
  • Le catalogue des nœuds est publié avec le schéma JSON de chaque configuration, généré depuis les schémas mêmes que l’API valide : un éditeur ne peut pas dériver du moteur.
  • Chaque nœud persiste son résultat avant que le suivant ne commence. Une exécution interrompue reprend au premier nœud non terminé ; un nœud réussi n’est jamais rejoué. Le partenaire reçoit un fichier, pas deux.
  • Chaque nœud choisit sa conduite en cas d’erreur — échouer, sauter, dérouter — et son nombre de tentatives, espacées.
  • Les branches indépendantes d’un graphe s’exécutent en parallèle, dans une limite fixée et sous un budget mémoire par exécution ; les sorties restent déterministes — une jonction assemble ses entrées dans l’ordre des ports, jamais dans l’ordre d’achèvement — et la reprise après incident ne rejoue aucune action.
Ce qui distingue un workflow d’un parcours

Un parcours est une machine à états par contact, qui vit des semaines : attentes, branches, objectifs de conversion. Un workflow traite des lots et produit des fichiers, en quelques secondes ou minutes. Les deux modèles ne sont pas fusionnés — un même moteur ferait mal les deux.

Ils partagent en revanche leur socle : le moteur d’expressions, le stockage des fichiers, le chiffrement des identifiants, la garde contre les cibles réseau internes, le journal d’audit et les classes de clés. Deux ponts les relient : une étape de parcours qui lance un workflow, et un nœud de workflow qui inscrit des contacts dans un parcours.

Éditeur : essayer, reprendre, partir d’une recette

On construit un workflow en le regardant tourner, sans rien livrer ; on répare une exécution sans tout refaire.

  • Essayer une étape : depuis l’éditeur, le nœud choisi et ses ancêtres s’exécutent sur le brouillon en cours, et ses données de sortie s’affichent sous le nœud. Chaque source rend au plus vingt éléments par défaut, cent au maximum.
  • Un essai est sans effet de bord : aucune action, aucune destination — e-mail compris —, aucun sous-workflow n’est exécuté ; un fichier récupéré reste en place chez le partenaire. Les essais n’entrent ni dans l’historique des exécutions ni dans les statistiques, et sont purgés après 24 heures. Ils comptent dans le quota d’exécutions de l’espace.
  • Reprendre une exécution en échec depuis le nœud fautif : une nouvelle exécution réutilise les sorties déjà produites hors de l’aval de ce nœud — ni réextraction, ni redépôt, ni nouvelle entrée de journal pour elles — et rejoue le nœud en échec et sa suite sous les règles du premier passage. L’exécution d’origine reste intacte.
  • Une reprise est refusée, avec sa raison, quand elle ne peut pas être sûre : définition modifiée depuis, gouvernance de santé changée, sorties déjà purgées, fichier d’entrée indisponible, sous-workflow à relancer en aval. Elle ne prolonge la conservation de rien.
  • Recettes : des modèles de départ, prêts à adapter. La première alerte par e-mail l’adresse opérationnelle de l’espace à chaque échec d’exécution, sans jamais porter le message d’erreur. Une recette ne crée rien d’elle-même et ne porte aucune adresse : la connexion est déclarée et vérifiée, puis le workflow publié, comme tout autre.
  • L’éditeur garde un historique du brouillon — cent pas, annuler et rétablir —, copie, colle et duplique des nœuds avec leurs liens internes, au clavier ou à la souris. Le presse-papiers est interne à l’éditeur et au workflow ouvert : jamais le presse-papiers du système, jamais un autre workflow. Aucun raccourci n’est capturé dans un champ de saisie.

Déclencheurs

Six manières de démarrer. Un workflow en pause, ou sans version publiée, ne se réveille jamais.

  • Planification : une expression à cinq champs, évaluée dans le fuseau de l’espace — « deux heures du matin » veut dire deux heures chez le client, y compris la nuit du changement d’heure. Une occurrence produit exactement une exécution, quel que soit le nombre d’instances du planificateur. Un calendrier ouvré facultatif écarte les samedis, les dimanches et les jours fériés — France métropolitaine, ou Alsace-Moselle — : l’occurrence est sautée, ou reportée au prochain jour ouvré à la même heure, sans jamais doubler l’exécution d’un jour qui a la sienne.
  • Manuel : un appel d’API avec clé d’idempotence, accompagné si le workflow l’attend d’un fichier déposé juste avant. Un workflow qui ne déclare pas ce déclencheur refuse l’appel.
  • Événement métier ou de plateforme — contact créé, inscription à une liste, consentement accordé, désinscription, fin d’inscription, campagne terminée, export terminé, changement de sévérité de réputation, échec d’un workflow — avec une condition facultative évaluée avant que l’élément n’entre dans le lot, et une fenêtre de regroupement de zéro à une heure qui rassemble les événements d’un même intervalle dans une seule exécution.
  • URL d’entrée à jeton : un appel HTTP entrant dont le corps JSON devient le premier lot. Le jeton est montré une fois, stocké haché, régénérable, révocable ; une signature peut être exigée. Rien du corps n’est jamais journalisé, et un jeton inconnu, révoqué ou en pause répond la même chose : sonder n’apprend rien.
  • Depuis un parcours : une étape lance le workflow pour le contact courant — parce que le workflow l’a autorisé en déclarant ce déclencheur.
  • Depuis un autre workflow : un sous-workflow appelé avec le lot courant, au même consentement : l’appelé déclare qu’il accepte d’être appelé.
Le lot déclencheur se lit par un seul nœud

Événement, URL d’entrée, étape de parcours ou workflow appelant : les quatre déclencheurs qui apportent un lot le font lire par un seul nœud source, et chaque élément a la même forme — l’événement, le contact, la charge utile. La charge utile est classée personnelle sans exception : son contenu est écrit par l’appelant, pas par nous, et une omission se verrait chez le partenaire plutôt qu’à la compilation. Pour la livrer à une cible technique, on la pseudonymise, ou l’on déclare la destination comme personnelle.

La déduplication se fait par événement : deux livraisons du même événement donnent un seul élément, même à travers deux fenêtres. Les éléments vivent en base, jamais dans la file, et disparaissent avec leur exécution.

Sources

Chaque source déclare une projection explicite. Un workflow ne lit jamais « tout le contact ».

  • Membres d’un segment — hors d’un workflow de santé, refusé si le segment dérive d’un critère de santé : l’appartenance elle-même révélerait la donnée.
  • Abonnés d’une liste, et contacts filtrés par une expression. Filtrer n’est pas exporter : l’expression peut lire une colonne qui n’est pas projetée.
  • Événements métier sur une fenêtre de temps, avec leurs références opaques ; tout champ de charge utile est personnel.
  • Agrégats de statistiques, du même vocabulaire fermé que les tableaux de bord : un compte masqué par le seuil d’affichage sort vide, pas en clair.
  • Journal des messages : identifiants opaques, statuts, compteurs, dates — ni adresse de destinataire, ni sujet rendu, ni texte d’erreur du fournisseur.
  • Journal d’audit : des noms de champs, jamais des valeurs, et les empreintes de la chaîne pour la vérifier hors de Missivia.
  • Les contacts sont lus par lots, sur un curseur : jamais une table entière en mémoire.
  • Un fichier, récupéré sur une connexion ou déposé au lancement : voir Fichiers en entrée.
Les fenêtres de temps se comptent depuis le départ de l’exécution

« Depuis » et « jusqu’à » acceptent l’instant présent, un décalage relatif au début de l’exécution — sept jours, trente-six heures — ou une date. La référence est le début de l’exécution, pas l’heure où le nœud tourne : une reprise après incident relit exactement la même fenêtre, et un dépôt rejoué reste idempotent.

Fichiers en entrée

Un lot de leads chez un partenaire, un retour de prestataire, un fichier fourni à la main : un workflow le récupère, le déchiffre, le lit en colonnes, en fait des contacts.

  • Quatre points d’entrée : SFTP, S3 compatible et HTTP sur une connexion déclarée et vérifiée, ou un dépôt fourni au lancement d’une exécution manuelle. Un seul fichier par exécution.
  • Après lecture, le fichier distant est laissé, déplacé dans un dossier de traitement ou supprimé, au choix. Une récupération HTTP ne suit aucune redirection, et un fichier inchangé depuis la dernière fois n’est pas repris.
  • La taille est bornée avant et pendant la lecture, par une limite de plateforme publiée sur la fiche de l’espace ; la lecture en colonnes est bornée elle aussi.
  • Chaque fichier entré écrit au journal d’audit une entrée d’import — nom, taille, empreinte —, et l’entrée consommée est tracée sur l’exécution : type, taille et empreinte, le nom n’étant montré qu’aux rôles du client.
  • Un dépôt sert une seule exécution ; non consommé, il est purgé après 24 heures, contenu compris. Consommé, il suit la conservation de l’exécution.
  • Déchiffrement OpenPGP par une clé d’espace, générée sur la plateforme ou importée — la clé privée n’est jamais restituée — ou par une phrase de passe tirée du coffre. Le fichier garde la classe de sa connexion d’origine, et la lecture en colonnes ne la fait jamais baisser.

Transformations et fonctions

Pas de nœud de code. Des nœuds typés, et un vocabulaire fermé de fonctions.

  • Projection (sélection, renommage, gabarits composés), filtre, tri, dédoublonnage, limite, découpage en lots.
  • Agrégation par une à trois clés — compte, somme, moyenne, minimum, maximum, compte distinct — ; jonction de deux flux par clé ; aiguillage de chaque élément vers une sortie nommée selon la valeur d’une colonne ; duplication du même lot vers plusieurs branches ; union de branches.
  • La classe d’une colonne composée est la plus élevée des colonnes qu’elle cite : un prénom et un identifiant donnent une colonne personnelle. Un compte est technique — compter n’est pas divulguer. Une jonction fait entrer les colonnes de droite avec leur propre classe : joindre une adresse à un lot technique le rend personnel.
  • Les fonctions — dates, chaînes, tableaux, nombres, logique, hachage — sont résolues à la compilation dans un registre fermé : un nom inconnu, une mauvaise arité, un motif dangereux sont refusés à l’écriture, avec leur position dans le texte de l’auteur.
  • Aucune fonction ne lit le réseau, un fichier ou l’horloge système : « maintenant » est l’instant de référence de l’exécution, et le premier du mois se calcule dans le fuseau de l’espace.
  • Une colonne personnelle hachée devient technique : une empreinte d’adresse n’est pas une adresse. Elle peut sortir vers une cible technique — c’est précisément l’usage : donner à un partenaire une clé de rapprochement sans lui donner les personnes. Le secret d’un hachage à clé est désigné par un nom, dérivé par espace, et ne s’écrit jamais dans l’expression.
Ce que le vocabulaire ne contient pas — et qu’un graphe ne peut pas y ajouter

Ni évaluation de code, ni fonction définie par l’utilisateur, ni appel HTTP, ni accès à un fichier, ni aléa, ni horloge système, ni expression régulière construite depuis une valeur, ni quoi que ce soit qui déchiffre ou inverse. Le registre est fermé — quarante-deux fonctions en six familles —, l’absence est vérifiable, et elle est testée. Étendre le vocabulaire est une livraison du produit, pas un contournement dans un graphe.

Hacher n’est pas une façon de faire sortir une donnée de santé : l’empreinte d’une colonne de santé reste classée santé, et ne sort que chiffrée vers une connexion de santé. Le même moteur sert les déclencheurs, les parcours et les templates ; le registre est publié comme une donnée de l’API, et la documentation en est générée — un exemple faux fait échouer un test.

Formats et chiffrement

Un fichier au format du partenaire, produit en flux, au nom déterministe.

  • CSV (séparateur, guillemets, en-tête, UTF-8 ou Latin-1), JSON Lines, JSON, XML (racine et élément paramétrables, nom de colonne conservé), Excel — une feuille, écrite ligne à ligne : un million de lignes ne fait pas grossir la mémoire.
  • Compression gzip, ou archive zip de plusieurs fichiers de la même exécution. L’archive porte la classe la plus élevée de ce qu’elle contient, et dit ce qu’elle contient — noms et tailles, jamais un contenu.
  • Chiffrement PGP pour la clé publique du destinataire, par une phrase de passe OpenPGP tirée du coffre, ou age.
  • Protection contre les formules de tableur en CSV, active par défaut : une cellule qui commencerait une formule est écrite précédée d’une apostrophe, un nombre ne l’est jamais. Elle se désactive pour un consommateur machine ; les exports CSV de l’API la gardent toujours.
  • Le nom du fichier dépend de l’exécution, pas de l’horloge au moment du dépôt : un dépôt rejoué donne le même nom, donc un seul fichier.
  • Chiffrer ne change pas la classe d’une donnée : ce qui autorise la sortie est la destination déclarée, pas la protection du transport.

Destinations déclarées

Rien ne sort vers une cible qui n’a pas été déclarée, une fois, par un administrateur de l’espace.

  • Quatre types : SFTP, HTTP, S3 compatible, e-mail avec pièce jointe. Les identifiants sont chiffrés par espace et jamais restitués ; une empreinte dit lesquels sont stockés.
  • Chaque destination porte la classe de données qu’elle peut recevoir — et, comme connexion de récupération, celle de ce qu’on en tire : technique, personnelle ou santé. La classe santé n’existe que pour une connexion SFTP, sur attestation : HTTP, S3 et e-mail ne reçoivent jamais de donnée de santé (voir Données de santé).
  • Changer l’hôte d’une connexion efface ses identifiants enregistrés, sauf s’ils sont ressaisis dans le même geste ; tout changement de cible remet la vérification à zéro, et rien ne se publie ni ne s’exécute sur cette connexion avant une nouvelle vérification réussie.
  • SFTP : l’empreinte de la clé d’hôte est obligatoire et comparée avant l’authentification — aucun mot de passe n’est envoyé à un hôte qui ne correspond pas. Le fichier est écrit sous un nom temporaire puis renommé : un partenaire qui scrute le dossier ne ramasse jamais un fichier à moitié écrit.
  • HTTP : clé d’idempotence par exécution et par nœud ; l’hôte repasse la garde contre les cibles internes au moment du dépôt, pas seulement à la déclaration. S3 : point d’accès épinglé sur la destination, clé d’objet déterministe, chiffrement côté serveur demandé à l’écriture.
  • E-mail : le fichier part en pièce jointe, par le relais interne, aux adresses déclarées sur la destination. Le nœud n’a pas de champ destinataire : changer qui reçoit une extraction est un acte d’administration de l’espace, pas une retouche de graphe.
  • Déclarer les destinations exige la classe de clé d’administration ; construire et lancer des workflows est ouvert à la classe opérateur. Une destination est vérifiée avant publication — connexion, clé d’hôte, dossier, sans rien écrire — et ne peut pas être supprimée tant qu’une version publiée la nomme.
Une adresse IP sortante fixe, sur demande, pour les trois protocoles

Certains partenaires filtrent par adresse source. Pour eux, la plateforme peut faire sortir tout dépôt SFTP, HTTP ou S3 — et chaque vérification de destination — par un mandataire placé dans le périmètre, sur un hôte à adresse fixe : le partenaire a alors une adresse à autoriser, la même pour les trois protocoles. Ce mandataire, exploité par la plateforme dans son périmètre, est une option de déploiement mise en place au contrat quand un partenaire l’exige ; sans lui, les dépôts sortent par les adresses de l’hébergeur. Le chiffrement TLS et SSH est posé au-dessus du tunnel, contre le point d’accès ou la clé d’hôte épinglés : le mandataire ne lit rien de ce qui passe.

Une fois le mandataire en place, il n’y a aucun repli automatique : s’il ne répond pas, le dépôt échoue et le dit, plutôt que de sortir par une adresse que le partenaire n’autorise pas sans que personne le sache.

Coffre de secrets de l’espace

Une phrase de passe partagée avec un partenaire, une clé de signature, un jeton d’en-tête : le workflow s’en sert sans jamais les montrer.

  • Une valeur est fournie, ou générée par la plateforme et montrée une seule fois. Elle n’est jamais restituée : une empreinte à clé, propre à l’espace, distingue deux versions sans permettre d’éprouver une valeur.
  • Un secret n’est jamais écrit dans la définition : il y est désigné par son nom, uniquement dans les champs de configuration prévus pour cela — jamais dans une expression, un chemin ou un nom de fichier.
  • Usages contrôlés : chaque secret déclare ce qu’il sert — chiffrement ou déchiffrement OpenPGP par phrase de passe, hachage à clé, en-tête HTTP, signature HTTP — et peut être lié à des connexions précises. Un usage non déclaré est refusé à la compilation.
  • Appels HTTP : en-têtes secrets posés sur chaque appel d’une connexion, signature HMAC-SHA256 des octets envoyés, horodatée si le partenaire le demande.
  • Rotation avec délai de grâce pour le déchiffrement ; un secret qu’une version publiée utilise ne se supprime pas, et le refus dit qui le cite. À l’exécution, les versions sont épinglées au démarrage et les valeurs retirées de toute erreur et de tout journal.
  • Chiffrement lié à sa ligne : une valeur recopiée dans un autre espace, un autre secret ou une autre version ne se déchiffre plus. Les rôles d’exploitation de la plateforme voient les noms et les usages, jamais une valeur.

Actions et ponts avec les parcours

Des nœuds qui écrivent dans l’espace — une autre question que la sortie, qui reçoit une autre réponse.

  • Créer ou mettre à jour un contact — avec une base légale déclarée pour créer une fiche —, poser des attributs, entrer ou sortir d’une liste, émettre un événement métier, inscrire dans un parcours publié.
  • Chaque action passe par la fonction métier qui la porte déjà : liste de suppression, contact inactif, quotas, consentement exigé par un parcours s’appliquent comme à un appel d’API. Aucune action n’écrit un consentement — un consentement se recueille, il ne se calcule pas. Un attribut de santé ne s’écrit que dans un workflow de santé, pour un contact qui porte déjà le consentement dédié.
  • L’idempotence est au grain de l’élément : une reprise ne rejoue pas un élément déjà réussi. Un refus métier sur un élément n’échoue pas le lot : l’élément sort marqué « sauté », et l’exécution continue.
  • Depuis un parcours, une étape lance un workflow pour le contact courant, en continuant aussitôt ou en attendant l’issue — bornée : une inscription ne reste pas bloquée parce qu’un partenaire est en panne.
  • Un sous-workflow appelé rend des colonnes présumées personnelles, revérifiées à l’exécution : un enfant ne peut pas rétrograder une donnée en la faisant transiter par lui.
  • Les boucles sont bornées dans les deux sens : une exécution née d’un événement ne peut pas le réémettre, la profondeur de chaînage est limitée, et un cycle d’appels entre workflows est refusé à la compilation.

Données de santé

Une personne habilitée peut faire entrer et sortir des données de santé par un workflow. Le cadre est fermé, et c’est le serveur qui le tient.

  • Un workflow doit être déclaré de santé, par une personne habilitée ; publier, activer, lancer, télécharger un fichier produit exigent la même habilitation. Il ne se déclenche pas depuis un parcours et ne s’appelle pas depuis un workflow qui n’est pas de santé.
  • Une donnée de santé n’entre que par une connexion SFTP classée santé, et n’en sort que chiffrée vers une telle connexion : HTTP, S3 et e-mail ne la reçoivent jamais.
  • Classer une connexion en santé exige une attestation écrite : le serveur se trouve dans un périmètre d’hébergement de données de santé, sous la responsabilité du responsable de traitement. La plateforme l’enregistre ; elle ne prétend pas la vérifier. Tout changement de cible — hôte, port, compte, empreinte de clé d’hôte — l’invalide : rien ne se publie ni ne s’exécute avant une nouvelle attestation et une nouvelle vérification.
  • Ce qui décide sur une colonne de santé — un filtre, un tri, une jonction, un regroupement — rend tout le flux dérivé de santé, jusqu’au bout : les adresses de la cohorte et un simple compte en aval compris. Hacher une colonne de santé ne la déclasse jamais.
  • Les colonnes de santé sont retirées des échantillons avant tout stockage ; les fichiers de travail sont chiffrés au repos ; les exécutions d’un workflow de santé n’existent pas pour les rôles d’exploitation de la plateforme.
  • Une valeur de santé ne s’écrit sur un contact que s’il porte déjà un consentement dédié accordé ; sinon l’élément est rejeté, sans rien écrire.

Gouvernance

Des règles appliquées à la compilation et rejouées à l’exécution — par le serveur, pas par une relecture.

  • Hors d’un workflow déclaré de santé, un attribut classé santé ne quitte jamais un espace, et un segment dérivé d’un critère de santé ne peut pas servir de source. Dans un workflow de santé, une donnée de santé ne sort que chiffrée, vers une connexion SFTP classée santé.
  • Rien ne va nulle part qui n’ait été déclaré comme destination de l’espace.
  • Une colonne personnelle n’atteint qu’une destination autorisée à en recevoir ; une destination technique ne reçoit que des champs techniques, des identifiants opaques et des agrégats.
  • Chaque dépôt écrit au journal d’audit une entrée d’export : les noms des champs, le compte d’éléments, la destination et l’empreinte du fichier — jamais une valeur. Un refus constaté à l’exécution — un segment devenu dérivé de la santé depuis la publication, une destination rétrogradée, une cible réseau bloquée — écrit une entrée de refus, et rien ne sort.
  • Les échantillons d’une exécution sont masqués selon la classe de la clé qui les lit : une clé opérateur voit les colonnes techniques et les comptes, le reste est « masqué ». Le fichier réel ne se télécharge qu’avec une clé d’administration. L’opérateur de la plateforme observe les exécutions d’un espace sans échantillon, sans destination et sans nom de fichier.
  • Des bornes par espace — exécutions par jour, destinations déclarées, éléments, taille, durée —, des métriques d’exploitation sans identifiant de nœud, et une alerte sur échec répété qui ne porte jamais le message d’erreur : il pourrait nommer l’hôte d’un partenaire.
Les bornes d’une exécution, par défaut
  • 200 000 éléments par exécution, 200 Mio par fichier produit, 15 minutes par exécution, une exécution à la fois par espace.
  • 500 exécutions démarrées par jour et 20 destinations déclarées par espace — deux bornes que l’opérateur règle, zéro valant « sans borne ». Un refus de quota dit quand le compteur se rouvre.
  • Profondeur de chaînage limitée à trois, quelle que soit la voie — sous-workflow, étape de parcours, événement émis.
  • Alerte au troisième échec consécutif ; le compteur vit en base, pour qu’un redéploiement n’oublie pas que le dépôt de minuit rate depuis trois nuits.
  • Exécutions, échantillons et fichiers produits conservés trente jours par défaut — plancher un jour, plafond : la durée de conservation des contacts de l’espace.