Files
rpa_vision_v3/.kiro/specs/visual-workflow-builder/design.md
Dom a7de6a488b feat: replay E2E fonctionnel — 25/25 actions, 0 retries, SomEngine via serveur
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>
2026-03-31 14:04:41 +02:00

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