14 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	✅ CHECKLIST D'AMÉLIORATIONS PRIORISÉES (ICE Scoring)
Légende ICE: Impact (1-10) / Confiance (1-10) / Effort (1-10, 1=facile)
Score ICE = (Impact × Confiance) / Effort
🔴 P0 — CRITICAL (>10 jours, éliminer gels UI et sécurité)
1. [P0] Intégration Meilisearch pour recherche côté serveur
ICE: 10/10/7 = 14.3
Pourquoi: Recherche actuelle O(N) frontend bloque UI, impossible de scaler >1000 notes. Meilisearch offre typo-tolerance, highlights serveur, facettes natives, temps de réponse <50ms.
Étapes concrètes:
- Ajouter service Docker Meilisearch dans 
docker-compose.yml - Créer script d'indexation backend (
server/meilisearch-indexer.mjs) - Définir schéma index (voir section Architecture)
 - Créer 
SearchMeilisearchServiceAngular appelant/api/search - Mapper opérateurs Obsidian → filtres Meilisearch
 - Migrer 
SearchOrchestratorServicepour déléguer à backend 
Critères d'acceptation:
- ✅ Recherche retourne en <150ms P95 sur 1000 notes
 - ✅ Opérateurs 
tag:,path:,file:fonctionnels - ✅ Highlights retournés par serveur (pas de calcul frontend)
 - ✅ Typo-tolerance activée (distance 2)
 
Estimation: 5 jours
2. [P0] Ajouter DOMPurify pour sanitization XSS
ICE: 10/10/2 = 50.0
Pourquoi: Vulnérabilité critique, Markdown malveillant peut injecter scripts. DOMPurify est le standard industrie (3M+ downloads/semaine).
Étapes concrètes:
npm install dompurify @types/dompurify- Remplacer 
escapeHtml()parDOMPurify.sanitize()dansMarkdownService - Configurer whitelist tags/attributes Obsidian-safe
 - Ajouter tests avec payloads XSS connus
 - Documenter politique sanitization
 
Critères d'acceptation:
- ✅ Payload 
<img src=x onerror=alert(1)>neutralisé - ✅ Markdown légitime (callouts, mermaid) préservé
 - ✅ Tests E2E passent avec notes malveillantes
 
Estimation: 1 jour
3. [P0] Implémenter CDK Virtual Scroll pour résultats de recherche
ICE: 9/10/3 = 30.0
Pourquoi: Actuellement 500 résultats = 500 nodes DOM, causant CLS et janky scroll. Virtual scroll réduit à ~15 nodes visibles, gain 97%.
Étapes concrètes:
- Importer 
ScrollingModuledepuis@angular/cdk/scrolling - Wrapper liste résultats dans 
<cdk-virtual-scroll-viewport> - Définir 
itemSizefixe (80px) ou dynamique - Ajouter 
trackBysurnoteIdpour optimiser change detection - Tester avec 1000+ résultats
 
Critères d'acceptation:
- ✅ Scroll fluide 60fps sur 1000 résultats
 - ✅ CLS <0.1
 - ✅ Temps de rendu initial <100ms
 
Estimation: 2 jours
4. [P0] Offloader parsing Markdown dans Web Worker
ICE: 9/9/6 = 13.5
Pourquoi: MarkdownService.render() bloque main thread 500ms+ sur notes avec mermaid/MathJax. Worker libère UI.
Étapes concrètes:
- Créer 
markdown.worker.tsavec MarkdownIt + plugins - Exposer API 
parse(markdown: string, options) => html - Créer 
MarkdownWorkerServiceAngular avec pool de workers (2-4) - Gérer communication async (Observable-based)
 - Ajouter fallback synchrone pour SSR
 - Migrer 
MarkdownServicepour déléguer au worker 
Critères d'acceptation:
- ✅ Parsing note 1000 lignes + mermaid: main thread <16ms (1 frame)
 - ✅ Rendu progressif (streaming) si possible
 - ✅ Pas de régression features (wikilinks, callouts)
 
