Files
ObsiGate/README.fr.md
T
bruno 8f26a418a9
CI / lint (push) Successful in 1m29s
CI / security (push) Successful in 1m3s
CI / test (push) Successful in 2m55s
CI / build (push) Successful in 55s
CI / e2e (push) Successful in 10m44s
test(ai): rendre le test du menu mention non flaky (nettoyage d'etat + attente du fetch)
2026-09-16 19:30:15 -04:00

40 KiB
Raw Blame History

ObsiGate

Version française — ce document est le miroir synchronisé de README.md (référence complète). Dernière synchronisation : juin 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 License: MIT Docker Python CI/CD

┌─────────────────────────────────────────────────────────┐
│  [🔍 Recherche...]          [☀/🌙 Thème]   ObsiGate    │
├──────────────┬──────────────────────────────────────────┤
│  SIDEBAR     │           CONTENT AREA                   │
│  ▼ Recettes  │   📄 Titre du fichier                    │
│    📁 Soupes │   Tags: #recette #rapide                 │
│    📄 Pizza  │   [Contenu Markdown rendu]               │
│  ▼ IT        │                                          │
│    📁 Docker │                                          │
│  Tags Cloud  │                                          │
└──────────────┴──────────────────────────────────────────┘

📋 Table des matières


✨ 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)
  • 👥 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)
  • 📱 É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)
  • 🗺️ 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)
  • 💡 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
  • 🎨 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

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 :

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 :

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

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

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

chmod +x build.sh
./build.sh

Alternative manuelle :

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 :
    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 :

docker-compose logs obsigate | grep -A4 "PREMIER"

Gestion des utilisateurs via CLI

# 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_PDF_EXTRACT_TIMEOUT Timeout extraction PDF (secondes) 30

Volume pour la persistance

Les données d'auth (users.json, secret.key) sont stockées dans /app/data :

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)

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

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

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 : [<img width="180" src="path/to/image.svg"/>](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]

Configuration

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

curl -X POST http://localhost:2020/api/attachments/rescan/MonVault

🖥️ Desktop (Tauri) — Application native

ObsiGate Desktop est une application native construite avec Tauri (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 :

Plateforme Format
Linux .deb + .AppImage
Windows .msi + .exe (NSIS)
# 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
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.

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

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

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 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 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

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)://<hôte>/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

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/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 :

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

Syntaxe de requête

Opérateur Description Exemple
tag:<nom> Filtrer par tag tag:recette docker
#<nom> Raccourci tag #linux serveur
vault:<nom> Filtrer par vault vault:IT kubernetes
title:<texte> Filtrer par titre title:pizza
path:<texte> Filtrer par chemin path:recettes/soupes
ext:<type> 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 + <embed>). 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 (<mark>), 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.

🔧 Dépannage

Port déjà utilisé :

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 :

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 :

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é

  • 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 (~5 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.

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

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 pour les standards de code et docs/DELIVERY_WORKFLOW.md pour la méthode de livraison obligatoire.


📄 Licence

Ce projet est sous licence MIT — voir le fichier LICENSE pour les détails.


🤝 Support


📝 Changelog

Consultez le CHANGELOG.md pour l'historique complet de toutes les versions (v1.0.0 → v2.5.2).


Projet : ObsiGate | Version : 2.5.2 | Dernière mise à jour : Juin 2026