ObsiGate/README.md

17 KiB
Raw Blame History

ObsiGate

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

┌─────────────────────────────────────────────────────────┐
│  [🔍 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

  • 🗂️ Multi-vault : Visualisez plusieurs vaults Obsidian simultanément
  • 🌳 Navigation arborescente : Parcourez vos dossiers et fichiers dans la sidebar
  • 🔍 Recherche fulltext : Recherche instantanée dans le contenu et les titres
  • 🏷️ Tag cloud : Filtrage par tags extraits des frontmatters YAML
  • 🔗 Wikilinks : Les [[liens internes]] Obsidian sont cliquables
  • 🎨 Syntax highlight : Coloration syntaxique des blocs de code
  • 🌓 Thème clair/sombre : Toggle persisté en localStorage
  • 🐳 Docker multi-platform : linux/amd64, linux/arm64, linux/arm/v7, linux/386
  • 🔒 Sécurité : Protection contre le path traversal, utilisateur non-root dans Docker
  • ❤️ 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

Éditez le fichier 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)

3. Lancer l'application

# Build local de l'image + démarrage
docker-compose up -d --build

# Vérifier les logs
docker-compose logs -f obsigate

Note

: ObsiGate est construit localement depuis le Dockerfile du projet. Sans build local, Docker essaiera de télécharger une image distante obsigate:latest qui n'existe pas forcément.

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 .obsidian
  3. Vérifiez les permissions : Docker doit pouvoir lire ces dossiers

Étape 2 : Configuration docker-compose.yml

Voici un exemple complet :

services:
  obsigate:
    build:
      context: .
    image: obsigate:latest
    container_name: obsigate
    restart: unless-stopped
    ports:
      - "2020:8080"  # Port local 2020 → Port conteneur 8080
    volumes:
      # Exemples de vaults (adaptez à vos chemins)
      - /home/user/Documents/Obsidian-Recettes:/vaults/Recettes:ro
      - /home/user/Documents/Obsidian-IT:/vaults/IT:ro
      - /home/user/Documents/Obsidian-Perso:/vaults/Perso:ro
    environment:
      # Configuration des vaults
      - VAULT_1_NAME=Recettes
      - VAULT_1_PATH=/vaults/Recettes
      - VAULT_2_NAME=IT
      - VAULT_2_PATH=/vaults/IT
      - VAULT_3_NAME=Perso
      - VAULT_3_PATH=/vaults/Perso

Étape 3 : Construction de l'image

# Build l'image Docker
docker build -t obsigate:latest .
 
# Puis démarrer le service
docker-compose up -d --build
 
# Ou utilisez le script de build multi-platform
chmod +x build.sh
./build.sh

Compatibilité Docker : l'image utilise la variante minimale de uvicorn et une version de fastapi compatible (0.110.3) afin d'éviter certaines dépendances optionnelles natives (watchfiles, uvloop, httptools, fastapi-cli, etc.) qui peuvent échouer au build sur certaines plateformes comme Alpine, ARM ou i386.


🌍 Variables d'environnement

Les vaults sont configurées par paires de variables 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_2_NAME Nom affiché de la vault IT
VAULT_2_PATH Chemin dans le conteneur /vaults/Obsidian_IT

Règles de nommage :

  • Utilisez uniquement des lettres, chiffres et tirets
  • Pas d'espaces ou caractères spéciaux
  • Le nom doit correspondre au chemin dans le conteneur

Ajouter une nouvelle vault

Méthode 1 : Édition directe

  1. Arrêtez le conteneur :

    docker-compose down
    
  2. Ajoutez un volume dans docker-compose.yml :

    volumes:
      - /nouveau/chemin/vault:/vaults/NouvelleVault:ro
    
  3. Ajoutez les variables d'environnement :

    environment:
      - VAULT_4_NAME=NouvelleVault
      - VAULT_4_PATH=/vaults/NouvelleVault
    
  4. Redémarrez :

    docker-compose up -d --build
    

Méthode 2 : Hot-reload (recommandé)

  1. Ajoutez le volume et les variables comme ci-dessus
  2. Appliquez les changements :
    docker-compose up -d --build
    
  3. Rechargez l'index via l'interface ou l'API :
    curl http://localhost:2020/api/index/reload
    

