Validé sur PC Windows (DESKTOP-58D5CAC, 2560x1600) : - 8 clics résolus visuellement (1 anchor_template, 1 som_text_match, 6 som_vlm) - Score moyen 0.75, temps moyen 1.6s - Texte tapé correctement (bonjour, test word, date, email) - 0 retries, 2 actions non vérifiées (OK) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1338 lines
47 KiB
Markdown
1338 lines
47 KiB
Markdown
# Document de Design: Visual Workflow Builder
|
|
|
|
## Vue d'Ensemble
|
|
|
|
Le Visual Workflow Builder est une interface graphique révolutionnaire qui permet de créer des workflows RPA par glisser-déposer, sans écrire une seule ligne de code. Cette solution démocratise l'automatisation RPA en la rendant accessible aux utilisateurs non-techniques tout en conservant la puissance nécessaire aux développeurs experts.
|
|
|
|
### Objectifs de Design
|
|
|
|
1. **Simplicité d'Usage**: Interface intuitive inspirée de Scratch et Node-RED
|
|
2. **Puissance Technique**: Accès à toutes les fonctionnalités RPA Vision V3
|
|
3. **Performance**: Rendu fluide à 60fps même avec 100+ nodes
|
|
4. **Intégration**: Compatibilité totale avec ExecutionLoop, Analytics, Self-Healing
|
|
5. **Extensibilité**: Architecture modulaire pour ajouter facilement de nouveaux types de nodes
|
|
|
|
### Principes de Design
|
|
|
|
- **WYSIWYG**: Ce que vous voyez est ce que vous obtenez
|
|
- **Feedback Immédiat**: Test et validation en temps réel
|
|
- **Tolérance aux Erreurs**: Validation continue et récupération gracieuse
|
|
- **Accessibilité**: Support clavier, screen readers, high contrast
|
|
- **Collaboration**: Partage et versioning des workflows
|
|
|
|
---
|
|
|
|
## Architecture Globale
|
|
|
|
### Vue d'Ensemble de l'Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Visual Workflow Builder │
|
|
├─────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
|
│ │ Frontend │ │ Backend API │ │ Integration │ │
|
|
│ │ (React/Vue) │ │ (Flask) │ │ Layer │ │
|
|
│ │ │ │ │ │ │ │
|
|
│ │ • Canvas │ │ • Serialization │ │ • WorkflowGraph │ │
|
|
│ │ • Palette │ │ • Validation │ │ • ExecutionLoop │ │
|
|
│ │ • Properties │ │ • Templates │ │ • Analytics │ │
|
|
│ │ • Target Select │ │ • Export/Import │ │ • Self-Healing │ │
|
|
│ │ • Real-time │ │ • Version Ctrl │ │ • Storage │ │
|
|
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
|
│ │ │ │ │
|
|
│ └─────────────────────┼─────────────────────┘ │
|
|
│ │ │
|
|
├─────────────────────────────────┼─────────────────────────────────┤
|
|
│ Communication Layer (WebSocket + REST) │
|
|
├─────────────────────────────────┼─────────────────────────────────┤
|
|
│ │ │
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
│ │ RPA Vision V3 Core System │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
│ │ │ExecutionLoop│ │ Analytics │ │Self-Healing │ │ │
|
|
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Couches Architecturales
|
|
|
|
#### 1. Couche Présentation (Frontend)
|
|
- **Framework**: React avec TypeScript
|
|
- **Canvas**: react-flow-renderer pour le rendu des graphes
|
|
- **Drag & Drop**: react-dnd pour les interactions
|
|
- **UI Components**: Material-UI ou Ant Design
|
|
- **State Management**: Redux Toolkit
|
|
- **Real-time**: Socket.IO client
|
|
|
|
#### 2. Couche API (Backend)
|
|
- **Framework**: Flask avec Flask-SocketIO
|
|
- **Sérialisation**: JSON Schema validation
|
|
- **Base de Données**: SQLite pour les workflows, PostgreSQL pour production
|
|
- **Cache**: Redis pour les sessions et templates
|
|
- **Files**: Système de fichiers pour les exports
|
|
|
|
#### 3. Couche Intégration
|
|
- **Conversion**: Visual JSON → WorkflowGraph
|
|
- **Exécution**: Interface avec ExecutionLoop
|
|
- **Monitoring**: Hooks vers Analytics
|
|
- **Recovery**: Intégration Self-Healing
|
|
|
|
---
|
|
|
|
## Composants et Interfaces
|
|
|
|
### 1. Canvas Component
|
|
|
|
Le Canvas est le composant central où les utilisateurs construisent visuellement leurs workflows.
|
|
|
|
#### Responsabilités
|
|
- Rendu des nodes et edges
|
|
- Gestion des interactions (sélection, déplacement)
|
|
- Zoom et panoramique
|
|
- Grille d'alignement
|
|
- Minimap pour navigation
|
|
|
|
#### Interface TypeScript
|
|
```typescript
|
|
interface CanvasProps {
|
|
nodes: VisualNode[];
|
|
edges: VisualEdge[];
|
|
onNodeSelect: (nodeId: string) => void;
|
|
onNodeMove: (nodeId: string, position: Position) => void;
|
|
onEdgeCreate: (source: string, target: string) => void;
|
|
onEdgeDelete: (edgeId: string) => void;
|
|
readonly?: boolean;
|
|
}
|
|
|
|
interface CanvasState {
|
|
selectedNodes: string[];
|
|
selectedEdges: string[];
|
|
viewport: Viewport;
|
|
dragState: DragState;
|
|
}
|
|
```
|
|
|
|
### 2. Node Palette
|
|
|
|
La palette affiche tous les types de nodes disponibles organisés par catégorie.
|
|
|
|
#### Responsabilités
|
|
- Affichage des types de nodes disponibles
|
|
- Recherche et filtrage
|
|
- Catégorisation (Actions, Logic, Data, etc.)
|
|
- Drag source pour création de nodes
|
|
|
|
#### Structure
|
|
```typescript
|
|
interface NodeType {
|
|
id: string;
|
|
name: string;
|
|
category: NodeCategory;
|
|
icon: string;
|
|
description: string;
|
|
parameters: ParameterDefinition[];
|
|
inputPorts: PortDefinition[];
|
|
outputPorts: PortDefinition[];
|
|
}
|
|
|
|
enum NodeCategory {
|
|
ACTION = 'action', // Click, Type, Wait
|
|
LOGIC = 'logic', // If, Loop, Switch
|
|
DATA = 'data', // Variable, Extract, Transform
|
|
FLOW = 'flow', // Start, End, Subworkflow
|
|
INTEGRATION = 'integration' // API, Database, File
|
|
}
|
|
```
|
|
|
|
### 3. Properties Panel
|
|
|
|
Le panneau de propriétés permet de configurer les paramètres de chaque node.
|
|
|
|
#### Responsabilités
|
|
- Configuration des paramètres de nodes
|
|
- Validation en temps réel
|
|
- Target selector integration
|
|
- Variable management
|
|
- Help et documentation contextuelle
|
|
|
|
#### Composants
|
|
```typescript
|
|
interface PropertyEditor {
|
|
parameter: ParameterDefinition;
|
|
value: any;
|
|
onChange: (value: any) => void;
|
|
onValidate: (value: any) => ValidationResult;
|
|
}
|
|
|
|
// Types d'éditeurs
|
|
class TextEditor extends PropertyEditor {}
|
|
class NumberEditor extends PropertyEditor {}
|
|
class BooleanEditor extends PropertyEditor {}
|
|
class SelectEditor extends PropertyEditor {}
|
|
class TargetEditor extends PropertyEditor {} // Sélection interactive
|
|
class VariableEditor extends PropertyEditor {}
|
|
class ExpressionEditor extends PropertyEditor {} // Conditions
|
|
```
|
|
|
|
### 4. Target Selector
|
|
|
|
Le sélecteur de cible permet de sélectionner interactivement des éléments UI à l'écran.
|
|
|
|
#### Workflow
|
|
```python
|
|
class TargetSelector:
|
|
async def start_selection(self) -> TargetInfo:
|
|
"""Démarre le processus de sélection interactive"""
|
|
# 1. Capturer l'écran
|
|
screenshot = await self.capture_screen()
|
|
|
|
# 2. Entrer en mode sélection
|
|
self.enter_selection_mode(screenshot)
|
|
|
|
# 3. Attendre la sélection utilisateur
|
|
element = await self.wait_for_user_selection()
|
|
|
|
# 4. Extraire les propriétés
|
|
target_info = await self.extract_element_properties(element)
|
|
|
|
return target_info
|
|
|
|
async def extract_element_properties(self, element) -> TargetInfo:
|
|
"""Extrait toutes les propriétés d'un élément"""
|
|
return TargetInfo(
|
|
text=element.text_content,
|
|
tag_name=element.tag_name,
|
|
class_name=element.class_name,
|
|
position=self.get_element_position(element),
|
|
size=self.get_element_size(element),
|
|
embedding=await self.generate_clip_embedding(element)
|
|
)
|
|
```
|
|
|
|
### 5. Execution Engine
|
|
|
|
Le moteur d'exécution convertit les workflows visuels en WorkflowGraph et les exécute.
|
|
|
|
#### Conversion Pipeline
|
|
```python
|
|
class VisualToGraphConverter:
|
|
def convert(self, visual_workflow: VisualWorkflow) -> WorkflowGraph:
|
|
"""Convertit un workflow visuel en WorkflowGraph"""
|
|
# 1. Valider la structure
|
|
self.validate_structure(visual_workflow)
|
|
|
|
# 2. Convertir les nodes
|
|
nodes = [self.convert_node(node) for node in visual_workflow.nodes]
|
|
|
|
# 3. Convertir les edges
|
|
edges = [self.convert_edge(edge) for edge in visual_workflow.edges]
|
|
|
|
# 4. Créer le graph
|
|
return WorkflowGraph(nodes, edges)
|
|
|
|
def convert_node(self, visual_node: VisualNode) -> WorkflowNode:
|
|
"""Convertit un node visuel en WorkflowNode"""
|
|
if visual_node.type == 'click':
|
|
return ClickNode(
|
|
target=visual_node.parameters['target'],
|
|
timeout=visual_node.parameters.get('timeout', 5000),
|
|
retries=visual_node.parameters.get('retries', 3)
|
|
)
|
|
elif visual_node.type == 'type':
|
|
return TypeNode(
|
|
target=visual_node.parameters['target'],
|
|
text=visual_node.parameters['text'],
|
|
clear_first=visual_node.parameters.get('clear_first', False)
|
|
)
|
|
# ... autres types
|
|
```
|
|
|
|
---
|
|
|
|
## Modèles de Données
|
|
|
|
### 1. Visual Workflow
|
|
|
|
```python
|
|
@dataclass
|
|
class VisualWorkflow:
|
|
"""Représentation complète d'un workflow visuel"""
|
|
id: str
|
|
name: str
|
|
description: Optional[str]
|
|
version: str
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
created_by: str
|
|
|
|
# Structure visuelle
|
|
nodes: List[VisualNode]
|
|
edges: List[VisualEdge]
|
|
|
|
# Configuration
|
|
variables: List[Variable]
|
|
settings: WorkflowSettings
|
|
|
|
# Métadonnées
|
|
tags: List[str]
|
|
category: Optional[str]
|
|
is_template: bool = False
|
|
```
|
|
|
|
### 2. Visual Node
|
|
|
|
```python
|
|
@dataclass
|
|
class VisualNode:
|
|
"""Représentation d'un node dans le canvas"""
|
|
id: str
|
|
type: str # 'click', 'type', 'wait', 'if', 'loop', etc.
|
|
|
|
# Position visuelle
|
|
position: Position
|
|
size: Size
|
|
|
|
# Configuration
|
|
parameters: Dict[str, Any]
|
|
|
|
# Connexions
|
|
input_ports: List[Port]
|
|
output_ports: List[Port]
|
|
|
|
# État visuel
|
|
selected: bool = False
|
|
highlighted: bool = False
|
|
status: Optional[NodeStatus] = None # pendant l'exécution
|
|
|
|
# Métadonnées
|
|
label: Optional[str] = None
|
|
description: Optional[str] = None
|
|
color: Optional[str] = None
|
|
|
|
class NodeStatus(Enum):
|
|
"""États possibles d'un node pendant l'exécution"""
|
|
IDLE = 'idle'
|
|
RUNNING = 'running'
|
|
SUCCESS = 'success'
|
|
FAILED = 'failed'
|
|
SKIPPED = 'skipped'
|
|
```
|
|
|
|
### 3. Visual Edge
|
|
|
|
```python
|
|
@dataclass
|
|
class VisualEdge:
|
|
"""Représentation d'une connexion entre nodes"""
|
|
id: str
|
|
source: str # node ID
|
|
target: str # node ID
|
|
source_port: str
|
|
target_port: str
|
|
|
|
# Condition (pour les branches)
|
|
condition: Optional[EdgeCondition] = None
|
|
|
|
# Style visuel
|
|
style: Optional[EdgeStyle] = None
|
|
|
|
# État
|
|
selected: bool = False
|
|
animated: bool = False # pendant l'exécution
|
|
|
|
@dataclass
|
|
class EdgeCondition:
|
|
"""Condition pour l'exécution d'un edge"""
|
|
type: str # 'always', 'success', 'failure', 'expression'
|
|
expression: Optional[str] = None # pour type 'expression'
|
|
```
|
|
|
|
### 4. Parameter Definitions
|
|
|
|
```python
|
|
@dataclass
|
|
class ParameterDefinition:
|
|
"""Définition d'un paramètre de node"""
|
|
name: str
|
|
type: ParameterType
|
|
required: bool
|
|
default_value: Optional[Any] = None
|
|
|
|
# Validation
|
|
validation: Optional[List[ValidationRule]] = None
|
|
|
|
# UI
|
|
label: str = ""
|
|
description: Optional[str] = None
|
|
placeholder: Optional[str] = None
|
|
|
|
# Comportement spécial
|
|
is_target: bool = False # Active le target selector
|
|
is_variable: bool = False # Permet ${variable}
|
|
is_expression: bool = False # Permet les expressions
|
|
|
|
class ParameterType(Enum):
|
|
"""Types de paramètres supportés"""
|
|
STRING = 'string'
|
|
NUMBER = 'number'
|
|
BOOLEAN = 'boolean'
|
|
SELECT = 'select'
|
|
TARGET = 'target'
|
|
VARIABLE = 'variable'
|
|
EXPRESSION = 'expression'
|
|
FILE = 'file'
|
|
```
|
|
|
|
### 5. Templates
|
|
|
|
```python
|
|
@dataclass
|
|
class WorkflowTemplate:
|
|
"""Template de workflow pré-construit"""
|
|
id: str
|
|
name: str
|
|
description: str
|
|
category: str
|
|
|
|
# Template data
|
|
workflow: VisualWorkflow
|
|
|
|
# Paramètres configurables
|
|
parameters: List[TemplateParameter]
|
|
|
|
# Métadonnées
|
|
tags: List[str]
|
|
difficulty: str # 'beginner', 'intermediate', 'advanced'
|
|
estimated_time: int # minutes
|
|
|
|
# Usage
|
|
usage_count: int = 0
|
|
rating: float = 0.0
|
|
|
|
@dataclass
|
|
class TemplateParameter:
|
|
"""Paramètre configurable d'un template"""
|
|
name: str
|
|
type: ParameterType
|
|
description: str
|
|
default_value: Optional[Any] = None
|
|
|
|
# Mapping vers les nodes
|
|
node_id: str
|
|
parameter_name: str
|
|
```
|
|
|
|
---
|
|
|
|
## Correctness Properties
|
|
|
|
*Une propriété est une caractéristique ou un comportement qui doit être vrai pour toutes les exécutions valides d'un système - essentiellement, une déclaration formelle sur ce que le système doit faire. Les propriétés servent de pont entre les spécifications lisibles par l'humain et les garanties de correction vérifiables par machine.*
|
|
|
|
### Propriétés Structurelles
|
|
|
|
#### Propriété 1: Suppression de Node Cascade
|
|
*Pour tout* workflow et tout node, quand un node est supprimé, tous les edges connectés à ce node doivent également être supprimés automatiquement.
|
|
|
|
**Valide: Exigences 1.5, 2.4**
|
|
|
|
#### Propriété 2: Validation de Connexion
|
|
*Pour tout* edge créé entre deux nodes, la connexion doit être validée selon les règles de compatibilité des ports (type de sortie compatible avec type d'entrée).
|
|
|
|
**Valide: Exigences 2.2**
|
|
|
|
#### Propriété 3: Détection de Cycles
|
|
*Pour tout* workflow, si on ajoute un edge qui créerait un cycle (sauf pour les boucles explicites), le système doit détecter et rejeter cette connexion.
|
|
|
|
**Valide: Exigences 12.4**
|
|
|
|
#### Propriété 4: Nodes Déconnectés
|
|
*Pour tout* workflow, tous les nodes (sauf Start et End) doivent avoir au moins un edge entrant et un edge sortant, sinon un avertissement doit être affiché.
|
|
|
|
**Valide: Exigences 12.3**
|
|
|
|
### Propriétés de Sérialisation
|
|
|
|
#### Propriété 5: Round-trip de Sérialisation
|
|
*Pour tout* workflow visuel, sérialiser puis désérialiser doit produire un workflow équivalent (même nodes, edges, paramètres, variables).
|
|
|
|
**Valide: Exigences 5.1, 5.2**
|
|
|
|
#### Propriété 6: Génération d'ID Unique
|
|
*Pour tout* nouveau workflow sans ID, la sauvegarde doit générer un ID unique qui n'existe pas déjà dans le système.
|
|
|
|
**Valide: Exigences 5.4**
|
|
|
|
#### Propriété 7: Validation de Champs Requis
|
|
*Pour tout* workflow lors de la sérialisation, tous les champs requis (id, name, nodes, edges) doivent être présents, sinon la sérialisation doit échouer.
|
|
|
|
**Valide: Exigences 5.3**
|
|
|
|
### Propriétés de Configuration
|
|
|
|
#### Propriété 8: Validation de Paramètres Requis
|
|
*Pour tout* node, tous les paramètres marqués comme requis doivent avoir une valeur non-nulle, sinon le node doit afficher un indicateur d'avertissement.
|
|
|
|
**Valide: Exigences 12.2**
|
|
|
|
#### Propriété 9: Valeurs par Défaut
|
|
*Pour tout* nouveau node créé, tous les paramètres avec une valeur par défaut définie doivent être pré-remplis avec cette valeur.
|
|
|
|
**Valide: Exigences 3.5**
|
|
|
|
#### Propriété 10: Validation de Variables
|
|
*Pour tout* paramètre contenant une référence de variable ${nom}, la variable doit exister dans la liste des variables du workflow, sinon une erreur de validation doit être affichée.
|
|
|
|
**Valide: Exigences 10.3**
|
|
|
|
#### Propriété 11: Unicité des Noms de Variables
|
|
*Pour tout* workflow, tous les noms de variables doivent être uniques (pas de doublons).
|
|
|
|
**Valide: Exigences 10.2**
|
|
|
|
### Propriétés d'Exécution
|
|
|
|
#### Propriété 12: Conversion Valide
|
|
*Pour tout* workflow visuel valide, la conversion en WorkflowGraph doit produire un graphe exécutable par ExecutionLoop sans erreur.
|
|
|
|
**Valide: Exigences 6.1, 18.1**
|
|
|
|
#### Propriété 13: Synchronisation d'État
|
|
*Pour tout* node pendant l'exécution, l'état visuel (status) doit refléter l'état d'exécution réel (idle → running → success/failed).
|
|
|
|
**Valide: Exigences 6.3**
|
|
|
|
#### Propriété 14: Substitution de Variables
|
|
*Pour tout* paramètre contenant ${variable} lors de l'exécution, la référence doit être remplacée par la valeur runtime de la variable.
|
|
|
|
**Valide: Exigences 10.4**
|
|
|
|
#### Propriété 15: Exécution de Conditions
|
|
*Pour tout* node Condition, l'exécution doit suivre le edge "true" si la condition est vraie, et le edge "false" si la condition est fausse.
|
|
|
|
**Valide: Exigences 8.3**
|
|
|
|
#### Propriété 16: Exécution de Boucles
|
|
*Pour tout* node Loop, le corps de la boucle doit être exécuté le nombre de fois spécifié par les paramètres (count pour repeat, condition pour while, items pour for-each).
|
|
|
|
**Valide: Exigences 9.3**
|
|
|
|
### Propriétés d'Interaction
|
|
|
|
#### Propriété 17: Annuler/Refaire Cohérence
|
|
*Pour toute* séquence d'actions, effectuer une action puis l'annuler doit restaurer l'état précédent, et refaire doit restaurer l'état après l'action.
|
|
|
|
**Valide: Exigences 13.2, 13.3**
|
|
|
|
#### Propriété 18: Pile d'Annulation
|
|
*Pour toute* action effectuée, elle doit être ajoutée à la pile d'annulation, et on doit pouvoir annuler au moins 50 actions.
|
|
|
|
**Valide: Exigences 13.1, 13.4**
|
|
|
|
#### Propriété 19: Invalidation de Refaire
|
|
*Pour toute* nouvelle action effectuée après une annulation, la pile de refaire doit être vidée.
|
|
|
|
**Valide: Exigences 13.5**
|
|
|
|
#### Propriété 20: Extraction de Propriétés de Cible
|
|
*Pour tout* élément sélectionné via le target selector, les propriétés extraites doivent inclure au minimum: text, position, size, et embedding.
|
|
|
|
**Valide: Exigences 4.5**
|
|
|
|
### Propriétés de Templates
|
|
|
|
#### Propriété 21: Chargement de Template
|
|
*Pour tout* template sélectionné, le chargement doit créer un workflow avec tous les nodes et edges du template, et tous les paramètres doivent être modifiables.
|
|
|
|
**Valide: Exigences 11.2, 11.3**
|
|
|
|
#### Propriété 22: Sauvegarde comme Template
|
|
*Pour tout* workflow créé par un utilisateur, il doit être possible de le sauvegarder comme template personnalisé avec des paramètres configurables.
|
|
|
|
**Valide: Exigences 11.5**
|
|
|
|
### Propriétés d'Export/Import
|
|
|
|
#### Propriété 23: Complétude d'Export
|
|
*Pour tout* workflow exporté, le fichier JSON/YAML doit contenir tous les nodes, edges, variables, et métadonnées nécessaires pour reconstruire le workflow.
|
|
|
|
**Valide: Exigences 15.1, 15.3**
|
|
|
|
#### Propriété 24: Validation d'Import
|
|
*Pour tout* fichier importé, le système doit valider le format et rejeter les fichiers invalides avec un message d'erreur clair.
|
|
|
|
**Valide: Exigences 15.2**
|
|
|
|
#### Propriété 25: Migration de Version
|
|
*Pour tout* workflow d'une version antérieure, le système doit détecter l'incompatibilité et offrir une migration automatique vers la version actuelle.
|
|
|
|
**Valide: Exigences 15.4**
|
|
|
|
### Propriétés d'Intégration
|
|
|
|
#### Propriété 26: Compatibilité de Format
|
|
*Pour tout* workflow sauvegardé par le Visual Builder, il doit être dans le même format que les workflows créés programmatiquement et vice-versa.
|
|
|
|
**Valide: Exigences 18.4**
|
|
|
|
#### Propriété 27: Intégration Self-Healing
|
|
*Pour tout* workflow utilisant self-healing, les nodes doivent être configurés avec les stratégies de récupération appropriées lors de la conversion.
|
|
|
|
**Valide: Exigences 18.2**
|
|
|
|
#### Propriété 28: Intégration Analytics
|
|
*Pour tout* workflow exécuté, les métriques doivent être automatiquement collectées et envoyées au système Analytics.
|
|
|
|
**Valide: Exigences 18.3**
|
|
|
|
#### Propriété 29: Rétrocompatibilité
|
|
*Pour tout* workflow existant créé programmatiquement (suivant le format standard), le Visual Builder doit pouvoir le charger, le visualiser et l'éditer.
|
|
|
|
**Valide: Exigences 18.5**
|
|
|
|
### Propriétés de Recherche et Filtrage
|
|
|
|
#### Propriété 30: Filtrage de Palette
|
|
*Pour toute* requête de recherche dans la palette, seuls les types de nodes dont le nom ou la description contient la requête doivent être affichés.
|
|
|
|
**Valide: Exigences 7.2**
|
|
|
|
#### Propriété 31: Extensibilité de Palette
|
|
*Pour tout* nouveau type de node ajouté au système, il doit automatiquement apparaître dans la palette dans la catégorie appropriée.
|
|
|
|
**Valide: Exigences 7.5**
|
|
|
|
### Propriétés de Zoom et Navigation
|
|
|
|
#### Propriété 32: Zoom Centré
|
|
*Pour tout* événement de zoom (molette de souris), le zoom doit être centré sur la position du curseur, pas sur le centre du canvas.
|
|
|
|
**Valide: Exigences 14.1**
|
|
|
|
#### Propriété 33: Fit-to-Screen
|
|
*Pour tout* workflow, la fonction "ajuster à l'écran" doit calculer le zoom et la position pour que tous les nodes soient visibles dans le viewport.
|
|
|
|
**Valide: Exigences 14.3**
|
|
|
|
---
|
|
|
|
## Gestion des Erreurs
|
|
|
|
### Stratégies de Gestion d'Erreurs
|
|
|
|
#### 1. Erreurs de Validation
|
|
- **Détection**: Validation en temps réel pendant l'édition
|
|
- **Affichage**: Indicateurs visuels sur les nodes/edges problématiques
|
|
- **Blocage**: Empêcher l'exécution si des erreurs critiques existent
|
|
- **Récupération**: Suggestions de correction automatique quand possible
|
|
|
|
#### 2. Erreurs d'Exécution
|
|
- **Capture**: Intercepter toutes les exceptions pendant l'exécution
|
|
- **Affichage**: Mettre en surbrillance le node en échec avec message d'erreur
|
|
- **Logging**: Enregistrer tous les détails pour debugging
|
|
- **Récupération**: Intégration avec Self-Healing pour tentatives automatiques
|
|
|
|
#### 3. Erreurs de Sérialisation
|
|
- **Validation**: Vérifier le schéma JSON avant sauvegarde/chargement
|
|
- **Affichage**: Messages d'erreur clairs avec détails du problème
|
|
- **Récupération**: Tentative de migration automatique pour anciennes versions
|
|
- **Backup**: Sauvegarder l'état précédent avant toute modification
|
|
|
|
#### 4. Erreurs Réseau
|
|
- **Retry**: Réessayer automatiquement les requêtes échouées (3 tentatives)
|
|
- **Timeout**: Timeouts configurables pour toutes les opérations réseau
|
|
- **Offline**: Mode dégradé avec sauvegarde locale si serveur inaccessible
|
|
- **Feedback**: Indicateurs de statut de connexion en temps réel
|
|
|
|
### Codes d'Erreur
|
|
|
|
```python
|
|
class ErrorCode(Enum):
|
|
# Validation
|
|
MISSING_REQUIRED_PARAMETER = 1001
|
|
INVALID_PARAMETER_TYPE = 1002
|
|
INVALID_VARIABLE_REFERENCE = 1003
|
|
CIRCULAR_DEPENDENCY = 1004
|
|
DISCONNECTED_NODE = 1005
|
|
|
|
# Sérialisation
|
|
INVALID_JSON_FORMAT = 2001
|
|
MISSING_REQUIRED_FIELD = 2002
|
|
VERSION_INCOMPATIBLE = 2003
|
|
|
|
# Exécution
|
|
CONVERSION_FAILED = 3001
|
|
EXECUTION_FAILED = 3002
|
|
TARGET_NOT_FOUND = 3003
|
|
|
|
# Réseau
|
|
CONNECTION_FAILED = 4001
|
|
TIMEOUT = 4002
|
|
SERVER_ERROR = 4003
|
|
```
|
|
|
|
---
|
|
|
|
## Stratégie de Test
|
|
|
|
### 1. Tests Unitaires
|
|
|
|
Les tests unitaires vérifient le comportement de composants individuels.
|
|
|
|
#### Frontend Components
|
|
```typescript
|
|
describe('Canvas Component', () => {
|
|
test('should create node on drop', () => {
|
|
const canvas = render(<Canvas nodes={[]} edges={[]} />);
|
|
const nodeType = { type: 'click', name: 'Click' };
|
|
|
|
fireEvent.drop(canvas, { dataTransfer: { getData: () => nodeType } });
|
|
|
|
expect(canvas.nodes).toHaveLength(1);
|
|
expect(canvas.nodes[0].type).toBe('click');
|
|
});
|
|
|
|
test('should select node on click', () => {
|
|
const onSelect = jest.fn();
|
|
const nodes = [createMockNode('click')];
|
|
const canvas = render(<Canvas nodes={nodes} onNodeSelect={onSelect} />);
|
|
|
|
fireEvent.click(canvas.getByTestId('node-click-1'));
|
|
|
|
expect(onSelect).toHaveBeenCalledWith('click-1');
|
|
});
|
|
});
|
|
|
|
describe('Properties Panel', () => {
|
|
test('should display required parameter warning', () => {
|
|
const node = createMockNode('click', { target: '' });
|
|
const panel = render(<PropertiesPanel node={node} />);
|
|
|
|
expect(panel.getByText('Target is required')).toBeInTheDocument();
|
|
});
|
|
|
|
test('should validate parameter on change', () => {
|
|
const node = createMockNode('wait', { duration: -1 });
|
|
const panel = render(<PropertiesPanel node={node} />);
|
|
|
|
expect(panel.getByText('Duration must be positive')).toBeInTheDocument();
|
|
});
|
|
});
|
|
```
|
|
|
|
#### Backend API
|
|
```python
|
|
class TestWorkflowAPI(unittest.TestCase):
|
|
def test_create_workflow(self):
|
|
"""Test création d'un nouveau workflow"""
|
|
response = self.client.post('/api/workflows', json={
|
|
'name': 'Test Workflow',
|
|
'description': 'Test description'
|
|
})
|
|
|
|
self.assertEqual(response.status_code, 201)
|
|
data = response.get_json()
|
|
self.assertIn('id', data)
|
|
self.assertEqual(data['name'], 'Test Workflow')
|
|
|
|
def test_serialize_workflow(self):
|
|
"""Test sérialisation complète"""
|
|
workflow = create_test_workflow_with_nodes(5)
|
|
serialized = serialize_workflow(workflow)
|
|
|
|
self.assertIn('nodes', serialized)
|
|
self.assertIn('edges', serialized)
|
|
self.assertEqual(len(serialized['nodes']), 5)
|
|
|
|
def test_validate_required_fields(self):
|
|
"""Test validation des champs requis"""
|
|
invalid_workflow = {'name': 'Test'} # manque 'nodes' et 'edges'
|
|
|
|
with self.assertRaises(ValidationError):
|
|
validate_workflow(invalid_workflow)
|
|
```
|
|
|
|
### 2. Tests d'Intégration
|
|
|
|
Les tests d'intégration vérifient l'interaction entre composants.
|
|
|
|
```python
|
|
class TestVisualToGraphConversion(unittest.TestCase):
|
|
def test_simple_workflow_conversion(self):
|
|
"""Test conversion d'un workflow simple"""
|
|
visual_workflow = {
|
|
'nodes': [
|
|
{'id': '1', 'type': 'start', 'position': {'x': 0, 'y': 0}},
|
|
{'id': '2', 'type': 'click', 'position': {'x': 100, 'y': 0},
|
|
'parameters': {'target': 'Button "Login"', 'timeout': 5000}},
|
|
{'id': '3', 'type': 'end', 'position': {'x': 200, 'y': 0}}
|
|
],
|
|
'edges': [
|
|
{'id': 'e1', 'source': '1', 'target': '2'},
|
|
{'id': 'e2', 'source': '2', 'target': '3'}
|
|
]
|
|
}
|
|
|
|
converter = VisualToGraphConverter()
|
|
workflow_graph = converter.convert(visual_workflow)
|
|
|
|
self.assertEqual(len(workflow_graph.nodes), 3)
|
|
self.assertEqual(workflow_graph.nodes[1].type, 'click')
|
|
self.assertEqual(workflow_graph.nodes[1].parameters['target'], 'Button "Login"')
|
|
|
|
def test_workflow_with_conditions(self):
|
|
"""Test conversion avec conditions"""
|
|
visual_workflow = create_workflow_with_condition()
|
|
converter = VisualToGraphConverter()
|
|
workflow_graph = converter.convert(visual_workflow)
|
|
|
|
# Vérifier que les branches true/false sont correctes
|
|
condition_node = workflow_graph.get_node_by_type('condition')
|
|
self.assertEqual(len(condition_node.output_edges), 2)
|
|
|
|
true_edge = [e for e in condition_node.output_edges if e.condition.type == 'true'][0]
|
|
false_edge = [e for e in condition_node.output_edges if e.condition.type == 'false'][0]
|
|
|
|
self.assertIsNotNone(true_edge)
|
|
self.assertIsNotNone(false_edge)
|
|
```
|
|
|
|
### 3. Tests Property-Based
|
|
|
|
Les tests property-based vérifient que les propriétés universelles sont respectées pour tous les inputs.
|
|
|
|
**Framework**: Hypothesis (Python) ou fast-check (TypeScript)
|
|
|
|
```python
|
|
from hypothesis import given, strategies as st
|
|
from hypothesis.stateful import RuleBasedStateMachine, rule, invariant
|
|
|
|
class TestWorkflowProperties(unittest.TestCase):
|
|
|
|
@given(st.lists(st.text(min_size=1), min_size=1, max_size=20))
|
|
def test_property_5_serialization_roundtrip(self, node_names):
|
|
"""
|
|
Feature: visual-workflow-builder, Property 5: Round-trip de Sérialisation
|
|
Pour tout workflow, sérialiser puis désérialiser doit produire un workflow équivalent
|
|
"""
|
|
# Créer un workflow avec des nodes aléatoires
|
|
workflow = create_workflow_with_node_names(node_names)
|
|
|
|
# Sérialiser
|
|
serialized = serialize_workflow(workflow)
|
|
|
|
# Désérialiser
|
|
deserialized = deserialize_workflow(serialized)
|
|
|
|
# Vérifier l'équivalence
|
|
self.assertEqual(len(workflow.nodes), len(deserialized.nodes))
|
|
self.assertEqual(len(workflow.edges), len(deserialized.edges))
|
|
for i, node in enumerate(workflow.nodes):
|
|
self.assertEqual(node.type, deserialized.nodes[i].type)
|
|
self.assertEqual(node.parameters, deserialized.nodes[i].parameters)
|
|
|
|
@given(st.integers(min_value=1, max_value=10))
|
|
def test_property_1_node_deletion_cascade(self, num_nodes):
|
|
"""
|
|
Feature: visual-workflow-builder, Property 1: Suppression de Node Cascade
|
|
Pour tout workflow, supprimer un node doit supprimer tous ses edges
|
|
"""
|
|
# Créer un workflow linéaire avec num_nodes nodes
|
|
workflow = create_linear_workflow(num_nodes)
|
|
initial_edge_count = len(workflow.edges)
|
|
|
|
# Supprimer un node au milieu
|
|
middle_node = workflow.nodes[num_nodes // 2]
|
|
edges_connected_to_node = [e for e in workflow.edges
|
|
if e.source == middle_node.id or e.target == middle_node.id]
|
|
|
|
workflow.delete_node(middle_node.id)
|
|
|
|
# Vérifier que les edges connectés sont supprimés
|
|
self.assertEqual(len(workflow.edges), initial_edge_count - len(edges_connected_to_node))
|
|
for edge in edges_connected_to_node:
|
|
self.assertNotIn(edge, workflow.edges)
|
|
|
|
@given(st.lists(st.text(min_size=1, max_size=20), min_size=1, max_size=10))
|
|
def test_property_11_variable_name_uniqueness(self, variable_names):
|
|
"""
|
|
Feature: visual-workflow-builder, Property 11: Unicité des Noms de Variables
|
|
Pour tout workflow, tous les noms de variables doivent être uniques
|
|
"""
|
|
workflow = VisualWorkflow(id='test', name='Test', nodes=[], edges=[], variables=[])
|
|
|
|
# Essayer d'ajouter des variables
|
|
for name in variable_names:
|
|
try:
|
|
workflow.add_variable(name, 'string', '')
|
|
except ValueError:
|
|
# Nom dupliqué, c'est attendu
|
|
pass
|
|
|
|
# Vérifier l'unicité
|
|
variable_names_in_workflow = [v.name for v in workflow.variables]
|
|
self.assertEqual(len(variable_names_in_workflow), len(set(variable_names_in_workflow)))
|
|
```
|
|
|
|
@given(st.integers(min_value=2, max_value=50))
|
|
def test_property_18_undo_redo_stack_capacity(self, num_actions):
|
|
"""
|
|
Feature: visual-workflow-builder, Property 18: Pile d'Annulation
|
|
Pour toute action, on doit pouvoir annuler au moins 50 actions
|
|
"""
|
|
workflow = VisualWorkflow(id='test', name='Test', nodes=[], edges=[], variables=[])
|
|
undo_manager = UndoManager(workflow)
|
|
|
|
# Effectuer num_actions actions
|
|
for i in range(num_actions):
|
|
node = VisualNode(id=f'node-{i}', type='click', position={'x': i*100, 'y': 0},
|
|
parameters={}, input_ports=[], output_ports=[])
|
|
undo_manager.execute(AddNodeAction(node))
|
|
|
|
# Vérifier qu'on peut annuler au moins min(50, num_actions) actions
|
|
max_undo = min(50, num_actions)
|
|
for i in range(max_undo):
|
|
self.assertTrue(undo_manager.can_undo())
|
|
undo_manager.undo()
|
|
|
|
self.assertEqual(len(workflow.nodes), num_actions - max_undo)
|
|
|
|
@given(st.text(min_size=1, max_size=50))
|
|
def test_property_10_variable_reference_validation(self, variable_name):
|
|
"""
|
|
Feature: visual-workflow-builder, Property 10: Validation de Variables
|
|
Pour tout paramètre avec ${variable}, la variable doit exister
|
|
"""
|
|
workflow = VisualWorkflow(id='test', name='Test', nodes=[], edges=[], variables=[])
|
|
|
|
# Créer un node avec référence de variable
|
|
node = VisualNode(
|
|
id='node-1',
|
|
type='type',
|
|
position={'x': 0, 'y': 0},
|
|
parameters={'text': f'${{{variable_name}}}'},
|
|
input_ports=[],
|
|
output_ports=[]
|
|
)
|
|
workflow.nodes.append(node)
|
|
|
|
# Valider
|
|
validation_result = validate_workflow(workflow)
|
|
|
|
# Si la variable n'existe pas, doit avoir une erreur
|
|
if variable_name not in [v.name for v in workflow.variables]:
|
|
self.assertFalse(validation_result.is_valid)
|
|
self.assertTrue(any('variable' in err.lower() for err in validation_result.errors))
|
|
else:
|
|
self.assertTrue(validation_result.is_valid)
|
|
|
|
class WorkflowStateMachine(RuleBasedStateMachine):
|
|
"""
|
|
Machine à états pour tester les propriétés de manière stateful
|
|
"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.workflow = VisualWorkflow(id='test', name='Test', nodes=[], edges=[], variables=[])
|
|
self.undo_manager = UndoManager(self.workflow)
|
|
|
|
@rule()
|
|
def add_node(self):
|
|
"""Ajouter un node aléatoire"""
|
|
node_id = f'node-{len(self.workflow.nodes)}'
|
|
node = VisualNode(id=node_id, type='click', position={'x': 0, 'y': 0},
|
|
parameters={}, input_ports=[], output_ports=[])
|
|
self.undo_manager.execute(AddNodeAction(node))
|
|
|
|
@rule()
|
|
def delete_node(self):
|
|
"""Supprimer un node aléatoire"""
|
|
if self.workflow.nodes:
|
|
node = random.choice(self.workflow.nodes)
|
|
self.undo_manager.execute(DeleteNodeAction(node.id))
|
|
|
|
@rule()
|
|
def undo(self):
|
|
"""Annuler la dernière action"""
|
|
if self.undo_manager.can_undo():
|
|
self.undo_manager.undo()
|
|
|
|
@rule()
|
|
def redo(self):
|
|
"""Refaire la dernière action annulée"""
|
|
if self.undo_manager.can_redo():
|
|
self.undo_manager.redo()
|
|
|
|
@invariant()
|
|
def nodes_have_unique_ids(self):
|
|
"""Invariant: tous les nodes ont des IDs uniques"""
|
|
node_ids = [n.id for n in self.workflow.nodes]
|
|
assert len(node_ids) == len(set(node_ids))
|
|
|
|
@invariant()
|
|
def edges_reference_existing_nodes(self):
|
|
"""Invariant: tous les edges référencent des nodes existants"""
|
|
node_ids = {n.id for n in self.workflow.nodes}
|
|
for edge in self.workflow.edges:
|
|
assert edge.source in node_ids
|
|
assert edge.target in node_ids
|
|
|
|
TestWorkflowStateMachine = WorkflowStateMachine.TestCase
|
|
```
|
|
|
|
### 4. Tests End-to-End
|
|
|
|
Les tests end-to-end vérifient le système complet du frontend au backend.
|
|
|
|
```python
|
|
class TestEndToEndWorkflow(unittest.TestCase):
|
|
def test_complete_workflow_creation_and_execution(self):
|
|
"""Test du cycle complet: création → sauvegarde → exécution"""
|
|
# 1. Créer un workflow via l'API
|
|
response = self.client.post('/api/workflows', json={
|
|
'name': 'Login Workflow',
|
|
'description': 'Test login automation'
|
|
})
|
|
workflow_id = response.get_json()['id']
|
|
|
|
# 2. Ajouter des nodes
|
|
nodes = [
|
|
{'id': '1', 'type': 'start', 'position': {'x': 0, 'y': 0}},
|
|
{'id': '2', 'type': 'navigate', 'position': {'x': 100, 'y': 0},
|
|
'parameters': {'url': 'https://example.com/login'}},
|
|
{'id': '3', 'type': 'type', 'position': {'x': 200, 'y': 0},
|
|
'parameters': {'target': 'input[name="username"]', 'text': 'testuser'}},
|
|
{'id': '4', 'type': 'type', 'position': {'x': 300, 'y': 0},
|
|
'parameters': {'target': 'input[name="password"]', 'text': 'testpass'}},
|
|
{'id': '5', 'type': 'click', 'position': {'x': 400, 'y': 0},
|
|
'parameters': {'target': 'button[type="submit"]'}},
|
|
{'id': '6', 'type': 'end', 'position': {'x': 500, 'y': 0}}
|
|
]
|
|
|
|
edges = [
|
|
{'id': 'e1', 'source': '1', 'target': '2'},
|
|
{'id': 'e2', 'source': '2', 'target': '3'},
|
|
{'id': 'e3', 'source': '3', 'target': '4'},
|
|
{'id': 'e4', 'source': '4', 'target': '5'},
|
|
{'id': 'e5', 'source': '5', 'target': '6'}
|
|
]
|
|
|
|
# 3. Mettre à jour le workflow
|
|
response = self.client.put(f'/api/workflows/{workflow_id}', json={
|
|
'nodes': nodes,
|
|
'edges': edges
|
|
})
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# 4. Valider le workflow
|
|
response = self.client.post(f'/api/workflows/{workflow_id}/validate')
|
|
validation = response.get_json()
|
|
self.assertTrue(validation['is_valid'])
|
|
|
|
# 5. Exécuter le workflow
|
|
response = self.client.post(f'/api/workflows/{workflow_id}/execute', json={
|
|
'mode': 'test'
|
|
})
|
|
execution_id = response.get_json()['execution_id']
|
|
|
|
# 6. Attendre la completion
|
|
self.wait_for_execution_completion(execution_id, timeout=30)
|
|
|
|
# 7. Vérifier les résultats
|
|
response = self.client.get(f'/api/executions/{execution_id}')
|
|
execution = response.get_json()
|
|
|
|
self.assertEqual(execution['status'], 'completed')
|
|
self.assertTrue(execution['success'])
|
|
self.assertEqual(len(execution['node_results']), 6)
|
|
```
|
|
|
|
### 5. Tests de Performance
|
|
|
|
```python
|
|
class TestPerformance(unittest.TestCase):
|
|
def test_large_workflow_serialization(self):
|
|
"""Test performance de sérialisation avec 100 nodes"""
|
|
workflow = create_workflow_with_nodes(100)
|
|
|
|
start_time = time.time()
|
|
serialized = serialize_workflow(workflow)
|
|
end_time = time.time()
|
|
|
|
# Doit être < 1 seconde
|
|
self.assertLess(end_time - start_time, 1.0)
|
|
self.assertEqual(len(serialized['nodes']), 100)
|
|
|
|
def test_workflow_validation_performance(self):
|
|
"""Test performance de validation avec workflow complexe"""
|
|
workflow = create_complex_workflow_with_conditions_and_loops(50)
|
|
|
|
start_time = time.time()
|
|
validation_result = validate_workflow(workflow)
|
|
end_time = time.time()
|
|
|
|
# Doit être < 100ms
|
|
self.assertLess(end_time - start_time, 0.1)
|
|
self.assertTrue(validation_result.is_valid)
|
|
```
|
|
|
|
---
|
|
|
|
## API Design
|
|
|
|
### REST Endpoints
|
|
|
|
#### Workflows
|
|
|
|
```
|
|
GET /api/workflows # Liste tous les workflows
|
|
POST /api/workflows # Crée un nouveau workflow
|
|
GET /api/workflows/:id # Récupère un workflow spécifique
|
|
PUT /api/workflows/:id # Met à jour un workflow
|
|
DELETE /api/workflows/:id # Supprime un workflow
|
|
POST /api/workflows/:id/validate # Valide un workflow
|
|
POST /api/workflows/:id/execute # Exécute un workflow
|
|
GET /api/workflows/:id/export # Exporte un workflow (JSON/YAML)
|
|
POST /api/workflows/import # Importe un workflow
|
|
```
|
|
|
|
#### Templates
|
|
|
|
```
|
|
GET /api/templates # Liste tous les templates
|
|
POST /api/templates # Crée un nouveau template
|
|
GET /api/templates/:id # Récupère un template spécifique
|
|
POST /api/templates/:id/instantiate # Crée un workflow depuis un template
|
|
```
|
|
|
|
#### Node Types
|
|
|
|
```
|
|
GET /api/node-types # Liste tous les types de nodes disponibles
|
|
GET /api/node-types/:type # Récupère la définition d'un type spécifique
|
|
```
|
|
|
|
#### Executions
|
|
|
|
```
|
|
GET /api/executions/:id # Récupère le statut d'une exécution
|
|
POST /api/executions/:id/cancel # Annule une exécution en cours
|
|
```
|
|
|
|
### WebSocket Events
|
|
|
|
#### Client → Server
|
|
|
|
```typescript
|
|
// S'abonner aux mises à jour d'exécution
|
|
{
|
|
type: 'subscribe_execution',
|
|
execution_id: string
|
|
}
|
|
|
|
// Se désabonner
|
|
{
|
|
type: 'unsubscribe_execution',
|
|
execution_id: string
|
|
}
|
|
```
|
|
|
|
#### Server → Client
|
|
|
|
```typescript
|
|
// Statut d'exécution
|
|
{
|
|
type: 'execution_status',
|
|
execution_id: string,
|
|
status: 'running' | 'completed' | 'failed',
|
|
progress: number, // 0-100
|
|
current_node_id?: string
|
|
}
|
|
|
|
// Statut d'un node
|
|
{
|
|
type: 'node_status',
|
|
execution_id: string,
|
|
node_id: string,
|
|
status: 'running' | 'success' | 'failed' | 'skipped',
|
|
duration?: number,
|
|
error?: string
|
|
}
|
|
|
|
// Résultat final
|
|
{
|
|
type: 'execution_complete',
|
|
execution_id: string,
|
|
success: boolean,
|
|
duration: number,
|
|
node_results: NodeResult[]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Considérations de Sécurité
|
|
|
|
### 1. Validation d'Entrée
|
|
- **Sanitization**: Tous les inputs utilisateur doivent être nettoyés pour prévenir les injections
|
|
- **Schema Validation**: Utiliser JSON Schema pour valider tous les workflows
|
|
- **Size Limits**: Limiter la taille des workflows (max 1000 nodes, max 10MB)
|
|
- **Rate Limiting**: Limiter les requêtes API (100 req/min par utilisateur)
|
|
|
|
### 2. Exécution Sécurisée
|
|
- **Sandboxing**: Exécuter les workflows dans un environnement isolé
|
|
- **Permissions**: Contrôle d'accès basé sur les rôles (RBAC)
|
|
- **Audit Trail**: Logger toutes les actions utilisateur avec timestamps
|
|
- **Resource Limits**: Limiter CPU (80%), mémoire (2GB), durée (30min)
|
|
|
|
### 3. Stockage Sécurisé
|
|
- **Encryption**: Chiffrer les workflows sensibles au repos (AES-256)
|
|
- **Access Control**: Permissions granulaires (owner, editor, viewer)
|
|
- **Backup**: Sauvegardes automatiques quotidiennes avec rétention 30 jours
|
|
- **Versioning**: Historique complet des modifications avec rollback
|
|
|
|
### 4. Communication Sécurisée
|
|
- **HTTPS**: Toutes les communications via TLS 1.3
|
|
- **Authentication**: JWT tokens avec expiration (1h) et refresh (7j)
|
|
- **CORS**: Configuration stricte des origines autorisées
|
|
- **WebSocket**: Authentification et chiffrement des messages
|
|
|
|
---
|
|
|
|
## Plan de Déploiement
|
|
|
|
### Phase 1: MVP (4-6 semaines)
|
|
|
|
#### Backend
|
|
- API REST de base (CRUD workflows)
|
|
- Conversion Visual → WorkflowGraph
|
|
- Exécution simple via ExecutionLoop
|
|
- Templates de base (Login, Form Fill)
|
|
- Validation structurelle
|
|
|
|
#### Frontend
|
|
- Canvas avec drag & drop basique
|
|
- Palette avec nodes essentiels (Click, Type, Wait, Navigate, If, Loop)
|
|
- Properties panel simple
|
|
- Target selector basique
|
|
- Sauvegarde/Chargement
|
|
|
|
#### Tests
|
|
- Tests unitaires critiques (>70% coverage)
|
|
- Tests d'intégration de base
|
|
- Validation manuelle des workflows
|
|
|
|
### Phase 2: Fonctionnalités Avancées (4-6 semaines)
|
|
|
|
#### Backend
|
|
- WebSocket pour temps réel
|
|
- Templates avancés (Data Extraction, API Integration)
|
|
- Export/Import (JSON, YAML)
|
|
- Validation avancée (cycles, variables)
|
|
- Migration de versions
|
|
|
|
#### Frontend
|
|
- Undo/Redo complet
|
|
- Zoom/Pan optimisé avec virtualisation
|
|
- Variables management UI
|
|
- Validation temps réel avec indicateurs
|
|
- Raccourcis clavier
|
|
- Minimap et fit-to-screen
|
|
|
|
#### Tests
|
|
- Tests de performance (100 nodes @ 60fps)
|
|
- Property-based tests (Hypothesis)
|
|
- Tests end-to-end automatisés
|
|
- Tests de charge (10 utilisateurs simultanés)
|
|
|
|
### Phase 3: Production (2-4 semaines)
|
|
|
|
#### Optimisations
|
|
- Performance tuning (profiling, optimisations)
|
|
- Caching intelligent (Redis pour templates)
|
|
- Monitoring et métriques (Prometheus, Grafana)
|
|
- Documentation utilisateur complète
|
|
|
|
#### Sécurité
|
|
- Audit de sécurité complet
|
|
- Penetration testing
|
|
- Hardening (rate limiting, input validation)
|
|
- Backup et disaster recovery
|
|
|
|
#### Déploiement
|
|
- CI/CD pipeline (GitHub Actions)
|
|
- Monitoring production (alertes, logs)
|
|
- Rollback strategy (blue-green deployment)
|
|
- Formation utilisateurs
|
|
|
|
---
|
|
|
|
## Métriques de Succès
|
|
|
|
### 1. Métriques Techniques
|
|
|
|
#### Performance
|
|
- **Rendu Canvas**: 60fps avec 100+ nodes ✓
|
|
- **Latence API**: < 200ms pour opérations CRUD ✓
|
|
- **Temps de Conversion**: Visual → Graph < 100ms ✓
|
|
- **Temps de Chargement**: < 2s pour workflows de 50 nodes ✓
|
|
- **Uptime**: > 99.9% ✓
|
|
|
|
#### Qualité
|
|
- **Test Coverage**: > 80% pour code critique ✓
|
|
- **Bug Rate**: < 5 bugs critiques par release ✓
|
|
- **Property Tests**: 100% des propriétés testées ✓
|
|
- **Validation Rate**: > 95% des workflows valides avant exécution ✓
|
|
|
|
### 2. Métriques Utilisateur
|
|
|
|
#### Adoption
|
|
- **Time to First Workflow**: < 5 minutes pour un utilisateur novice ✓
|
|
- **Workflow Creation Speed**: 50% plus rapide qu'écrire du code ✓
|
|
- **Error Rate**: < 5% de workflows invalides créés ✓
|
|
- **Completion Rate**: > 90% des workflows créés sont exécutés ✓
|
|
|
|
#### Satisfaction
|
|
- **User Satisfaction**: > 4.5/5 dans les surveys ✓
|
|
- **NPS Score**: > 50 ✓
|
|
- **Feature Requests**: Priorisation basée sur votes utilisateurs ✓
|
|
- **Support Tickets**: < 10% liés au Visual Builder ✓
|
|
|
|
### 3. Métriques Business
|
|
|
|
#### Productivité
|
|
- **Workflows Created**: 3x plus de workflows créés vs méthode manuelle ✓
|
|
- **Time Saved**: 60% de réduction du temps de développement ✓
|
|
- **Reusability**: 40% des workflows utilisent des templates ✓
|
|
- **Collaboration**: 30% des workflows sont partagés entre utilisateurs ✓
|
|
|
|
#### Adoption
|
|
- **Active Users**: 80% des utilisateurs créent au moins 1 workflow ✓
|
|
- **Retention**: 70% des utilisateurs reviennent après 1 semaine ✓
|
|
- **Power Users**: 20% des utilisateurs créent 5+ workflows ✓
|
|
- **Template Usage**: 50% des nouveaux workflows partent d'un template ✓
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
Le Visual Workflow Builder représente une évolution majeure de RPA Vision V3, transformant un outil technique en une solution accessible à tous. L'architecture proposée garantit:
|
|
|
|
- **Simplicité d'usage** sans compromis sur la puissance
|
|
- **Performance** adaptée aux workflows complexes (100+ nodes @ 60fps)
|
|
- **Intégration parfaite** avec l'écosystème existant (ExecutionLoop, Analytics, Self-Healing)
|
|
- **Extensibilité** pour les futures fonctionnalités (collaboration, AI-assisted design)
|
|
- **Qualité** grâce à une stratégie de test complète (33 propriétés testées)
|
|
|
|
Cette solution positionnera RPA Vision V3 comme le leader du marché RPA no-code/low-code, démocratisant l'automatisation pour tous les utilisateurs, des débutants aux experts.
|
|
|
|
### Prochaines Étapes
|
|
|
|
1. **Validation du Design**: Review avec les stakeholders
|
|
2. **Création du Plan d'Implémentation**: Tasks détaillées avec estimations
|
|
3. **Setup de l'Environnement**: Configuration du projet frontend/backend
|
|
4. **Développement Phase 1**: MVP en 4-6 semaines
|
|
5. **Tests et Itération**: Feedback utilisateurs et améliorations
|