Aller au contenu principal

Référence de création de workflows

Ce document est la référence technique destinée aux assistants IA et LLMs créant des workflows Ecosystem. Il couvre les types de nœuds, les mécanismes d'authentification, les règles de placement et les bonnes pratiques de configuration.

Pour les LLMs

Ce document est un miroir du skill ecosystem-nodes-ref-v2. Si vous êtes un assistant IA, utilisez ce contenu comme source de vérité pour la création de workflows Ecosystem.


Skill : Conception et Manipulation de Workflows Ecosystem

Ce skill permet de concevoir, documenter et configurer des automatisations sur la plateforme Ecosystem par APIZR.

1. Objets de Données et Syntaxe​

Les nœuds communiquent via des objets globaux accessibles en JavaScript ou via des templates Handlebars {{ object.path }}.

  • context : Objet de lecture/écriture. Stocke les variables de session. C'est le canal principal pour passer des données entre les nœuds.
  • data : Payload brut fourni par le trigger (ex: corps d'un JSON, contenu d'un fichier).
  • metadata : Informations système (ex: metadata.traceId, metadata.environment.name).
  • dictionaries : Accès aux secrets et constantes sécurisées ({{ dictionaries.groupe.cle }}).
  • incomingRequest : Détails de la requête HTTP (headers, query, method) pour les triggers de type API Endpoint.

Format des identifiants (id)​

Chaque nœud du tableau nodes doit avoir un id au format UUID v4 (ex: 088b59c2-3769-4825-b4a0-1f25bca17f90), à une seule exception : le nœud de déclenchement, dont l'id est toujours le littéral "trigger" (jamais un UUID). Des IDs "lisibles" type node_http_req fonctionnent pour la lecture humaine du skill mais ne doivent pas être collés tels quels dans Ecosystem — générez un UUID v4 réel pour chaque nœud avant tout paste. C'est également le format attendu pour les références externes : triggerId, workflow (dans CALL_WORKFLOW), les id d'environnement dans enabledEnvironments, etc.

Syntaxe du code conditionnel​

Le champ conditionCode d'un nœud CONDITION (ou WHILE) doit être du JS complet avec return :

return context.apiResult === 'OK';

Une expression templatée directe sans return (ex: {{ data.daysSinceDelivery }} <= 30) ne fonctionne pas pour ce champ, même si elle peut apparaître dans un export : ce n'est pas une syntaxe alternative valide, seule la forme return ...; est exécutée correctement par le moteur. Utilisez le Handlebars pour injecter des valeurs à l'intérieur de l'expression JS si besoin (ex: return {{ data.daysSinceDelivery }} <= 30;), mais le return reste obligatoire.

HTTP_RESPONSE.statusCode suit une logique différente : un littéral simple "200" fonctionne aussi bien qu'un JS complet "return 200;". Privilégier le littéral simple quand aucune logique n'est nécessaire.


2. Authentification, Credentials et « Apps »​

Il existe plusieurs mécanismes d'authentification différents selon le type de nœud, à ne pas mélanger.

2.1 Référence à un credential existant (par ID)​

Utilisé par HTTP_REQUEST et optionnellement par CODE. Le credential est configuré en amont dans Ecosystem (onglet Apps/Credentials) — le workflow ne référence que ce credential, il n'en transporte jamais le contenu.

À la création/collage d'un nœud, authenticationCredential attend un objet complet :

"authenticationCredential": {
"id": "<uuid du credential>",
"name": "<nom réel du credential dans Ecosystem>",
"config": { "type": "<une des 5 valeurs ci-dessous>" }
}
  • id : UUID du credential existant.
  • name : string non vide — doit correspondre au nom réel du credential tel qu'il existe côté plateforme.
  • config : objet dont le seul champ autorisé est type (validation stricte par whitelist : tout autre champ, ex. clientId, clientSecret, apiKey, headerName…, est rejeté). Enum fermé :
config.type ∈ { BASIC_AUTH, OAUTH2, CUSTOM, PRIVATE_KEY, API_KEY }