Estimation: 4 jours
5. [P0] Debounce/Incremental rebuild des index (Search + Graph)
ICE: 8/10/3 = 26.7
Pourquoi: Actuellement effect(() => rebuildIndex(allNotes())) reconstruit tout à chaque mutation, coût O(N²) sur édition.
Étapes concrètes:
- Remplacer effect par 
debounceTime(300)surallNotes()signal - Implémenter rebuild incrémental: détecter delta notes (added/updated/removed)
 - Update index partiellement pour delta uniquement
 - Ajouter flag 
isIndexingpour désactiver search pendant rebuild - Logger timing rebuild dans console
 
Critères d'acceptation:
- ✅ Édition note: index update <50ms (vs 300ms actuellement)
 - ✅ Pas de gel UI perceptible
 - ✅ Index cohérent après updates multiples
 
Estimation: 3 jours
6. [P0] Lazy load Mermaid + MathJax + highlight.js
ICE: 8/10/2 = 40.0
Pourquoi: 1.8MB chargés au boot alors qu'utilisés seulement si note contient code/diagramme. Lazy import réduit TTI de 2s.
Étapes concrètes:
- Convertir imports statiques en 
import()dynamiques - Dans 
MarkdownService.renderFence(), charger mermaid on-demand - Détecter présence 
$$avant charger MathJax - Wrapper imports dans 
NgZone.runOutsideAngular()pour éviter CD - Ajouter spinner pendant chargement initial
 
Critères d'acceptation:
- ✅ TTI initial <2.5s (vs 4.2s actuellement)
 - ✅ Premier diagramme mermaid rendu <500ms après chargement lib
 - ✅ Pas de flash of unstyled content
 
Estimation: 2 jours
7. [P0] Implémenter /api/log backend pour diagnostics
ICE: 7/10/4 = 17.5
Pourquoi: Impossible diagnostiquer problèmes production sans logs structurés. Client logging existe mais pas d'endpoint backend.
Étapes concrètes:
- Créer route POST 
/api/logdansserver/index.mjs - Parser batch d'événements (schéma LogRecord)
 - Valider/sanitize données (éviter injection logs)
 - Persister dans fichier JSON rotatif (max 10MB) ou stdout structuré
 - Ajouter corrélation sessionId + requestId
 - Exposer GET 
/api/log/healthpour monitoring 
Critères d'acceptation:
- ✅ Batch de 50 événements persisté en <50ms
 - ✅ Rotation logs automatique
 - ✅ Champs sensibles (query, path) hashés/redacted
 - ✅ Corrélation sessionId fonctionne
 
Estimation: 3 jours
🟡 P1 — HIGH (5-8 jours, optimisations majeures)
8. [P1] Configurer Service Worker + Workbox pour cache offline
ICE: 7/8/4 = 14.0
Pourquoi: Actuellement chaque visite = full reload. SW cache assets statiques + API responses, réduction 80% trafic.
Étapes concrètes:
- Installer 
@angular/service-worker - Créer 
ngsw-config.jsonavec stratégies cache:- Assets: cache-first
 /api/vault: network-first, fallback cache (stale-while-revalidate)/api/attachments: cache-first
 - Ajouter 
ServiceWorkerModule.register()dans app config - Implémenter update notifications
 
Critères d'acceptation:
- ✅ Offline: app charge depuis cache
 - ✅ Rechargement vault: <500ms si cached
 - ✅ Update notification après deploy
 
Estimation: 3 jours
9. [P1] Ajouter budgets Lighthouse dans angular.json
ICE: 6/10/1 = 60.0
Pourquoi: Pas de garde-fou, bundle grossit sans alerte. Budgets cassent build si dépassés.
Étapes concrètes:
- Ajouter section 
budgetsdansangular.json:"budgets": [ { "type": "initial", "maximumWarning": "1.5mb", "maximumError": "2mb" }, { "type": "anyComponentStyle", "maximumWarning": "50kb" } ] - Configurer CI pour fail si budgets dépassés
 - Monitorer avec 