🔨 Build multi-platform

Pour les architectures multiples (Raspberry Pi, NAS, etc.) :

# Rendre le script exécutable
chmod +x build.sh

# Lancer le build multi-platform
./build.sh

Architectures supportées :

  • linux/amd64 (PC, serveurs standards)
  • linux/arm64 (Raspberry Pi 4, Apple Silicon, NAS modernes)
  • linux/arm/v7 (Raspberry Pi 3, anciens NAS)
  • linux/386 (Systèmes 32-bit legacy)

Pour un build local uniquement :

docker buildx build --platform linux/amd64 --load -t obsigate:latest .

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

🔌 API

ObsiGate expose une API REST complète :

Endpoint Description Méthode
/api/health Health check (status, version, stats) GET
/api/vaults Liste des vaults configurées GET
/api/browse/{vault}?path= Navigation dans les dossiers GET
/api/file/{vault}?path= Contenu rendu d'un fichier GET
/api/file/{vault}/raw?path= Contenu brut d'un fichier GET
/api/file/{vault}/download?path= Téléchargement d'un fichier GET
/api/file/{vault}/save?path= Sauvegarder un fichier PUT
/api/file/{vault}?path= Supprimer un fichier DELETE
/api/search?q=&vault=&tag= Recherche fulltext GET
/api/tags?vault= Tags uniques avec compteurs GET
/api/index/reload Force un re-scan des vaults GET

Tous les endpoints exposent des schémas Pydantic documentés. La doc interactive est disponible sur /docs (Swagger UI).

Exemple d'utilisation :

# Health check
curl http://localhost:2020/api/health

# Lister les vaults
curl http://localhost:2020/api/vaults

# Rechercher
curl "http://localhost:2020/api/search?q=recette&vault=all"

# Obtenir un fichier
curl "http://localhost:2020/api/file/Recettes?path=pizza.md"

🔧 Dépannage

Problèmes courants

Port déjà utilisé :

# Vérifier qui utilise le port
sudo netstat -tulpn | grep 2020
# Changer le port dans docker-compose.yml
ports:
  - "2021:8080"

Vault non trouvée :

  • Vérifiez que les chemins sont absolus
  • Assurez-vous que les permissions permettent la lecture
  • Redémarrez le conteneur après modification

Build échoue :

# Nettoyer et rebuild
docker system prune -f
docker-compose down
docker build --no-cache -t obsigate:latest .
docker-compose up -d

Logs pour debugging :

# Logs en temps réel
docker-compose logs -f obsigate

# Logs détaillés
docker-compose logs --tail=100 obsigate

Performance

Métrique Estimation
Indexation ~12s pour 1000 fichiers markdown
Recherche fulltext < 50ms (index en mémoire, zéro I/O disque)
Résolution wikilinks O(1) via table de lookup
Mémoire ~80150MB par 1000 fichiers (contenu capé à 100KB/fichier)
Image Docker ~180MB (multi-stage, sans outils de build)
CPU Minimal ; pas de polling, pas de watchers

Optimisations clés (v1.1.0)

  • Recherche sans I/O : le contenu des fichiers est mis en cache dans l'index mémoire
  • Scoring multi-facteurs : titre exact (+20), titre partiel (+10), chemin (+5), tag (+3), fréquence contenu (x1 par occurrence, capé à 10)
  • Rendu Markdown singleton : le renderer mistune est instancié une seule fois
  • AbortController : les requêtes de recherche obsolètes sont annulées côté client
  • Debounced icon rendering : lucide.createIcons() est batché via requestAnimationFrame

🛡️ Sécurité

  • Path traversal : tous les endpoints fichier valident que le chemin résolu reste dans la vault
  • Utilisateur non-root : le conteneur Docker tourne sous l'utilisateur obsigate
  • Volumes read-only : les vaults sont montées en :ro par défaut dans docker-compose