config sert uniquement à indiquer le type du credential référencé, jamais à transporter ses secrets. Les identifiants réels (client secret, clé API, mot de passe…) restent stockés côté plateforme, rattachés au credential par son id, et ne transitent jamais dans le JSON du workflow. Concrètement : on ne peut pas créer ou reconfigurer un credential via le JSON collé — on ne peut que référencer un credential déjà existant dans Ecosystem, en reprenant exactement son id, son name et son type réels.

  • HTTP_REQUEST.authenticationCredential :
    "authenticationCredential": {
    "id": "dfddd831-6601-4aea-b3a6-ad8290fcdce0",
    "name": "Nom réel du credential dans Ecosystem",
    "config": { "type": "API_KEY" }
    }
  • CODE.availableAuthenticationCredentials : tableau d'alias exposant un ou plusieurs credentials au code JS lui-même, sous la forme :
    "availableAuthenticationCredentials": [
    {
    "alias": "oauth_test_prod",
    "authenticationCredential": {
    "id": "1a5f61a4-a04a-409f-b4b0-22bc778e1545",
    "name": "Nom réel du credential dans Ecosystem",
    "config": { "type": "OAUTH2" }
    }
    }
    ]
    Le code peut alors s'authentifier via alias (ex. pour faire un appel axios authentifié directement depuis un nœud CODE) sans exposer le secret en clair. Si aucun credential n'est nécessaire, le tableau est vide [].

2.2 Credentials inline (embarqués dans le nœud)​

Utilisé par les nœuds FTP (SEND_FILE_TO_FTP, LIST_FILES_FROM_FTP, et par extension READ_FILE_FROM_FTP, MOVE_FILE_FROM_FTP, DELETE_FILE_FROM_FTP). Contrairement au HTTP_REQUEST, il n'y a pas de référence à un ID externe : les identifiants sont saisis directement dans la config du nœud, sous un objet credentials avec un type discriminant :

  • Mot de passe :
    "credentials": { "type": "PASSWORD", "username": "sdf", "password": "sdf" }
  • Clé privée (SFTP) :
    "credentials": { "type": "PRIVATE_KEY", "username": "sdf", "privateKey": "sdf", "passphrase": "sdf" }
    ⚠️ Ceci contredit la bonne pratique n°4 (section 4) qui recommande de ne jamais saisir de secret en clair : pour les nœuds FTP, il est fortement recommandé de piocher ces valeurs via {{ dictionaries.groupe.cle }} plutôt que de les coder en dur, même si le schéma JSON l'autorise techniquement.

2.3 Ressource applicative (« App ») pour l'envoi d'e-mails​

SEND_EMAIL référence une App/ressource d'envoi (boîte mail ou service configuré côté plateforme) via resourceGroup. Ce champ est obligatoire pour que l'envoi soit routé via la bonne identité d'expéditeur. Au collage, c'est un objet, pas une chaîne :

"resourceGroup": { "id": "a6039d83-f983-417a-a41c-ad9dd52eb8c5" }

2.4 Récapitulatif​

MécanismeNœuds concernésChampForme au collage
Référence par credential (externe)HTTP_REQUESTauthenticationCredential{ "id": "<uuid>", "name": "<nom réel>", "config": { "type": "<enum, seul champ autorisé>" } }
Référence par credential + alias (utilisable en JS)CODEavailableAuthenticationCredentials[].{alias, authenticationCredential}authenticationCredential = { "id": "<uuid>", "name": "<nom réel>", "config": { "type": "<enum>" } }
Credentials inlineSEND_FILE_TO_FTP, LIST_FILES_FROM_FTP, autres nœuds FTPcredentials.{type, username, password|privateKey/passphrase}objet à plat — seul cas où des secrets transitent réellement dans le JSON
Référence à une ressource applicative (App)SEND_EMAILresourceGroup{ "id": "<uuid>" }

2.5 Pièges de validation à connaître au collage​

L'export d'un flux (fonction "exporter" côté canvas) aplatit certaines références en simples chaînes UUID — c'est le format lisible en lecture. Le collage (import d'un flux JSON dans le canvas) attend au contraire des objets structurés pour ces mêmes références. Si vous récupérez un authenticationCredential ou un resourceGroup depuis un export et que vous le recollez tel quel, le collage échoue. Utilisez systématiquement les formes objet documentées en 2.1 et 2.3, jamais la forme aplatie de l'export.