ng build --stats-json+ webpack-bundle-analyzer 
Critères d'acceptation:
- ✅ Build warning si bundle >1.5MB
 - ✅ Build error si >2MB
 - ✅ CI pipeline fail sur dépassement
 
Estimation: 0.5 jour
10. [P1] Dockerfile multi-stage optimisé + healthcheck
ICE: 6/9/3 = 18.0
Pourquoi: Image actuelle 450MB+, redéploiement lent. Multi-stage réduit à <150MB.
Étapes concrètes:
- Stage 1 (builder): 
FROM node:20-alpine, build Angular + prune devDeps - Stage 2 (runtime): 
FROM node:20-alpine, copier dist + node_modules prod uniquement - Utiliser 
.dockerignore(node_modules, .git, .angular, tests) - Ajouter HEALTHCHECK curl 
/api/health - Configurer non-root user (security)
 
Critères d'acceptation:
- ✅ Image finale <150MB
 - ✅ Build time <3min
 - ✅ Healthcheck passe dans Kubernetes/Docker Swarm
 
Estimation: 2 jours
11. [P1] Variables d'environnement structurées (12-factor app)
ICE: 6/9/2 = 27.0
Pourquoi: Config hardcodée empêche multi-instance (dev/staging/prod avec différentes voûtes).
Étapes concrètes:
- Créer 
.env.example:VAULT_PATH=/app/vault VAULT_ID=primary MEILISEARCH_URL=http://meilisearch:7700 MEILISEARCH_KEY=masterKey LOG_LEVEL=info - Charger avec 
dotenvdansserver/index.mjs - Exposer config runtime via 
/api/config(non-sensitive seulement) - Documenter dans README
 
Critères d'acceptation:
- ✅ Plusieurs instances pointent vers voûtes différentes
 - ✅ Dev/staging/prod configs séparées
 - ✅ Pas de secrets hardcodés
 
Estimation: 1.5 jour
12. [P1] Ajouter CSP headers + NGINX hardening
ICE: 6/8/2 = 24.0
Pourquoi: Défense en profondeur contre XSS. CSP bloque inline scripts non whitelistés.
Étapes concrètes:
- Créer 
docker/config/nginx.confavec:add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;"; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header Referrer-Policy no-referrer-when-downgrade; - Tester avec CSP reporter
 - Activer Brotli compression
 - Configurer rate limiting (optional)
 
Critères d'acceptation:
- ✅ CSP headers présents dans réponses
 - ✅ Aucun inline script bloqué (app fonctionne)
 - ✅ Score Mozilla Observatory A+
 
Estimation: 1.5 jour
13. [P1] Implémenter throttle RAF pour redraws canvas graph
ICE: 5/9/2 = 22.5
Pourquoi: draw() appelé à chaque scheduleRedraw() sans throttle, GPU surchargé sur mobile.
Étapes concrètes:
- Ajouter flag 
isScheduleddansGraphCanvasComponent - Wrapper 
scheduleRedraw()pour éviter multiples RAF pending - Utiliser 
requestAnimationFrame()comme gate (déjà présent mais pas optimal) - Limiter FPS max à 60 (skip frames si <16ms depuis dernier draw)
 
Critères d'acceptation:
- ✅ Max 60fps rendering (monitoring via Chrome DevTools)
 - ✅ CPU réduit de 30% sur interactions graph
 - ✅ Pas de visual jank
 
Estimation: 1 jour
14. [P1] Étendre tests E2E Playwright (graph freeze, search perf)
ICE: 5/8/3 = 13.3
Pourquoi: Tests actuels incomplets, régressions performance passent inaperçues.
Étapes concrètes:
- Créer 
e2e/search-performance.spec.ts:- Charger vault 500 notes
 - Mesurer temps search <150ms
 - Vérifier pas de freeze main thread >100ms
 
 - Créer 
e2e/graph-interaction.spec.ts:- Cliquer node graph
 - Mesurer temps avant sélection <100ms
 
 - Ajouter fixtures vault de test (small/medium/large)
 - Intégrer dans CI
 
Critères d'acceptation:
- ✅ Tests passent avec vault 500 notes
 - ✅ Fail si search >150ms P95
 - ✅ CI exécute E2E avant merge
 
