# Plan d'action VWB — 13 avril 2026 Audit ciblé du **Visual Workflow Builder** (`visual_workflow_builder/`) — backend Flask port 5002, frontend React+Vite port 3002 — suite aux retours flous de Dom : « la bibliothèque s'efface tout le temps » + idée d'importer les workflows Léa pour les corriger. --- ## Section A — État des lieux ### Stack réelle en production (PIDs live) - **Backend 5002** → `backend/app.py` (Flask complet, blueprints v3, SQLAlchemy) — **c'est celui qui sert le VWB** - **Backend 5003** → `backend/app_lightweight.py` (serveur HTTP natif fallback, 1451 lignes, mode quasi-inutile aujourd'hui) - **Frontend 3002** → `frontend_v4/` (Vite + React 18, `@xyflow/react`, TypeScript) — actif - **BDD utilisée** → `backend/instance/workflows.db` (via `.env DATABASE_URL=sqlite:///workflows.db`) — **3 workflows** dedans (« Classement de dossier », « bloc notes », « Onlyoffice »), tous `source='manual'`, aucun `review_status` - **BDD fantôme** → `backend/instance/vwb_v3.db` (schema identique, **0 workflows**) — zombie de `app.py` ligne 47 (`'sqlite:///vwb_v3.db'` en défaut) ### Ce qui marche bien - **API v3** est complète et propre : 44 routes réparties (`session`, `workflow`, `capture`, `execute`, `match`, `review`, `learned_workflows`, `dag_execute`). Modèles SQLAlchemy avec champs review (`source`, `review_status`, `review_feedback`, `reviewed_at`). - **Pont Léa ↔ VWB déjà implémenté et câblé** : - Backend : `api_v3/learned_workflows.py` (459 l.) + `services/learned_workflow_bridge.py` (604 l.) - Frontend : `services/api.ts` expose `getLearnedWorkflows`, `importLearnedWorkflow`, `exportForLea` ; `components/WorkflowSelector.tsx` charge et propose d'importer les workflows non-importés - Endpoints fonctionnels : logs du 15 avril montrent `GET /api/v3/learned-workflows?os=linux → 200` - **Système de review** : composants `ReviewModal.tsx`, `WorkflowValidation.tsx`, `WorkflowManagerModal.tsx` + backend `api_v3/review.py` prêt. Un workflow importé arrive en `review_status='pending_review'`. - Tests backend localisés : `backend/tests/` (test_models.py, test_coaching_api.py). Workflow CRUD complet. - Logs rotatifs propres (`backend/logs/vwb.log`, 5 MB × 3). ### Ce qui est cassé / douteux 1. **BUG CRITIQUE — Bibliothèque de captures qui s'efface** Fichier : `frontend_v4/src/components/CaptureLibrary.tsx` lignes 25-62 - Stockage dans **`sessionStorage`** (clé `captureLibrary_v2`) → purgé à chaque fermeture d'onglet ou redémarrage du navigateur - Cap arbitraire à **50 captures** max (`slice(0, 49)`) - Les captures sont des base64 PNG → sessionStorage ne tient pas plus de quelques dizaines de Mo au total - C'est très probablement **le bug** que Dom décrit 2. **BUG — Deux composants concurrents pour la même bibliothèque** - `CaptureLibrary.tsx` écrit dans `sessionStorage['captureLibrary_v2']` - `CapturePanel.tsx` lignes 51-62 écrit dans `sessionStorage['captureLibrary']` (ancienne clé, jamais migrée à l'envers) - Résultat : deux listes de captures tenues en parallèle, désynchronisées, invisibles l'une pour l'autre 3. **Base fantôme `vwb_v3.db`** - `app.py` l.47 : `'sqlite:///vwb_v3.db'` en défaut - Si un jour `.env` n'est pas chargé (ex : systemd mal configuré), le VWB passe silencieusement sur l'autre BDD **vide** et Dom voit ses workflows disparaître - Dette : deux fichiers `instance/` (`backend/instance/` et `visual_workflow_builder/instance/`) créent de la confusion 4. **404 en prod — `/api/correction-packs/stats`** - Logs récents : deux 404 à chaque chargement - La route n'existe pas côté backend, elle est appelée par le **frontend legacy** (`frontend/src/hooks/useCorrectionPacks.ts`) - Dom voit sans doute des erreurs CORS/404 dans la console réseau selon quel frontend il ouvre 5. **Double logging (tous les logs en double)** - `app.py` attache un handler au **root logger** + Flask attache le sien → chaque ligne loguée deux fois - Bruit dans les logs, rend le debug plus dur 6. **Confusion run.sh vs run_v4.sh** - `run.sh` lance frontend legacy port 3000 (via webpack react-scripts) + app.py - `run_v4.sh` lance frontend_v4 port 3002 + app.py - Les deux coexistent, Dom peut cliquer sur l'un ou l'autre sans savoir - `launch.sh` mentionné dans le README **n'existe pas** (README obsolète) 7. **Workflow « Unnamed Workflow »** - Les JSON Léa ont souvent `"name": "Unnamed Workflow"` (cf. `notepad_enriched.json`) - L'import les reprend tel quel — la liste du VWB devient illisible vite 8. **Tests d'intégration VWB datent de janvier** - `tests/integration/test_vwb_*.py` : 6 fichiers - `tests/property/test_vwb_frontend_v2_*` : 14 fichiers — ciblent `frontend/` (v2), pas `frontend_v4/` - Aucun test cible le pont learned_workflows → pas de garde-fou pour C2 ### Dette technique identifiable - **3 backends Flask** (`app.py`, `app_lightweight.py`, `app_catalogue_simple.py`) pour 403 + 1451 + 1370 lignes = 3224 lignes. Un seul tourne. - **2 frontends** (`frontend/` = react-scripts v2, `frontend_v4/` = Vite v4) avec duplication partielle des composants — seul le v4 est vivant - **2 bases SQLite** nommées différemment, schéma identique - **`catalog_routes.py.backup_20260122_163105`** (127 Ko) traîne dans le repo - Screenshots `.screenshot2026-*.png` (8 fichiers × ~220 Ko) traînent à la racine backend - Migrations Alembic présentes mais **un seul fichier** (`001_initial_schema.py`) alors que le schéma a évolué (`review_status` ajouté après) --- ## Section B — Quick wins (< 1 jour chacun) Classés par ratio impact/effort décroissant : ### B1. 🔥 Migrer la bibliothèque de captures de `sessionStorage` vers `localStorage` **Effort** : 30 min **Impact** : résout le bug principal rapporté par Dom - Remplacer `sessionStorage.*` par `localStorage.*` dans `CaptureLibrary.tsx` et `CapturePanel.tsx` - Unifier sur une seule clé `captureLibrary_v3` (migration ascendante depuis les deux anciennes) - Augmenter le cap à 200 captures + ajouter un bouton « vider la bibliothèque » - Attention : `localStorage` plafonne ~5 Mo, les PNG base64 saturent vite — **meilleure option** : persister côté backend via `/api/v3/capture/library` (ajout d'une petite table) et ne garder que des IDs+thumbnails en localStorage ### B2. 🔥 Renommer le fichier « Unnamed Workflow » à l'import **Effort** : 20 min **Impact** : moyen (lisibilité immédiate dans la liste) - `api_v3/learned_workflows.py` l.210 : si `wf_meta["name"] == "Unnamed Workflow"` → `f"Appris {datetime:%d/%m %H:%M}"` - Idem exposer ce nom dans `WorkflowSelector.tsx` ligne 120 quand on affiche la liste learned ### B3. Supprimer la BDD fantôme **Effort** : 15 min **Impact** : élimine un foot-gun discret - Modifier `app.py` l.47 : défaut `'sqlite:///workflows.db'` (aligné sur `.env`) - Supprimer `backend/instance/vwb_v3.db` + `visual_workflow_builder/instance/workflows.db` (vestige) - Documenter dans le `.env.example` le chemin absolu recommandé ### B4. Corriger le double logging **Effort** : 15 min **Impact** : faible (quality-of-life debug) - `app.py` l.40 : remplacer `logging.getLogger().addHandler(...)` par `app.logger.addHandler(...)` et `logging.getLogger('werkzeug').addHandler(...)`, puis `propagate = False` ### B5. Supprimer le 404 `/api/correction-packs/stats` **Effort** : 20 min **Impact** : faible (erreurs dans la console navigateur) - Option A (propre) : stubber la route dans `api/correction_packs.py` qui retourne `{"success": true, "stats": {"total": 0}}` - Option B : retirer l'appel côté `frontend/src/hooks/useCorrectionPacks.ts` ligne 229 - Option B préférable si le frontend legacy est condamné (voir E1) ### B6. Nettoyer les fichiers parasites **Effort** : 10 min **Impact** : cosmétique + réduire la confusion - Supprimer `backend/catalog_routes.py.backup_20260122_163105` (127 Ko) - Supprimer les 8 screenshots `.screenshot2026-*.png` à la racine backend - `.gitignore` : ajouter `*.screenshot*.png`, `*.backup_*` ### B7. Clarifier run.sh **Effort** : 20 min **Impact** : moyen (Dom et moi perdons du temps sur quel frontend lancer) - Renommer `run.sh` → `run_legacy.sh` avec bandeau warning - Mettre à jour `README.md` du VWB pour refléter `run_v4.sh` comme canonique - Supprimer la mention `launch.sh` qui n'existe pas **Total Quick Wins : ~2h30 de dev** pour résoudre la douleur principale + 4 dettes visibles. --- ## Section C — Chantiers moyens (1-3 jours) ### C1. Finaliser le flux « Import Léa → review VWB → replay » **Effort** : 1 jour **Contexte** : toute la plomberie existe (backend+frontend), mais la boucle n'est pas testée end-to-end depuis le premier replay réussi du 13 avril. Actuellement `source='learned_import'` déclenche bien `review_status='pending_review'`, mais : - Le frontend n'a **pas de banner** « ⚠ 2 workflows importés en attente de review » visible au démarrage (il y a bien un `pendingReviewCount` dans `App.tsx` mais je n'ai pas vérifié son affichage) - Quand Dom ouvre un workflow en `pending_review`, aucun indicateur visuel sur les étapes automatiquement générées par le bridge (ex: warning sur les `compound` décomposés, warning sur les `by_position` convertis en `x_pct/y_pct`) - Pas de bouton « rejouer le workflow tel quel sans review » pour tester vite **Actions** : 1. Vérifier l'affichage `pendingReviewCount` dans le header + ajouter un badge coloré 2. Dans `StepNode.tsx`, afficher un ⚠️ quand `step.parameters.compound_steps` existe ou quand `metadata.core_edge_id` manque d'info 3. Exposer les `warnings` retournés par l'import dans un panneau dépliant sur le workflow importé 4. Bouton « Valider et exécuter » qui passe `review_status='approved'` puis lance le replay via `/execute` ### C2. Persister la bibliothèque de captures côté serveur **Effort** : 1,5 jour **Contexte** : extension de B1 si on veut une bibliothèque réellement persistante et partagée entre sessions/machines - Nouvelle table `captures_library(id, screenshot_b64, timestamp, label, favorite, workflow_id NULL)` - Endpoints `GET/POST/DELETE /api/v3/captures/library` - `CaptureLibrary.tsx` : fetch initial + mutations, plus de localStorage - Bonus : associer une capture à un step (fav pour référence future) ### C3. Unifier les deux frontends — retirer `frontend/` (legacy) **Effort** : 2 jours (avec vérif de non-régression) **Contexte** : `frontend/` (v2 React 19 + MUI + Redux) n'est plus maintenu, `frontend_v4/` (Vite + xyflow) est la cible. 14 tests `tests/property/test_vwb_frontend_v2_*` pointent vers le v2. - Auditer ce que le v4 ne fait pas encore (CorrectionPacksDashboard, CoachingPanel, etc.) → décider si on porte ou si on abandonne - Archiver `frontend/` dans `_archives/` ou le supprimer - Désactiver `run.sh` ou le refaire pointer sur v4 - Porter ou supprimer les tests `test_vwb_frontend_v2_*` ### C4. Consolider les 3 `app*.py` **Effort** : 1 jour **Contexte** : `app.py` est le seul utilisé pour le VWB. `app_lightweight.py` sert uniquement à l'endpoint catalogue VLM sur 5003 (un seul endpoint utile). `app_catalogue_simple.py` n'est plus référencé. - Supprimer `app_catalogue_simple.py` - Déplacer le seul endpoint utile de `app_lightweight.py` dans `app.py` + retirer le port 5003 de `services.conf` - Supprimer `app_lightweight.py` - Gain : -2800 lignes, un seul point d'entrée ### C5. Lier étape VWB ↔ screenshot source du workflow Léa **Effort** : 2 jours **Contexte** : actuellement quand on importe un workflow Léa, les steps sont **des actions sans contexte visuel**. Pour pouvoir « corriger visuellement » (idée Dom), il faut que chaque step affiche : - Le screenshot `from_node` (état avant l'action) - Le screenshot `to_node` (état après) - Les bbox cliquées (target) - Les workflows Léa contiennent déjà des `screenshot_hash` dans leurs nodes (à vérifier dans `notepad_enriched.json`) - Modifier `convert_learned_to_vwb_steps` pour persister les screenshots en tant que `VisualAnchor` + `anchor_id` sur le step - Enrichir `StepNode.tsx` pour afficher la vignette **Note** : c'est ce qui donne du sens à l'idée de Dom. Sans ça, l'import Léa→VWB donne des étapes abstraites « click(x=42%, y=68%) » que personne ne peut corriger visuellement. --- ## Section D — Chantiers lourds (>1 semaine) ### D1. Refonte du stockage workflow : un seul format canonique **Effort** : 1-2 semaines **Justification** : aujourd'hui on a 2 formats (core JSON de Léa vs SQLite VWB) avec un bridge. Le bridge perd de l'information (ex: `compound` décomposé, metadata core/screenshots abandonnés en route). À chaque nouvelle feature du core (C2 aujourd'hui, grounding, extraction, etc.) il faut mettre à jour le bridge. **Proposition** : VWB stocke directement le format core JSON (ou un surset strict). Les « steps » VWB deviennent une **vue dérivée** du graphe core, pas une copie. Les corrections humaines modifient le JSON core. **À faire seulement si** l'import Léa→VWB devient un flux majeur et que le bridge montre ses limites. Pour l'instant, le bridge fait le job. ### D2. Mode collaboratif / multi-utilisateurs **Effort** : 2-3 semaines **Justification** : aucune pour aujourd'hui. Dom est seul à utiliser le VWB. À garder dans le coin de la tête pour quand les premiers clients testeront. --- ## Section E — Non-décisions Choses qu'on **ne fera pas**, pour se prémunir des tentations. ### E1. Ne PAS réécrire le frontend en v5 Pourquoi : le v4 Vite+xyflow est récent (mars 2026), propre, bien structuré. Pas de raison architecturale. La migration v3→v4 a déjà coûté cher (cf. nombreux `CORRECTION_TYPESCRIPT_*.md` en janvier). ### E2. Ne PAS unifier `instance/*.db` en PostgreSQL Pourquoi : SQLite convient pour un outil desktop mono-utilisateur. PostgreSQL ajoute une dépendance runtime sans valeur tangible tant qu'on est seul. Le `.env` mentionne déjà l'option, gardée pour plus tard. ### E3. Ne PAS porter CorrectionPacksDashboard sur le v4 Pourquoi : la fonctionnalité « correction packs » est en doublon conceptuel avec le nouveau flux `review_status` + `learned_workflow_bridge`. Autant fermer proprement correction_packs (C4 bis) plutôt que le migrer. ### E4. Ne PAS rajouter de tests property pour le v4 tout de suite Pourquoi : 14 tests `test_vwb_frontend_v2_*` existent déjà et ne tournent plus (pointent vers le v2). Avant de recréer des tests property, il faut décider si on garde le v2 ou pas (C3). Refaire 14 tests pour les jeter dans 2 semaines = gâchis. ### E5. Ne PAS implémenter le mode WebSocket realtime pour le VWB Pourquoi : le polling actuel (500 ms dans `App.tsx`) suffit pour l'usage. WebSocket existe déjà (`socketio`) mais n'est câblé nulle part dans le v4. On peut l'ajouter quand une vraie feature le demande (ex: collaborative editing = E1/D2 → pas maintenant). --- ## Section F — Recommandation d'ordre **Semaine 1 — quick wins utilisateur (jour J)** 1. B1 — localStorage pour CaptureLibrary (30 min) → résout le bug principal 2. B2 — nom lisible à l'import (20 min) → la liste devient utilisable 3. B3 — supprimer BDD fantôme (15 min) → évite un bug futur 4. B6 — nettoyer les fichiers parasites (10 min) → hygiène 5. B7 — clarifier run.sh (20 min) → moins de confusion Total : ~2h de dev pour un retour utilisateur net dès demain. **Semaine 1 — chantier moyen utile (jours J+1 à J+3)** 6. C1 — finaliser le flux « Import Léa → review → replay ». C'est la VALEUR DIRECTE de l'idée de Dom : « importer les workflows Léa pour les corriger visuellement ». **Semaine 2 — étendre la valeur (si C1 tient la route)** 7. C5 — lier step ↔ screenshot source. C'est ce qui transforme le VWB en **vrai outil de correction visuelle**. Sans ça, l'import Léa est abstrait. **Semaine 3+ — consolidation (quand bande passante)** 8. C3 — retirer frontend legacy (gain de clarté) 9. C4 — consolider les 3 `app*.py` (gain dette) 10. C2 — bibliothèque captures serveur (si B1 montre ses limites) **Justification globale** : - **Les 2h de quick wins** donnent à Dom une expérience visible et immédiate (bibliothèque qui ne s'efface plus, liste lisible, moins de bruit). - **C1** capitalise sur l'investissement existant (le pont Léa/VWB est déjà codé à 80%, il faut juste finir le dernier kilomètre — les warnings visuels et le bouton « valider et exécuter »). - **C5** est le vrai game-changer pour l'idée de Dom, mais ne vaut le coup que si C1 a confirmé que le flux globalement fonctionne. Si C1 révèle que le bridge perd trop d'info, on saute direct à D1 (refonte). - **C3/C4** sont de la dette : on s'en occupe quand on a quelqu'un sous la main pour pas ralentir les features. **À éviter** : commencer par C3 ou C4 (dette) parce qu'aucun impact utilisateur visible → pas de ROI court terme. --- ## Risques identifiés - **Backup BDD** : `backend/instance/backups/` contient un seul backup du 23/01. Aucune rotation automatique. Risque de perte : 3 workflows seulement mais ce sont ceux de Dom → ajouter un backup quotidien via `backup_ssd.sh` (déjà existant à la racine `~/ai/`). - **`localStorage` quota** : B1 seul ne suffira pas à long terme. Prévoir C2 si Dom fait plus de 50-100 captures en PNG base64. - **Modèle `Workflow` sans cascade sur source='learned_import'** : si Dom supprime un workflow importé, rien ne met à jour le JSON core sur disque → divergence. Acceptable tant que l'import est monodirectionnel (disque → VWB) mais à surveiller. --- ## Métriques de succès - Bibliothèque persiste après reload navigateur : testable manuellement en 30 s - Liste de workflows ne contient plus « Unnamed Workflow » : testable via SQL - Un workflow Léa importé a un badge « à réviser » visible, et le bouton « Valider et exécuter » le fait tourner sans quitter le VWB - 0 warning 404 dans `backend/logs/vwb.log` après B5 - `run_v4.sh` unique script documenté dans README