Rappels utiles en cas d'erreur de validation au collage :

  • Un message "X must be an object" signifie que le champ attend une structure imbriquée, pas une chaîne.
  • Un message "property X should not exist" signifie une validation stricte par liste blanche : le champ en question n'existe pas dans le schéma, quelle que soit sa pertinence apparente — ne pas l'ajouter, même par analogie avec un autre nœud.
  • authenticationCredential.config n'accepte que la clé type ; toute tentative d'y placer des identifiants (client secret, clé API, mot de passe…) est rejetée par la plateforme — cohérent avec le fait que ces informations restent gérées côté serveur (voir 2.1).

Recommandation pratique : avant de coller un flux généré ou modifié manuellement, configurez le nœud concerné une fois via l'interface Ecosystem pour vérifier la forme exacte attendue, notamment pour tout champ qui n'est pas encore couvert dans ce skill.


3. Logique de Placement (Layout Engine)​

Pour garantir la lisibilité sur le canvas et éviter les chevauchements, les coordonnées x et y doivent suivre ces règles :

Grille et Espacement​

  • Incrément vertical (DY) : $+200$ unités par nœud.
  • Décalage horizontal (DX) : $0$ pour le flux principal, $+800$ pour marquer l'entrée dans un bloc imbriqué.

Stratégie de calcul des positions​

  1. Flux Linéaire : Si le nœud B suit le nœud A, alors B.y = A.y + 200 et B.x = A.x.
  2. Entrée de Boucle (FOREACH / WHILE) :
    • Le premier nœud à l'intérieur de la boucle (loopStartNodeId) doit être positionné à x = parent.x + 800 et y = parent.y + 200.
  3. Sortie de Boucle :
    • Le nœud défini dans le champ next de la boucle reprend l'alignement x du nœud de la boucle, avec un y supérieur au dernier nœud interne.
  4. Bifurcation (CONDITION / SWITCH) :
    • Branche positive ou premier cas : x = parent.x + 800.
    • Branche négative ou cas par défaut : x = parent.x + 800.
  5. Gestion d'erreurs (ON_ERROR) : Toujours placé de manière isolée, idéalement à gauche du trigger (x: -800, y: 0).

4. Référentiel des Types de Nœuds​

Contrôle de Flux​

