ObsiViewer/docs/ARCHITECTURE/AUDIT_STAFF_ENGINEER_SYNTHESE.md

81 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🔍 AUDIT STAFF ENGINEER — ObsiViewer
**Date:** 6 octobre 2025
**Auditeur:** Staff Engineer (Frontend Angular 20 + Node/DevOps)
**Scope:** Architecture, Performance, Sécurité, DX, Ops
---
## A) SYNTHÈSE EXÉCUTIVE (≤300 mots)
### État actuel
ObsiViewer est une application Angular 20 standalone, bien structurée mais souffrant de **problèmes critiques de performance** et d'absence d'architecture de recherche scalable. Le graph view utilise d3-force dans un Web Worker (bon), mais la recherche frontend synchrone bloque le thread principal.
### 🔴 Faiblesses majeures identifiées
1. **Recherche synchrone bloquante (P0)**`SearchOrchestratorService.execute()` itère sur tous les contextes dans le main thread, gel UI sur voûtes >500 notes. Impact: UX critique.
2. **Pas de virtualisation des résultats (P0)** — Liste de résultats rendue intégralement dans le DOM, causant CLS et ralentissement sur 200+ résultats. Impact: performance.
3. **Parsing Markdown synchrone (P0)**`MarkdownService.render()` bloque sur mermaid/highlight.js/MathJax, freeze de 500ms+ sur notes complexes. Impact: UX critique.
4. **Pas de sanitization XSS (P0 Sécurité)** — HTML brut rendu sans DOMPurify, vulnérabilité sur Markdown malveillant. Impact: sécurité critique.
5. **Indexation reconstruite à chaque effet (P0)**`SearchIndexService.rebuildIndex()` et `GraphIndexService.rebuildIndex()` déclenchés sur mutation du signal `allNotes()`, coût O(N²). Impact: performance.
6. **Pas de lazy loading des bibliothèques lourdes (P1)** — Mermaid (1.2MB) et highlight.js chargés au démarrage, TTI >4s. Impact: chargement initial.
7. **Aucune stratégie de cache HTTP (P1)** — Pas d'ETag, Service Worker, ou cache IndexedDB pour les métadonnées. Impact: rechargements inutiles.
8. **Logs non structurés backend (P1)**`/api/log` inexistant, pas de corrélation des événements, diagnostic impossible. Impact: observabilité.
### Opportunités majeures
- **Meilisearch** pour recherche côté serveur (typo-tolerance, highlights, facettes)
- **CDK Virtual Scroll** pour listes (réduction DOM de 95%)
- **Web Workers** pour parsing Markdown et indexation
- **Docker multi-stage** pour optimisation déploiement
### Métriques actuelles estimées
- **TTI:** ~4.2s (budget: <2.5s)
- **Search P95:** 800ms+ sur 500 notes (budget: <150ms)
- **Graph freeze:** 1.5s+ au clic (budget: <100ms)
- **Bundle size:** ~2.8MB (budget: <1.5MB)
---
## B) TABLEAU DES FAIBLESSES DÉTAILLÉES
| Catégorie | Fichier/Zone | Description | Symptôme | Cause racine | Evidence | Risque | Priorité |
|-----------|--------------|-------------|----------|--------------|----------|--------|----------|
| **Performance** | `search-orchestrator.service.ts:164-200` | Boucle synchrone sur tous les contextes | Gel UI 800ms+ sur 500 notes | Itération bloquante dans main thread | L.164 `for (const context of allContexts)` | Abandon utilisateur | **P0** |
| **Performance** | `app.component.ts:232-251` | Résultats de recherche non virtualisés | CLS, scroll janky sur 200+ résultats | Rendu DOM complet de la liste | Computed signal sans CDK Virtual Scroll | UX dégradée | **P0** |
| **Performance** | `markdown.service.ts:53-92` | Parsing Markdown synchrone | Freeze 500ms+ sur notes avec mermaid | `mermaid.render()` et `hljs.highlight()` dans main thread | L.53 render() bloquant | UX critique | **P0** |
| **Sécurité** | `markdown.service.ts:564-571` | Pas de sanitization HTML | Vulnérabilité XSS via Markdown malveillant | `escapeHtml()` custom au lieu de DOMPurify | Aucune lib sanitization trouvée | **CVE potentielle** | **P0** |
| **Performance** | `search-index.service.ts:80-146` | Rebuild index complet à chaque mutation | CPU spike 300ms+ sur edit | Effect déclenché sur `allNotes()` mutation | L.310 `effect(() => this.searchIndex.rebuildIndex())` | Gel éditeur | **P0** |
| **Performance** | `graph-index.service.ts` + `app.component.ts:304-307` | Rebuild graph index à chaque mutation | Calcul redondant O(N²) | Même pattern que search index | L.304 effect sans debounce | Gel éditeur | **P0** |
| **Architecture** | Pas de backend Meilisearch | Recherche frontend limitée | Pas de typo-tolerance, highlights serveur | Absence d'engine de recherche dédié | Opérateurs Obsidian mappés côté client | Scalabilité bloquée | **P0** |
| **Performance** | `package.json:44` | Mermaid chargé au démarrage (1.2MB) | TTI >4s | Import statique au lieu de lazy | L.44 dépendance non lazy | Slow initial load | **P1** |
| **Performance** | Aucun Virtual Scroll (CDK) | Liste tags, résultats non optimisées | Scroll janky sur 500+ items | Angular CDK non utilisé | `@angular/cdk` présent mais inutilisé | UX liste | **P1** |
| **Performance** | Pas de Service Worker | Rechargement complet à chaque visite | Pas de cache offline | Workbox non configuré | Aucun `ngsw-config.json` | Expérience offline nulle | **P1** |
| **Ops** | `Dockerfile:1-56` | Pas de multi-stage optimisé | Image 450MB+ | node:20-bullseye-slim pas assez slim | L.21 runtime inclut build tools | Déploiement lent | **P1** |
| **Ops** | Aucune variable d'env structurée | Config hardcodée | Pas de VAULT_ID, SEARCH_URL | `assets/config.local.js` non paramétré | Impossible multi-instance | **P1** |
| **DX** | Pas de budgets Lighthouse | Pas de garde-fou performance | Régressions non détectées | `angular.json` sans budgets | Aucun `budgets` configuré | Dégradation continue | **P1** |
| **Sécurité** | Aucun CSP header | XSS non mitigé | Pas de Content-Security-Policy | NGINX config absente | `nginx.conf` minimal | Défense en profondeur manquante | **P1** |
| **Observabilité** | `/api/log` non implémenté | Diagnostics impossibles | Pas de corrélation événements | Backend Express minimal | `server/index.mjs` sans routes log | Debug production impossible | **P1** |
| **Performance** | `vault.service.ts:96-142` | Graph data recalculé trop souvent | Computed sans memoization fine | Computed signal redéclenché | L.96-142 calcul O(N×M) | CPU gaspillé | **P2** |
| **Architecture** | Pas de lazy routes | Tout chargé au boot | TTI impacté par code inutile | Application standalone sans routing lazy | Pas de loadChildren | Bundle monolithique | **P2** |
| **DX** | Tests E2E partiels | Couverture <30% estimée | Pas de tests graph freeze | Playwright configuré mais incomplet | `e2e/*.spec.ts` limités | Régressions non catchées | **P2** |
| **Performance** | `graph-canvas.component.ts:373-403` | Redessins canvas non throttlés | GPU surchargé | `draw()` appelé à chaque tick sans RAF guard | L.364 scheduleRedraw sans throttle | Batterie mobile | **P2** |
| **Sécurité** | Markdown attrs non validés | Injection potentielle via `{.class}` | markdown-it-attrs sans whitelist | L.157 allowedAttributes minimal | XSS edge case | **P2** |
---
**Points forts à préserver:**
- Web Worker pour graph layout (d3-force offload)
- OnPush change detection (appliqué partout)
- Signals/Computed pour réactivité
- Architecture modulaire services/components
- Logging client structuré (base solide)
---