# 🚀 PLAN D'EXÉCUTION & MÉTRIQUES ## 1. RÉSUMÉ EXÉCUTABLE — Ordre d'Attaque des P0 (Semaine 1) ### Jour 1: Sécurité Critique **Objectif:** Éliminer vulnérabilité XSS **Tasks:** - [ ] Installer DOMPurify: `npm install dompurify @types/dompurify` - [ ] Remplacer `escapeHtml()` par `DOMPurify.sanitize()` dans `MarkdownService` - [ ] Configurer whitelist: `ALLOWED_TAGS`, `ALLOWED_ATTR` - [ ] Tests avec payloads XSS (OWASP Top 10) - [ ] Commit + merge **Critère de succès:** Payload `` neutralisé --- ### Jour 2-3: Performance UI Immédiate **Objectif:** Éliminer gels perceptibles **Tasks:** - [ ] Implémenter CDK Virtual Scroll pour résultats de recherche (2h) - [ ] Ajouter `trackBy` sur toutes les listes `@for` (1h) - [ ] Debounce rebuild index (search + graph) avec `debounceTime(300)` (3h) - [ ] Tests E2E: search 500 notes <150ms (2h) **Critère de succès:** Aucun gel UI >100ms sur actions utilisateur --- ### Jour 4-5: Offload Computation **Objectif:** Libérer main thread **Tasks:** - [ ] Créer `markdown.worker.ts` avec MarkdownIt (4h) - [ ] Implémenter `MarkdownWorkerService` avec pool 2 workers (3h) - [ ] Lazy load Mermaid + `runOutsideAngular()` (2h) - [ ] Lazy load MathJax (1h) - [ ] Tests rendering note 1000 lignes + mermaid (2h) **Critère de succès:** Parsing note complexe: main thread <16ms --- ### Jour 6-7: Backend Meilisearch MVP **Objectif:** Recherche scalable **Tasks:** - [ ] Docker Compose: ajouter service Meilisearch (1h) - [ ] Backend: script indexation `meilisearch-indexer.mjs` (3h) - [ ] Créer `SearchMeilisearchService` Angular (2h) - [ ] Mapper opérateurs Obsidian → filtres (3h) - [ ] Route `/api/search` avec parsing opérateurs (3h) - [ ] Tests: opérateurs `tag:`, `path:`, `file:` (2h) **Critère de succès:** Search retourne <150ms P95 sur 1000 notes --- ### Jour 8: Observabilité **Objectif:** Diagnostics production **Tasks:** - [ ] Créer route POST `/api/log` (2h) - [ ] Implémenter validation + sanitization logs (2h) - [ ] Rotation logs automatique (10MB max) (1h) - [ ] Tests: batch 50 événements <50ms (1h) **Critère de succès:** Logs persistés avec corrélation sessionId --- ## 2. PLAN D'IMPLÉMENTATION PAR ÉTAPES ### Phase 1: CRITIQUE (Semaine 1-2) — 8 jours **Focus:** Sécurité + Performance bloquante | Item | Effort | Dépendances | Risque | |------|--------|-------------|--------| | DOMPurify sanitization | 1j | Aucune | Faible | | CDK Virtual Scroll | 2j | Aucune | Faible | | Debounce index rebuild | 3j | Aucune | Moyen | | Markdown Web Worker | 4j | Aucune | Moyen | | Lazy load Mermaid/MathJax | 2j | Aucune | Faible | | Meilisearch integration | 5j | Docker setup | Élevé | | /api/log backend | 3j | Aucune | Faible | **Livrable:** Version 1.1.0 — "Performance & Security" **Métriques cibles:** TTI <2.5s, Search P95 <150ms, 0 vulnérabilités XSS --- ### Phase 2: OPTIMISATION (Semaine 3-4) — 7 jours **Focus:** Caching + Infra | Item | Effort | Dépendances | Risque | |------|--------|-------------|--------| | Service Worker + Workbox | 3j | Aucune | Moyen | | Budgets Lighthouse | 0.5j | Aucune | Faible | | Dockerfile multi-stage | 2j | Aucune | Faible | | Variables d'env (12-factor) | 1.5j | Aucune | Faible | | CSP headers + NGINX | 1.5j | Docker | Faible | | Throttle RAF canvas | 1j | Aucune | Faible | | Tests E2E étendus | 2.5j | Playwright | Moyen | **Livrable:** Version 1.2.0 — "Infrastructure" **Métriques cibles:** Offline support, Image <150MB, A+ Mozilla Observatory --- ### Phase 3: NICE-TO-HAVE (Semaine 5+) — 5 jours **Focus:** Code splitting + Optimisations avancées | Item | Effort | Dépendances | Risque | |------|--------|-------------|--------| | Lazy routes Angular | 3j | Routing refactor | Moyen | | GraphData memoization | 1.5j | Aucune | Faible | | markdown-it-attrs whitelist | 0.5j | Aucune | Faible | | Progressive rendering | 2j | Aucune | Moyen | | IndexedDB cache | 3j | Dexie.js | Moyen | | OpenTelemetry (opt.) | 4j | Infra monitoring | Élevé | **Livrable:** Version 1.3.0 — "Polish" **Métriques cibles:** Initial bundle <800KB, Cache hit rate >80% --- ## 3. MÉTRIQUES À SUIVRE (Performance & Erreurs) ### A) Métriques Performance (Lighthouse + Custom) | Métrique | Actuel (estimé) | Cible Phase 1 | Cible Phase 2 | Cible Phase 3 | Seuil Alerte | |----------|-----------------|---------------|---------------|---------------|--------------| | **TTI (Time to Interactive)** | 4.2s | 2.5s | 2.0s | 1.5s | >3s (P95) | | **LCP (Largest Contentful Paint)** | 2.8s | 2.0s | 1.5s | 1.2s | >2.5s (P75) | | **FID (First Input Delay)** | 120ms | 80ms | 50ms | 30ms | >100ms (P95) | | **CLS (Cumulative Layout Shift)** | 0.15 | 0.1 | 0.05 | 0.02 | >0.1 (P75) | | **Bundle Size (initial)** | 2.8MB | 1.8MB | 1.5MB | 800KB | >2MB | | **Bundle Size (lazy chunks)** | N/A | 500KB | 300KB | 200KB | >500KB | | **Search P95 Latency** | 800ms | 150ms | 100ms | 50ms | >200ms | | **Graph Interaction P95** | 1500ms | 500ms | 100ms | 50ms | >300ms | | **Markdown Parse P95** | 500ms | 100ms | 50ms | 16ms | >150ms | | **Memory Heap (steady state)** | 120MB | 100MB | 80MB | 60MB | >150MB | **Outils de mesure:** - Lighthouse CI (automatisé dans pipeline) - Chrome DevTools Performance profiler - `performance.mark()` + `performance.measure()` custom - Real User Monitoring (RUM) via `/api/log` PERFORMANCE_METRIC events --- ### B) Métriques Erreurs & Stabilité | Métrique | Cible | Seuil Alerte | Action | |----------|-------|--------------|--------| | **Error Rate** | <0.1% sessions | >1% | Rollback deploy | | **XSS Vulnerabilities** | 0 | >0 | Blocage release | | **Search Error Rate** | <0.5% queries | >2% | Investigate index corruption | | **Graph Freeze Rate** | <0.1% interactions | >1% | Degrade to simple view | | **Worker Crash Rate** | <0.01% | >0.5% | Fallback to sync mode | | **API /log Uptime** | >99.5% | <95% | Scale backend | | **CSP Violations** | <10/day | >100/day | Review inline scripts | **Alertes configurées via:** - Sentry (erreurs runtime) - LogRocket (session replay on error) - Custom `/api/log` aggregation + Grafana --- ### C) Métriques Business (UX) | Métrique | Actuel | Cible | Mesure | |----------|--------|-------|--------| | **Searches per Session** | 2.3 | 4.0 | Via SEARCH_EXECUTED events | | **Graph View Engagement** | 15% users | 40% | Via GRAPH_VIEW_OPEN events | | **Bookmark Usage** | 8% users | 25% | Via BOOKMARKS_MODIFY events | | **Session Duration** | 3.2min | 8min | Via APP_START → APP_STOP | | **Bounce Rate (no interaction)** | 35% | <20% | First event within 30s | --- ## 4. COMMANDES À EXÉCUTER (Vérification & Bench) ### Performance Benchmark **Lighthouse CI (automatisé):** ```bash # Install npm install -g @lhci/cli # Run Lighthouse on dev server ng serve & sleep 5 lhci autorun --config=.lighthouserc.json # Expected output: # ✅ TTI: <2.5s # ✅ FCP: <1.5s # ✅ Performance Score: >85 ``` **`.lighthouserc.json`:** ```json { "ci": { "collect": { "url": ["http://localhost:3000"], "numberOfRuns": 3 }, "assert": { "assertions": { "categories:performance": ["error", {"minScore": 0.85}], "first-contentful-paint": ["error", {"maxNumericValue": 1500}], "interactive": ["error", {"maxNumericValue": 2500}], "cumulative-layout-shift": ["error", {"maxNumericValue": 0.1}] } }, "upload": { "target": "temporary-public-storage" } } } ``` --- ### Bundle Analysis ```bash # Build with stats ng build --configuration=production --stats-json # Analyze with webpack-bundle-analyzer npx webpack-bundle-analyzer dist/stats.json # Expected: # ✅ Initial bundle: <1.5MB # ✅ Vendor chunk: <800KB # ✅ Lazy chunks: <300KB each ``` --- ### Search Performance Test **Script: `scripts/bench-search.ts`** ```typescript import { performance } from 'perf_hooks'; async function benchSearch() { const queries = [ 'tag:#project', 'path:folder1/ important', 'file:home -tag:#archive', 'has:attachment task:TODO' ]; const results = []; for (const query of queries) { const start = performance.now(); const response = await fetch('http://localhost:4000/api/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query, vaultId: 'primary' }) }); const data = await response.json(); const duration = performance.now() - start; results.push({ query, duration, hits: data.estimatedTotalHits, serverTime: data.processingTimeMs }); } console.table(results); const p95 = results.sort((a, b) => b.duration - a.duration)[Math.floor(results.length * 0.95)].duration; console.log(`\n✅ Search P95: ${p95.toFixed(2)}ms (target: <150ms)`); } benchSearch(); ``` **Exécution:** ```bash npx ts-node scripts/bench-search.ts # Expected output: # ┌─────────┬──────────────────────────────┬──────────┬──────┬────────────┐ # │ (index) │ query │ duration │ hits │ serverTime │ # ├─────────┼──────────────────────────────┼──────────┼──────┼────────────┤ # │ 0 │ 'tag:#project' │ 48.2 │ 23 │ 12.5 │ # │ 1 │ 'path:folder1/ important' │ 52.7 │ 8 │ 15.8 │ # │ 2 │ 'file:home -tag:#archive' │ 45.3 │ 1 │ 10.2 │ # │ 3 │ 'has:attachment task:TODO' │ 61.5 │ 5 │ 18.9 │ # └─────────┴──────────────────────────────┴──────────┴──────┴────────────┘ # ✅ Search P95: 61.5ms (target: <150ms) ``` --- ### E2E Tests Performance **Playwright config additions:** ```typescript // playwright.config.ts export default defineConfig({ use: { trace: 'retain-on-failure', video: 'on-first-retry', }, reporter: [ ['html'], ['json', { outputFile: 'test-results/results.json' }] ], timeout: 30000, expect: { timeout: 5000 } }); ``` **Run E2E with performance assertions:** ```bash npx playwright test --reporter=html # Expected: # ✅ search-performance.spec.ts (4/4 passed) # - Search 500 notes completes in <150ms # - No main thread freeze >100ms # - UI remains interactive during search # - Virtual scroll renders without CLS ``` --- ### Docker Image Size Verification ```bash # Build optimized image docker build -f docker/Dockerfile -t obsiviewer:optimized . # Check size docker images obsiviewer:optimized # Expected: # REPOSITORY TAG SIZE # obsiviewer optimized 145MB (vs 450MB before) # Verify healthcheck docker run -d -p 4000:4000 --name test obsiviewer:optimized sleep 10 docker inspect --format='{{.State.Health.Status}}' test # Expected: healthy ``` --- ### Security Scan ```bash # XSS payload tests npm run test:e2e -- e2e/security-xss.spec.ts # CSP violations check curl -I http://localhost:4000 | grep -i "content-security-policy" # Expected: # content-security-policy: default-src 'self'; script-src 'self' 'unsafe-eval'; ... # npm audit npm audit --production # Expected: # found 0 vulnerabilities ``` --- ### Meilisearch Index Stats ```bash # Check index health curl http://localhost:7700/indexes/vault_primary/stats \ -H "Authorization: Bearer masterKey" # Expected response: { "numberOfDocuments": 823, "isIndexing": false, "fieldDistribution": { "title": 823, "content": 823, "tags": 645, "path": 823 } } # Test search latency curl -X POST http://localhost:7700/indexes/vault_primary/search \ -H "Authorization: Bearer masterKey" \ -H "Content-Type: application/json" \ -d '{"q":"project","limit":50}' \ -w "\nTime: %{time_total}s\n" # Expected: Time: 0.035s (<50ms) ``` --- ## 5. DASHBOARD MÉTRIQUES (Grafana/Custom) **Panels recommandés:** 1. **Search Performance** - P50/P95/P99 latency (line chart) - Error rate (gauge) - Queries per minute (counter) 2. **Graph Interactions** - Freeze events count (bar chart) - Node click → selection latency (histogram) - Viewport FPS (line chart) 3. **Frontend Vitals** - LCP, FID, CLS (timeseries) - Bundle size evolution (area chart) - Memory heap (line chart) 4. **Backend Health** - /api/vault response time (line chart) - Meilisearch indexing status (state timeline) - Log ingestion rate (counter) 5. **User Engagement** - Active sessions (gauge) - Feature adoption (pie chart: search/graph/bookmarks/calendar) - Session duration distribution (histogram) **Exemple config Prometheus + Grafana:** ```yaml # docker-compose.yml additions services: prometheus: image: prom/prometheus volumes: - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090" grafana: image: grafana/grafana ports: - "3001:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin volumes: - ./monitoring/grafana-dashboards:/var/lib/grafana/dashboards ``` --- ## 6. CRITÈRES DE SUCCÈS GLOBAUX ### Phase 1 (Semaine 1-2) ✅ - [ ] Lighthouse Performance Score: **>85** - [ ] Search P95: **<150ms** (1000 notes) - [ ] TTI: **<2.5s** - [ ] Aucune vulnérabilité XSS détectée - [ ] Main thread freeze: **<100ms** sur toutes interactions - [ ] `/api/log` opérationnel avec rotation ### Phase 2 (Semaine 3-4) ✅ - [ ] Lighthouse Performance Score: **>90** - [ ] Image Docker: **<150MB** - [ ] Offline support: app charge depuis cache - [ ] CSP headers configurés, score Mozilla Observatory: **A+** - [ ] Tests E2E coverage: **>60%** - [ ] Bundle budgets respectés (no warnings) ### Phase 3 (Semaine 5+) ✅ - [ ] Initial bundle: **<800KB** - [ ] Search P95: **<50ms** - [ ] Graph interaction P95: **<50ms** - [ ] Cache hit rate: **>80%** - [ ] Memory steady state: **<60MB** --- ## 7. COMMANDES QUOTIDIENNES (CI/CD) **Pre-commit:** ```bash npm run lint npm run test:unit ``` **Pre-push:** ```bash npm run build npm run test:e2e ``` **CI Pipeline (GitHub Actions exemple):** ```yaml name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '20' - run: npm ci - run: npm run lint - run: npm run test:unit - run: npm run build - run: npx lhci autorun - run: npm run test:e2e security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: npm audit --production - run: npm run test:e2e -- e2e/security-xss.spec.ts docker: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - run: docker build -t obsiviewer:${{ github.sha }} . - run: | SIZE=$(docker images obsiviewer:${{ github.sha }} --format "{{.Size}}") echo "Image size: $SIZE" # Fail if >200MB ``` --- **FIN DU PLAN D'EXÉCUTION** Toutes les métriques, commandes et critères sont prêts à être appliqués immédiatement.