# ObsiGate — Roadmap > **Version :** 2.0.0-dev | **Dernière mise à jour :** 2026-06-18 > Voir aussi [CHANGELOG.md](./CHANGELOG.md), [AUDIT_TECHNIQUE.md](./docs/AUDIT_TECHNIQUE_2026-05-27.md) --- ## Légende | Icône | Signification | |---|---| | ✅ | Terminé | | 🔵 | En cours | | ⚪ | Prévu / Backlog | | 🔴 Impact | Critique / Bloquant | | 🟡 Impact | Utile / Attendu | | 🟢 Impact | Nice-to-have / Confort | --- ## ✅ Complété (v1.0.0 → v2.0.0-dev) ### Fondations (v1.0.0 → v1.4.0) | # | Feature | Effort | Impact | |---|---|---|---| | 1 | FastAPI backend — CRUD fichiers, vaults, recherche full-text | 5j | 🔴 | | 2 | Moteur TF-IDF + stemming français (`snowballstemmer`) | 2j | 🔴 | | 3 | Watchdog — indexation temps réel avec debounce | 1j | 🟡 | | 4 | Interface SPA vanilla JS — sidebar, viewer, éditeur CodeMirror | 8j | 🔴 | | 5 | Sécurité : JWT + Argon2id, rate limiting, audit log, CSP headers | 3j | 🔴 | | 6 | Protection path traversal, utilisateur non-root Docker | 0.5j | 🔴 | | 7 | Compression GZip SSE-safe, Cache-Control immutable | 0.5j | 🟢 | | 8 | PWA : manifest, service worker, mode standalone | 1j | 🟡 | ### UX & Productivité (v1.5.0 → v1.6.0) | # | Feature | Effort | Impact | |---|---|---|---| | 9 | Publication publique de documents (lien partageable, token) | 1j | 🟡 | | 10 | Webhooks HTTP avec signature HMAC-SHA256 | 1j | 🟡 | | 11 | Dashboard statistiques (fichiers, tags, taille, vaults) | 0.5j | 🟡 | | 12 | Gestion des conflits Syncthing | 0.5j | 🟢 | | 13 | Index inversé incrémental (hook pattern) | 1j | 🟡 | | 14 | Backlinks panel dans le viewer | 0.5j | 🟡 | | 15 | Fichiers non-supportés → UI download | 0.3j | 🟢 | | 16 | Redaction de secrets (`secret_redactor.py`) | 0.5j | 🟡 | | 17 | Backup automatique avant écriture, restauration | 1j | 🟡 | | 18 | Vue graphe — Barnes-Hut, focus, plein écran, export PNG | 3j | 🟡 | | 19 | Header flat design, sticky panels, navigation historique ← → ↑ | 1j | 🟢 | | 20 | Ctrl+survol → aperçu contenu formaté | 0.5j | 🟢 | ### Architecture (v1.5.1) | # | Feature | Effort | Impact | |---|---|---|---| | 21 | Split `app.js` (8 875 lignes) → 16 modules ES | 3j | 🔴 | | 22 | Validateur imports/exports CI + tests unitaires frontend Node.js | 0.5j | 🟡 | ### CI/CD & Qualité (v1.6.0) | # | Feature | Effort | Impact | |---|---|---|---| | 23 | Pipeline Gitea Actions : lint → test → security → build | 1j | 🔴 | | 24 | Ruff (0 erreur) + Mypy (0 erreur) + Bandit SAST + Pip-audit | 0.5j | 🟡 | | 25 | Pytest : 285 tests, 63% coverage | 3j | 🔴 | ### AI Editor (v1.7.0) | # | Feature | Effort | Impact | |---|---|---|---| | 26 | Toolbar : Edit, Tone, Translate, Generate, Rewrite, Toolbox | 2j | 🟡 | | 27 | Multi-provider : DeepSeek, OpenRouter, Gemini | 1j | 🟡 | | 28 | 16 endpoints REST `/api/ai/{action}` + backend `ai.py` / `ai_routes.py` | 2j | 🟡 | | 29 | Auto-save silencieux (2s debounce), loading toasts | 0.5j | 🟢 | ### Fonctionnalités avancées (v1.8.0 → v1.9.0) | # | Feature | Effort | Impact | |---|---|---|---| | 30 | Export PDF via WeasyPrint (endpoint API + lien share public) | 1j | 🟡 | | 31 | Palette de commandes `Ctrl+Alt+Space` | 1j | 🟡 | | 32 | Barre d'outils mobile + palette fichiers/commandes 📱 | 1j | 🟡 | | 33 | Drag & drop de fichiers | 1j | 🟡 | | 34 | Filtres recherche avancés : `created:`, `modified:`, `size:` | 0.5j | 🟡 | | 35 | Fichiers récents par vault | 0.5j | 🟡 | | 36 | Indicateur AI Actif (header + toast) | 0.3j | 🟢 | | 37 | Page d'accueil de vault (liste récursive par date, style recherche) | 0.5j | 🟡 | | 38 | Indexation non-bloquante (background thread) | 0.5j | 🟡 | | 39 | Git tags semver (v1.8.0, v1.9.0) | 0.2j | 🟢 | ### Gestion des Backups (v1.9.0) | # | Feature | Effort | Impact | |---|---|---|---| | 40 | Diff viewer : unifié + côte à côte, restauration depuis backup | 1j | 🟡 | | 41 | Gestionnaire de backups : page complète, filtre, suppression, purge | 1.5j | 🟡 | | 42 | Purge par vault avec confirmation, preview contenu (100 Ko) | 0.5j | 🟡 | | 43 | Compression gzip des vieux backups (niveau 6) | 0.5j | 🟢 | | 44 | Backup automatique périodique (`POST /api/backups/auto`) | 1j | 🟡 | | 45 | Restauration depuis le gestionnaire (extraction timestamp, confirmation) | 0.5j | 🟡 | | 46 | Auto-nettoyage : `max_backups_per_file` (défaut 10) | 0.5j | 🟡 | ### Mermaid.js (v2.0.0-dev) | # | Feature | Effort | Impact | |---|---|---|---| | 47 | CDN mermaid@11, `securityLevel: strict`, `startOnLoad: false` | 0.5j | 🟡 | | 48 | `renderMermaidBlocks()` — parse, rendu SVG, bloc d'erreur stylisé | 1j | 🟡 | | 49 | 22 templates (flowchart → sankey-beta) | 0.5j | 🟡 | | 50 | Live preview dans l'éditeur (debounce 500ms, panneau `#mermaid-live-preview`) | 1j | 🟡 | | 51 | Thème dark/light synchronisé, export SVG + PNG | 1j | 🟡 | | 52 | Rendu inline dans le viewer Markdown | 0.5j | 🟡 | | 53 | Zoom molette + drag + boutons +/- | 0.5j | 🟢 | | 54 | Mode plein écran avec header bar (icônes zoom, copy, download, close) | 0.5j | 🟢 | | 55 | Focus mode — clic diagramme → panneau latéral 480px | 0.3j | 🟡 | | 56 | Pré-processeur Obsidian (`[[liens]]`, `![[img]]`, `==highlight==`) | 0.3j | 🟡 | | 57 | Header bar : type de diagramme + toggle Code/Preview + copy SVG + download PNG | 1j | 🟡 | --- ## 🔵 En cours (P1) ### 58. Tests E2E Playwright ✅ FAIT - **Effort :** 2-3 jours | **Impact :** 🔴 - **Description :** Tests navigateur automatisés pour les flows critiques : login, navigation vault, recherche full-text, ouverture/édition/sauvegarde de fichier, rendu Mermaid, export PDF. - **Implémentation :** 44 tests Playwright (chromium-desktop) + 12 tests mobile dans `tests/e2e/obsigate.spec.ts`. Intégré au CI Gitea (job `e2e` après `build`). - **Sous-tâches :** - [x] Installation Playwright + config (`playwright.config.ts`) - [x] Fixtures : vault de test (utilise les vaults Docker existants) - [x] Test : dashboard → stats, tabs, Quick Help, sidebar - [x] Test : recherche full-text → résultats, snippets, tri pertinence/date - [x] Test : ouverture fichier → viewer Markdown, métadonnées - [x] Test : éditeur → Forge, basic modal, Ctrl+S - [x] Test : rendu Mermaid dans le viewer + preview Forge - [x] Test : export PDF → bouton présent - [x] Test : mode sombre → toggle, persistence localStorage - [x] Test : responsive mobile → layout, recherche, barre flottante - [x] Test : barre flottante résultats → compteur, nav, toggles Aa/wd - [x] Test : sauvegardes → filtres Tous/Recherches/Répertoires - [x] Test : raccourcis clavier → Ctrl+K, /, Escape - [x] Test : menu contextuel répertoire - [x] Intégration CI : job `e2e` dans `.gitea/workflows/ci.yml` --- ## ⚪ Backlog — Priorité 3 (P3) ### 59. Mode hors-ligne PWA complet ✅ FAIT - **Effort :** 3-4 jours | **Impact :** 🟡 - **Description :** Service worker avancé avec IndexedDB pour permettre la navigation et la recherche en mode hors-ligne, avec file de synchronisation au retour réseau. - **Implémentation :** `offline-db.js` (377 lignes) + `offline.js` (209 lignes). IndexedDB 3 stores (files, content, pending). Badge hors-ligne dans le header. Modale résolution de conflits. - **Sous-tâches :** - [x] IndexedDB : stockage local de l'index des fichiers (paths, titles, tags) - [x] Moteur de recherche offline via IndexedDB (cursor + filtre) - [x] Cache des fichiers markdown récemment ouverts (derniers 50, prune) - [x] Stratégie de cache : Network First avec fallback IndexedDB - [x] File de synchronisation : modifications offline → appliquées au retour réseau - [x] UI indicateur : badge « Hors-ligne » + compteur de modifications en attente - [x] Gestion des conflits : détection et résolution manuelle (choix version locale vs serveur) ### 61. Plugins système — Extensions utilisateur - **Effort :** 4-5 jours | **Impact :** 🟢 - **Description :** Système de plugins permettant aux utilisateurs d'étendre ObsiGate avec des renderers personnalisés, des opérateurs de recherche, et des hooks d'UI. Inspiré du modèle de plugins Obsidian. - **Sous-tâches :** - [ ] Spécification du format de plugin : `plugin.json` (name, version, hooks, permissions) - [ ] API de hooks : `onFileRender`, `onSearchFilter`, `onEditorAction`, `onSidebarItem` - [ ] Sandbox d'exécution : Web Worker isolé pour le code plugin - [ ] UI : page « Plugins » dans les paramètres (installer, activer/désactiver, désinstaller) - [ ] Distribution : dépôt de plugins communautaire (fichier JSON index) - [ ] Hot-reload : activation/désactivation sans rechargement de page - [ ] Sécurité : manifest de permissions, validation de signature, CSP restrictif ### 62. Collaboration temps réel — Édition simultanée - **Effort :** 5-7 jours | **Impact :** 🟢 - **Description :** Permettre à plusieurs utilisateurs d'éditer le même document markdown en même temps, comme Google Docs. Chaque personne voit en temps réel ce que les autres tapent, avec leur curseur affiché en couleur. - **WebSocket** : connexion persistante bidirectionnelle entre le navigateur et le serveur. Contrairement à HTTP où le client doit constamment demander « y a-t-il du nouveau ? » (polling), le WebSocket permet au serveur de pousser les changements instantanément. Une room WebSocket est créée par fichier ouvert — tous les utilisateurs qui éditent le même fichier rejoignent la même room. - **Yjs + CRDT** : Yjs est une bibliothèque qui implémente un algorithme CRDT (Conflict-free Replicated Data Type). Imagine deux personnes qui tapent en même temps au même endroit — sans CRDT, on aurait un conflit et du texte perdu. Avec CRDT, les deux modifications sont fusionnées mathématiquement sans perte. Chaque caractère reçoit un identifiant unique, et l'ordre final est déterministe même si les opérations arrivent dans le désordre. Pas besoin de verrouiller le fichier ni de résoudre des conflits manuellement. - **Awareness** : chaque utilisateur voit le curseur des autres (position, sélection) représenté par un nom et une couleur. Un indicateur dans la barre d'outils montre qui est connecté. - **Persistance** : le serveur sauvegarde périodiquement le document (debounce 2s après la dernière modification) pour que les changements survivent à une déconnexion. - **Pourquoi c'est important :** Permet le travail d'équipe sur la documentation, les notes de réunion, les spécifications techniques, les brainstorms. C'est le passage d'ObsiGate de « outil personnel » à « outil d'équipe ». - **Sous-tâches :** - [ ] Serveur WebSocket : endpoint `/ws/collab/{vault}/{path}` avec gestion des rooms - [ ] Intégration Yjs : `Y.Doc` partagé, `Y.Text` pour le contenu markdown - [ ] Awareness : curseurs colorés par utilisateur, sélections visibles - [ ] Synchro backend : persistance périodique du document (debounce 2s) - [ ] Gestion des droits : vérification `check_vault_access` par connexion WS - [ ] UI : indicateur de présence (avatars dans la barre d'outils éditeur) - [ ] UI : curseurs distants dans CodeMirror (extension collaborative) - [ ] Gestion des déconnexions : reconnexion automatique, merge state au retour - [ ] Tests de charge : 5+ utilisateurs simultanés sur le même fichier ### 63. Internationalisation (i18n) — Multilingue - **Effort :** 2-3 jours | **Impact :** 🟡 | **Statut :** ✅ Terminé - **Description :** Support de l'anglais et du français via un système de clés de traduction. - **Sous-tâches :** - [x] Extraction des chaînes : ~1200 clés UI extraites - [x] Format : JSON `fr.json` + `en.json` dans `frontend/locales/` → 1206 clés parfaitement synchronisées - [x] Fonction `t(key)` → `frontend/js/i18n.js` avec `_applyDOM()`, `data-i18n`, `data-i18n-attr`, `data-i18n-placeholder`, `data-i18n-html`, support des templates `{var}` - [x] Sélecteur de langue dans les paramètres (persisté localStorage `obsigate-lang`) - [x] Traduction des messages backend → les toast/showToast sont maintenant i18n dans tous les fichiers JS - [x] Documentation multilingue → `README.md` + `README.fr.md` - [x] Nettoyage des clés inutilisées → locales nettoyées - [x] Tous les fichiers JS utilisent `t()` → plus de texte FR en dur (ai.js, sync.js, graph.js, autocomplete.js) - [x] Interface principale : dashboard, sidebar, editor, search, settings → EN/FR complet - [x] Guide d'utilisation : 18 sections (Intro → Astuces) → tous les paragraphes traduits - [x] Thèmes, palette de commandes, raccourcis, webhooks → EN/FR complet - [x] Messages système : toasts, statuts, événements → EN/FR complet ### 64. MFA — Authentification multi-facteurs ✅ FAIT - **Effort :** 2 jours (réalisé) | **Impact :** 🟡 - **Description :** Ajout d'un second facteur d'authentification obligatoire pour les comptes administrateur. Deux méthodes sont proposées : - **TOTP** (Time-based One-Time Password) : l'utilisateur scanne un QR code avec son app d'authentification (Google Authenticator, Authy, Bitwarden) qui génère un code à 6 chiffres renouvelé toutes les 30 secondes. Au login, après avoir saisi son mot de passe, l'utilisateur doit entrer le code affiché sur son téléphone. Même si le mot de passe est volé, le compte reste protégé car l'attaquant n'a pas le téléphone. - **WebAuthn** (clés de sécurité physiques) : l'utilisateur enregistre une clé USB (YubiKey, SoloKey) ou utilise la biométrie de son appareil (empreinte digitale, Face ID, Windows Hello). Au login, le navigateur demande de toucher la clé physique ou de scanner le doigt. C'est le niveau de sécurité le plus élevé — résistant au phishing car la clé vérifie le domaine du site avant de répondre. - **Codes de secours** : 8 codes à usage unique imprimables, à conserver en lieu sûr, qui permettent de se connecter même si on perd son téléphone ou sa clé. Chaque code ne fonctionne qu'une seule fois. - **Pourquoi c'est important :** Le vol de mot de passe est la cause #1 de brèches de sécurité. Avec un vault Obsidian contenant des notes personnelles, projets sensibles, secrets et tokens API, l'authentification par simple mot de passe n'est plus suffisante. Le MFA empêche 99.9% des attaques de prise de compte automatisées (source : Microsoft Security). - **Sous-tâches :** - [ ] TOTP : génération de secret, QR code, vérification code 6 chiffres - [ ] WebAuthn : enregistrement de clé, assertion, attestation - [ ] UI : page « Sécurité du compte » avec activation/désactivation MFA - [x] Flow login : mot de passe → challenge TOTP si activé - [ ] Recovery codes : 8 codes de backup à usage unique - [x] Stockage : totp_secret + `webauthn_credential_id` dans `users.json` ### 65. Thèmes personnalisés — CSS variables ✅ FAIT - **Effort :** 1-2 jours (réalisé) | **Impact :** 🟢 - **Description :** Exposition de variables CSS pour permettre aux utilisateurs de créer des thèmes personnalisés. Presets inclus : light, dark, high-contrast, sepia. - **Sous-tâches :** - [x] Audit des variables CSS existantes → 40+ variables - [x] Presets: light, dark, high-contrast, sepia (générés dynamiquement) - [x] UI : sélecteur de thème dans les paramètres (swatches grid) - [x] Import/export de thème personnalisé (JSON) - [x] Application dynamique via document.documentElement.style.setProperty ### 66. Export multi-formats ✅ FAIT - **Effort :** 1-2 jours (réalisé) | **Impact :** 🟢 - **Description :** Export de notes individuelles ou de vaults entiers en HTML standalone, bundle Markdown (.zip), et ePub pour liseuses. - **Sous-tâches :** - [x] Export HTML standalone : CSS inliné, images en base64, navigation inter-fichiers - [x] Export MD bundle : ZIP du vault avec structure préservée - [x] Export ePub : conversion markdown → ePub (zipfile + mistune, 0 nouvelle dep) - [x] UI : dropdown Export dans toolbar viewer (HTML / MD bundle / ePub) - [x] Endpoints : `GET /api/export/html`, `GET /api/export/md-bundle`, `GET /api/export/epub` ### 74. Support complet des documents PDF — ✅ Pratiquement complet - **Effort :** 4-5 jours | **Impact :** 🟡 | **Statut :** ✅ FAIT (sauf C3 pdf/info endpoint) - **Description :** Prise en charge native des fichiers PDF dans ObsiGate avec parité fonctionnelle complète avec les documents Markdown : apparition dans l'arborescence, indexation full-text, visualisation inline dans le navigateur, recherche TF-IDF, et téléchargement. - **Implémentation réelle (vérifiée) :** - Backend `backend/pdf_reader.py` (existant) — extraction pypdf + pymupdf (fallback), métadonnées, TOC - `backend/indexer.py` — `.pdf` dans SUPPORTED_EXTENSIONS, extraction dans `index_document()` - `backend/main.py` — flag `is_pdf: True` retourné par `api_file_view`, endpoint `GET /api/file/{vault}/pdf/stream` avec support Range/206 - `backend/search.py` — filtre `ext:pdf` (déjà implémenté avant cette PR) - `frontend/js/viewer.js:451-480` — branche `if (data.is_pdf)` + iframe + toolbar + TOC + bouton download - **Tests :** `tests/test_pdf.py` (13 tests, 100% verts) — text/metadata/TOC + edge cases + indexation + filtre - **Bug fixé dans cette PR :** `PdfReader` NameError dans `pdf_reader.py` quand pymupdf est installé (la variable `PdfReader` n'était déclarée que dans la branche `except ImportError`) - `backend/requirements-test.txt` (nouveau) — `reportlab` pour générer des PDFs de test - **Sous-tâches :** ##### A. Backend — Extraction de texte PDF (1-1.5 jour) - [ ] **A1. Dépendance** : Ajouter `pymupdf` (PyMuPDF/fitz) à `requirements.txt` — bibliothèque C performante avec extraction texte + métadonnées, déjà compatible avec l'image Docker (libs système GTK/Pango déjà présentes pour WeasyPrint). Alternative légère : `pypdf` (pure Python, pas de deps système) si pymupdf pose problème. - [ ] **A2. Module `backend/pdf_reader.py`** : Créer un module dédié avec les fonctions : - `extract_pdf_text(file_path: Path) -> str` : extrait tout le texte du PDF, page par page, avec séparateur `\f` entre pages. Gère les PDF encodés, protégés par mot de passe (retourne erreur explicite), et corrompus. - `extract_pdf_metadata(file_path: Path) -> dict` : extrait titre, auteur, sujet, nombre de pages, taille. - `extract_pdf_preview(file_path: Path, max_chars: int = 100000) -> str` : extrait les N premiers caractères pour l'indexation (limité par `SEARCH_CONTENT_LIMIT`). - [ ] **A3. Fallback pypdf** : Si pymupdf non disponible (exception d'import), fallback automatique sur `pypdf` avec un log warning. Code structuré avec une interface abstraite (`PdfReader` protocol) pour swap transparent. ##### B. Backend — Indexation des PDF (1 jour) - [ ] **B1. Ajout à `SUPPORTED_EXTENSIONS`** : Ajouter `.pdf` au set dans `backend/indexer.py:56`. Déclencher un rebuild complet de l'index (incrémental via le file watcher pour les nouveaux PDFs). - [ ] **B2. Modification de `index_document()`** (`backend/indexer.py:524`) : Dans la fonction d'indexation, détecter l'extension `.pdf` et appeler `extract_pdf_text()` au lieu de `read_text()`. Le texte extrait alimente le pipeline TF-IDF existant — aucun changement nécessaire dans `search.py`. - [ ] **B3. Métadonnées PDF dans le document info** : Enrichir la structure de retour de `index_document()` avec les champs spécifiques PDF : `page_count`, `pdf_title` (titre extrait des métadonnées, prioritaire sur le nom de fichier), `pdf_author`. - [ ] **B4. Gestion d'erreur robuste** : PDF corrompu → log warning + skip (ne pas bloquer l'indexation). PDF volumineux (>50 Mo) → log info + extraction tronquée à `SEARCH_CONTENT_LIMIT`. Timeout d'extraction configurable (30s par défaut). ##### C. Backend — API endpoints PDF (0.5 jour) - [ ] **C1. Modification de `api_file_view()`** (`backend/main.py:2270`) : Avant la tentative de `read_text()`, détecter `.pdf` par extension. Pour les PDF : - Extraire le texte avec `extract_pdf_text()` - Extraire les métadonnées (pages, auteur) - Retourner une réponse structurée : `is_pdf: true`, `page_count`, `pdf_metadata`, `html` (aperçu texte formaté), `raw_length` - Le champ `html` contient un rendu texte simple (pas de markdown) : texte paginé ou première page formatée - [ ] **C2. Nouvel endpoint `GET /api/file/{vault}/pdf/stream`** : Sert le fichier PDF brut avec `Content-Type: application/pdf` et `Content-Disposition: inline` pour visualisation dans le navigateur. Supporte le `Range` header (HTTP 206 Partial Content) pour le streaming progressif des gros PDFs — essentiel pour la performance sur des documents volumineux. - [ ] **C3. Nouvel endpoint `GET /api/file/{vault}/pdf/info`** : Retourne les métadonnées seules (pages, titre, auteur) sans le contenu — permet à l'UI d'afficher les infos avant de charger le PDF lourd. - [ ] **C4. Endpoint download** : Déjà fonctionnel (`/api/file/{vault}/download`) — aucun changement nécessaire. ##### D. Frontend — Arborescence de fichiers (0.5 jour) - [ ] **D1. Icône et filtre** : L'icône PDF (`file-text` de Lucide) est déjà mappée dans `EXT_ICONS` (`frontend/js/utils.js:129`). Une fois `.pdf` dans `SUPPORTED_EXTENSIONS`, les PDFs apparaissent automatiquement dans l'arborescence via l'API `list_directory`. Aucun changement UI nécessaire. - [ ] **D2. Distinction visuelle** (optionnel) : Sous-titre léger sous le nom du fichier dans l'arborescence indiquant le nombre de pages (ex: « 12 pages ») pour différencier rapidement les PDF des MD. Donnée disponible via l'API `pdf/info`. - [ ] **D3. Drag & drop et upload** : Le mécanisme d'upload existant (`POST /api/file/{vault}/upload`) fonctionne déjà pour tout type de fichier. Vérifier que le MIME type `application/pdf` est correctement détecté et que le watcher réindexe automatiquement. ##### E. Frontend — Viewer PDF (1 jour) - [ ] **E1. Rendu inline natif** : Utiliser le visualiseur PDF intégré du navigateur via `