Skip to content

Workflows (MVP4)

Vue d'ensemble

Le module workflows expose un brouillon de workflow par entreprise pour l'éditeur no-code.

Le backend stocke:

  • la métadonnée du workflow (workflows), incluant input_source_id (rétrocompat / premier bloc Source du canvas qui a une source liée)
  • les nœuds (workflow_nodes), avec pour chaque bloc de type source une source Heriade optionnelle (workflow_nodes.input_source_idsources) — chaque bloc Source a sa propre liaison
  • les liens (workflow_edges)

Connexions entre blocs (ordre du pipeline)

Règles de liaison acceptées à la sauvegarde (alignées sur l’éditeur) :

  • Source → Traitement
  • Traitement → Traitement
  • Traitement → Destination

Les cycles orientés sont rejetés côté éditeur lors de la création d’une arête. L’ordre d’exécution attendu pour un graphe sans cycle est un ordre topologique (pour tout arc u → v, le nœud u est exécuté avant v). Une implémentation de référence côté front est computeWorkflowExecutionOrder dans front/src/pages/admin/workflows/workflow-execution-order.js.

Endpoints

GET /workflows/current

Retourne le brouillon courant de l'entreprise du user connecté.

Comportement:

  • si un workflow existe, il est renvoyé
  • sinon un brouillon est créé automatiquement

PUT /workflows/current/canvas

Sauvegarde le canvas complet.

Payload:

  • nodes[] avec { id, type, label, x, y } et, pour type === "source", inputSourceUuid (uuid ou null) : fichier Heriade lié à ce nœud uniquement
  • edges[] avec { id, source, target }
  • inputSourceUuid à la racine (optionnel, déprécié) : si le premier bloc source du tableau nodes n’a pas de inputSourceUuid, cette valeur s’applique à ce premier bloc uniquement

Lors de la sauvegarde, si un inputSourceUuid de bloc source ne correspond à aucune source Heriade active accessible pour l’utilisateur (supprimée, UUID inconnu), la liaison de ce nœud est enregistrée comme vide (null) et un avertissement est écrit dans les logs — la sauvegarde du canvas n’échoue pas pour autant.

Résolution des sources (alignée sur GET /sources) :

  • Rôle autre que super-admin : seules les sources dont enterprise_id est celui du workflow sont acceptées (comme le scope du workflow).
  • Super-admin : toute source non supprimée (deleted_at null) avec l’UUID fourni est acceptée, même si son enterprise_id diffère de celui du workflow — cohérent avec la liste Heriade qui n’est pas filtrée par entreprise pour ce rôle.

La sauvegarde remplace l'état courant dans une transaction:

  1. suppression edges
  2. suppression nodes
  3. insertion nodes
  4. insertion edges

Sécurité

Routes protégées par:

  • AuthGuard
  • AdminGuard

Le workflow est scoppé à l'entreprise du user (user.enterprise.id).

Migration SQL