Estimation: 2.5 jours
🟢 P2 — MEDIUM (3-5 jours, nice-to-have)
15. [P2] Lazy routes Angular pour code-splitting
ICE: 5/7/4 = 8.75
Pourquoi: Bundle monolithique, tout chargé au boot. Lazy routes réduit initial bundle de 40%.
Étapes concrètes:
- Créer routes avec 
loadComponent:{ path: 'graph', loadComponent: () => import('./graph/...') } - Séparer features: graph, calendar, bookmarks en chunks
 - Preload strategy: 
PreloadAllModulesou custom - Mesurer impact avec webpack-bundle-analyzer
 
Critères d'acceptation:
- ✅ Initial bundle <800KB (vs 1.5MB)
 - ✅ Routes chargent <300ms
 - ✅ Pas de flash of content
 
Estimation: 3 jours
16. [P2] Memoization fine du computed graphData
ICE: 4/8/2 = 16.0
Pourquoi: graphData recalcule O(N×M) à chaque mutation de allNotes(), même si notes non liées changent.
Étapes concrètes:
- Comparer hash du tableau notes (shallow equality)
 - Ajouter cache Map<notesHash, GraphData>
 - Retourner cached si hash identique
 - Logger cache hit/miss
 
Critères d'acceptation:
- ✅ Édition note sans liens: pas de recalcul graph
 - ✅ Cache hit rate >80%
 
Estimation: 1.5 jour
17. [P2] Valider markdown-it-attrs avec whitelist stricte
ICE: 4/7/1 = 28.0
Pourquoi: {.class} syntax peut injecter classes malveillantes, risque XSS edge case.
Étapes concrètes:
- Configurer 
allowedAttributeswhitelist stricte:allowedAttributes: ['id', 'class'], allowedClasses: ['callout', 'md-*', 'hljs-*'] - Tester avec payloads injection
 - Documenter classes autorisées
 
Critères d'acceptation:
- ✅ 
{.malicious-script}rejeté - ✅ Classes légitimes passent
 
Estimation: 0.5 jour
18. [P2] Progressive rendering pour longues listes (tags, files)
ICE: 4/6/3 = 8.0
Pourquoi: Liste 1000 tags freeze 200ms au render. Progressive rendering (batch 50/frame) fluide.
Étapes concrètes:
- Wrapper liste dans composant custom avec rendering batched
 - Utiliser 
requestIdleCallbackpour render par chunks - Afficher skeleton pendant batching
 
Critères d'acceptation:
- ✅ 1000 tags rendus sans freeze perceptible
 - ✅ Interaction possible pendant rendering
 
Estimation: 2 jours
19. [P2] IndexedDB cache pour métadonnées vault
ICE: 4/6/4 = 6.0
Pourquoi: Rechargement vault requête complète /api/vault, lent sur >500 notes. Cache IDB réduit à delta.
Étapes concrètes:
- Créer 
VaultCacheServiceavec Dexie.js - Persister notes + timestamps dans IDB
 /api/vault?since=<timestamp>pour delta uniquement- Merger delta avec cache local
 
Critères d'acceptation:
- ✅ Rechargement vault: <500ms avec cache (vs 2s)
 - ✅ Sync delta fonctionne
 
Estimation: 3 jours
20. [P2] Monitoring OpenTelemetry (optionnel)
ICE: 3/5/5 = 3.0
Pourquoi: Observabilité production, traces distribuées. Coût setup élevé vs bénéfice pour petit projet.
Étapes concrètes:
- Installer 
@opentelemetry/sdk-node - Instrumenter Express avec auto-instrumentation
 - Exporter traces vers Jaeger/Zipkin
 - Ajouter spans custom pour opérations longues
 
Critères d'acceptation:
- ✅ Traces visibles dans Jaeger
 - ✅ P95 latency API <200ms
 
Estimation: 4 jours
Total items: 20 (10 P0, 7 P1, 3 P2)
Total effort estimé: ~48 jours (10 semaines avec 1 dev)