ObsiGate/README.md

571 lines
20 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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](https://img.shields.io/badge/Version-1.1.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/)
```
┌─────────────────────────────────────────────────────────┐
│ [🔍 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](#-fonctionnalités)
- [Architecture](#-architecture)
- [Prérequis](#-prérequis)
- [Installation rapide](#-installation-rapide)
- [Configuration détaillée](#-configuration-détaillée)
- [Variables d'environnement](#-variables-denvironnement)
- [Ajouter une nouvelle vault](#-ajouter-une-nouvelle-vault)
- [Build multi-platform](#-build-multi-platform)
- [Utilisation](#-utilisation)
- [API](#-api)
- [Performance](#-performance)
- [Dépannage](#-dépannage)
- [Stack technique](#-stack-technique)
- [Changelog](#-changelog)
---
## ✨ 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
- **🖼️ Images Obsidian** : Support complet des syntaxes d'images Obsidian avec résolution intelligente
- **🎨 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
```bash
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 :
```yaml
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
```bash
# 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 :
```yaml
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
```bash
# 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_1_ATTACHMENTS_PATH` | Chemin relatif vers le dossier d'attachements (optionnel) | `06_Boite_a_Outils/6.2_Attachments` |
| `VAULT_1_SCAN_ATTACHMENTS` | Activer le scan d'images au démarrage (optionnel, défaut: true) | `true` |
| `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** :
```bash
docker-compose down
```
2. **Ajoutez un volume** dans `docker-compose.yml` :
```yaml
volumes:
- /nouveau/chemin/vault:/vaults/NouvelleVault:ro
```
3. **Ajoutez les variables d'environnement** :
```yaml
environment:
- VAULT_4_NAME=NouvelleVault
- VAULT_4_PATH=/vaults/NouvelleVault
```
4. **Redémarrez** :
```bash
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** :
```bash
docker-compose up -d --build
```
3. **Rechargez l'index** via l'interface ou l'API :
```bash
curl http://localhost:2020/api/index/reload
```
---
## 🔨 Build multi-platform
Pour les architectures multiples (Raspberry Pi, NAS, etc.) :
```bash
# 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 :**
```bash
docker buildx build --platform linux/amd64 --load -t obsigate:latest .
```
---
## <20> Rendu d'images Obsidian
ObsiGate supporte **toutes les syntaxes d'images Obsidian** avec un système de résolution intelligent multi-stratégies.
### Syntaxes supportées
1. **Standard Markdown avec attributs HTML** (compatible Obsidian) :
```markdown
[<img width="180" height="60" src="path/to/image.svg"/>](https://example.com)
```
2. **Wiki-link embed avec chemin complet** :
```markdown
![[06_Boite_a_Outils/6.2_Attachments/image.svg]]
```
3. **Wiki-link embed avec nom de fichier uniquement** :
```markdown
![[image.svg]]
```
4. **Markdown standard** :
```markdown
![alt text](path/to/image.png)
```
### Résolution intelligente des chemins
ObsiGate utilise 7 stratégies de résolution par ordre de priorité :
1. **Chemin absolu** : Si le chemin est absolu et existe
2. **Dossier d'attachements configuré** : Via `VAULT_N_ATTACHMENTS_PATH`
3. **Index de démarrage (match unique)** : Recherche par nom de fichier dans l'index
4. **Même répertoire** : Relatif au fichier markdown courant
5. **Racine du vault** : Relatif à la racine du vault
6. **Index de démarrage (match le plus proche)** : Si plusieurs fichiers portent le même nom
7. **Fallback** : Affiche un placeholder stylisé `[image not found: filename.ext]`
### Configuration
Pour optimiser la résolution, configurez le dossier d'attachements de chaque vault :
```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
Pour rescanner les images d'un vault après ajout/suppression :
```bash
curl -X POST http://localhost:2020/api/attachments/rescan/MonVault
```
---
## <20>📖 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` |
---
## 🔌 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 |
| `/api/image/{vault}?path=` | Servir une image avec MIME type approprié | GET |
| `/api/attachments/rescan/{vault}` | Rescanner les images d'un vault | POST |
| `/api/attachments/stats?vault=` | Statistiques d'images indexées | GET |
> Tous les endpoints exposent des schémas Pydantic documentés. La doc interactive est disponible sur `/docs` (Swagger UI).
**Exemple d'utilisation :**
```bash
# 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é :**
```bash
# 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 :**
```bash
# Nettoyer et rebuild
docker system prune -f
docker-compose down
docker build --no-cache -t obsigate:latest .
docker-compose up -d
```
**Logs pour debugging :**
```bash
# 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](CONTRIBUTING.md) pour les détails.
---
## 📄 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)
- **Auteur** : Bruno Beloeil
---
## 📝 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*