Skip to content

BDD-160 — Exporter et importer un workflow au format JSON

1. User Story

En tant qu'administrateur d'entreprise, je veux pouvoir exporter mon workflow de transformation au format JSON et le réimporter, afin de pouvoir le sauvegarder localement et le restaurer en cas de problème.

La sauvegarde reste entièrement à la charge de l'administrateur : l'Outil BDD ne conserve aucun historique de versions côté serveur, il ne fait que produire un fichier téléchargeable et le relire pour reconstruire un workflow.

2. Critères d'acceptance

#CritèreStatut
1Un bouton « Exporter » est disponible sur la page d'un workflow et télécharge un JSON contenant la configuration complète (nœuds, connexions, paramètres)
2Un bouton « Importer » permet d'uploader un fichier JSON précédemment exporté et recrée le workflow correspondant
3Le fichier JSON exporté contient suffisamment d'informations pour reconstruire fidèlement le workflow (structure des nœuds, types, configurations)
4Si le fichier JSON importé est invalide ou incompatible, un message d'erreur explicite est affiché
5L'import crée un nouveau workflow distinct — il ne remplace jamais un workflow existant

3. Périmètre fonctionnel

Backend

FichierRôle
back/src/api/workflows/dto/workflow-export.dto.ts (nouveau)WorkflowExportFileDto (enveloppe schemaVersion + exportedAt + workflow), WorkflowExportPayloadDto, ImportWorkflowRequestDto (Swagger multipart), WorkflowImportResponseDto. Réutilise WorkflowNodeDto/WorkflowEdgeDto existants par composition.
back/src/exceptions/workflow.exceptions.tsAjout de WorkflowImportMissingFileException (400) et WorkflowImportInvalidFileException (400, message contextualisé).
back/src/api/workflows/workflows.service.tsAjout de exportWorkflow() (réutilise getByUuid) et importWorkflow() (valide, régénère les uuids nœuds/connexions, délègue la reconstruction à saveWorkflowCanvas() existant, calcule les importWarnings).
back/src/api/workflows/workflows.controller.tsGET /workflows/:workflowUuid/export et POST /workflows/import (upload multipart via FileInterceptor, mémoire uniquement — pas de stockage S3).

Frontend

FichierRôle
front/src/pages/admin/workflows/workflow-json-backup.js (nouveau)downloadWorkflowJsonBackup() : déclenche le téléchargement du JSON exporté (nom de fichier assaini à partir du nom du workflow).
front/src/stores/workflow-store.jsActions exportWorkflow(workflowUuid) et importWorkflow(file) (upload FormData).
front/src/pages/admin/workflows/WorkflowEditorPage.vueBouton « Exporter le workflow (JSON) » dans le menu « Autres actions » de l'éditeur. Bouton « Importer » dans l'en-tête de la liste des workflows, avec <input type="file"> masqué et gestion des avertissements d'import.

4. Comportement détaillé

Format du fichier exporté

json
{
  "schemaVersion": "1.0",
  "exportedAt": "2026-07-01T10:00:00.000Z",
  "workflow": {
    "name": "Mon workflow",
    "nodes": [
      { "id": "…uuid…", "type": "source", "label": "Entrée", "x": 0, "y": 0, "sourceMode": "document", "inputDocumentUuid": "…" }
    ],
    "edges": [
      { "id": "…uuid…", "source": "…uuid nœud…", "target": "…uuid nœud…" }
    ]
  }
}

nodes/edges suivent exactement la forme de WorkflowNodeDto/WorkflowEdgeDto utilisée par PUT /workflows/:uuid/canvas — l'export est un « instantané » du canvas, pas une projection partielle. C'est ce qui garantit la fidélité de reconstruction exigée par le critère 3 : tout ce qui est nécessaire pour rejouer une sauvegarde de canvas est déjà présent.

Validation à l'import — choix technique

L'import valide le fichier avec les mêmes classes class-validator que celles utilisées pour SaveWorkflowCanvasDto (WorkflowNodeDto, WorkflowEdgeDto), plutôt qu'avec un validateur JSON Schema dédié (ex. ajv) :

  • Le projet valide déjà systématiquement ses entrées via NestJS Pipes + class-validator (convention back/CLAUDE.md) — introduire un second mécanisme de validation aurait dupliqué la définition de la forme des nœuds/connexions dans deux formats différents, avec un risque de divergence silencieuse entre les deux au fil des évolutions.
  • Le ValidationPipe global (whitelist: true) et class-validator produisent déjà des messages d'erreur détaillés par champ, suffisants pour le critère 4.

Le schéma ci-dessus (structure du fichier .json) fait office de documentation du contrat d'export/import ; il n'est pas exécuté comme validateur à l'exécution.