🏗️ Stack technique

  • Backend : Python 3.11 + FastAPI 0.110 + Uvicorn
  • Frontend : Vanilla JS + HTML + CSS (zéro framework, zéro build)
  • Rendu Markdown : mistune 3.x
  • Image Docker : python:3.11-slim (multi-stage)
  • Base de données : Aucune (index en mémoire uniquement)
  • Architecture : SPA + API REST

🏠 Architecture

┌─────────────────┐     ┌─────────────────────────────────────────┐
│   Navigateur    │◄───►│  FastAPI (backend/main.py)             │
│   (SPA)         │ REST │                                         │
│                 │      │  ┌──────────────┐  ┌──────────────┐  │
│  app.js         │      │  │ indexer.py  │  │  search.py    │  │
│  style.css      │      │  │ (scan+cache)│  │ (in-memory)  │  │
│  index.html     │      │  └───────┬──────┘  └──────┬───────┘  │
└─────────────────┘      │        │              │              │
                         │        └──────┬───────┘              │
                         │             │                        │
                         │    ┌────────┴─────────┐            │
                         │    │ Index en mémoire │            │
                         │    │ (fichiers, tags, │            │
                         │    │  contenu, lookup)│            │
                         │    └──────────────────┘            │
                         └─────────────────────────────────────────┘
         ┌───────────────────────────────┐
         │  Filesystem (vaults montées)  │
         │  /vaults/Recettes  (ro)       │
         │  /vaults/IT         (ro)      │
         └───────────────────────────────┘

Flux de données :

  1. Au démarrage, indexer.py scanne tous les vaults en parallèle (thread pool)
  2. Le contenu, les tags (YAML + inline) et les métadonnées sont mis en cache en mémoire
  3. Une table de lookup O(1) est construite pour la résolution des wikilinks
  4. Les requêtes de recherche utilisent l'index en mémoire (zéro I/O disque)
  5. Le frontend SPA communique via REST et gère l'état côté client

📝 Développement

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
│   └── requirements.txt
├── frontend/            # Interface web (Vanilla JS, zéro framework)
│   ├── index.html       # Page SPA + modales (aide, config, éditeur)
│   ├── app.js           # Logique SPA, gestion d'état, API client
│   └── style.css        # Styles (CSS variables, thèmes, responsive)
├── Dockerfile           # Multi-stage, healthcheck, non-root
├── docker-compose.yml   # Déploiement avec healthcheck
├── build.sh             # Build multi-platform (amd64/arm64/arm/v7/i386)
└── CONTRIBUTING.md      # Guide de contribution

Contribuer

Voir CONTRIBUTING.md pour les détails.


📄 Licence

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


🤝 Support


📝 Changelog

v1.1.0 (2025)

Sécurité

  • Protection path traversal sur tous les endpoints fichier
  • Utilisateur non-root dans le conteneur Docker
  • Dockerfile multi-stage (élimination des outils de build)

Performance

  • Recherche fulltext en mémoire (zéro I/O disque par requête)
  • Table de lookup O(1) pour la résolution des wikilinks
  • Renderer mistune mis en cache (singleton)
  • Scoring multi-facteurs (titre, chemin, tags, fréquence)
  • lucide.createIcons() batché via requestAnimationFrame
  • AbortController sur les requêtes de recherche

Robustesse

  • Swap atomique de l'index (thread-safe) pendant le reload
  • Extraction des tags inline (#tag) depuis le contenu markdown
  • Modèles Pydantic sur tous les endpoints API
  • Gestion d'erreurs avec toasts utilisateur (frontend)
  • États de chargement pour la sidebar et le contenu
  • Remplacement de on_event déprécié par lifespan

Infrastructure

  • Endpoint /api/health pour monitoring
  • Healthcheck Docker (Dockerfile + docker-compose)
  • build.sh amélioré (variable version, checks, couleurs)

Documentation

  • Docstrings complètes sur toutes les fonctions Python
  • Schémas Pydantic documentés (Swagger UI auto-générée)
  • README : sections Architecture, Performance, Sécurité, Changelog
  • CONTRIBUTING.md ajouté

v1.0.0 (2025)

  • Version initiale

Projet : ObsiGate | Version : 1.1.0 | Dernière mise à jour : 2025