- #108: images parity — tree + indexing (never read bytes into TF-IDF), fix broken standalone viewer (img src points to JSON /raw instead of /api/image), zoom/pan viewer, thumbnails, SVG sandbox hardening - #109: audio/video — HTML5 players, shared media streaming endpoint with Range/206 (extract helper from existing pdf/stream), codec fallback UI, PWA/mobile notes - Update effort summary (8 items, ~28-43 days)
313 lines
30 KiB
Markdown
313 lines
30 KiB
Markdown
# ObsiGate — Roadmap
|
||
|
||
> **Version :** 2.16.6 | **Dernière mise à jour :** 2026-09-22
|
||
> **Ce fichier ne contient que le travail à venir** (🔵 En cours + ⚪ Backlog) et un index compact
|
||
> vers les fonctionnalités livrées.
|
||
> - **Méthode de livraison à appliquer pour toute tâche : [DELIVERY_WORKFLOW.md](./DELIVERY_WORKFLOW.md)**
|
||
> - Historique des versions : [CHANGELOG.md](../CHANGELOG.md)
|
||
> - Détail des fonctionnalités livrées : [docs/archive/COMPLETED_v1-v2.md](./archive/COMPLETED_v1-v2.md)
|
||
> - Fiches détaillées par feature : [docs/features/](./features/)
|
||
> - Bugs / TODO : [ISSUES_TODOLIST.md](./ISSUES_TODOLIST.md)
|
||
|
||
---
|
||
|
||
## Légende
|
||
|
||
| Icône | Signification |
|
||
|---|---|
|
||
| ✅ | Terminé |
|
||
| 🔵 | En cours |
|
||
| ⚪ | Prévu / Backlog |
|
||
| 🔴 Impact | Critique / Bloquant |
|
||
| 🟡 Impact | Utile / Attendu |
|
||
| 🟢 Impact | Nice-to-have / Confort |
|
||
|
||
> **Convention :** chaque item porte un **ID stable `#NN`** (clé de jointure entre roadmap,
|
||
> changelog et commits). Une fonctionnalité livrée sort de ce fichier et entre dans l'index
|
||
> « Complété » ci-dessous, avec son détail dans `docs/features/` ou l'archive.
|
||
|
||
---
|
||
|
||
## 🔵 En cours
|
||
|
||
### 77. Application Desktop native — Tauri (Windows / Linux / macOS)
|
||
|
||
- **Effort :** 8-12 jours | **Impact :** 🟡 | **Framework :** Tauri v2 (Rust + Webview)
|
||
- **Statut :** livré (A→F) — projet Tauri, backend Python embarqué, fonctionnalités natives, jumplist vaults, bannière 1er lancement, build CI, UX, 24 tests Rust. Détail complet : [features/desktop-tauri.md](./features/desktop-tauri.md)
|
||
- **Reste à faire :**
|
||
- [x] **Signature de l'updater Tauri** (gratuit) : paire de clés générée, `pubkey` renseignée, `createUpdaterArtifacts` activé, secrets CI câblés
|
||
- [x] **Manifeste `latest.json`** généré par `scripts/updater_manifest.py` (intégré à `publish_release.py`), endpoint updater pointé sur `main`
|
||
- [ ] **Signature de code Windows** : non retenue (pas de certificat) — alternatives : livrer non signé, SignPath.io (OSS gratuit), Certum OSS, Azure Trusted Signing, certificat EV
|
||
- [ ] Exécuter les 6 tests E2E **manuels** — protocole documenté : [DESKTOP_E2E_CHECKLIST.md](./DESKTOP_E2E_CHECKLIST.md)
|
||
|
||
---
|
||
|
||
## ⚪ Backlog — Priorité 4 (P4)
|
||
|
||
### 73. Synchronisation multi-appareils — Obsidian Sync compatible
|
||
|
||
- **Effort :** 6-8 jours | **Impact :** 🟢
|
||
- **Description :** Synchronisation des vaults entre plusieurs instances d'ObsiGate via un protocole de synchronisation décentralisé ou compatible Obsidian Sync. Alternative self-hosted à Obsidian Sync.
|
||
- **Sous-tâches :**
|
||
- [ ] Protocole : évaluation CRDT vs OT vs diff/patch pour fichiers markdown
|
||
- [ ] Transport : WebSocket ou polling HTTPS avec compression
|
||
- [ ] Merge strategy : LWW (Last Writer Wins) avec historique des deux versions
|
||
- [ ] Détection de changements : hash SHA-256 par fichier, journal des modifications
|
||
- [ ] UI : page « Synchronisation » avec statut par appareil, historique des syncs
|
||
- [ ] Conflits : UI de résolution manuelle (diff côte à côte entre version locale et distante)
|
||
- [ ] Chiffrement : optionnel, chiffrement AES-256-GCM avant transmission
|
||
- [ ] Pairing : échange de clé publique + code QR pour appairage des appareils
|
||
|
||
---
|
||
|
||
## ⚪ Backlog — Priorité 2 (P2)
|
||
|
||
### 83. Barre d'outils d'édition mobile — style Obsidian Android
|
||
|
||
- **Effort :** 3-5 jours | **Impact :** 🟡 | **Zone :** frontend (mobile)
|
||
- **Statut :** ✅ livré — ruban horizontal défilable ancré au-dessus du clavier, commandes étendues et personnalisation persistée. Détail : [archive/COMPLETED_v1-v2.md](./archive/COMPLETED_v1-v2.md) (section #83).
|
||
- **Description :** remplacer la barre de mise en forme Markdown actuelle par un **ruban horizontal
|
||
défilable** ancré juste au-dessus du clavier virtuel, reprenant l'ergonomie de l'app Android
|
||
Obsidian : fond anthracite aux coins arrondis, insertion/enrobage de la syntaxe au curseur ou sur
|
||
la sélection, et personnalisation des commandes via une icône clé à molette.
|
||
- **Sous-tâches :**
|
||
- [x] Ruban horizontal défilable (glissement tactile gauche/droite) ancré au-dessus du clavier
|
||
- [x] Actions rapides : annuler, refaire, `[[ ]]` (lien interne), modèle/fichiers, tag `#`, pièce jointe
|
||
- [x] Formatage : H1–H6, gras, italique, barré (`~~`), surligné (`==`), code en ligne/bloc, citation (`>`)
|
||
- [x] Liens externes, listes à puces/numérotées, case à cocher (`- [ ]`), indenter / désindenter
|
||
- [x] Personnalisation (clé à molette) : ajouter / supprimer / réordonner les commandes
|
||
- [x] i18n FR/EN + tests frontend (helpers purs) + E2E mobile
|
||
|
||
---
|
||
|
||
## ⚪ Backlog — Média (images, audio, vidéo)
|
||
|
||
### 108. Support complet des images — arborescence, visionneuse, indexation
|
||
|
||
- **Effort :** 3-4 jours | **Impact :** 🟡 | **Zone :** backend (indexer, main) + frontend (viewer, utils)
|
||
- **Statut :** ⚪ Prévu
|
||
- **Description :** parité fonctionnelle des images avec les autres fichiers du vault : apparition dans l'arborescence, ouverture directe dans une visionneuse dédiée (zoom molette, pan, navigation dossier), indexation (nom + métadonnées), miniatures. Actuellement seul l'affichage *inline* dans un document markdown (`![[image.png]]`) fonctionne ; l'image isolée est invisible dans l'arborescence et son affichage standalone est cassé.
|
||
- **Architecture actuelle (vérifiée sur `main` @ v2.16.6) :**
|
||
- `SUPPORTED_EXTENSIONS` (`backend/indexer.py:61`) : aucune extension image → images filtrées de l'arborescence et de l'index.
|
||
- `api_file_view()` (`backend/main.py:~2411`) : branche `IMAGE_EXTENSIONS` (`.png .jpg .jpeg .gif .svg .webp .bmp .ico`) qui retourne `is_image: true`, MAIS le `<img src>` généré pointe vers `/api/file/{vault}/raw?path=…` — un endpoint qui retourne du **JSON** (`FileRawResponse`, `main.py:1569`), pas des octets d'image. Affichage standalone cassé. Le frontend (`frontend/js/viewer.js:600`, branche `data.is_image`) reproduit la même URL cassée pour le bouton « Plein écran ».
|
||
- `/api/image/{vault}` (`backend/main.py:3160`) : endpoint existant et fonctionnel qui sert les octets avec le bon MIME type. C'est LUI que doivent utiliser le `<img>` backend et le frontend. L'auth navigateur fonctionne (middleware JWT avec fallback cookie `access_token`).
|
||
- `image_processor.py` + `attachment_indexer.py` : réécriture des 4 syntaxes Obsidian (`![[img]]`, ``…) vers `/api/image` avec résolution multi-stratégie → **l'inline markdown fonctionne déjà**, aucun changement requis.
|
||
- CSP : `img-src 'self' data: blob:` — compatible, rien à assouplir.
|
||
- **Sous-tâches :**
|
||
|
||
##### A. Backend — arborescence & indexation (1 j)
|
||
- [ ] **A1.** Créer `backend/media_types.py` : constantes partagées `IMAGE_EXTENSIONS`, `AUDIO_EXTENSIONS`, `VIDEO_EXTENSIONS` (réutilisées par #109) ; remplacer le set local de `api_file_view()`.
|
||
- [ ] **A2.** Intégrer les extensions images à `SUPPORTED_EXTENSIONS` (`indexer.py:61`) **avec branche binaire** : `index_document()` ne doit JAMAIS `read_text()`/`read_bytes()` une image — indexer nom/taille/mtime uniquement, `content: ""` pour que le TF-IDF reste propre.
|
||
- [ ] **A3.** Vérifier le reindex watchdog sur création/suppression d'image (même filtre d'extensions, couvert par A2).
|
||
- [ ] **A4.** Recherche : le nom de fichier est déjà indexé (`chatScreenshot.png` trouvable par « screenshot ») ; ajouter le filtre `ext:png`/`ext:jpg` (mécanisme des filtres `ext:` existants) ; comptabiliser les images à part dans les compteurs du dashboard (#11).
|
||
|
||
##### B. Backend — correction affichage standalone (0,5 j)
|
||
- [ ] **B1.** Fix `<img>` cassé : `api_file_view()` → `src="/api/image/{vault}?path=…"` (URL encodée) ; idem `viewer.js:600` (bouton Plein écran).
|
||
- [ ] **B2.** Métadonnées : dimensions via `<img onload>` frontend (`naturalWidth/naturalHeight` — gratuit, recommandé ; Pillow seulement si C1 est retenu).
|
||
- [ ] **B3.** Sécurité SVG : sur `/api/image`, ajouter `Content-Security-Policy: sandbox` (ou `Content-Disposition: attachment`) quand `ext == .svg` — un SVG ouvert directement dans un onglet exécute son JS (XSS same-origin) ; dans une balise `<img>` il est inoffensif.
|
||
|
||
##### C. Backend — miniatures (1 j, phase 2 tolérable)
|
||
- [ ] **C1.** Dépendance `pillow>=10.0` (wheels précompilés, rien de système dans `python:3.11-slim`).
|
||
- [ ] **C2.** `GET /api/media/{vault}/thumb` : miniature 256 px WebP, cache disque `/data/.obsigate-cache/thumbs/{sha1(path+mtime)}.webp` (invalidation naturelle par mtime). SVG : servir l'original. GIF animé : première frame.
|
||
- [ ] **C3.** Génération dans un thread pool (`run_in_executor`), fallback original si timeout 2 s.
|
||
|
||
##### D. Frontend — visionneuse (1 j)
|
||
- [ ] **D1.** `EXT_ICONS` (`frontend/js/utils.js`) : extensions images → icône Lucide `image`.
|
||
- [ ] **D2.** Visionneuse digne de ce nom dans `viewer.js` : image centrée `object-fit:contain`, **zoom molette (0,1×–8×), pan au drag, double-clic reset**, boutons +/−/reset, badge de zoom.
|
||
- [ ] **D3.** Navigation ←/→ entre images du même dossier (données `list_directory` déjà disponibles) ; bouton « Ouvrir original » (nouvel onglet, `/api/image`).
|
||
- [ ] **D4.** Barre d'outils : Télécharger (déjà fonctionnel), lightbox plein viewport (fond `rgba(0,0,0,.9)`), panneau métadonnées repliable (dimensions, taille, type, date).
|
||
- [ ] **D5.** (Optionnel 🟢) Vue galerie vignettes pour les dossiers d'images via `/api/media/thumb`, `loading="lazy"`.
|
||
- [ ] **D6.** Split View (#75) : rendu dans `getContentArea()` du panneau actif ; vérifier le cache d'onglets.
|
||
|
||
##### E. Tests (0,5 j)
|
||
- [ ] **E1.** `test_image_api.py` : `/api/image` octets + MIME ; SVG avec header sandbox ; `api_file_view` → `is_image: true` avec URL `/api/image` dans le html.
|
||
- [ ] **E2.** `test_image_indexing.py` : image visible dans `list_directory`, indexée avec contenu vide, watcher OK, rien de binaire dans le TF-IDF.
|
||
- [ ] **E3.** Playwright (#58) : clic sur une image de l'arborescence → visionneuse rendue ; zoom molette applique la transform.
|
||
|
||
- **Points d'attention / risques**
|
||
- **Ne jamais lire les octets dans l'indexeur** — dérive n°1 d'un A2 bâclé (UnicodeDecodeError de masse dans les logs, TF-IDF pollué).
|
||
- **`_attachments/`** : les vaults Obsidian réels contiennent des milliers d'images → vérifier la fluidité de l'arborescence et le coût du scan d'index.
|
||
- **HEIC (iPhone)** : non décodable par les navigateurs → hors scope v1, documenter la limitation ; `pillow-heif` en v2 si demande.
|
||
- **Parité Obsidian Desktop** : la visionneuse D2 doit atteindre le même confort zoom/pan, sinon l'utilisateur repart sur le desktop.
|
||
|
||
---
|
||
|
||
### 109. Support audio & vidéo — lecteurs intégrés HTML5
|
||
|
||
- **Effort :** 2-3 jours | **Impact :** 🟡 | **Zone :** backend (media streaming) + frontend (viewer)
|
||
- **Statut :** ⚪ Prévu — dépend du socle `media_types.py` de #108-A1
|
||
- **Description :** prise en charge des fichiers audio (`.mp3 .m4a .aac .wav .ogg .oga .opus .flac`) et vidéo (`.mp4 .webm .mov .m4v`) avec la même parité que les autres fichiers : apparition dans l'arborescence, indexation du nom, lecture directe dans le viewer via les balises HTML5 `<audio>` / `<video>`. Actuellement ces fichiers tombent dans le chemin binaire « Ce fichier est binaire et ne peut pas être affiché » + bouton download (`frontend/js/viewer.js:622`).
|
||
- **Choix technique — lecteurs HTML5 natifs, pas de transcodage :**
|
||
- `<video>`/`<audio>` sont natifs partout (Chrome, Firefox, Edge, Safari, mobile) : play, scrub, volume, vitesse 0,25–2×, PiP, plein écran — sans une ligne de JS de contrôle.
|
||
- **Zéro dépendance lourde** : pas de ffmpeg dans l'image Docker, pas de file de transcodage. Les formats web-natifs (MP4/H.264, WebM, MP3, AAC, Opus, FLAC, WAV) couvrent l'immense majorité des notes vocales et screencasts.
|
||
- Le vrai travail serveur est le **support HTTP `Range` / 206 Partial Content** : sans lui, pas de scrub (le navigateur retélécharge tout pour se positionner) et Safari refuse le MP4. Bonne nouvelle : `pdf/stream` (`backend/main.py:2617`) **implémente déjà les Range** (206, `Content-Range`, 416) — extraire cette logique en helper `stream_file_with_range(file_path, request, media_type)` et s'en servir pour les trois médias.
|
||
- Métadonnées (durée, résolution) lues **côté client** via `loadedmetadata` (`duration`, `videoWidth/videoHeight`) — aucun ffprobe serveur nécessaire.
|
||
- **Sous-tâches :**
|
||
|
||
##### A. Backend — socle média partagé (1 j) — bénéficie aussi à #74/#108
|
||
- [ ] **A1.** Ajouter `AUDIO_EXTENSIONS` / `VIDEO_EXTENSIONS` dans `backend/media_types.py` (#108-A1) et les intégrer à `SUPPORTED_EXTENSIONS` avec la branche « contenu non parsé » (#108-A2).
|
||
- [ ] **A2.** Extraire le helper Range de `pdf/stream` en fonction réutilisable ; nouvel endpoint `GET /api/media/{vault}?path=…` : streaming par chunks 64 ko (`aiofiles`), 206 + `Content-Range` + `Accept-Ranges`, 416 sur Range invalide, MIME via `mimetypes` + map de secours (`.m4a→audio/mp4`, `.opus→audio/ogg`, `.mov→video/quicktime`, `.m4v→video/mp4`).
|
||
- [ ] **A3.** Gardes-fous : `_resolve_safe_path`, `check_vault_access`, taille inline max `OBSIGATE_MEDIA_MAX_INLINE_MB` (défaut 500 — au-delà, UI download).
|
||
- [ ] **A4.** `api_file_view()` : branches AVANT le `read_text()` → `is_audio: true` / `is_video: true` (+ `size_bytes`, `stream_url` vers `/api/media`). `pdf/stream` bascule sur le helper A2 (comportement inchangé, tests de régression).
|
||
|
||
##### B. Frontend — lecteur audio (0,5 j)
|
||
- [ ] **B1.** Dispatch `data.is_audio` dans `viewer.js` : `<audio controls src=stream_url>` pleine largeur, artwork placeholder (icône Lucide `music`), titre + voûte + taille dans la toolbar, durée formatée via `loadedmetadata`.
|
||
- [ ] **B2.** `EXT_ICONS` : audio → Lucide `audio-lines` ; vidéo → `video`.
|
||
- [ ] **B3.** Pause au changement d'onglet (comportement fichier standard, cohérence #75) — pas de lecture persistante en v1.
|
||
|
||
##### C. Frontend — lecteur vidéo (0,5 j)
|
||
- [ ] **C1.** Dispatch `data.is_video` : `<video controls playsinline>` centré, `max-height: calc(100vh - header)`, fond noir, letterboxing.
|
||
- [ ] **C2.** Vérifier le bouton pop-out avec médias (médias same-origin, `X-Frame-Options: SAMEORIGIN` compatible).
|
||
- [ ] **C3.** Codec non supporté (`.mkv`, `.avi`, HEVC…) : sur l'événement `error` de l'élément média → remplacer le lecteur par l'UI binaire existante + message « Ce format ne peut pas être lu dans votre navigateur » + Télécharger / Ouvrir dans un nouvel onglet (le player OS prend le relais).
|
||
|
||
##### D. Recherche & intégrations (0,5 j)
|
||
- [ ] **D1.** Filtres `ext:mp3`, `ext:mp4`, etc. (mécanisme #108-A4).
|
||
- [ ] **D2.** Fichiers récents (#35) / dashboards : exclure les médias des previews de contenu (aucun texte).
|
||
- [ ] **D3.** BooksLM (#76) : exclure les médias du contexte collecté (pas de texte extractible).
|
||
- [ ] **D4.** (Hors scope, noter la porte) Transcription audio via Whisper sur le provider AI existant.
|
||
|
||
##### E. Mobile & PWA (0,25 j)
|
||
- [ ] **E1.** Tester le scrub sur iOS Safari (exige un Range strictement correct) et Android Chrome.
|
||
- [ ] **E2.** Service worker (#59) : exclure les médias du cache offline (taille), stratégie Network First inchangée pour le reste.
|
||
|
||
##### F. Tests (0,5 j)
|
||
- [ ] **F1.** `test_media_stream.py` : `bytes=0-1023` → 206 + Content-Range + 1024 octets ; Range hors borne → 416 ; sans Range → 200 + Accept-Ranges ; path traversal refusé ; voûte sans accès refusée. Régression : `pdf/stream` inchangé après extraction du helper.
|
||
- [ ] **F2.** `test_media_indexing.py` : un `.mp3` apparaît dans l'arborescence, indexé sans contenu, watcher sans erreur.
|
||
- [ ] **F3.** Playwright : fixtures binaires minimaux commités dans `tests/fixtures/` (mini `.mp3` sine wave ~2 ko, mini `.mp4`) → `<audio>` et `<video>` rendus.
|
||
|
||
- **Points d'attention / risques**
|
||
- **Range est LE prérequis** (sous-tâche la plus testée, pas une option) : sans 206 correct, Safari casse et le scrub hache la bande passante.
|
||
- **Formats hors web-natifs** (`.mkv`, `.avi`, HEVC, AC-4) : non lisibles sans transcodage (ffmpeg hors scope) — le fallback C3 les rend téléchargeables proprement au lieu de silencieusement cassés.
|
||
- **Poids disque** : une vidéo de 1 Go dans un vault ralentit les backups (#17, gzip) — envisager d'exclure les gros médias de la compression gzip.
|
||
- **Sous uvicorn (worker unique)** : lectures vidéo simultanées = file descriptors + bande passante ; surveiller via le health check enrichi (#68).
|
||
- **Hors scope v1** : HLS, sous-titres (`<track src=.vtt>`), thumbnails vidéo (première frame) — extensions naturelles documentées ici.
|
||
|
||
---
|
||
|
||
## ⚪ Backlog — Sécurité, architecture & performance (P0/P1)
|
||
|
||
### 84. Consolidation & sécurité — revue statique 2026-09-13 (phase 1)
|
||
|
||
- **Effort :** 6-9 jours | **Impact :** 🔴 | **Zone :** backend + frontend | **Référence :** [ISSUES_TODOLIST.md](./ISSUES_TODOLIST.md) BUG-021 → BUG-034
|
||
- **Statut :** 🟢 livré (phase 1) — sanitizer XSS, rate-limit/lockout MFA, isolation vaults, ReDoS, SSRF webhooks, cycle de vie des sessions, politique de mot de passe, verrous `users.json`, audits IP, rate-limit par compte, symlinks, recherche via inverted index, token en cookie HttpOnly. Détail : [archive/COMPLETED_v1-v2.md](./archive/COMPLETED_v1-v2.md) (section #84).
|
||
- **Description :** traiter toutes les vulnérabilités critiques et importantes issues de la revue statique : XSS markdown (`escape=False`) et page publique de partage, brute-force MFA, isolation des vaults (`resolve_safe_path`), ReDoS, SSRF webhooks, cycle de vie des sessions, politique de mot de passe, races `users.json`, audits IP, rate-limit partagé, indexation symlinks.
|
||
- **Sous-tâches :**
|
||
- [x] Assainir le rendu markdown (sanitizer serveur en whitelist) et la page de partage (échappement `title`/frontmatter) — *DOMPurify client non ajouté (défense en profondeur serveur suffisante)*
|
||
- [x] Rate-limit + lockout sur les endpoints MFA (`totp/verify`, `recovery`, `webauthn/verify`)
|
||
- [x] Corriger `resolve_safe_path` (comparaison de chemin stricte par segment) + test de régression
|
||
- [x] Rotation du refresh token, révocation de l'access token au logout, persistance des JTI révoqués
|
||
- [x] Valider la politique de mot de passe à la création ; bloquer le SSRF des webhooks et externaliser les secrets
|
||
- [x] Verrous sur les mutations `users.json` ; consigner l'adresse IP réelle dans les audits
|
||
- [x] Ignorer les symlinks de l'index ; caps CPU/timeout regex (ReDoS)
|
||
- [~] Durcir la CSP — *partiel* : directives `object-src`/`base-uri`/`form-action`/`frame-ancestors` ajoutées et token retiré de `sessionStorage` ; migration **nonce** restante (nécessite la conversion des gestionnaires d'événements inline)
|
||
|
||
### 85. Refonte architecturale — découpage du monolithe & persistance d'état (phase 2)
|
||
|
||
- **Effort :** 8-12 jours | **Impact :** 🟡 | **Zone :** backend
|
||
- **Description :** extraire le monolithe `backend/main.py` (~4 260 lignes) en routers FastAPI par domaine et rendre persistant l'état qui ne l'est pas (index de recherche, JTI révoqués, compteurs de rate-limit) pour préparer le multi-nœuds.
|
||
- **Sous-tâches :**
|
||
- [ ] Routers par domaine : files, search, share, webhooks, plugins, collab, admin, ai
|
||
- [ ] Centraliser le contrat d'outils IA sur `tools/registry.py` (permissions, quotas, redaction)
|
||
- [ ] Persister index, JTI révoqués et compteurs de rate-limit (SQLite/Redis)
|
||
- [ ] Verrous asyncio autour de l'index global et des stores JSON ; service de partage public (expiration, révocation, quotas)
|
||
|
||
### 87. Amélioration continue — tests, CI/CD, revues de sécurité (phase 4)
|
||
|
||
- **Effort :** 3-5 jours | **Impact :** 🟡 | **Zone :** `.gitea/workflows/`, `tests/`
|
||
- **Description :** renforcer le pipeline (`.gitea/workflows/ci.yml`, `desktop-build.yml`) pour le rendre bloquant par défaut et accompagner les phases 1 → 3.
|
||
- **Sous-tâches :**
|
||
- [ ] Jobs CI sécurité (bandit/semgrep/trivy, audits pip/npm) + tests E2E XSS (page de partage + lecteur markdown)
|
||
- [ ] Tests de concurrence (`users.json`), fuzzing de timing regex, couverture des composants critiques
|
||
- [ ] Revue périodique des dépendances ; documentation utilisateur FR/EN synchronisée ; contrôle automatisé de la conformité au DoD
|
||
|
||
---
|
||
|
||
## ✅ Complété — index
|
||
|
||
> Détail complet dans [docs/archive/COMPLETED_v1-v2.md](./archive/COMPLETED_v1-v2.md) et
|
||
> [docs/features/](./features/). Cette table est la seule source de navigation ; ne pas
|
||
> re-détailler les items livrés ici.
|
||
|
||
| # | Domaine / fonctionnalité | Version | Détails |
|
||
|---|---|---|---|
|
||
| BUG-047 | Versionnage — source unique `VERSION` + bump SemVer automatique au commit (hooks + tag) | 2.3.0 | [DEVELOPMENT_AND_RELEASES.md](./DEVELOPMENT_AND_RELEASES.md) |
|
||
| 90 | Barre d'actions du document — regroupement fonctionnel + spacers | 2.3.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 89 | Drag & drop complet de fichiers/dossiers & intégration Assistant IA | 2.3.0 | [features/drag-and-drop-ai.md](./features/drag-and-drop-ai.md) |
|
||
| 1–8 | Fondations (FastAPI, TF-IDF + stemming, watchdog, SPA, sécurité, path traversal, gzip, PWA) | 1.0.0→1.4.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 9–20 | UX & productivité (share, webhooks, dashboard, conflits, backlinks, redaction, backups, graphe, header, aperçu) | 1.5.0→1.6.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 21–22 | Architecture (split `app.js` → 16 modules, validateur imports CI) | 1.5.1 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 23–25 | CI/CD & qualité (Gitea Actions, Ruff/Mypy/Bandit/Pip-audit, pytest) | 1.6.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 26–29 | AI Editor (toolbar, multi-provider, 16 endpoints, auto-save) | 1.7.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 30–39 | Fonctionnalités avancées (export PDF, palette, mobile, drag & drop, filtres, indexation non-bloquante) | 1.8.0→1.9.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 40–46 | Gestion des backups (diff, gestionnaire, purge, auto, rétention) | 1.9.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 47–57 | Mermaid.js (22 templates, live preview, thèmes, zoom, plein écran, pré-processeur Obsidian) | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 58 | Tests E2E Playwright (44 desktop + 12 mobile, CI) | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 59 | Mode hors-ligne PWA complet (IndexedDB, file de synchro, conflits) | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 63 | Internationalisation i18n FR/EN | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 65 | Thèmes personnalisés (light/dark/high-contrast/sepia, import/export) | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 66 | Export multi-formats (HTML, MD bundle, ePub) | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 71 | Tableau de bord administrateur | 2.0.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 64 | MFA (TOTP + WebAuthn + recovery codes) | 2.1.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 74 | Support complet des documents PDF | 2.1.0 | [features/pdf.md](./features/pdf.md) |
|
||
| 75 | Éditeur multi-panneaux (Split View) | 2.1.0 | [features/split-view.md](./features/split-view.md) |
|
||
| 61 | Plugins système (sandbox Web Worker, hooks, 9 endpoints) | 2.2.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 67 | Notifications web — Push API | 2.2.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 68 | Health check enrichi | 2.2.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 72 | API publique documentée — OpenAPI 3.1 | 2.2.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 76 | BooksLM — Console AI contextuelle par répertoire | 2.2.0 | [features/bookslm.md](./features/bookslm.md) |
|
||
| 78 | Éditeur Excalidraw | 2.2.0 | [features/excalidraw.md](./features/excalidraw.md) |
|
||
| 62 | Collaboration temps réel — Édition simultanée (Yjs/CRDT, WebSocket, awareness) | 2.3.0 | [features/collaboration.md](./features/collaboration.md) |
|
||
| 79 | Assistant IA — Outils (function calling) & serveur MCP | 2.3.0 | [features/ai-tools-mcp.md](./features/ai-tools-mcp.md) |
|
||
| 80 | Assistant IA — Rendu Markdown, liens fichiers/paths & sessions | 2.3.0 | [features/ai-assistant-ux.md](./features/ai-assistant-ux.md) |
|
||
| 81 | Assistant IA — Commandes (`@`, `/`), skills, images & capacités des modèles | 2.3.0 | [features/ai-assistant-commands.md](./features/ai-assistant-commands.md) |
|
||
| 82 | Assistant IA — Section « Fournisseur & modèle » compacte (recherche modèle + info capacités, BUG-043) | 2.3.0 | [features/ai-provider-picker.md](./features/ai-provider-picker.md) |
|
||
| 69 | Éditeur mobile natif — Interface tactile optimisée | 2.3.0 | [features/mobile-editor.md](./features/mobile-editor.md) |
|
||
| 70 | Recherche sémantique — Embeddings vectoriels (hybride TF-IDF + RRF) | 2.3.0 | [features/semantic-search.md](./features/semantic-search.md) |
|
||
| 77 | Application Desktop native — Tauri | 🔵 en cours | [features/desktop-tauri.md](./features/desktop-tauri.md) |
|
||
| 84 | Consolidation & sécurité — revue statique 2026-09-13 (phase 1, BUG-021→034) | 2.3.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 83 | Barre d'outils d'édition mobile — ruban style Obsidian Android | 2.3.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 88 | Assistant IA — contexte applicatif (documents ouverts, répertoire, recherche, fichiers récents) & liens de fichiers fiables (BUG-041, BUG-042) | 2.3.0 | [features/ai-app-context.md](./features/ai-app-context.md) |
|
||
| 91 | Assistant IA — Zone de discussion façon Notion : post ancré en haut, fournisseur/modèle discret & barre d'actions | 2.3.0 | [features/ai-assistant-conversation-ux.md](./features/ai-assistant-conversation-ux.md) |
|
||
| 93 | Édition inline — « Editer » et « Forge » remplacent la vue lecture (assistant IA qui met le document à jour) | 2.3.0 | [features/editeur-inline.md](./features/editeur-inline.md) |
|
||
| 94 | Assistant IA — Bouton de soumission arrondi + icône renouvelée (arrow-up) | 2.4.0 | [features/ai-assistant-history.md](./features/ai-assistant-history.md) |
|
||
| 95 | Assistant IA — Historique permanent des conversations (persistance backend) | 2.4.0 | [features/ai-assistant-history.md](./features/ai-assistant-history.md) |
|
||
| 96 | Assistant IA — Accès rapide à l'historique depuis la sidebar de navigation | 2.4.0 | [features/ai-assistant-history.md](./features/ai-assistant-history.md) |
|
||
| 97 | Assistant IA — Panneau « + » extensible (fichiers, Deep Research, contextes, skills…) | 2.4.0 | [features/ai-assistant-history.md](./features/ai-assistant-history.md) |
|
||
| 98 | Assistant IA — Filtre de recherche dans la sidebar « Historique IA » | 2.5.0 | [features/ai-assistant-history.md](./features/ai-assistant-history.md) |
|
||
| 99 | Sidebar — Filtrage des vues « Récents » et « Sauvegardes » | 2.6.0 | [features/sidebar-filters.md](./features/sidebar-filters.md) |
|
||
| 100 | Assistant IA — Deep Research en pastille (au lieu du texte injecté) | 2.6.0 | [features/ai-assistant-history.md](./features/ai-assistant-history.md) |
|
||
| 101 | Forge — Assistant IA partagé (bouton AI Panel = assistant, fournisseur/modèle configuré, autocomplétion) + plein écran Forge/Editer | 2.8.0 | [features/forge-assistant.md](./features/forge-assistant.md) |
|
||
| BUG-057 | Assistant IA — bouton « Ajouter » fonctionnel dans l'éditeur Forge (en plus d'« Editer ») | 2.9.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 102 | Assistant IA — bouton « Ajouter la section » par bloc de code (insertion du bloc seul) | 2.9.0 | [archive](./archive/COMPLETED_v1-v2.md) |
|
||
| 92 | Assistant IA — Écosystème d'outils phase 2 (recherche à clé, cache/retry, Playwright, crawl, Gitea/GitHub, documents XLSX/DOCX/CSV/PDF) | 2.10.0 | [features/ai-tools-roadmap.md](./features/ai-tools-roadmap.md) |
|
||
| 103 | Configuration — clés utilisateur des sources connectées & recherche à clé (page Configurations, `data/api_keys.json`, priorité sur l'env) | 2.11.0 | [features/ai-tools-roadmap.md](./features/ai-tools-roadmap.md) |
|
||
| 104 | Configuration — Redesign UI de la section « Clés API IA » : recherche fournisseurs, carte défaut 2 colonnes + badges de capacités, cartes dépliables, footer d'actions sticky | 2.12.0 | [features/ai-keys-ui.md](./features/ai-keys-ui.md) |
|
||
| 105 | Guide d'utilisation — audit de couverture complet, téléchargement Markdown/PDF, guide desktop élargi, section Architecture (Mermaid) + BUG-067 | 2.13.0 | [features/guide-coverage-105.md](./features/guide-coverage-105.md) |
|
||
| 106 | Assistant IA — Actions instantanées contextuelles, catalogue « Toutes les actions » & frontmatter complet | 2.14.0 | [features/ai-quick-actions.md](./features/ai-quick-actions.md) |
|
||
| 107 | Configuration — Gestion des clés API & MCP : création/révocation de jetons longue durée (1 j, 1 mois, 6 mois, 1 an, sans fin), une seule clé pour l'API REST et le serveur MCP, « dernière utilisation », store `data/api_tokens.json` sans secret persisté | 2.15.0 | [features/api-mcp-tokens-107.md](./features/api-mcp-tokens-107.md) |
|
||
| 86 | Optimisation globale des performances (phase 3) — scan différentiel, excalidraw différé, garde-fou `replace` (inverted index / PDF lazy / caps regex déjà livrés via BUG-033/040/025) | 2.16.0 | [features/perf-phase3-86.md](./features/perf-phase3-86.md) |
|
||
|
||
---
|
||
|
||
## 📊 Résumé des efforts
|
||
|
||
| Priorité | Items | Effort total estimé |
|
||
|---|---|---|
|
||
| ✅ Complété | #1 → #59, #61–72, #74–76, #78–84, #86, #88–93, #94–100, #102–107, #92 | ~120 jours réalisés |
|
||
| 🔵 P2 restant | #77 Desktop : signature de code (non retenue), 6 tests E2E **manuels** ([protocole](./DESKTOP_E2E_CHECKLIST.md)) | ~0,5-1 jour |
|
||
| ⚪ Média | #108 Images (arborescence, visionneuse, indexation) + #109 Audio/vidéo (lecteurs HTML5, Range) | 5-7 jours |
|
||
| ⚪ P4 restant | #73 Sync (6-8j) | 6-8 jours |
|
||
| ⚪ P0/P1 restant | #85, #87 Refonte architecturale, CI/CD (BUG-035 → BUG-040 corrigés, #86 livré) | ~11-17 jours |
|
||
| **Total restant** | **8 items + finitions** | **~28-43 jours** |
|
||
|
||
---
|
||
|
||
## Notes
|
||
|
||
- Les items P3/P4 ne sont pas ordonnés par priorité interne — à raffiner selon les retours utilisateurs.
|
||
- L'effort inclut le développement + tests unitaires + intégration CI, mais pas la documentation utilisateur.
|
||
- Les items marqués 🟢 (nice-to-have) sont de bons candidats pour des contributions externes.
|
||
- **Maintenance de ce fichier :** quand un item passe à ✅, déplacer son détail vers
|
||
`docs/features/<slug>.md` (grosse feature) ou `docs/archive/COMPLETED_v1-v2.md` (item court),
|
||
ajouter une ligne dans l'index « Complété », et consigner la version dans le [CHANGELOG](../CHANGELOG.md).
|