Appearance
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), incluantinput_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_id→sources) — 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, pourtype === "source",inputSourceUuid(uuid ounull) : fichier Heriade lié à ce nœud uniquementedges[]avec{ id, source, target }inputSourceUuidà la racine (optionnel, déprécié) : si le premier bloc source du tableaunodesn’a pas deinputSourceUuid, 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_idest celui du workflow sont acceptées (comme le scope du workflow). - Super-admin : toute source non supprimée (
deleted_atnull) avec l’UUID fourni est acceptée, même si sonenterprise_iddiffè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:
- suppression edges
- suppression nodes
- insertion nodes
- insertion edges
Sécurité
Routes protégées par:
AuthGuardAdminGuard
Le workflow est scoppé à l'entreprise du user (user.enterprise.id).
Migration SQL
Scripts :
sql/tool_11_add_workflows.sqlsql/tool_12_workflow_input_source.sql(colonnesworkflows.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éesuccess:truesi le pipeline n'a pas échoué sur un nœud (les avertissements métier restent un succès HTTP)status: statut finalsuccess|failed|warning(ex. baisse de lignes après un bloc sans erreur bloquante)durationMs: durée totale côté serveur pour cette exécutionmessage: 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_executedrowsIn,rowsOut,durationMserror?sifailed- pour un nœud Destination réussi / en avertissement :
rowCount,columnCountcomme auparavant
Règles :
- Au moins un bloc Source et un bloc Destination requis
- Ordre topologique (même contrat que
computeWorkflowExecutionOrdercô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.
| Étape | Comportement |
|---|---|
| Source | Téléchargement S3 complet → parse (FileParserService) → matérialisation PostgreSQL staging |
| Traitement | SQL sur tables staging (WorkflowMapperStagingService, WorkflowNettoyerStagingService, WorkflowCroiserStagingService, WorkflowColonneTexteStagingService) |
| Destination | Export CSV/Excel par lots depuis staging → upload S3 → artifactRef |
| Fin de run | DROP 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)
| Sujet | Comportement |
|---|---|
| Preview éditeur | GET /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 dur | WORKFLOW_RUN_MAX_ROWS : absent ou 0 = pas de plafond ; entier > 0 = refus au-delà (WorkflowRunMaxRowsExceededException) |
| Run — avertissement | WORKFLOW_RUN_WARN_ROWS (défaut 500000, 0 = off) : run warning + champ warning + toast |
| Export Destination | Lecture 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 fichier | FILE_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 SELECTsur staging (plus de chargement intégral en mémoire Node). - Destination : export CSV (texte) ou Excel (flux
exceljs) par lots depuis staging → upload S3 →artifactRefdans 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 +fileNameavec extension). Les nouveaux exports utilisent une clé S3 du typeworkflow_export_{runSlice}.csv; les clés legacy (UUID seul) reçoivent l'extension viaoutputType. 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 SELECTavec littéraux SQL viaWorkflowColonneTexteStagingService). - Configuration JSONB :
type: "colonne_texte",columns: [{ columnName, textValue }]. - Aperçu éditeur :
applyColonneTexteToRowssur l’échantillon amont (depot-previewou 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 (=,!=,<=, …), conditionsi … alors … sinon …. - Aperçu éditeur :
applyColonneCalculeeToRows(même moteur que le backworkflow-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 SELECTentre deux tables staging amont. - Métriques
rows_in/rows_outpar agrégats SQL (COUNT), sans matérialiser la jointure en mémoire Node. - L’aperçu éditeur conserve
simulateCroiserJoinsur é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,messagesi é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 UI | Données | Historique (workflow_runs) |
|---|---|---|
| Panneau Source / bouton Prévisualiser | Échantillon (≈ 20 lignes dépôt, ≈ 5 lignes simulation bloc) | Non |
| Bouton Lancer | Fichier 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 desupdate:nodesVue 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 :
saveCanvasrafraîchit la liste des workflows sans activerloading(é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 ; deuxq-selectpar paire de colonnes (gauche / droite). - Config :
joinKeyPairs[]etleftBranchRootNodeId(uuid du prédécesseur direct choisi comme tablel) dansconfigurationJSONB ; rétrocompatjoinKeys/joinKey. SileftBranchRootNodeIdest absent ou invalide, repli sur le tri stable des ids des deux prédécesseurs (pas la position sur le canvas). - Prévisualisation :
simulateCroiserJoincomparerow[left]àrow[right]par paire. - Exécution staging :
WorkflowCroiserStagingServicegénèreON l.<col_gauche> = r.<col_droite>pour chaque paire (AND), typesinner/leftinchangé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.