Reconstruction à l'import (WorkflowsService.importWorkflow)

  1. Parsing JSON du buffer uploadé → WorkflowImportInvalidFileException si le contenu n'est pas un JSON valide.
  2. Validation de forme (class-validator) de l'enveloppe, y compris schemaVersion (doit valoir "1.0" — toute autre valeur est rejetée explicitement).
  3. Régénération de tous les uuids de nœuds et de connexions (randomUUID()) — nécessaire car workflow_nodes.uuid/workflow_edges.uuid sont uniques en base : réimporter un fichier alors que le workflow d'origine existe encore provoquerait un conflit sans cette étape.
  4. Contrôle de cohérence de la topologie importée (mêmes règles que la sauvegarde manuelle du canvas : Entrée → Traitement, Traitement → Traitement, Traitement → Destination) avant toute écriture en base, pour ne jamais laisser un workflow vide orphelin si le fichier est incompatible.
  5. Création du nouveau workflow puis délégation à saveWorkflowCanvas() (méthode existante, inchangée) pour la résolution des références externes (source Heriade, document/dossier dépôt, connexion API) scopées à l'entreprise courante.
  6. Comparaison entre les références demandées dans le fichier et celles effectivement résolues pour construire importWarnings[] : une référence externe introuvable dans l'entreprise courante (fichier supprimé, dossier différent, etc.) est retirée du nœud sans faire échouer l'import — l'utilisateur est prévenu, le reste du workflow est restauré.

Frontend

  • Export : dans l'éditeur, menu « Autres actions » → « Exporter le workflow (JSON) ». Le fichier est nommé <nom-du-workflow>-workflow.json.
  • Import : sur la page de liste des workflows, bouton « Importer » → sélection d'un fichier → upload multipart → redirection automatique vers le nouveau workflow créé. Si des références ont été retirées, un avertissement liste les blocs concernés.

5. Tests

Backend — unitaires (workflows.service.spec.ts)

  • exportWorkflow retourne une enveloppe versionnée avec nodes/edges fidèles au canvas.
  • importWorkflow : fichier absent, JSON invalide, schemaVersion non supportée, connexion référençant un nœud absent, topologie incompatible — dans tous les cas, aucun workflow n'est créé en base.
  • importWorkflow régénère bien de nouveaux uuids (distincts du fichier importé).
  • importWorkflow signale un avertissement et retire la référence quand un document dépôt lié n'est pas retrouvé dans l'entreprise courante.

Backend — E2E (test/e2e/workflows-controller.e2e-spec.ts)

  • GET /workflows/:uuid/export : 401 sans jeton, 404 sur un workflow inconnu, 200 avec enveloppe JSON reconstructible.
  • POST /workflows/import : 401 sans jeton, 400 sans fichier, 400 sur contenu non-JSON, 400 sur connexion référençant un nœud absent.
  • Scénario de restauration complet : export d'un workflow → suppression (soft delete) du workflow d'origine → import du fichier exporté → nouveau workflow distinct créé, visible dans la liste, l'ancien restant absent (soft-deleted).

Frontend — unitaires (Vitest)

  • workflow-store.spec.js : exportWorkflow appelle bien GET /workflows/:uuid/export ; importWorkflow poste un FormData vers POST /workflows/import et rafraîchit la liste ; gestion des erreurs (retour null + notification).
  • workflow-json-backup.spec.js : le téléchargement déclenché a le bon type MIME et un nom de fichier assaini à partir du nom du workflow.

Frontend — E2E Playwright mock (e2e/pages/admin/admin-workflow-bdd-160.spec.js)

  • Export depuis le menu « Autres actions » → déclenche un vrai téléchargement navigateur dont le contenu est vérifié.
  • Import d'un fichier JSON → redirection vers le nouveau workflow créé.
  • Import d'un fichier rejeté par le serveur → message d'erreur explicite affiché à l'écran.

6. Points d'attention

  • Aucune modification du code existant : exportWorkflow/importWorkflow sont des méthodes ajoutées au service, qui délèguent entièrement la persistance à saveWorkflowCanvas() déjà en place (mêmes règles de validation de topologie, mêmes résolutions de références externes, mêmes logs).
  • Pas de stockage S3 : le fichier importé n'est traité qu'en mémoire (file.buffer), à la différence du dépôt de documents (ADR-03) qui persiste en S3 — ce n'est pas un document métier, seulement un flux de restauration ponctuel.
  • Import = toujours une création : conforme au critère 5, jamais de mise à jour d'un workflow existant, même si le nom du fichier importé correspond à un workflow encore actif (dans ce cas, la contrainte d'unicité du nom existante — WorkflowDuplicateNameException — s'applique comme pour POST /workflows et POST /:uuid/duplicate).