TypeUsageConfig Clé
CONDITIONBranchement logique (Si/Alors).conditionCode (JS complet avec return — obligatoire, pas d'expression templatée sans return), conditions (tableau {value, next}).
SWITCHAiguillage selon plusieurs valeurs.variable (template), cases (tableau {value, next, isDefault?}), noMatchBehaviour.
FOREACHItération sur un tableau de données.foreachCode (source), itemKey (nom de l'itérateur), codeExecution (SIMPLE | ADVANCED), batch.size, loopStartNodeId.
WHILERépétition tant qu'une condition est vraie.conditionCode (JS), mode (WHILE = test avant boucle, DO_WHILE = test après, exécute au moins une fois), loopStartNodeId.
WAITMet le workflow en pause.time (durée en millisecondes).
ON_ERRORDéclenche un flux spécifique en cas d'erreur.enabledEnvironments : tableau d'objets {id, name, slug} (et non une simple liste d'IDs) — slugs observés : studio, staging, production.

Intégration et API​

TypeUsageConfig Clé
HTTP_REQUESTAppel d'API tierce (REST, SOAP, GraphQL).method, url, headers, bodyMode (RAW | FORM_DATA | FORM_URL_ENCODED | GRAPHQL), body, timeout, retry.count, extractors[] (JSONPath), anonymize.{body,response,headers}, authenticationCredential, stopWorkflowOnFailure.
HTTP_RESPONSEEnvoi de la réponse au client (Trigger API).statusCode (littéral "200" ou JS "return 200;"), responseTemplate (Body), headers.
CALL_WORKFLOWExécute un autre workflow de la compagnie.workflow (ID), inherits.{context, data} (booléens), dataKey, contextKey (clés sous lesquelles le résultat est stocké dans le contexte appelant).
AGENTUtilise un LLM (GPT, Claude, Gemini).model, systemPrompt, message, outputKey, recursionLimit (nombre max d'itérations d'outils autorisées à l'agent, ex: 25).

Données et Bases​

TypeUsageConfig Clé
CODEExécution de logique métier complexe en JS.code (Node.js/ES6), availableAuthenticationCredentials[] (voir section 2.1).
DATABASE_POSTGRESQLLecture/Écriture sur PostgreSQL.query, binds (injection via $1, $2), outputKey, stopWorkflowOnFailure.
DATABASE_SNOWFLAKEAnalyse de données sur Snowflake.query, outputKey, asyncExec (booléen — exécution asynchrone de la requête), stopWorkflowOnFailure.
SEND_EVENTPublication vers Google Pub/Sub.provider.{type, projectId, topicId}, body.
SEND_AWS_SQSEnvoi de message vers AWS SQS.region, queue.{type, url, messageBody}.
SEND_EMAILEnvoi d'e-mail.to[], subject, content, sendAsHtml (booléen), resourceGroup (UUID de l'App/boîte d'envoi, voir 2.3), stopWorkflowOnFailure.

Fichiers et FTP​

TypeUsageConfig Clé
LIST_FILES_FROM_FTPRécupère la liste des fichiers distants.server, port, path, extensions[] (filtre par extension), recursive (booléen), filesKey, credentials (voir 2.2).
READ_FILE_FROM_FTPTélécharge et analyse un fichier.server, filePath, parseAs (CSV, XML, JSON, RAW), fileKey, credentials.
SEND_FILE_TO_FTPDépose un fichier sur un serveur.server, port, filePath, contentMode (SIMPLE | ADVANCED | RAW), content, credentials.
MOVE_FILE_FROM_FTPDéplace ou renomme un fichier FTP.sourcePath, destinationPath, credentials.
DELETE_FILE_FROM_FTPSupprime un fichier du serveur.path, credentials.

5. Détails avancés — HTTP_REQUEST​

C'est le nœud le plus riche en options ; l'export réel montre 4 variantes de bodyMode avec des structures de body différentes.

5.1 bodyMode: "RAW"​

body est une chaîne JSON classique, avec templating Handlebars à l'intérieur des valeurs :

"body": "{\"test\":\"test\"}"

5.2 bodyMode: "FORM_DATA" (multipart)​

body est une chaîne JSON décrivant chaque champ du formulaire avec un type discriminant FIELD ou FILE :

"body": "{\"query\":{\"type\":\"FIELD\",\"content\":\"sdf\"},\"sdf\":{\"type\":\"FILE\",\"content\":\"sdf\",\"name\":\"{{context.file}}\"}}"

Le header Content-Type doit être multipart/form-data.

5.3 bodyMode: "GRAPHQL"​

body est un objet JSON avec une clé unique query contenant la requête GraphQL, elle-même templatable :

"body": "{\"query\":\"query Post($postId: ID!) { post(id: $postId) { id name {{context.lang}} } }\"}"

5.4 bodyMode: "FORM_URL_ENCODED"​

Même logique que RAW, mais le header attendu est application/x-www-form-urlencoded.

5.5 extractors[]​

Chaque extracteur peut être anonymisé individuellement (en plus du flag global anonymize) :

{ "part": "BODY", "name": "testcontextbis", "path": "$.test", "anonymize": true }
  • part : BODY ou HEADERS.
  • anonymize : masque la valeur extraite dans les logs d'exécution — utile pour des données sensibles (tokens, PII) même si l'extraction reste fonctionnelle.

5.6 anonymize (niveau nœud)​

Objet distinct des extractors[].anonymize, contrôle le masquage dans les logs au niveau global de l'appel :

"anonymize": { "headers": false, "body": true, "response": true }

5.7 retry​

"retry": { "count": 2 }

Nombre de tentatives en cas d'échec, avant application éventuelle de stopWorkflowOnFailure.


6. Bonnes Pratiques de Configuration​

  1. Extractors : Nommez toujours vos extracteurs de manière explicite pour qu'ils soient lisibles dans le context (ex: last_order_id au lieu de id). Activez anonymize: true sur tout extracteur qui capture une donnée sensible (token, email, IBAN…).
  2. Résilience : Utilisez stopWorkflowOnFailure: true pour les étapes critiques, ou gérez l'erreur via un nœud CONDITION basé sur context.lastResponse.success. Combinez avec retry.count sur les appels HTTP_REQUEST instables.
  3. Handlebars : Privilégiez les templates {{ context.variable }} dans les champs de texte pour plus de flexibilité. Pour conditionCode (CONDITION/WHILE), le return JS reste obligatoire — le Handlebars ne sert qu'à injecter des valeurs à l'intérieur de l'expression, pas à la remplacer.
  4. Sécurité : Ne saisissez jamais de clés d'API ou de mots de passe en texte brut. Utilisez les identifiants (authenticationCredential pour HTTP/CODE) ou les dictionnaires ({{ dictionaries.groupe.cle }}) — y compris pour les champs credentials inline des nœuds FTP, qui acceptent le templating malgré leur apparence de config statique.
  5. Code JS : Les nœuds CODE et CONDITION supportent les librairies standards (lodash, dayjs, axios). Évitez les boucles infinies. Si le code doit appeler une API authentifiée, déclarez le credential dans availableAuthenticationCredentials plutôt que de coder le secret en dur.
  6. Emails : Vérifiez toujours que resourceGroup correspond à une App d'envoi valide et autorisée pour l'environnement cible (Studio/Staging/Production) — un resourceGroup de test en production entraîne un échec silencieux ou un envoi depuis la mauvaise identité.
  7. Agents IA : Bornez systématiquement recursionLimit à une valeur raisonnable (ex: 25) pour éviter les boucles d'appels d'outils incontrôlées et les surcoûts.
  8. ON_ERROR : Précisez explicitement les environnements (enabledEnvironments) sur lesquels le gestionnaire d'erreur doit se déclencher — un tableau vide [] désactive le nœud partout.

7. Exemple de Workflow (Standard structure)​

Un workflow doit toujours commencer par un nœud avec l'ID "trigger". La structure JSON suit le format :

{
"id": "node_id",
"name": "Nom du nœud",
"config": { "type": "TYPE_DU_NOEUD", ... },
"parents": ["id_du_parent"],
"next": "id_du_suivant",
"position": { "x": 0, "y": 0 }
}

Référence de la structure de chaque nœud​

ℹ️ Dans l'exemple ci-dessous, authenticationCredential.config ({ "type": "OAUTH2" } / { "type": "API_KEY" }) n'accepte que la clé type — tout autre champ (secrets, identifiants) est rejeté par la plateforme. Remplacez id, name et type par ceux d'un credential réellement existant dans votre instance Ecosystem.

{
"version": "2.0.0",
"semver": "1.0.0",
"nodes": [
{
"id": "trigger",
"name": "Point d'entrée API",
"config": { "type": "TRIGGER", "triggerId": "e6cbf9e2-9d4b-4c7f-8c3e-7c8b2d0f5a11" },
"parents": [],
"next": "c2c16e70-2602-43ba-b7d5-fc56aff0fd76",
"position": { "x": 0, "y": 0 }
},
[{
"id": "5a5a8830-9650-4e85-8b4c-42d47145483b",
"name": "Gestionnaire d'erreurs global",
"config": {
"type": "ON_ERROR",
"enabledEnvironments": [
{ "id": "846b7c88-0158-4914-8c4c-ef1f883b664f", "name": "Studio", "slug": "studio" },
{ "id": "f672aa14-0977-4a1f-af82-8ffe0465398f", "name": "Production", "slug": "production" }
]
},
"parents": [],
"next": "344aba08-f5f5-4246-9450-202a8081e7b4",
"position": { "x": -800, "y": 0 }
},
{
"id": "c2c16e70-2602-43ba-b7d5-fc56aff0fd76",
"name": "Initialisation Context",
"config": {
"type": "CODE",
"code": "context.items = [1, 2, 3];\ncontext.counter = 0;\ncontext.status = 'START';",
"availableAuthenticationCredentials": [
{
"alias": "oauth_test_prod",
"authenticationCredential": {
"id": "1a5f61a4-a04a-409f-b4b0-22bc778e1545",
"name": "Nom réel du credential dans Ecosystem",
"config": { "type": "OAUTH2" }
}
}
]
},
"parents": ["trigger"],
"next": "cd591a16-71c8-4fc2-ae95-0bf33bc3c393",
"position": { "x": 0, "y": 200 }
},
{
"id": "cd591a16-71c8-4fc2-ae95-0bf33bc3c393",
"name": "Boucle FOREACH",
"config": {
"type": "FOREACH",
"codeExecution": "ADVANCED",
"foreachCode": "context.items",
"itemKey": "currentItem",
"loopStartNodeId": "088b59c2-3769-4825-b4a0-1f25bca17f90",
"batch": { "size": 1 }
},
"parents": ["c2c16e70-2602-43ba-b7d5-fc56aff0fd76"],
"next": "0dd87e29-93ae-40e6-bd48-bc4851aa3102",
"position": { "x": 0, "y": 400 }
},
{
"id": "088b59c2-3769-4825-b4a0-1f25bca17f90",
"name": "Appel API Externe",
"config": {
"type": "HTTP_REQUEST",
"method": "GET",
"url": "https://api.example.com/data/{{ context.currentItem }}",
"headers": { "Accept": "application/json" },
"bodyMode": "RAW",
"timeout": 10,
"retry": { "count": 2 },
"extractors": [
{ "part": "BODY", "name": "apiResult", "path": "$.status", "anonymize": false }
],
"anonymize": { "headers": false, "body": false, "response": false },
"authenticationCredential": {
"id": "dfddd831-6601-4aea-b3a6-ad8290fcdce0",
"name": "Nom réel du credential dans Ecosystem",
"config": { "type": "API_KEY" }
},
"stopWorkflowOnFailure": true
},
"parents": ["cd591a16-71c8-4fc2-ae95-0bf33bc3c393"],
"next": "31b81df7-3fcb-4b70-a330-68e6d487ed62",
"position": { "x": 800, "y": 600 }
},
{
"id": "31b81df7-3fcb-4b70-a330-68e6d487ed62",
"name": "Vérification Statut",
"config": {
"type": "CONDITION",
"conditionCode": "return context.apiResult === 'OK';",
"conditions": [
{ "value": true, "next": "b0d37eb8-4670-40d6-aad5-ae5143010dd2" },
{ "value": false, "next": "00e5b34f-ed8b-4cec-8089-beb98cfa1452" }
]
},
"parents": ["088b59c2-3769-4825-b4a0-1f25bca17f90"],
"position": { "x": 800, "y": 800 }
},
{
"id": "b0d37eb8-4670-40d6-aad5-ae5143010dd2",
"name": "Pause 1s",
"config": { "type": "WAIT", "time": "1000" },
"parents": ["31b81df7-3fcb-4b70-a330-68e6d487ed62"],
"position": { "x": 400, "y": 1000 }
},
{
"id": "00e5b34f-ed8b-4cec-8089-beb98cfa1452",
"name": "Réponse HTTP (Trigger API)",
"config": {
"type": "HTTP_RESPONSE",
"statusCode": "200",
"responseTemplate": "{\"status\": \"processed\"}",
"headers": { "Content-Type": "application/json" }
},
"parents": ["31b81df7-3fcb-4b70-a330-68e6d487ed62"],
"position": { "x": 800, "y": 1200 }
},
{
"id": "0dd87e29-93ae-40e6-bd48-bc4851aa3102",
"name": "Boucle WHILE",
"config": {
"type": "WHILE",
"mode": "WHILE",
"conditionCode": "return context.counter < 3;",
"loopStartNodeId": "5d1ca2c1-08bd-4359-8786-9b7df39903c3"
},
"parents": ["cd591a16-71c8-4fc2-ae95-0bf33bc3c393"],
"next": "06eeecd3-b5ad-47a6-897e-f274a2b6b66b",
"position": { "x": 0, "y": 1400 }
},
{
"id": "5d1ca2c1-08bd-4359-8786-9b7df39903c3",
"name": "Requête PostgreSQL",
"config": {
"type": "DATABASE_POSTGRESQL",
"host": "db.example.com",
"database": "prod",
"query": "SELECT * FROM logs WHERE id = $1",
"binds": ["$.context.counter"],
"outputKey": "pgData",
"stopWorkflowOnFailure": true
},
"parents": ["0dd87e29-93ae-40e6-bd48-bc4851aa3102"],
"next": "7eb13ebc-36c9-4be8-9375-c60e61aad1db",
"position": { "x": 800, "y": 1600 }
},
{
"id": "7eb13ebc-36c9-4be8-9375-c60e61aad1db",
"name": "Requête Snowflake",
"config": {
"type": "DATABASE_SNOWFLAKE",
"query": "SELECT count(*) FROM raw_data",
"outputKey": "sfData",
"asyncExec": false,
"stopWorkflowOnFailure": true
},
"parents": ["5d1ca2c1-08bd-4359-8786-9b7df39903c3"],
"position": { "x": 800, "y": 1800 }
},
{
"id": "06eeecd3-b5ad-47a6-897e-f274a2b6b66b",
"name": "Aiguillage Flux",
"config": {
"type": "SWITCH",
"variable": "{{ context.status }}",
"noMatchBehaviour": "DEFAULT_CASE",
"cases": [
{ "value": "START", "next": "39fb1126-eff0-40d7-b087-7553ea145908" },
{ "value": "END", "next": "6ac7d382-e13a-40e3-ac0e-997b8c3a8853" },
{ "value": "default", "isDefault": true }
]
},
"parents": ["0dd87e29-93ae-40e6-bd48-bc4851aa3102"],
"position": { "x": 0, "y": 2000 }
},
{
"id": "39fb1126-eff0-40d7-b087-7553ea145908",
"name": "Assistant IA (Agent)",
"config": {
"type": "AGENT",
"model": { "provider": "OPENAI", "name": "gpt-4" },
"systemPrompt": "Tu es un assistant technique.",
"message": "Analyse ces données : {{ context.pgData }}",
"outputKey": "aiAnalysis",
"recursionLimit": 25
},
"parents": ["06eeecd3-b5ad-47a6-897e-f274a2b6b66b"],
"next": "266d9b13-ce22-412c-9cf2-c9b73e16403e",
"position": { "x": 0, "y": 2200 }
},
{
"id": "266d9b13-ce22-412c-9cf2-c9b73e16403e",
"name": "Event Google Pub/Sub",
"config": {
"type": "SEND_EVENT",
"provider": { "type": "GCP_PUBSUB", "projectId": "my-project", "topicId": "my-topic" },
"body": "{\"analysis\": \"{{ context.aiAnalysis }}\"}"
},
"parents": ["39fb1126-eff0-40d7-b087-7553ea145908"],
"next": "66dbece7-627f-4a56-bf04-8c57ba4d7beb",
"position": { "x": 0, "y": 2400 }
},
{
"id": "66dbece7-627f-4a56-bf04-8c57ba4d7beb",
"name": "Message AWS SQS",
"config": {
"type": "SEND_AWS_SQS",
"region": "eu-west-1",
"queue": { "type": "STANDARD", "url": "https://sqs.aws.com/queue", "messageBody": "Sync Task Completed" }
},
"parents": ["266d9b13-ce22-412c-9cf2-c9b73e16403e"],
"next": "6ac7d382-e13a-40e3-ac0e-997b8c3a8853",
"position": { "x": 0, "y": 2600 }
},
{
"id": "6ac7d382-e13a-40e3-ac0e-997b8c3a8853",
"name": "Appel Sous-Workflow",
"config": {
"type": "CALL_WORKFLOW",
"workflow": "e0d3a2c4-2222-4b7a-9a2a-9a6b9f0c1234",
"inherits": { "context": true, "data": false },
"dataKey": "subWorkflowData",
"contextKey": "subWorkflowContext"
},
"parents": ["66dbece7-627f-4a56-bf04-8c57ba4d7beb"],
"next": "0d2f475a-02c1-4c4b-b181-bb9ce14d73f5",
"position": { "x": 0, "y": 2800 }
},
{
"id": "0d2f475a-02c1-4c4b-b181-bb9ce14d73f5",
"name": "FTP: Lister Fichiers",
"config": {
"type": "LIST_FILES_FROM_FTP",
"server": "ftp.example.com",
"port": "21",
"path": "/inbox",
"extensions": ["csv"],
"recursive": false,
"filesKey": "ftpFiles",
"credentials": { "type": "PASSWORD", "username": "{{ dictionaries.ftp.user }}", "password": "{{ dictionaries.ftp.pass }}" }
},
"parents": ["6ac7d382-e13a-40e3-ac0e-997b8c3a8853"],
"next": "841e41c7-13ff-4580-bc2d-c6c7d2f557e1",
"position": { "x": 0, "y": 3000 }
},
{
"id": "841e41c7-13ff-4580-bc2d-c6c7d2f557e1",
"name": "FTP: Lire Fichier",
"config": {
"type": "READ_FILE_FROM_FTP",
"server": "ftp.example.com",
"filePath": "/inbox/data.csv",
"parseAs": { "type": "CSV", "delimiter": "," },
"fileKey": "csvData"
},
"parents": ["0d2f475a-02c1-4c4b-b181-bb9ce14d73f5"],
"next": "8bca0f3d-81e0-49cc-b1ce-d8806b80fc44",
"position": { "x": 0, "y": 3200 }
},
{
"id": "8bca0f3d-81e0-49cc-b1ce-d8806b80fc44",
"name": "FTP: Envoyer Fichier",
"config": {
"type": "SEND_FILE_TO_FTP",
"server": "ftp.example.com",
"filePath": "/outbox/report.txt",
"contentMode": "SIMPLE",
"content": "Rapport généré le {{ metadata.date }}"
},
"parents": ["841e41c7-13ff-4580-bc2d-c6c7d2f557e1"],
"next": "e0401e16-fa61-40eb-a992-dfada70116be",
"position": { "x": 0, "y": 3400 }
},
{
"id": "e0401e16-fa61-40eb-a992-dfada70116be",
"name": "FTP: Déplacer Fichier",
"config": {
"type": "MOVE_FILE_FROM_FTP",
"server": "ftp.example.com",
"sourcePath": "/inbox/data.csv",
"destinationPath": "/archive/data.csv"
},
"parents": ["8bca0f3d-81e0-49cc-b1ce-d8806b80fc44"],
"next": "a17042b5-4426-43c3-9c8f-79db00d58b79",
"position": { "x": 0, "y": 3600 }
},
{
"id": "a17042b5-4426-43c3-9c8f-79db00d58b79",
"name": "FTP: Supprimer Fichier",
"config": { "type": "DELETE_FILE_FROM_FTP", "server": "ftp.example.com", "path": "/temp/temp_file.tmp" },
"parents": ["e0401e16-fa61-40eb-a992-dfada70116be"],
"next": "ba6523bd-575e-4ccb-b7eb-0f5af80d816d",
"position": { "x": 0, "y": 3800 }
},
{
"id": "ba6523bd-575e-4ccb-b7eb-0f5af80d816d",
"name": "Notification Email Succès",
"config": {
"type": "SEND_EMAIL",
"to": ["admin@example.com"],
"subject": "Workflow Terminé",
"content": "Le traitement est terminé avec succès.",
"sendAsHtml": true,
"resourceGroup": { "id": "a6039d83-f983-417a-a41c-ad9dd52eb8c5" },
"stopWorkflowOnFailure": true
},
"parents": ["a17042b5-4426-43c3-9c8f-79db00d58b79"],
"position": { "x": 0, "y": 4000 }
},
{
"id": "344aba08-f5f5-4246-9450-202a8081e7b4",
"name": "Notification Email Erreur",
"config": {
"type": "SEND_EMAIL",
"to": ["devs@example.com"],
"subject": "Échec du Workflow",
"content": "Une erreur est survenue. Trace: {{ metadata.traceId }}",
"sendAsHtml": true,
"resourceGroup": { "id": "a6039d83-f983-417a-a41c-ad9dd52eb8c5" },
"stopWorkflowOnFailure": true
},
"parents": ["5a5a8830-9650-4e85-8b4c-42d47145483b"],
"position": { "x": -800, "y": 200 }
}
]
}