32 KiB
ObsiGate — Historique des fonctionnalités complétées (v1.0.0 → v2.2)
Rôle : archive détaillée des fonctionnalités livrées. Le suivi des versions est la responsabilité de CHANGELOG.md ; la Roadmap ne contient plus que le travail à venir et un index compact vers ce fichier.
Les grosses fonctionnalités disposent d'une fiche dédiée dans
docs/features/: #74 PDF · #75 Split View · #76 BooksLM · #77 Desktop Tauri · #78 Excalidraw.
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 | 🟡 |
#58 — Tests E2E Playwright ✅
- 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 (jobe2eaprèsbuild). - Sous-tâches :
- Installation Playwright + config (
playwright.config.ts) - Fixtures : vault de test (utilise les vaults Docker existants)
- Test : dashboard → stats, tabs, Quick Help, sidebar
- Test : recherche full-text → résultats, snippets, tri pertinence/date
- Test : ouverture fichier → viewer Markdown, métadonnées
- Test : éditeur → Forge, basic modal, Ctrl+S
- Test : rendu Mermaid dans le viewer + preview Forge
- Test : export PDF → bouton présent
- Test : mode sombre → toggle, persistence localStorage
- Test : responsive mobile → layout, recherche, barre flottante
- Test : barre flottante résultats → compteur, nav, toggles Aa/wd
- Test : sauvegardes → filtres Tous/Recherches/Répertoires
- Test : raccourcis clavier → Ctrl+K, /, Escape
- Test : menu contextuel répertoire
- Intégration CI : job
e2edans.gitea/workflows/ci.yml
- Installation Playwright + config (
#59 — Mode hors-ligne PWA complet ✅ TERMINÉ
- 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 :
- IndexedDB : stockage local de l'index des fichiers (paths, titles, tags)
- Moteur de recherche offline via IndexedDB (cursor + filtre)
- Cache des fichiers markdown récemment ouverts (derniers 50, prune)
- Stratégie de cache : Network First avec fallback IndexedDB
- File de synchronisation : modifications offline → appliquées au retour réseau
- UI indicateur : badge « Hors-ligne » + compteur de modifications en attente
- 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 : 🟢 | Statut : ✅ Livré (backend + frontend + tests + docs)
- 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,onFileCreate,onFileDelete,onVaultMount - Sandbox d'exécution : Web Worker isolé pour le code plugin (blob URL, postMessage structuré, CSP sans importScripts)
- UI : page « Plugins » dans les paramètres (installer, activer/désactiver, désinstaller, template, viewer)
- Distribution : dépôt de plugins communautaire (fichier JSON index) — ⚪ NON RETENU (backlog)
- Hot-reload : activation/désactivation sans rechargement de page (marker
.disabled) - Sécurité : manifest de permissions, validation path-traversal, CSP restrictif
- Spécification du format de plugin :
- Livré :
- Backend
backend/plugins.py— validation manifest (name regex, semver, hooks/permissions autorisés), stockage par vault<vault>/.obsigate-plugins/, lifecycle complet, validation ZIP (path traversal, limite 100 fichiers, 500KB/fichier), 9 endpoints/api/plugins/*(admin-gated pour install/uninstall/enable/disable), template API. - Frontend
frontend/js/plugins.js— PluginManager, sandbox Web Worker (code via blob URL, protocole postMessage structuré), UI Settings > Plugins, hooks dispatch (executeHook/onFileRender/onSearchFilter/…). - Tests :
tests/test_plugins.py(44) +tests/frontend/plugins.test.mjs(21) — validation, lifecycle, ZIP/dir sécurité, protocole sandbox, isolation DOM/CSP. - Docs :
docs/PLUGINS.md.
- Backend
- En backlog (non retenu) : dépôt communautaire (index JSON), signature de code des plugins.
#63 — Internationalisation (i18n) — Multilingue ✅ TERMINÉ
- 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 :
- Extraction des chaînes : ~1200 clés UI extraites
- Format : JSON
fr.json+en.jsondansfrontend/locales/→ 1206 clés parfaitement synchronisées - Fonction
t(key)→frontend/js/i18n.jsavec_applyDOM(),data-i18n,data-i18n-attr,data-i18n-placeholder,data-i18n-html, support des templates{var} - Sélecteur de langue dans les paramètres (persisté localStorage
obsigate-lang) - Traduction des messages backend → les toast/showToast sont maintenant i18n dans tous les fichiers JS
- Documentation multilingue →
README.md+README.fr.md - Nettoyage des clés inutilisées → locales nettoyées
- Tous les fichiers JS utilisent
t()→ plus de texte FR en dur (ai.js, sync.js, graph.js, autocomplete.js) - Interface principale : dashboard, sidebar, editor, search, settings → EN/FR complet
- Guide d'utilisation : 18 sections (Intro → Astuces) → tous les paragraphes traduits
- Thèmes, palette de commandes, raccourcis, webhooks → EN/FR complet
- Messages système : toasts, statuts, événements → EN/FR complet
#64 — MFA — Authentification multi-facteurs ✅ TERMINÉ (TOTP + WebAuthn + recovery codes)
- 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 (
backend/auth/webauthn_mfa.py, libwebauthn==2.6.0, challenges in-memory TTL 180s à usage unique) — FAIT en 2026-09 (commitab795ec) - UI : page « Sécurité du compte » avec activation/désactivation MFA + gestion des clés WebAuthn (liste, ajout, retrait)
- Flow login : mot de passe → challenge TOTP OU WebAuthn selon
mfa_methodretourné par /login - Recovery codes : 8 codes de backup à usage unique (générés à l'activation, hachés SHA-256)
- Stockage :
mfa_secret+webauthn_credentials[]dansusers.json - Tests :
tests/test_mfa.py(29) +tests/test_webauthn.py(10, authentificateur virtuel CBOR/EC P-256)
#65 — Thèmes personnalisés — CSS variables ✅ TERMINÉ
- 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 :
- Audit des variables CSS existantes → 40+ variables
- Presets: light, dark, high-contrast, sepia (générés dynamiquement)
- UI : sélecteur de thème dans les paramètres (swatches grid)
- Import/export de thème personnalisé (JSON)
- Application dynamique via document.documentElement.style.setProperty
#66 — Export multi-formats ✅ TERMINÉ
- 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 :
- Export HTML standalone : CSS inliné, images en base64, navigation inter-fichiers
- Export MD bundle : ZIP du vault avec structure préservée
- Export ePub : conversion markdown → ePub (zipfile + mistune, 0 nouvelle dep)
- UI : dropdown Export dans toolbar viewer (HTML / MD bundle / ePub)
- Endpoints :
GET /api/export/html,GET /api/export/md-bundle,GET /api/export/epub
#67 — Notifications web — Push API ✅ TERMINÉ
- Effort : 2 jours | Impact : 🟢
- Description : Recevoir des notifications sur le bureau ou le téléphone quand un fichier est modifié, ajouté ou supprimé dans un de vos vaults, même si ObsiGate n'est pas ouvert dans le navigateur.
- Fonctionnement : Le navigateur s'abonne auprès du serveur via la Push API (standard W3C). Le serveur stocke l'abonnement (endpoint + clés de chiffrement). Quand un fichier change (détecté par le watcher existant), le serveur envoie une notification chiffrée au push service du navigateur (Firebase pour Chrome, APNs pour Safari, etc.), qui la relaye au navigateur même s'il est fermé. Le service worker ObsiGate affiche alors la notification système.
- Contenu : titre du fichier modifié, nom du vault, type d'action (créé/modifié/supprimé). Un clic sur la notification ouvre directement le fichier dans ObsiGate.
- Configuration : activation/désactivation par vault. L'utilisateur choisit pour quels vaults il reçoit des notifications.
- VAPID : protocole d'authentification volontaire qui permet au serveur de s'identifier auprès du push service sans avoir à s'enregistrer comme application. Une paire de clés publique/privée est générée — la clé publique est partagée avec le navigateur, la clé privée reste sur le serveur.
- Pourquoi c'est important : Collaborer sans avoir à constamment rafraîchir l'interface pour voir si quelqu'un a modifié quelque chose. Particulièrement utile en équipe ou pour les vaults partagés via Syncthing — on sait immédiatement quand une note est mise à jour.
- Implémentation :
backend/push.py, endpointsPOST /api/push/subscribe, config VAPID dansconfig.json, UI toggle par vault. Livré avec #77 (commitac16fc1). - Sous-tâches :
- Souscription Push : endpoint
POST /api/push/subscribe(stockagesubscription+vault) - Envoi : webhook interne
on_file_change→ dispatch notification via Web Push - Configuration VAPID : clés publique/privée dans
config.json - UI : permission navigateur + toggle activer/désactiver par vault
- Payload : titre du fichier, vault, action (created/modified/deleted)
- Clic sur notification → ouvre le fichier dans ObsiGate
- Souscription Push : endpoint
#68 — Health check enrichi ✅ TERMINÉ
- Effort : 1 jour | Impact : 🟢
- Description : Un endpoint
/api/healthqui ne se contente pas de dire « je suis vivant », mais donne un diagnostic complet de l'état du serveur. Essentiel pour le monitoring et le debugging.- Métriques exposées :
- Index : nombre de fichiers indexés, nombre de tokens, date de la dernière indexation complète. Permet de détecter si l'indexeur est bloqué ou ne tourne plus.
- Mémoire : consommation RAM du processus (RSS), heap Python utilisé. Permet de détecter les fuites mémoire avant qu'elles ne crashent le serveur.
- Uptime : depuis quand le serveur tourne. Simple, mais indispensable pour corréler un problème avec un redémarrage.
- Connexions : nombre de connexions SSE actives (recherche en cours, streaming AI, etc.). Permet de savoir combien d'utilisateurs sont connectés.
- Backups : nombre total, âge du backup le plus ancien, espace disque consommé. Permet de détecter si les backups s'accumulent anormalement.
- Disque : espace libre sur la partition
/data. Évite le crash silencieux quand le disque est plein.
- Format : JSON structuré, facile à intégrer dans des outils de monitoring (Prometheus, Grafana, Uptime Kuma, Healthchecks.io).
- Sécurité : l'endpoint public
/api/healthretourneokoudegraded, l'endpoint détaillé est protégé par authentification admin.
- Métriques exposées :
- Implémentation :
GET /api/health/detailed(admin-gated) dansbackend/main.py:1176. Livré avec #77 (commitac16fc1). - Sous-tâches :
- Métriques index : nombre de fichiers, nombre de tokens, génération courante
- Métriques mémoire : RSS, heap used (via
psutilou/proc/self/status) - Métriques uptime :
time.time() - server_start_time - Métriques backups : nombre total, âge du plus vieux, espace disque
- Format réponse JSON structuré :
{ status, uptime, index, memory, backups, connections } - Endpoint séparé
GET /api/health/detailed(protégé admin)
#71 — Tableau de bord administrateur ✅ Terminé
- Effort : 2 jours | Impact : 🟢 | Statut : ✅ Terminé (2026-08, commits
46be24f/88ab8db/01453bc) - Description : Une page web dédiée accessible uniquement aux administrateurs qui centralise tout le monitoring et la gestion du serveur ObsiGate en un seul endroit. Un cockpit de pilotage pour le sysadmin.
- Implémentation réelle (vérifiée) :
- Backend
backend/admin.py(nouveau, 261 lignes) — 4 endpoints admin-gated (require_admin) :GET /api/admin/stats— CPU/RAM/Disk/Uptime via psutilGET /api/admin/audit— 500 dernières entrées d'audit avec filtresuser/action/limit/offsetGET /api/admin/backup-stats— compte + taille + age par vaultGET /api/admin/stream— Server-Sent Events qui push les stats toutes les 5s
backend/main.py— routeur monté + middleware gzip bypass pour/api/admin/streambackend/requirements.txt— ajoutpsutil>=5.9- Tests :
tests/test_admin.py(13 tests, 100% verts) — couvrent auth + filtres + format SSE
- Backend
- Complété (2026-08) :
frontend/admin.html(472 l.) +frontend/js/admin.js(544 l.) — dashboard standalone avec navigation par sections sticky + thèmes- Lien « Admin » dans le user menu (
#admin-menu-row, gatingrole === "admin") - Widgets temps réel via EventSource
/api/admin/stream+ snapshot/api/admin/stats - CRUD users + fix routing
/admin.html+ fix scroll
#72 — API publique documentée — OpenAPI 3.1 ✅ TERMINÉ
- Effort : 1-2 jours (réalisé) | Impact : 🟢 | Statut : ✅ Livré (2026-09-11)
- Implémentation réelle :
backend/openapi_docs.py— 18 tags documentés + assignation automatique par préfixe de route (tag_for_path,canonical_tag), enrichissement du schéma (enrich_openapi_schema: sécuritébearerAuth/cookieAuth, erreurs 401/403/404/422/500, exemples requête/réponse, serveur,externalDocs), page/apiautonome (render_api_landing).backend/schemas.py—response_modelPydantic pour ~35 endpoints qui n'en avaient pas.backend/main.py—FastAPI(...)enrichi (description Markdown, contact, licence, tags) + overrideapp.openapi; routes/apiet/api/.backend/ai_routes.py/backend/bookslm_routes.py—response_model(AI status, BooksLM context) + documentation SSE.- Frontend — entrée « API » du menu d'options (i18n FR/EN) ouvrant
/docs. - Tests —
tests/test_openapi.py(58 tests) +tests/frontend/ai.test.mjs(7 tests).
- Description : Une page de documentation interactive et auto-générée de toutes les API REST d'ObsiGate, accessible via un bouton dans l'interface. L'équivalent d'un manuel technique mais qui se teste en direct.
- OpenAPI 3.1 : c'est le format standard mondial pour décrire une API REST. Un seul fichier JSON/YAML contient la description de tous les endpoints, leurs paramètres, les formats de réponse, les codes d'erreur, et les modèles de données. Ce standard est supporté par des centaines d'outils.
- Swagger UI : une interface web qui lit le fichier OpenAPI et génère automatiquement une documentation interactive. L'utilisateur voit chaque endpoint, peut remplir les paramètres dans un formulaire, cliquer « Execute » et voir la réponse réelle de l'API en direct. Parfait pour les développeurs qui veulent intégrer ObsiGate à leurs scripts ou comprendre comment fonctionne l'API.
- Redoc : une alternative à Swagger UI, plus propre et orientée lecture, idéale pour la documentation publique.
- Contenu documenté :
- Les 40+ endpoints existants, regroupés par catégorie (Fichiers, Vaults, Recherche, Auth, AI, Backups).
- Chaque endpoint avec description, paramètres obligatoires/optionnels, exemples de requête et réponse.
- Les modèles de données Pydantic exposés comme schémas JSON (ex: structure d'un
FileInfo, d'unSearchResult). - Les codes d'erreur possibles avec leur signification.
- Auto-génération : FastAPI génère déjà partiellement le schéma OpenAPI. Le travail consiste à compléter les docstrings manquantes, ajouter
response_modelsur les endpoints qui n'en ont pas, et enrichir avec des exemples.
- Pourquoi c'est important : Une API sans documentation est comme un logiciel sans interface — techniquement fonctionnel mais inutilisable. Avec une doc OpenAPI, ObsiGate devient intégrable dans n'importe quel écosystème. Un développeur peut en 5 minutes comprendre comment uploader un fichier, chercher dans un vault, ou récupérer le contenu d'une note — et écrire un script qui automatise ses workflows.
- Sous-tâches :
- Audit des endpoints existants → compléter les docstrings manquants
- Ajout de
response_modelsur tous les endpoints (40+ actuellement, ~15 sans modèle) - Exemples dans les schémas :
examples=[...]pour les endpoints clés - Tagging des endpoints par catégorie (Files, Vaults, Search, Auth, AI, Backups)
- Serveur mock :
prismouopenapi-generatorpour tests sans backend — ⚪ NON RETENU (le schéma 3.1 est validé partests/test_openapi.py) - Page de documentation intégrée : lien dans le menu header (« API »)
#84 — Consolidation & sécurité (phase 1) ✅ TERMINÉ
Traitement des vulnérabilités de la revue statique du 2026-09-13 (BUG-021 → BUG-034).
- Sanitizer XSS serveur (
backend/services/sanitizer.py, stdlib, liste blanche de balises/attributs/schémas) appliqué au rendu markdown et à la page publique/s/{token}(titre, frontmatter et JSON échappés,</script>neutralisé). - Auth durcie : rate-limit IP + compte et verrouillage sur les endpoints MFA ;
rotation du refresh token et révocation de l'access token au logout ; politique de
mot de passe centralisée (8–128) ;
password_changed_atinvalide les jetons antérieurs ; verrouRLocksurusers.json. - Isolation & réseau :
resolve_safe_pathcompare par segments (vault≠vault-evil) ; webhooks protégés contre le SSRF (HTTPS, IP privées bloquées, résolution vérifiée, redirections interdites, secret externalisé) ; IP client réelle dans les audits. - Robustesse : validation des regex (ReDoS), symlinks hors vault ignorés à
l'indexation, recherche simple et
search_fulltextbranchés sur l'inverted index. - Frontend : token d'accès en mémoire + cookie
HttpOnly(plus desessionStorage), CSP durcie (object-src,base-uri,form-action,frame-ancestors). - Tests :
tests/test_security_hardening.py(30) ; suite backend 961 passed / 6 skipped ; ruff + mypy 0 ; suites frontend vertes.
#83 — Barre d'outils d'édition mobile (ruban style Obsidian) ✅ TERMINÉ
La barre de mise en forme flottante du mode édition mobile est remplacée par un ruban horizontal défilable ancré juste au-dessus du clavier virtuel.
- Ruban (
frontend/js/mobile-editor.js,frontend/style.css) : fond anthracite aux coins arrondis, insertion/enrobage au curseur ou sur la sélection. - Commandes : annuler/refaire,
[[ ]](lien interne), fichiers/modèles, tag#, pièce jointe, H1–H6, gras, italique, barré (~~), surligné (==), code en ligne/bloc, citation, lien externe, listes à puces/numérotées, case à cocher, indenter/désindenter, coller, A−/A+. - Personnalisation : icône ⚙ → ajouter / retirer / réordonner les commandes,
persisté dans
localStorage(obsigate-mobile-ribbon). - Ancrage clavier (
BUG-019) :window.visualViewport→ variable CSS--kb-offset. - Correctifs associés : BUG-017 (tuiles du tableau de bord), BUG-018 (en-tête de l'éditeur mobile), BUG-020 (double barre de défilement).
- Tests :
tests/frontend/mobile-editor.test.mjs(35) + E2Emobile-editor.spec.js.
#90 — Barre d'actions du document : regroupement fonctionnel ✅ TERMINÉ
Réordonnancement des boutons du haut du document en quatre groupes
séparés par des barres verticales (span.action-sep) :
[TOC] [pop-out] [Bookmark] | [Editer] [Source] [.md] [Forge] | [Copier] [PDF] [Export] | [Partager]
Fichiers texte non markdown :
[pop-out] [Bookmark] | [Editer] [Source] [.ext] [Pretty] | [Copier] | [Partager]
- Viewer principal (
frontend/js/viewer.js,renderFile) : construction par groupesnavBtns/editBtns/exportBtns/shareBtns; TOC ancré au markdown seul (.sh/.py/etc. sans TOC) ; « Pretty » (fichiers texte) ancré au groupe édition après le bouton d'extension ; les spacers d'un groupe vide (ex. fichier image ou binaire) ne sont pas rendus. - Pop-out (
frontend/popout.html) : même assemblage groupé, ordre aligné. - CSS (
frontend/style.css) : règle.file-actions .action-sep(trait 1 px,var(--border-md),align-self: stretch). - Tests :
tests/frontend/toolbar-order.test.mjs(9, statiques).
#102 — Assistant IA : « Ajouter » dans Forge + ajout d'un bloc de code ✅ TERMINÉ
Deux compléments au bouton « Ajouter » de l'assistant IA.
- BUG-057 — Forge :
bookslm.js::_insertIntoEditor()ne ciblait questate.editorView(CodeMirror de « Editer ») et affichait « Aucun document ouvert dans l'éditeur » en Forge. Il prend désormais en charge les trois surfaces : CodeMirror, l'iframe Forge (délégation parpostMessage({ type: 'parent-insert' }), insert au curseur viainsertAtCursorcôtéeditor-poc.html) et le textarea de repli. - #102 — Ajout d'un bloc : chaque bloc de code d'une réponse reçoit un bouton
« Ajouter la section » (révélé au survol,
.bookslm-code-insert) qui insère uniquement le contenu du bloc (sans les délimiteurs```), au lieu de la réponse complète. - Tests :
tests/frontend/ai.test.mjs(+3 : Forge, textarea, bloc de code) ;tests/frontend/editor-inline.test.mjs(+1 : handlerparent-insert).
#152 — Viewer XLSX : affichage, édition, téléchargement ✅ TERMINÉ
Les fichiers .xlsx s'ouvrent dans un dédié : un tableau HTML par feuille (onglets en cas de
multi-feuilles, en-têtes A1, cellules contenteditable), bouton Enregistrer actif dès la
première modification et téléchargement du fichier d'origine.
| Aspect | Détail |
|---|---|
| Lecture | backend/xlsx_reader.py — openpyxl read_only, formules affichées comme texte, plafond 500×40 cellules par feuille |
| Écriture | PUT /api/file/{vault}/xlsx/save → services/mutations.edit_xlsx_cells (backup avant écriture, refs A1 validées, str→int/float, 500 cellules max par requête) |
| Frontend | renderXlsxViewer dans frontend/js/viewer.js (onglets, cellules sales, Entrée/Échap, collage monoligne) |
| Limite connue | Le round-trip openpyxl conserve valeurs/formules/styles mais perd graphiques, images et tableaux croisés |
#157 — Recherche : facette « Extensions » ✅ TERMINÉ
Le panneau de facettes de la page de résultats de recherche affiche désormais trois groupes :
Vaults, Tags et Extensions. Le troisième liste les extensions de fichiers présents
dans le résultat courant (.md, .xlsx, .pdf, …) avec leur compteur ; un clic ajoute
l'opérateur ext:<type> à la requête (un ext: déjà actif est remplacé, jamais dupliqué).
L'ensemble du panneau se replie/rouvre d'un clic sur un bouton discret (chevron), état
mémorisé dans localStorage.
| Aspect | Détail |
|---|---|
| Backend | backend/search.py::advanced_search — facets.extensions : compteurs par extension normalisée (sans point, en minuscules), triés par fréquence · backend/schemas.py::SearchFacets expose le champ (sinon le response_model le supprimait — corrigé après livraison de 2.46.0) |
| Frontend | frontend/js/search.js::renderAdvancedSearchResults — groupe [data-facet="extensions"], items montés en textContent (les suffixes viennent de noms de fichiers non fiables) ; panneau repliable via .search-facets__toggle + data-collapsed (état obsigate_facets_collapsed) |
| i18n / aide | help.desc_facet_extensions, search.facets_collapse/_expand (FR/EN), guide docs/GUIDES/RECHERCHE_PDF_EXCALIDRAW.md |
| Tests | tests/test_search.py::test_facets (route réelle /api/search/advanced, assertion stricte facets.extensions), tests/frontend/search-facets.test.mjs (5 tests JSDOM, ajoutés au CI), e2e obsigate.spec.ts (facette visible + repli/rouverture) |
Grosses fonctionnalités — fiches dédiées
| # | Feature | Version | Fiche |
|---|---|---|---|
| 74 | Support complet des documents PDF | 2.1.0 | features/pdf.md |
| 75 | Éditeur multi-panneaux (Split View) | 2.1.0 | features/split-view.md |
| 76 | BooksLM — Console AI contextuelle par répertoire | 2.2.0 | features/bookslm.md |
| 77 | Application Desktop native — Tauri | 2.2.0+ (en cours) | features/desktop-tauri.md |
| 78 | Éditeur Excalidraw | 2.2.0 | features/excalidraw.md |