Scripts :

  • sql/tool_11_add_workflows.sql
  • sql/tool_12_workflow_input_source.sql (colonnes workflows.input_source_id + workflow_nodes.input_source_id, BDD-93)
  • sql/tool_15_workflow_run_history.sql (historique d'exécution par workflow, BDD-96)
  • sql/tool_16_workflow_run_staging.sql (convention tables staging éphémères, BDD-120)

Exécution manuelle (BDD-107)

POST /workflows/:workflowUuid/run

Lance l'exécution du pipeline tel qu'enregistré en base (le front déclenche une sauvegarde du canvas avant l'appel).

Réponse :

  • runUuid : identifiant de l'exécution persistée
  • success : true si le pipeline n'a pas échoué sur un nœud (les avertissements métier restent un succès HTTP)
  • status : statut final success | failed | warning (ex. baisse de lignes après un bloc sans erreur bloquante)
  • durationMs : durée totale côté serveur pour cette exécution
  • message : message global optionnel (souvent l'erreur du premier nœud en échec)
  • nodes[] : pour chaque nœud traité dans l'ordre topologique :
    • nodeId, nodeType (source | traitement | destination)
    • status : success | warning | failed | not_executed
    • rowsIn, rowsOut, durationMs
    • error? si failed
    • pour un nœud Destination réussi / en avertissement : rowCount, columnCount comme auparavant

Règles :

  • Au moins un bloc Source et un bloc Destination requis
  • Ordre topologique (même contrat que computeWorkflowExecutionOrder côté front)
  • En cas d'échec sur un nœud, les nœuds suivants sont not_executed
  • Traitement : moteurs alignés sur le front (mapper, nettoyer, croiser, colonne_texte, colonne_calculee)
  • Destination : propage la sortie amont (voir BDD-115 pour export / lastResult)

Implémentation : WorkflowRunStagingExecutionService (enregistré sous le token WorkflowRunService), persistance historique via WorkflowRunHistoryService, moteurs dans back/src/api/workflows/execution/.

Exécution complète fichier dépôt (BDD-120)

Le lancement manuel (POST /workflows/:workflowUuid/run) charge toutes les lignes du fichier dépôt lié au bloc Source (input_document_id), sans passer par SourcesService.getPreview ni créer de source Heriade.

ÉtapeComportement
SourceTéléchargement S3 complet → parse (FileParserService) → matérialisation PostgreSQL staging
TraitementSQL sur tables staging (WorkflowMapperStagingService, WorkflowNettoyerStagingService, WorkflowCroiserStagingService, WorkflowColonneTexteStagingService)
DestinationExport CSV/Excel par lots depuis staging → upload S3 → artifactRef
Fin de runDROP SCHEMA staging_run_{runUuid} CASCADE (isolation entre exécutions)

Staging : schéma staging_run_{runUuidSansTirets}, table par nœud node_{nodeUuidSansTirets}. Convention : sql/tool_16_workflow_run_staging.sql.

Aperçu éditeur (panneau Source) : GET /workflows/depot-preview?documentUuid= — parse borné (voir BDD-129), ~20 lignes affichées. Distinct de l'exécution complète (Lancer).

Services : back/src/api/workflows/staging/.

Fiche ticket : BDD-120.

Grands volumes (BDD-129)

SujetComportement
Preview éditeurGET /workflows/depot-preview — parse au plus WORKFLOW_DEPOT_PREVIEW_PARSE_ROWS (défaut 200), retour UI WORKFLOW_DEPOT_PREVIEW_MAX_ROWS (défaut 20)
Run — plafond durWORKFLOW_RUN_MAX_ROWS : absent ou 0 = pas de plafond ; entier > 0 = refus au-delà (WorkflowRunMaxRowsExceededException)
Run — avertissementWORKFLOW_RUN_WARN_ROWS (défaut 500000, 0 = off) : run warning + champ warning + toast
Export DestinationLecture staging par pages de WORKFLOW_EXPORT_BATCH_SIZE lignes (défaut 5000)
Export ExcelÉcriture xlsx en flux (exceljs), même lecture par lots — adapté aux grands volumes
Upload fichierFILE_SIZE_LIMIT (Mo) — module documents, non modifié par BDD-129

Fiche ticket : BDD-129.

Mapper / Nettoyer / Destination (BDD-121, SQL BDD-129)

  • Mapper / Nettoyer : CREATE TABLE … AS SELECT sur staging (plus de chargement intégral en mémoire Node).
  • Destination : export CSV (texte) ou Excel (flux exceljs) par lots depuis staging → upload S3 → artifactRef dans la réponse du run.
  • Téléchargement : GET /workflows/:workflowUuid/runs/:runUuid/export-download?artifactRef={bucket/key}&outputType=export_csv|export_excel (URL signée + fileName avec extension). Les nouveaux exports utilisent une clé S3 du type workflow_export_{runSlice}.csv ; les clés legacy (UUID seul) reçoivent l'extension via outputType.
  • publish_heriade : publication en Source Heriade (WORKFLOW_PUBLISHED, versions v1/v2…). Voir BDD-97. Rattachement environnement métier : MVP3.

Colonne texte (BDD-132)

  • Ajout d’une ou plusieurs colonnes à valeur texte fixe sur toutes les lignes (CREATE TABLE … AS SELECT avec littéraux SQL via WorkflowColonneTexteStagingService).
  • Configuration JSONB : type: "colonne_texte", columns: [{ columnName, textValue }].
  • Aperçu éditeur : applyColonneTexteToRows sur l’échantillon amont (depot-preview ou sortie traitement précédent).

Fiche ticket : BDD-132.

Colonne calculée (BDD-133)

  • Ajout d’une ou plusieurs colonnes ligne à ligne via expressions sécurisées (pas de SQL arbitraire utilisateur).
  • Configuration JSONB : type: "colonne_calculee", columns: [{ columnName, expression }, …] (legacy : columnName + expression à la racine).
  • Une colonne peut référencer les colonnes définies avant elle dans le même bloc ; le staging inline le SQL des colonnes précédentes dans le même SELECT.
  • Syntaxe MVP : références [nom_colonne], opérateurs + - * /, comparaisons (=, !=, <=, …), condition si … alors … sinon ….
  • Aperçu éditeur : applyColonneCalculeeToRows (même moteur que le back workflow-colonne-calculee.engine).
  • Exécution run : WorkflowColonneCalculeeStagingService (CREATE TABLE … AS SELECT + expression compilée en SQL whitelisté).

Fiche ticket : BDD-133.

Croiser SQL (BDD-122)

  • Jointure INNER ou LEFT via CREATE TABLE … AS SELECT entre deux tables staging amont.
  • Métriques rows_in / rows_out par agrégats SQL (COUNT), sans matérialiser la jointure en mémoire Node.
  • L’aperçu éditeur conserve simulateCroiserJoin sur échantillon.

Progression et historique d'exécution (BDD-96)

Les exécutions déclenchées par POST /workflows/:workflowUuid/run sont enregistrées pour permettre une consultation ultérieure (même graphe).

GET /workflows/:workflowUuid/runs

Liste les exécutions du workflow, les plus récentes en premier.

Éléments typiques :

  • runUuid, status (success | failed | warning)
  • startedAt, finishedAt?, durationMs?
  • message?

GET /workflows/:workflowUuid/runs/:runUuid

Détail d'une exécution avec les étapes ordonnées (executionOrder) :

  • nodeId, nodeType, status, rowsIn, rowsOut, durationMs, error?

Migration SQL : sql/tool_15_workflow_run_history.sql (tables workflow_runs, workflow_run_steps).

Consultation de l'historique (BDD-100)

Réutilise les endpoints ci-dessus. Côté front :

  • Liste workflows : bouton Historique des exécutions → dialog avec filtre Workflow puis liste (date, durée, statut) et détail par étape (rows_in, rows_out, durée, error, message si échec).
  • Éditeur : onglet Historique du Résumé utilise le même composant WorkflowRunHistoryPanels.

Fiche ticket : BDD-100.

Aperçu éditeur vs exécution complète (BDD-124)

Deux parcours distincts :

Action UIDonnéesHistorique (workflow_runs)
Panneau Source / bouton PrévisualiserÉchantillon (≈ 20 lignes dépôt, ≈ 5 lignes simulation bloc)Non
Bouton LancerFichier dépôt entier via staging PostgreSQL (BDD-120)Oui — rows_in, rows_out, duration_ms par étape

Les métriques affichées dans Dernière exécution, Historique et le dialog liste workflows proviennent uniquement d’un Lancer réussi (ou partiel). Elles sont calculées côté back à partir des tables staging (COUNT SQL pour Croiser, comptages staging pour Mapper / Nettoyer / Destination).

Libellés front centralisés : front/src/pages/admin/workflows/workflow-execution-hints.js.

Fiche ticket : BDD-124.

Ergonomie de l'éditeur (BDD-128)

Retours UX sur la cohérence visuelle de l'éditeur no-code :

  • Barre d'outils : styles partagés (workflow-editor-toolbar.scss) pour Sauvegarder, Ajouter un bloc, Résumé et Lancer.
  • Palette : WorkflowBlockPaletteMenu — ajout au clic (addBlockAtViewportCenter) ou par glisser-déposer.
  • Inspecteur : hiérarchie des sections Source (WorkflowInspectorSection).
  • Canvas : icônes des nœuds unifiées (couleur primaire #263286).

Correctif connexe sur le téléchargement d'export après exécution : voir paramètre outputType sur export-download ci-dessus.

Fiche ticket : BDD-128.

Renommage des blocs canvas (BDD-130)

Le libellé affiché sur chaque nœud est stocké dans workflow_nodes.label (payload canvas nodes[].label pour tous les types : source, traitement, destination).

Côté front :

  • Fusion : workflow-canvas-label.js / workflow-canvas.sync.js — lors des update:nodes Vue Flow, un libellé entrant égal au défaut du type (Source, Traitement, Destination) n'écrase pas un nom personnalisé déjà saisi.
  • Saisie : useWorkflowCanvasNodeLabelDraft — brouillon local debouncé dans le tiroir ; trim à la perte de focus et à la persistance (toWorkflowNode).
  • Autosave : saveCanvas rafraîchit la liste des workflows sans activer loading (évite l'overlay « Chargement du workflow… » sur le canvas).
  • Position : workflow-canvas-position.js + @node-drag-stop — les coordonnées déplacées sont persistées (position_x / position_y) et ne reviennent pas au point d'ajout initial après autosave.

Fiche ticket : BDD-130.

Notes d'évolution

  • Le scope actuel est un brouillon unique par entreprise.
  • Les prochaines US pourront introduire versionning, publication et des exports d'exécution enrichis.

Résolution des sources en amont d'un Traitement

Pour charger les colonnes / l'échantillon du panneau Mapper ou Nettoyer, l'éditeur collecte les UUID des sources Heriade atteignables depuis le nœud traitement actif en remontant les arêtes : prédécesseurs source (avec inputSourceUuid défini) et prédécesseurs traitement (récursion). Les traitements intermédiaires sont supposés ne pas changer les noms de colonnes (ex. Nettoyer ne filtre que des lignes) : les métadonnées de colonnes restent celles des sources trouvées.

Implémentation : front/src/pages/admin/workflows/workflow-upstream-sources.resolver.js.

Bloc Traitement « Nettoyer » (BDD-98)

Sous-type traitement avec configuration.type === "nettoyer". Voir la fiche ticket BDD-98 — Configurer le bloc Nettoyer et le moteur front workflow-nettoyer.engine.js.

La simulation (Mapper / Nettoyer) s’appuie sur les lignes chargées depuis les sources via GET /sources/:uuid/data : pagination automatique (100 lignes par requête, plafond configurable côté front WORKFLOW_SOURCE_PREVIEW_MAX_ROWS, défaut 10 000) jusqu’à couvrir la table ou le plafond. Ce n’est pas l’exécution serveur du graphe complet ; une US « exécution pipeline » matérialisera les résultats intermédiaires bloc par bloc.

Implémentation du chargement : front/src/pages/admin/workflows/workflow-source-preview.fetch.js.

Bloc Traitement « Croiser » (BDD-99)

Sous-type traitement avec configuration.type === "croiser". Voir la fiche ticket BDD-99 — Configurer le bloc Croiser.

Paires de colonnes gauche / droite (BDD-131)

Chaque clé de jointure est une paire { left, right } : colonne de la branche amont gauche (source A) et colonne de la branche droite (source B), sans exiger le même libellé.

  • UI : WorkflowCroiserPanel — sélecteur Branche gauche (table principale) + bouton Inverser gauche / droite ; deux q-select par paire de colonnes (gauche / droite).
  • Config : joinKeyPairs[] et leftBranchRootNodeId (uuid du prédécesseur direct choisi comme table l) dans configuration JSONB ; rétrocompat joinKeys / joinKey. Si leftBranchRootNodeId est absent ou invalide, repli sur le tri stable des ids des deux prédécesseurs (pas la position sur le canvas).
  • Prévisualisation : simulateCroiserJoin compare row[left] à row[right] par paire.
  • Exécution staging : WorkflowCroiserStagingService génère ON l.<col_gauche> = r.<col_droite> pour chaque paire (AND), types inner / left inchangés.

Fiche ticket : BDD-131.

Le panneau exige deux connexions entrantes. Chaque branche charge la sortie simulée du prédécesseur direct (Source, Mapper, Nettoyer, etc.) via workflow-traitement-preview.pipeline.js, et non plus systématiquement le fichier Source brut.

Bloc Destination (BDD-115)

Nœud destination avec configuration.type === "destination". Voir BDD-115 — Configurer le bloc Destination.

Options : export_csv, export_excel, publish_heriade. L'aperçu charge la sortie simulée du prédécesseur direct (même règle que Mapper / Nettoyer). Le lancement manuel du workflow (US dédiée) remplira configuration.lastResult.

Chaînage des aperçus (Mapper / Nettoyer / Croiser)

Règle : un traitement = entrée = sortie du nœud directement en amont ; Source = fichier dépôt (GET /workflows/depot-preview?documentUuid= pour l'aperçu éditeur). Chaîne récursive documentée dans BDD-99.