# ObsiGate > **Version française** — ce document est le miroir synchronisé de [README.md](README.md) (référence complète). Dernière synchronisation : septembre 2026. **Porte d'entrée web ultra-léger pour vos vaults Obsidian** — Accédez, naviguez et recherchez dans toutes vos notes Obsidian depuis n'importe quel appareil via une interface web moderne et responsive. [![Version](https://img.shields.io/badge/Version-2.23.0-blue.svg)]() [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://www.docker.com/) [![Python](https://img.shields.io/badge/Python-3.11+-green.svg)](https://www.python.org/) [![CI/CD](https://img.shields.io/badge/CI%2FCD-Gitea_Actions-green.svg)](https://git.dracodev.net/Projets/ObsiGate/actions) ![Interface ObsiGate — tableau de bord Statistiques avec vaults, tags et raccourcis clavier](docs/images/obsigate-home.png) > Interface web d'ObsiGate : sidebar multi-vault, recherche globale, statistiques et raccourcis. --- ## 📚 Guides Les **guides d'utilisation** pas à pas se trouvent dans [`docs/GUIDES/`](docs/GUIDES/) : | Guide | Contenu | |---|---| | 🚀 [Prise en main](docs/GUIDES/PRISE_EN_MAIN.md) | Premier lancement, interface, navigation, vaults, raccourcis | | 🔍 [Recherche, PDF & Excalidraw](docs/GUIDES/RECHERCHE_PDF_EXCALIDRAW.md) | Syntaxe de requête, recherche sémantique, lecteur PDF, diagrammes | | 🤖 [Assistant IA & Forge](docs/GUIDES/ASSISTANT_IA_FORGE.md) | Fournisseurs, éditeur IA, BooksLM, Forge, commandes `@` / `/` | | 📝 [Édition & collaboration](docs/GUIDES/COLLABORATION.md) | Édition simultanée, curseurs distants, persistance | | 📱 [PWA & hors-ligne](docs/GUIDES/PWA_HORS_LIGNE.md) | Installation, cache hors-ligne, file de synchro, notifications | | 🔌 [API REST](docs/GUIDES/API_REST.md) | Authentification, clés API, endpoints, exemples `curl`, SSE | | 🧩 [Serveur MCP](docs/GUIDES/MCP.md) | Brancher Claude Desktop, Cursor, Cline… sur vos vaults | | 🔒 [Authentification & sécurité](docs/GUIDES/AUTHENTIFICATION_SECURITE.md) | Utilisateurs, MFA, permissions par vault, durcissement | | 🐳 [Déploiement Docker](docs/GUIDES/DEPLOIEMENT_DOCKER.md) | `docker-compose`, volumes, reverse proxy, mises à jour | | 🖥️ [Desktop (Tauri)](docs/GUIDES/DESKTOP.md) | Installation, premier lancement, build depuis les sources, dépannage | > Index complet : [`docs/GUIDES/README.md`](docs/GUIDES/README.md). --- ## 📋 Table des matières - ✨ [Fonctionnalités](#fonctionnalites) - 📚 [Guides](#guides) - 🚀 [Prérequis](#prerequis) - ⚡ [Installation rapide](#installation-rapide) - ⚙️ [Configuration détaillée](#configuration-detaillee) - 🌍 [Variables d'environnement](#variables-denvironnement) - 🔒 [Authentification](#authentification) - ➕ [Ajouter une nouvelle vault](#ajouter-une-nouvelle-vault) - 🔨 [Build & déploiement avec build.sh](#build-deploiement-avec-buildsh) - 🖼️ [Rendu d'images Obsidian](#rendu-dimages-obsidian) - 🖥️ [Desktop (Tauri) — Application native](#desktop-tauri-application-native) - 📖 [Utilisation](#utilisation) - 👥 [Collaboration temps réel](#collaboration-temps-reel) - 🔌 [API](#api) - 🔍 [Recherche avancée](#recherche-avancee) - 🔧 [Dépannage](#depannage) - ⚡ [Performance](#performance) - 🛡️ [Sécurité](#securite) - 🏗️ [Stack technique](#stack-technique) - 🏠 [Architecture](#architecture) - 📝 [Développement](#developpement) - 📄 [Licence](#licence) - 🤝 [Support](#support) - 📝 [Changelog](#changelog) --- ## ✨ Fonctionnalités - **🤖 AI Editor intégré** — Éditeur CodeMirror 6 avec toolbar IA : amélioration, correction, traduction, génération, réécriture personnalisée, toolbox (liste, tableau, frontmatter, canvas) — multi-provider DeepSeek/OpenRouter/Gemini - **🧩 Serveur MCP & agent IA** — Serveur Model Context Protocol intégré (`/mcp`) et assistant avec function calling : lisez, cherchez et modifiez vos vaults depuis Claude Desktop, Cursor… avec confirmations two-step, permissions par vault, rate limiting et redaction des secrets ([guide](docs/GUIDES/MCP.md)) - **👥 Collaboration temps réel** — Édition simultanée d'un même document (Yjs/CRDT) : curseurs distants colorés, indicateur de présence, fusion sans conflit, reconnexion automatique et persistance serveur ([détail](docs/features/collaboration.md)) - **📖 Guide d'utilisation intégré** — Aide complète en FR/EN accessible depuis le menu Options : interface, navigation, recherche, fichiers, IA, sécurité, API & intégrations (OpenAPI, MCP), hors-ligne, collaboration, desktop, plus une section **Architecture** avec diagramme Mermaid ; téléchargeable en **Markdown** et **PDF** dans la langue courante ([détail](docs/features/guide-coverage-105.md)) - **📱 Éditeur mobile natif** — Édition optimisée pour le tactile : barre d'outils Markdown flottante (gras/italique/code/liste/lien), bouton « Coller » persistant (contournement iOS), zoom par pincement et hauteur ajustable, raccourcis swipe (liens entrants / table des matières) et mode lecture plein écran avec navigation entre fichiers ([détail](docs/features/mobile-editor.md)) - **🗺️ Vue graphe interactive** — Canvas force-directed avec Barnes-Hut O(n log n), filtres (tag, type), profondeur, mode focus, historique de navigation ←→↑, export PNG, aperçu au survol (Ctrl+click) - **🗂️ Multi-vault** : Visualisez plusieurs vaults Obsidian simultanément - **🌳 Navigation arborescente** : Parcourez vos dossiers et fichiers dans la sidebar - **🔍 Recherche avancée** : Moteur TF-IDF avec stemming français, normalisation des accents, snippets surlignés, facettes, pagination et tri — plus une **recherche sémantique** optionnelle (embeddings `all-MiniLM-L6-v2`, fusion hybride TF-IDF + RRF) activable via le toggle `~` ([détail](docs/features/semantic-search.md)) - **💡 Autocomplétion intelligente** : Suggestions de fichiers, tags et historique avec navigation clavier - **🧩 Syntaxe de requête** : Opérateurs `tag:`, `#`, `vault:`, `title:`, `path:`, `ext:` avec chips visuels - **📜 Historique de recherche** : Persisté en localStorage (max 50 entrées, LIFO, dédupliqué) - **🏷️ Tag cloud** : Filtrage par tags extraits des frontmatters YAML - **🔗 Wikilinks** : Les `[[liens internes]]` Obsidian sont cliquables - **🖼️ Images Obsidian** : Support complet des syntaxes d'images Obsidian avec résolution intelligente - **🎬 Audio & vidéo** : Lecteurs HTML5 intégrés (`.mp3 .wav .flac .mp4 .webm`…) avec streaming HTTP Range (lecture, déplacement, plein écran) et **lecture persistante** (mini-lecteur flottant / mini-fenêtre vidéo, retour au média ou arrêt à tout moment, contrôles écran verrouillé via Media Session), repli téléchargement si le format n'est pas lisible par le navigateur - **🎨 Diagrammes Excalidraw** : Visualiseur/éditeur natif des fichiers `.excalidraw` et `.excalidraw.md` (iframe sandboxée, auto-save, thème clair/sombre, texte des diagrammes indexé pour la recherche) - **🎨 Syntax highlight** : Coloration syntaxique des blocs de code - **🌓 Thème clair/sombre** : Toggle persisté en localStorage - **📡 Synchronisation temps réel** : Surveillance automatique des fichiers via watchdog avec mise à jour incrémentale de l'index - **📡 Server-Sent Events** : Notifications SSE pour les changements d'index avec reconnexion automatique - **➕ Gestion dynamique des vaults** : Ajout/suppression de vaults via API sans redémarrage - **🖥️ Application desktop native** : Tauri (Rust) + backend Python embarqué, sans Docker ni navigateur - **🐳 Docker multi-platform** : linux/amd64, linux/arm64, linux/arm/v7, linux/386 - **🔒 Authentification** : JWT + Argon2id, sessions persistantes, contrôle d'accès par vault - **🛡️ Sécurité** : Rate limiting, audit log, backup automatique, redaction de secrets, headers CSP, protection path traversal, utilisateur non-root - **⚡ Performance** : Compression GZip, Cache-Control immutable, index inversé incrémental, search sans I/O disque - **❤️ Healthcheck** : Endpoint `/api/health` intégré pour Docker et monitoring --- ## 🚀 Prérequis ### Système requis - **Docker** >= 20.10 - **docker-compose** >= 2.0 - **Espace disque** : ~200MB pour l'image Docker ### Systèmes supportés - Linux (Ubuntu, Debian, CentOS, etc.) - macOS (Intel et Apple Silicon) - Windows (avec Docker Desktop) - NAS compatibles Docker (Synology, QNAP, etc.) --- ## ⚡ Installation rapide ### 1. Cloner le dépôt ```bash git clone https://git.dracodev.net/Projets/ObsiGate.git cd ObsiGate ``` ### 2. Configurer vos vaults et vos secrets Éditez `docker-compose.yml` pour ajouter vos vaults Obsidian : ```yaml volumes: - /chemin/absolu/vers/votre/vault:/vaults/NomDeVotreVault:ro ``` > **Important** : Le chemin doit être absolu et le volume en lecture seule (`:ro`) Créez votre fichier `.env` pour l'authentification et les secrets : ```bash cp .env.example .env # Éditez .env pour configurer vos mots de passe et options ``` > **Ne committez jamais `.env` !** Il est dans `.gitignore`. Utilisez `.env.example` comme référence. ### 3. Lancer l'application ```bash chmod +x build.sh # une seule fois ./build.sh # build + déploiement en une commande ``` > Options utiles : `./build.sh --help`, `./build.sh --cache` (rebuild rapide), `./build.sh --build-only` (construire sans démarrer). ### 4. Accéder à l'interface Ouvrez votre navigateur sur : **http://localhost:2020** --- ## ⚙️ Configuration détaillée ### Étape 1 : Préparation des vaults 1. **Localisez vos vaults Obsidian** sur votre système 2. **Notez les chemins absolus** vers chaque dossier 3. **Vérifiez les permissions** : Docker doit pouvoir lire ces dossiers ### Étape 2 : Configuration docker-compose.yml ```yaml services: obsigate: build: context: . image: obsigate:latest container_name: obsigate restart: unless-stopped ports: - "2020:8080" # Port local 2020 → Port conteneur 8080 volumes: - /home/user/Documents/Obsidian-Recettes:/vaults/Recettes:ro - /home/user/Documents/Obsidian-IT:/vaults/IT:ro - ./data:/app/data # Persistance des données d'auth environment: - VAULT_1_NAME=Recettes - VAULT_1_PATH=/vaults/Recettes - VAULT_2_NAME=IT - VAULT_2_PATH=/vaults/IT - OBSIGATE_AUTH_ENABLED=true - OBSIGATE_ADMIN_USER=admin env_file: - .env # Contient OBSIGATE_ADMIN_PASSWORD et autres secrets ``` ### Étape 3 : Build & déploiement ```bash chmod +x build.sh ./build.sh ``` **Alternative manuelle :** ```bash docker compose build --no-cache docker compose up -d ``` > **Compatibilité Docker** : l'image utilise une variante minimale d'`uvicorn` et `fastapi 0.110.3` afin d'éviter les dépendances optionnelles natives (`watchfiles`, `uvloop`, …) qui peuvent échouer au build sur Alpine, ARM ou i386. --- ## 🌍 Variables d'environnement Les vaults sont configurées par paires `VAULT_N_NAME` / `VAULT_N_PATH` (N = 1, 2, 3…) : | Variable | Description | Exemple | |----------|-------------|---------| | `VAULT_1_NAME` | Nom affiché de la vault | `Recettes` | | `VAULT_1_PATH` | Chemin dans le conteneur | `/vaults/Obsidian-RECETTES` | | `VAULT_1_ATTACHMENTS_PATH` | Dossier d'attachements (optionnel) | `06_Boite_a_Outils/6.2_Attachments` | | `VAULT_1_SCAN_ATTACHMENTS` | Scan d'images au démarrage (défaut : true) | `true` | **Règles de nommage :** lettres, chiffres et tirets uniquement ; pas d'espaces ; le nom doit correspondre au chemin dans le conteneur. --- ## 🔒 Authentification > **Désactivée par défaut** — Compatible avec toutes les installations existantes. Système optionnel basé sur **JWT + Argon2id** avec contrôle d'accès par vault. ### Activer l'authentification 1. `cp .env.example .env` 2. Éditez `.env` : ```bash OBSIGATE_AUTH_ENABLED=true OBSIGATE_ADMIN_USER=admin OBSIGATE_ADMIN_PASSWORD=votre_mot_de_passe # Laissez vide = auto-généré (voir logs) # OBSIGATE_SECURE_COOKIES=false # true si derrière HTTPS ``` 3. Dans `docker-compose.yml` : `env_file: - .env` > **Ne mettez jamais de mot de passe dans `docker-compose.yml` !** Utilisez toujours `.env`. ### Premier démarrage Si aucun utilisateur n'existe, ObsiGate crée automatiquement un compte admin et **affiche le mot de passe une seule fois dans les logs** : ```bash docker-compose logs obsigate | grep -A4 "PREMIER" ``` ### Gestion des utilisateurs via CLI ```bash # Créer un utilisateur docker exec obsigate python backend/create_admin.py create alice MonMotDePasse --role user --vaults Recettes IT # Créer un admin avec accès total docker exec obsigate python backend/create_admin.py create bob SecretPass --role admin --vaults "*" # Lister / supprimer docker exec obsigate python backend/create_admin.py list docker exec obsigate python backend/create_admin.py delete alice ``` ### Interface d'administration Un compte **admin** connecté voit une icône 🛡️ dans le header : liste, création/édition/suppression d'utilisateurs, assignation des vaults, activation/désactivation de comptes. ### Contrôle d'accès par vault | Valeur vaults | Accès | |---------------|-------| | `["*"]` | Toutes les vaults (y compris futures) — défaut admin | | `["Recettes", "IT"]` | Uniquement ces vaults | | `[]` | Aucun accès | ### Variables d'environnement d'auth | Variable | Description | Défaut | |----------|-------------|--------| | `OBSIGATE_AUTH_ENABLED` | Activer l'authentification | `false` | | `OBSIGATE_ADMIN_USER` | Nom de l'admin auto-créé | `admin` | | `OBSIGATE_ADMIN_PASSWORD` | Mot de passe admin (vide = auto-généré) | *(auto)* | | `OBSIGATE_SECURE_COOKIES` | Cookie `Secure` (HTTPS uniquement) | `false` | | `OBSIGATE_ACCESS_TOKEN_TTL` | Durée de vie token JWT (secondes) | `3600` | | `OBSIGATE_REFRESH_TOKEN_TTL` | Durée de vie refresh token (secondes) | `2592000` | | `OBSIGATE_LOGIN_MAX_ATTEMPTS` | Tentatives de login max par IP | `10` | | `OBSIGATE_ACCOUNT_MAX_ATTEMPTS` | Tentatives de login max par compte | `10` | | `OBSIGATE_LOGIN_WINDOW_SECONDS` | Fenêtre de rate limiting (secondes) | `900` | | `OBSIGATE_TRUST_PROXY` | Faire confiance à `X-Forwarded-For` pour l'IP client (reverse proxy) | `false` | | `OBSIGATE_WEBHOOK_ALLOW_HTTP` | Autoriser les webhooks non HTTPS | `false` | | `OBSIGATE_WEBHOOK_ALLOW_PRIVATE` | Autoriser les webhooks vers des adresses privées/boucle | `false` | | `OBSIGATE_PDF_MAX_SIZE_MB` | Taille max des PDF extraits (text indexation) | `50` | | `OBSIGATE_MEDIA_MAX_INLINE_MB` | Taille max pour la lecture audio/vidéo intégrée (au-delà : téléchargement) | `500` | | `OBSIGATE_PDF_EXTRACT_TIMEOUT` | Timeout extraction PDF (secondes) | `30` | | `OBSIGATE_TAVILY_API_KEY` / `OBSIGATE_BRAVE_API_KEY` / `OBSIGATE_SERPAPI_API_KEY` / `OBSIGATE_EXA_API_KEY` | Fournisseurs de recherche web à clé (essayés avant SearXNG) | — | | `OBSIGATE_WEB_PROVIDERS` | Ordre des fournisseurs de recherche (ex. `brave,searxng`) | — | | `OBSIGATE_WEB_RETRY` | Réessais réseau des outils web (backoff maison) | `1` | | `OBSIGATE_WEB_CACHE_TTL` | Durée du cache SQLite des résultats web (secondes, `0` = off) | `900` | | `OBSIGATE_GITEA_URL` / `OBSIGATE_GITEA_TOKEN` | Source connectée Gitea (outil `git_list_repos`…) | — | | `OBSIGATE_GITHUB_TOKEN` | Jeton GitHub (outil `git_list_repos`…) | — | > Ces clés peuvent aussi être saisies **depuis l'interface** (menu → Configurations → > « Sources connectées & recherche ») : la valeur saisie est stockée dans `data/api_keys.json` > et prime sur la variable d'environnement. ### Volume pour la persistance Les données d'auth (`users.json`, `secret.key`) sont stockées dans `/app/data` : ```yaml volumes: - ./data:/app/data # Persistance des utilisateurs et clé JWT ``` --- ## ➕ Ajouter une nouvelle vault ### Méthode 1 : Édition directe 1. `docker-compose down` 2. Ajoutez le volume : `- /nouveau/chemin/vault:/vaults/NouvelleVault:ro` 3. Ajoutez les variables : `VAULT_4_NAME=NouvelleVault` + `VAULT_4_PATH=/vaults/NouvelleVault` 4. Redémarrez : `./build.sh` ### Méthode 2 : Hot-reload (recommandé) 1. Ajoutez volume + variables comme ci-dessus 2. `./build.sh` 3. `curl http://localhost:2020/api/index/reload` ### Méthode 3 : API dynamique (sans redémarrage) ```bash curl -X POST http://localhost:2020/api/vaults/add \ -H "Content-Type: application/json" \ -d '{"name": "NouvelleVault", "path": "/vaults/NouvelleVault"}' curl -X DELETE http://localhost:2020/api/vaults/NouvelleVault ``` --- ## 🔨 Build & déploiement avec build.sh ### Utilisation de base ```bash chmod +x build.sh # une seule fois ./build.sh # build from scratch + démarrage ``` ### Options disponibles | Option | Description | |--------|-------------| | `--help`, `-h` | Affiche l'aide complète | | `--build-only` | Construit l'image sans démarrer le conteneur | | `--no-cache` | Rebuild complet sans cache Docker **(défaut)** | | `--cache` | Utilise le cache Docker (plus rapide si peu de changements) | | `--progress=plain` | Sortie verbeuse (recommandé pour le debug) | | `--progress=tty` | Sortie interactive avec barres de progression | ### Ce que fait le script 1. **Vérifie** Docker et Docker Compose (versions) 2. **Valide** `docker-compose.yml` (présence + syntaxe) 3. **Vérifie chaque volume** monté (avertit si la source n'existe pas) 4. **Construit** l'image Docker (multi-stage, ~180MB) 5. **Démarre** le conteneur (`docker compose up -d`) 6. **Affiche** statut + logs en temps réel ### Arrêter / redémarrer ```bash docker compose down # Arrêter docker compose up -d # Redémarrer sans rebuild docker compose logs -f # Voir les logs ``` --- ## 🖼️ Rendu d'images Obsidian ObsiGate supporte **toutes les syntaxes d'images Obsidian** avec résolution intelligente multi-stratégies. ### Syntaxes supportées 1. **Markdown standard avec attributs HTML** : `[](https://example.com)` 2. **Wiki-link embed chemin complet** : `![[06_Boite_a_Outils/6.2_Attachments/image.svg]]` 3. **Wiki-link embed nom de fichier** : `![[image.svg]]` 4. **Markdown standard** : `![alt text](path/to/image.png)` ### Résolution intelligente (7 stratégies, par priorité) 1. Chemin absolu 2. Dossier d'attachements configuré (`VAULT_N_ATTACHMENTS_PATH`) 3. Index de démarrage (match unique) 4. Même répertoire que le fichier markdown 5. Racine du vault 6. Index de démarrage (match le plus proche) 7. Fallback : placeholder stylisé `[image not found: filename.ext]` ### Visionneuse & arborescence Les images sont de plein droit des fichiers du vault : elles apparaissent dans l'arborescence, sont indexées (nom + métadonnées, **jamais les octets**) et s'ouvrent dans une **visionneuse dédiée** — zoom molette 0,1×–8×, pan au glisser, double-clic pour réinitialiser, navigation ←/→ entre les images du dossier (avec pellicule de miniatures WebP), panneau de métadonnées, lightbox plein écran, ouverture de l'original et téléchargement. Le filtre de recherche `ext:png`/`ext:jpg` est disponible. Formats décodables : PNG, JPEG, GIF, WebP, BMP, ICO, SVG (SVG servi avec une politique CSP `sandbox`). **HEIC/HEIF** (iPhone) n'est pas décodable par les navigateurs et n'est pas pris en charge. ### Configuration ```yaml environment: - VAULT_1_NAME=MonVault - VAULT_1_PATH=/vaults/MonVault - VAULT_1_ATTACHMENTS_PATH=Assets/Images # Chemin relatif - VAULT_1_SCAN_ATTACHMENTS=true # Activer le scan (défaut) ``` ### Rescan manuel ```bash curl -X POST http://localhost:2020/api/attachments/rescan/MonVault ``` --- ## 🖥️ Desktop (Tauri) — Application native > 📖 Guide complet : [Desktop (Tauri)](docs/GUIDES/DESKTOP.md) ObsiGate Desktop est une application native construite avec [Tauri](https://tauri.app/) (Rust + webview système). Elle embarque le backend Python et le frontend dans un exécutable standalone — zéro Docker, zéro ligne de commande. > 🚧 **Version 2.0.0 — binaires en cours de stabilisation.** Pour l'instant, le build depuis les sources est recommandé. ### Fonctionnalités desktop natives | Fonctionnalité | Web | Desktop | |---|---|---| | Accès fichiers local | Via upload | Natif (sélecteur dossier) | | Thème système | Manuel | Auto (suit OS dark/light) | | Notifications | Service Worker | Natif OS | | Associations `.md` | ❌ | ✅ « Ouvrir avec ObsiGate » | | Tray icon | ❌ | ✅ Barre des tâches | | Auto-update | ❌ | ✅ Vérifie les releases Gitea | | Mode hors-ligne | Limité | Complet (backend local) | ### Téléchargement (binaires pré-buildés) Les releases sont publiées sur [Gitea](https://git.dracodev.net/Projets/ObsiGate/releases) : | Plateforme | Format | |---|---| | **Linux** | `.deb` + `.AppImage` | | **Windows** | `.msi` + `.exe` (NSIS) | ```bash # Linux — .deb (Debian/Ubuntu/Deepin) sudo dpkg -i obsigate_2.0.0_amd64.deb # Linux — .AppImage (toute distrib) chmod +x ObsiGate_2.0.0_amd64.AppImage && ./ObsiGate_2.0.0_amd64.AppImage ``` ```cmd REM Windows : double-cliquer sur ObsiGate_2.0.0_x64.msi (ou le setup NSIS) ``` ### Démarrage 1. **Lancez l'application** depuis le menu ou la ligne de commande 2. Le backend Python démarre automatiquement sur `127.0.0.1:17890` (splash « Démarrage… » pendant le boot) 3. La fenêtre s'ouvre et charge l'interface ObsiGate 4. **Premier lancement** : sélectionnez le dossier de vos vaults Obsidian via le sélecteur natif 5. Pour fermer : icône tray → Quitter (arrêt propre du backend) ### Build depuis les sources Guide détaillé : [desktop/README.md](./desktop/README.md). #### Prérequis communs | Outil | Version | Installation | |---|---|---| | Rust (cargo) | ≥ 1.75 | `rustup` | | Tauri CLI | ≥ 2.0 | `cargo install tauri-cli` | | Git | — | — | | Dépendances système Linux | — | `sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev` | > **Important — staging :** `tauri.conf.json` embarque `backend/**` et `frontend/**` **depuis le dossier `desktop/`**. > Les scripts de build copient automatiquement `../backend` et `../frontend` dans `desktop/` avant `cargo tauri build`. > Sans ce staging, le build échoue avec « glob pattern backend/**/* path not found ». #### 🪟 Windows — `build-windows.bat` ```cmd REM Prérequis (via Scoop) : rustup, curl, git scoop install rustup curl git rustup default stable cargo install tauri-cli cd desktop build-windows.bat ``` Étapes du script : 1. Tue les processus Python résiduels (`taskkill /F /IM python.exe`) 2. Télécharge **Python 3.11 embed** (python.org) → `desktop\python-embed\` + activation de pip (`python311._pth`) 3. `pip install -r ..\backend\requirements.txt` dans l'embed 4. **Staging** : copie `..\backend` et `..\frontend` dans `desktop\` 5. `cargo tauri build --target x86_64-pc-windows-msvc --bundles nsis` 6. Copie `python-embed` à côté de l'exécutable (`target\x86_64-pc-windows-msvc\release\`) pour le mode dev local 7. Nettoie les dossiers stagés → **Artefact :** `desktop\target\x86_64-pc-windows-msvc\release\bundle\nsis\ObsiGate_2.0.0_x64-setup.exe` #### 🐧 Linux — `build-linux.sh` ```bash cd desktop chmod +x build-linux.sh ./build-linux.sh ``` Étapes du script : 1. Vérifie Rust + Tauri CLI, installe les dépendances système (apt) 2. Crée un venv Python `desktop/python-embed/venv` + `pip install -r ../backend/requirements.txt` 3. **Staging** : copie `../backend` et `../frontend` dans `desktop/` 4. `cargo tauri build --target x86_64-unknown-linux-gnu --bundles deb,appimage` 5. Copie le runtime (`python-embed/`, `backend/`, `frontend/`) à côté de l'exécutable → **Artefacts :** - `desktop/target/x86_64-unknown-linux-gnu/release/bundle/deb/obsigate_2.0.0_amd64.deb` - `desktop/target/x86_64-unknown-linux-gnu/release/bundle/appimage/ObsiGate_2.0.0_amd64.AppImage` ### 🤖 Builds CI/CD — artefacts automatiques **Oui** — le workflow [`.gitea/workflows/desktop-build.yml`](./.gitea/workflows/desktop-build.yml) construit les binaires desktop à chaque push sur `main` touchant `desktop/**`, `frontend/**` ou `backend/**` (et manuellement via `workflow_dispatch`), sur des **runners self-hosted** : | Job | Runner | Artefacts (conservés 30 jours) | |---|---|---| | `build-windows` | `[self-hosted, windows, desktop]` | `desktop/target/release/bundle/msi/*.msi` | | `build-linux` | `[self-hosted, linux, desktop]` | `*.AppImage` + `*.deb` | - Les artefacts sont téléchargeables depuis la page **Actions** du run Gitea. - La publication en **Gitea Release** est prévue sur les tags `v*` (étape `Publish to Gitea Release`). - Le workflow web [`.gitea/workflows/ci.yml`](./.gitea/workflows/ci.yml) gère de son côté lint → tests → sécurité → build Docker → e2e Playwright. ### Architecture Desktop ``` ┌────────────────────────────────────────────┐ │ Tauri (Rust) │ │ ├─ Webview (webview système) │ │ │ └─ Frontend (HTML/JS/CSS) │ │ └─ Sidecar Python │ │ └─ uvicorn backend.main:app │ │ └─ port 127.0.0.1:17890 │ └────────────────────────────────────────────┘ ``` Cycle de vie : Tauri spawn le backend Python → health check → splash de démarrage → redirection vers la webview. À la fermeture : kill propre du backend. --- ## 📖 Utilisation ### Interface web 1. **Navigation** : Cliquez sur les vaults dans la sidebar pour les développer 2. **Recherche** : Utilisez la barre de recherche pour chercher dans toutes les vaults 3. **Tags** : Cliquez sur les tags pour filtrer les contenus 4. **Wikilinks** : Les liens `[[page]]` sont cliquables et navigables 5. **Images** : Toutes les syntaxes d'images Obsidian sont rendues automatiquement 6. **Thème** : Basculez entre thème clair/sombre avec l'icône 🌙/☀️ ### Raccourcis clavier | Action | Raccourci | |--------|-----------| | Recherche | `Ctrl + K` ou `/` | | Toggle thème | `Ctrl + T` | | Focus recherche | `Esc` | --- ## 👥 Collaboration temps réel > 📖 Guide complet : [Édition & collaboration](docs/GUIDES/COLLABORATION.md) Plusieurs utilisateurs peuvent éditer le même document markdown simultanément (façon Google Docs) : - **Fusion sans conflit** grâce à Yjs (CRDT) : deux personnes peuvent taper au même endroit, aucune modification n'est perdue. - **Curseurs distants colorés** et sélections visibles dans CodeMirror, avec le nom de chaque utilisateur. - **Indicateur de présence** dans l'en-tête de l'éditeur (avatars + statut de connexion). - **Reconnexion automatique** (backoff exponentiel) : l'état est fusionné au retour. - **Persistance serveur** : le document est écrit sur disque 2 s après la dernière modification. - **Transport** : WebSocket `ws(s):///ws/collab/{vault}/{chemin}`, authentifié par cookie `access_token` (ou `?token=`) et soumis au contrôle d'accès par vault. Aucune configuration n'est nécessaire : ouvrez le même fichier dans deux navigateurs (ou deux fenêtres) pour voir la collaboration en action. --- ## 🔌 API > 📖 Guide complet : [API REST](docs/GUIDES/API_REST.md) · [Serveur MCP](docs/GUIDES/MCP.md) ObsiGate expose une API REST complète : | Endpoint | Description | Méthode | Auth | |----------|-------------|---------|------| | `/api/health` | Health check (status, version, stats) | GET | Non | | `/api/auth/status` | Statut auth (activé, utilisateurs présents) | GET | Non | | `/api/auth/login` | Connexion (access token + cookie refresh) | POST | Non | | `/api/auth/refresh` | Renouveler l'access token via cookie refresh | POST | Cookie | | `/api/auth/logout` | Déconnexion + révocation refresh token | POST | Oui | | `/api/auth/me` | Infos utilisateur courant | GET | Oui | | `/api/auth/change-password` | Changer son mot de passe | POST | Oui | | `/api/auth/admin/users` | Lister / créer des utilisateurs | GET/POST | Admin | | `/api/auth/admin/users/{u}` | Modifier / supprimer un utilisateur | PATCH/DELETE | Admin | | `/api/vaults` | Liste des vaults (filtrée par permissions) | GET | Oui | | `/api/browse/{vault}?path=` | Navigation dans les dossiers | GET | Oui | | `/api/file/{vault}?path=` | Contenu rendu d'un fichier | GET | Oui | | `/api/file/{vault}/raw?path=` | Contenu brut d'un fichier | GET | Oui | | `/api/file/{vault}/download?path=` | Téléchargement d'un fichier | GET | Oui | | `/api/file/{vault}/save?path=` | Sauvegarder un fichier | PUT | Oui | | `/api/file/{vault}?path=` | Supprimer un fichier | DELETE | Oui | | `/api/search/advanced` | Recherche avancée TF-IDF (+ `semantic=true` pour l'hybride) | GET | Oui | | `/api/suggest` / `/api/tags/suggest` | Autocomplétion | GET | Oui | | `/api/tags?vault=` | Tags uniques avec compteurs | GET | Oui | | `/api/index/reload` | Force un re-scan des vaults | GET | Admin | | `/api/events` | Flux SSE temps réel | GET | Oui | | `/api/vaults/add` / `/api/vaults/{name}` | Gestion dynamique des vaults | POST/DELETE | Admin | | `/api/image/{vault}?path=` | Servir une image | GET | Oui | | `/api/media/{vault}/thumb?path=&size=` | Miniature WebP (cache disque) | GET | Oui | | `/api/config` | Lire / écrire la configuration | GET/POST | Oui/Admin | | `/api/diagnostics` | Statistiques index et mémoire | GET | Admin | > Quand `OBSIGATE_AUTH_ENABLED=false`, tous les endpoints sont accessibles sans token. > Tous les endpoints exposent des schémas Pydantic documentés ; doc interactive sur `/docs` (Swagger UI). **Exemples :** ```bash curl http://localhost:2020/api/health curl http://localhost:2020/api/vaults curl "http://localhost:2020/api/search/advanced?q=recette%20tag:cuisine&vault=all&limit=20&offset=0&sort=relevance" curl "http://localhost:2020/api/suggest?q=piz&vault=all" curl "http://localhost:2020/api/file/Recettes?path=pizza.md" ``` --- ## 🔍 Recherche avancée > 📖 Guide complet : [Recherche, PDF & Excalidraw](docs/GUIDES/RECHERCHE_PDF_EXCALIDRAW.md) ### Syntaxe de requête | Opérateur | Description | Exemple | |-----------|-------------|---------| | `tag:` | Filtrer par tag | `tag:recette docker` | | `#` | Raccourci tag | `#linux serveur` | | `vault:` | Filtrer par vault | `vault:IT kubernetes` | | `title:` | Filtrer par titre | `title:pizza` | | `path:` | Filtrer par chemin | `path:recettes/soupes` | | `ext:` | Filtrer par type de fichier | `ext:md kubernetes` | | `"phrase exacte"` | Recherche de phrase | `tag:"multi mots"` | Les opérateurs sont combinables : `tag:linux vault:IT ext:md serveur web`. ### Support PDF Les fichiers PDF de vos vaults s'affichent en ligne dans le navigateur via le visualiseur PDF natif (iframe + ``). Le visualiseur streame le fichier via HTTP Range (206 Partial Content) — les gros PDF se chargent progressivement. Le texte est extrait à l'indexation (pypdf / pymupdf) — le contenu PDF est donc recherchable via la recherche full-text. Filtrez avec `ext:pdf` pour restreindre les résultats aux PDF. Les métadonnées (pages, titre, auteur) sont disponibles via `GET /api/file/{vault}/pdf/info` sans transférer le document. **Limitations :** pas d'OCR (les PDF scannés ne sont pas recherchables), pas d'annotation, pas d'édition du PDF lui-même. ### Diagrammes Excalidraw Les fichiers `.excalidraw` et `.excalidraw.md` s'ouvrent dans un éditeur visuel Excalidraw complet, intégré dans une iframe sandboxée — dessinez, modifiez et sauvegardez sans quitter ObsiGate. Les modifications sont sauvegardées automatiquement (2 s) ou avec `Ctrl+S` ; l'éditeur suit le thème clair/sombre. Le texte des éléments du diagramme est extrait à l'indexation : il est donc recherchable via la recherche full-text (`ext:excalidraw`). Les fichiers créés avec le **plugin Obsidian Excalidraw** (y compris le format `.excalidraw.md` compressé) sont compatibles. ### Raccourcis clavier | Raccourci | Action | |-----------|--------| | `Ctrl+K` / `Cmd+K` | Focaliser la barre de recherche | | `/` | Focaliser la recherche (hors champ texte) | | `↑` / `↓` | Naviguer dans les suggestions | | `Enter` | Sélectionner la suggestion active ou lancer la recherche | | `Escape` | Fermer les suggestions / quitter la recherche | ### Fonctionnalités - **TF-IDF** : scoring par fréquence pondérée des termes - **Boost titre** : correspondances dans le titre ×3 - **Normalisation des accents** : `resume` trouve `résumé` - **Snippets surlignés** (``), **facettes** (compteurs par vault/tag), **pagination** (50/page), **tri** pertinence/date, **chips** de filtres, **historique** (50 recherches) - **Recherche sémantique** (optionnelle) : le toggle `~` (ou `Alt+S`) fusionne le classement TF-IDF avec un classement par embeddings (RRF). Fonctionne sans dépendance avec un provider de hachage ; installez `backend/requirements-semantic.txt` et/ou renseignez `OBSIGATE_EMBEDDING_*` pour de vrais embeddings `all-MiniLM-L6-v2`. Voir [docs/features/semantic-search.md](docs/features/semantic-search.md). --- ## 🔧 Dépannage **Port déjà utilisé :** ```bash sudo netstat -tulpn | grep 2020 # Changer le port dans docker-compose.yml : ports: - "2021:8080" ``` **Vault non trouvée :** chemins absolus, permissions de lecture, redémarrer le conteneur après modification. **Build échoue :** ```bash docker system prune -f docker compose down ./build.sh --progress=plain # Si l'échec persiste : ./build.sh --progress=plain 2>&1 | tee build.log ``` **Logs pour debugging :** ```bash docker compose logs -f obsigate docker compose logs --tail=100 obsigate ``` **Desktop :** les logs du backend sont dans `%APPDATA%\ObsiGate\logs\backend.log` (Windows) / `~/.config/obsigate/logs/backend.log` (Linux). --- ## ⚡ Performance | Métrique | Estimation | |----------|------------| | **Indexation** | ~1–2s pour 1 000 fichiers markdown | | **Recherche avancée** | < 10ms pour la plupart des requêtes (index inversé + TF-IDF) | | **Résolution wikilinks** | O(1) via table de lookup | | **Mémoire** | ~80–150MB par 1 000 fichiers (contenu capé à 100 KB/fichier) | | **Image Docker** | ~180MB (multi-stage) | | **CPU** | Non-bloquant ; recherche offloadée sur thread pool dédié | ### Paramètres recommandés par taille de vault | Taille | Fichiers | `search_workers` | `prefix_max_expansions` | `max_content_size` | |--------|----------|-------------------|--------------------------|---------------------| | Petit | < 500 | 1 | 50 | 100 000 | | Moyen | 500–5 000 | 2 | 50 | 100 000 | | Grand | 5 000+ | 4 | 30 | 50 000 | Configurables via l'interface (Settings) ou l'API `/api/config`. ### Optimisations clés - **Index inversé avec set-intersection** + prefix matching par recherche binaire - **ThreadPoolExecutor** : recherche CPU-bound hors de l'event loop asyncio - **InvertedIndex incrémental** : hooks `add_document`/`remove_document`, plus de rebuild O(N) - **Compression GZip** (~70% de bande passante économisée) + **Cache-Control immutable** (1 an) - **Race condition guard** (`currentSearchId` + AbortController), progress bar, timeout 30s - **Rendu Markdown singleton**, debounced icon rendering, recherche sans I/O disque --- ## 🛡️ Sécurité > 📖 Guide complet : [Authentification & sécurité](docs/GUIDES/AUTHENTIFICATION_SECURITE.md) - **Path traversal** : tous les endpoints fichier valident que le chemin résolu reste dans la vault - **Rate limiting** : 10 tentatives de login max par IP sur 15 minutes + lockout par compte (5 tentatives) - **Audit log** : écritures/suppressions/config journalisées dans `data/audit.log` (JSON lines, rotation 10 MB) - **Backup automatique** : chaque modification/suppression sauvegardée dans `.obsigate-backup/` avec timestamp - **Secret redaction** : masquage automatique des JWT, clés API, tokens dans les aperçus - **Utilisateur non-root** : conteneur Docker sous `obsigate` (UID 1000) - **Volumes read-only** : vaults montées en `:ro` par défaut - **Secrets dans `.env`** : jamais dans `docker-compose.yml` - **Atomic writes** : tmp+replace pour users.json, shares.json, webhooks.json --- ## 🏗️ Stack technique - **Backend** : Python 3.11 + FastAPI 0.110 + Uvicorn - **Auth** : python-jose (JWT HS256) + argon2-cffi (Argon2id) - **File Watcher** : watchdog 4.x (inotify natif + fallback polling) - **Frontend** : Vanilla JS + HTML + CSS (zéro framework, zéro build) - **Rendu Markdown** : mistune 3.x - **PDF Export** : WeasyPrint 60+ - **Desktop** : Tauri v2 (Rust) + Python embarqué - **Image Docker** : python:3.11-slim (multi-stage) - **Stockage utilisateurs** : JSON local (`data/users.json`) — aucune base de données - **Architecture** : SPA + API REST + SSE --- ## 🏠 Architecture ``` ┌─────────────────┐ ┌─────────────────────────────────────────┐ │ Navigateur │◄───►│ FastAPI (backend/main.py) │ │ (SPA) │ REST │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ indexer.py │ │ search.py │ │ │ app.js │ │ │ (scan+cache) │ │ (in-memory) │ │ │ style.css │ │ └───────┬────── └──────┬───────┘ │ │ index.html │ │ │ │ │ └─────────────────┘ │ ┌───┴──────────────┴───┐ │ │ │ Index en mémoire │ │ │ │ (fichiers, tags, │ │ │ │ contenu, lookup) │ │ │ └───────────────────────┘ │ └─────────────────────────────────────────┘ ``` **Flux de données :** 1. Au démarrage, `indexer.py` scanne tous les vaults en parallèle (thread pool, non-bloquant) 2. Contenu, tags (YAML + inline) et métadonnées mis en cache en mémoire 3. Table de lookup O(1) pour la résolution des wikilinks 4. `watcher.py` surveille les fichiers (watchdog natif ou polling) 5. Modifications → mise à jour incrémentale de l'index 6. Changements notifiés au frontend via SSE 7. Recherche sur l'index mémoire (zéro I/O disque) 8. Le frontend SPA communique via REST + SSE --- ## 📝 Développement ### 🧪 Tests et CI — règles obligatoires (avant chaque push) > ⚠️ **Règle absolue — contributeurs humains et agents IA** : ne jamais faire > de `git push` sans avoir exécuté **localement** la séquence complète > ci-dessous avec **100 % de succès**. Le push ne sert pas à découvrir les > échecs : la CI est un filet de sécurité, pas un outil de diagnostic. #### Vérifications locales avant commit | Étape | Commande | Job CI équivalent | |---|---|---| | Lint backend | `ruff check backend/` | `lint` | | Validation des imports frontend | `node tests/frontend/validate-imports.mjs` | `lint` | | Tests unitaires frontend | `node tests/frontend/unit.test.mjs` | `lint` | | Tests backend | `pytest tests/ -q` | `test` | | **E2E Playwright** | `npm run test:e2e` (~10 min) | `e2e` | #### Tests E2E locaux (`npm run test:e2e`) Le script `scripts/run-e2e-local.sh` reproduit fidèlement les conditions du job CI `e2e` (`.gitea/workflows/ci.yml`) : - backend démarré nativement (venv `.venv-e2e`, Python 3.11 via `uv`) ; - authentification désactivée (`OBSIGATE_AUTH_ENABLED=false`) ; - fixtures `test_vault` (TestVault) et `test_dir` (TestDir) ; - port `2029` (baseURL de `playwright.config.ts`) ; - projet Playwright `chromium-desktop` uniquement (comme la CI). Prérequis : `uv`, Node.js ≥ 20, navigateurs Playwright (`npx playwright install chromium`). Le venv est créé automatiquement au premier lancement. Docker n'est pas nécessaire. ```bash npm run test:e2e # suite complète bash scripts/run-e2e-local.sh --headed # navigateur visible bash scripts/run-e2e-local.sh -g "reset panes" # filtre sur un test ``` Sous Windows, si `bash` n'est pas exploitable (WSL indisponible, git-bash bloqué par une politique de contrôle d'application), utiliser le lanceur PowerShell équivalent : ```powershell npm run test:e2e:ps pwsh -File scripts/run-e2e-local.ps1 -PlaywrightArgs @('-g','reset panes') ``` La suite doit se terminer sur **tous les tests passant** (60 actuellement), sans échec ni dépendance aux retries. En cas d'échec : corriger et relancer localement jusqu'à 100 %, puis seulement commiter. #### Règles d'écriture des tests (leçon apprise) - **Vérifier chaque sélecteur dans le DOM réel** avant de l'utiliser dans un test. Bug réel rencontré : un test ciblait `#cp-input` alors que l'input de la palette porte uniquement la classe `.cp-input` (aucun id) — le test ne pouvait passer dans aucun environnement. - Tout test nouveau ou modifié doit être **exécuté localement** (au minimum avec `-g "nom du test"`) avant le push. - Pas de contournements qui masquent une instabilité (`waitForTimeout` arbitraires, fallback silencieux) : traiter la cause racine. #### Commits et push - Message de commit : sujet à l'impératif ≤ 50 caractères ; corps (72 col.) uniquement s'il apporte une information utile. - Un commit = un changement logique (ne pas mêler fix et refactoring). - Push uniquement quand les 5 étapes locales sont vertes. Pipeline CI : `lint → test → security → build → e2e`. ### Structure du projet ``` ObsiGate/ ├── backend/ # API FastAPI │ ├── main.py # Endpoints, Pydantic models, rendu markdown │ ├── indexer.py # Scan des vaults, index en mémoire, lookup table │ ├── search.py # Moteur de recherche fulltext avec scoring │ ├── watcher.py # Surveillance fichiers (watchdog + debounce) │ ├── auth/ # Module d'authentification (JWT + Argon2id) │ └── create_admin.py # CLI gestion utilisateurs ├── frontend/ # Interface web (Vanilla JS, zéro framework) │ ├── index.html # Page SPA + écran de login + splash de boot │ ├── js/ # Modules ES (app, viewer, editor, graph, …) │ └── style.css # Styles (CSS variables, thèmes, responsive) ├── desktop/ # Application native Tauri (Rust + Python embarqué) │ ├── src/main.rs # Shell natif : cycle de vie backend, tray, menus │ ├── build-windows.bat │ └── build-linux.sh ├── data/ # Données persistantes (créé au démarrage) ├── Dockerfile # Multi-stage, healthcheck, non-root ├── docker-compose.yml # Déploiement avec healthcheck et auth env vars ├── build.sh # Build & déploiement automatisé └── docs/ # ROADMAP, guides, audits ``` ### Contribuer Voir [docs/CONTRIBUTING.md](./docs/CONTRIBUTING.md) pour les standards de code et [docs/DELIVERY_WORKFLOW.md](./docs/DELIVERY_WORKFLOW.md) pour la méthode de livraison obligatoire. --- ## 📄 Licence Ce projet est sous licence **MIT** — voir le fichier [LICENSE](LICENSE) pour les détails. --- ## 🤝 Support - **Issues** : [git.dracodev.net/Projets/ObsiGate/issues](https://git.dracodev.net/Projets/ObsiGate/issues) - **Documentation** : [git.dracodev.net/Projets/ObsiGate/wiki](https://git.dracodev.net/Projets/ObsiGate/wiki) --- ## 📝 Changelog Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.23.0). --- *Projet : ObsiGate | Version : 2.23.0 | Dernière mise à jour : Septembre 2026*