34 KiB
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.
┌─────────────────────────────────────────────────────────┐
│ [🔍 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
- Architecture
- Prérequis
- Installation rapide
- Configuration détaillée
- Variables d'environnement
- 🔒 Authentification
- Ajouter une nouvelle vault
- Build multi-platform
- Utilisation
- API
- Performance
- Dépannage
- Stack technique
- Changelog
✨ Fonctionnalités
- 🗂️ 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 normalisation des accents, snippets surlignés, facettes, pagination et tri
- 💡 Autocomplétion intelligente : Suggestions de fichiers, tags et historique avec navigation clavier
- 🧩 Syntaxe de requête : Opérateurs
tag:,#,vault:,title:,path: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
- 🎨 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
- 🐳 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é : Headers de sécurité (CSP, X-Frame-Options…), protection path traversal, utilisateur non-root
- ❤️ Healthcheck : Endpoint
/api/healthinté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
Dockerfiledu projet. Sans build local, Docker essaiera de télécharger une image distanteobsigate:latestqui 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
- Localisez vos vaults Obsidian sur votre système
- Notez les chemins absolus vers chaque dossier
.obsidian - 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
uvicornet une version defastapicompatible (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
🔒 Authentification
Désactivée par défaut — Compatible avec toutes les installations existantes.
ObsiGate supporte un système d'authentification optionnel basé sur JWT + Argon2id avec contrôle d'accès par vault.
Activer l'authentification
Dans docker-compose.yml, décommentez les variables d'auth :
environment:
# ... vaults ...
- OBSIGATE_AUTH_ENABLED=true
# - OBSIGATE_ADMIN_USER=admin # Défaut: admin
# - OBSIGATE_ADMIN_PASSWORD= # Vide = mot de passe auto-généré (voir logs)
# - OBSIGATE_SECURE_COOKIES=false # true si derrière un reverse-proxy HTTPS
Premier démarrage
Si aucun utilisateur n'existe, ObsiGate crée automatiquement un compte admin et affiche le mot de passe dans les logs :
docker-compose logs obsigate | grep -A4 "PREMIER"
============================================================
PREMIER DÉMARRAGE — Compte admin créé automatiquement
Utilisateur : admin
Mot de passe : xK9mQ3pLr7wN2jT5
CHANGEZ CE MOT DE PASSE dès la première connexion !
============================================================
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 les utilisateurs
docker exec obsigate python backend/create_admin.py list
# Supprimer un utilisateur
docker exec obsigate python backend/create_admin.py delete alice
Interface d'administration
Lorsqu'un compte admin est connecté, une icône 🛡️ apparaît dans le header. Cliquer dessus ouvre le panneau d'administration permettant de :
- Lister tous les utilisateurs
- Créer / modifier / supprimer des utilisateurs
- Assigner les vaults accessibles par utilisateur
- Activer/désactiver des 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 |
Volume pour la persistance
Les données d'auth (users.json, secret.key) sont stockées dans /app/data. Ajoutez un volume pour les persister :
volumes:
# vaults...
- ./data:/app/data # Persistance des utilisateurs et clé JWT
➕ Ajouter une nouvelle vault
Méthode 1 : Édition directe
-
Arrêtez le conteneur :
docker-compose down -
Ajoutez un volume dans
docker-compose.yml:volumes: - /nouveau/chemin/vault:/vaults/NouvelleVault:ro -
Ajoutez les variables d'environnement :
environment: - VAULT_4_NAME=NouvelleVault - VAULT_4_PATH=/vaults/NouvelleVault -
Redémarrez :
docker-compose up -d --build
Méthode 2 : Hot-reload (recommandé)
- Ajoutez le volume et les variables comme ci-dessus
- Appliquez les changements :
docker-compose up -d --build - Rechargez l'index via l'interface ou l'API :
curl http://localhost:2020/api/index/reload
Méthode 3 : API dynamique (sans redémarrage)
Ajoutez une vault à chaud via l'API (le volume doit déjà être monté) :
curl -X POST http://localhost:2020/api/vaults/add \
-H "Content-Type: application/json" \
-d '{"name": "NouvelleVault", "path": "/vaults/NouvelleVault"}'
Supprimez une vault :
curl -X DELETE http://localhost:2020/api/vaults/NouvelleVault
🔨 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 .
<EFBFBD>️ 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
-
Standard Markdown avec attributs HTML (compatible Obsidian) :
[<img width="180" height="60" src="path/to/image.svg"/>](https://example.com) -
Wiki-link embed avec chemin complet :
![[06_Boite_a_Outils/6.2_Attachments/image.svg]] -
Wiki-link embed avec nom de fichier uniquement :
![[image.svg]] -
Markdown standard :

Résolution intelligente des chemins
ObsiGate utilise 7 stratégies de résolution par ordre de priorité :
- Chemin absolu : Si le chemin est absolu et existe
- Dossier d'attachements configuré : Via
VAULT_N_ATTACHMENTS_PATH - Index de démarrage (match unique) : Recherche par nom de fichier dans l'index
- Même répertoire : Relatif au fichier markdown courant
- Racine du vault : Relatif à la racine du vault
- Index de démarrage (match le plus proche) : Si plusieurs fichiers portent le même nom
- Fallback : Affiche un placeholder stylisé
[image not found: filename.ext]
Configuration
Pour optimiser la résolution, configurez le dossier d'attachements de chaque vault :
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 :
curl -X POST http://localhost:2020/api/attachments/rescan/MonVault
<EFBFBD>📖 Utilisation
Interface web
- Navigation : Cliquez sur les vaults dans la sidebar pour les développer
- Recherche : Utilisez la barre de recherche pour chercher dans toutes les vaults
- Tags : Cliquez sur les tags pour filtrer les contenus
- Wikilinks : Les liens
[[page]]sont cliquables et navigables - Images : Toutes les syntaxes d'images Obsidian sont rendues automatiquement
- 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 | 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 (retourne 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 | 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. 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
# Recherche simple (legacy)
curl "http://localhost:2020/api/search?q=recette&vault=all"
# Recherche avancée avec TF-IDF, facettes et pagination
curl "http://localhost:2020/api/search/advanced?q=recette%20tag:cuisine&vault=all&limit=20&offset=0&sort=relevance"
# Autocomplétion de titres
curl "http://localhost:2020/api/suggest?q=piz&vault=all"
# Autocomplétion de tags
curl "http://localhost:2020/api/tags/suggest?q=rec&vault=all"
# Obtenir un fichier
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 |
"phrase exacte" |
Recherche de phrase | tag:"multi mots" |
Les opérateurs sont combinables : tag:linux vault:IT serveur web recherche "serveur web" dans le vault IT avec le tag linux.
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 basé sur la fréquence des termes pondérée par l'inverse de la fréquence documentaire
- Boost titre : Les correspondances dans le titre reçoivent un score 3× supérieur
- Normalisation des accents :
resumetrouverésumé,elephanttrouveéléphant - Snippets surlignés : Les termes trouvés sont encadrés par
<mark>dans les extraits - Facettes : Compteurs par vault et par tag dans les résultats
- Pagination : Navigation par pages de 50 résultats
- Tri : Par pertinence (TF-IDF) ou par date de modification
- Chips visuels : Les filtres actifs sont affichés comme des chips colorés supprimables
- Historique : Les 50 dernières recherches sont mémorisées en localStorage
🔧 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 | ~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, sans outils de build) |
| 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 |
Ces paramètres sont configurables via l'interface (Settings) ou l'API /api/config.
Optimisations clés (v1.2.0)
- Index inversé avec set-intersection : la recherche utilise les posting lists pour un retrieval O(k × postings) au lieu de O(N) scan complet
- Prefix matching par recherche binaire : O(log V + k) au lieu de O(V) scan linéaire du vocabulaire
- ThreadPoolExecutor : les fonctions de recherche CPU-bound sont offloadées du event loop asyncio
- Race condition guard :
currentSearchId+AbortControllerempêchent le rendu de résultats obsolètes - Progress bar : barre de progression animée pendant la recherche
- Search timeout : abandon automatique après 30s (configurable)
- Query time display : temps serveur affiché dans les résultats (
query_time_ms) - Staleness detection fix : utilisation d'un compteur de génération au lieu de
id(index)pour détecter les changements d'index
Optimisations 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é viarequestAnimationFrame
🛡️ 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
:ropar défaut dans docker-compose
🏗️ 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
- 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 │ │
│ │ │ ┌──────────────┐ ┌──────────────┐ │
│ 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 :
- Au démarrage,
indexer.pyscanne tous les vaults en parallèle (thread pool) - Le contenu, les tags (YAML + inline) et les métadonnées sont mis en cache en mémoire
- Une table de lookup O(1) est construite pour la résolution des wikilinks
watcher.pydémarre la surveillance des fichiers (watchdog natif ou polling)- Les modifications détectées déclenchent une mise à jour incrémentale de l'index
- Les changements sont notifiés au frontend via Server-Sent Events (SSE)
- Les requêtes de recherche utilisent l'index en mémoire (zéro I/O disque)
- Le frontend SPA communique via REST + SSE 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
│ ├── watcher.py # Surveillance fichiers (watchdog + debounce)
│ ├── auth/ # Module d'authentification
│ │ ├── password.py # Argon2id hashing
│ │ ├── jwt_handler.py # Tokens JWT + révocation
│ │ ├── user_store.py # CRUD users.json (atomique)
│ │ ├── middleware.py # Dépendances FastAPI auth
│ │ └── router.py # Endpoints /api/auth/*
│ ├── create_admin.py # CLI gestion utilisateurs
│ └── requirements.txt
├── frontend/ # Interface web (Vanilla JS, zéro framework)
│ ├── index.html # Page SPA + écran de login
│ ├── app.js # Logique SPA, AuthManager, AdminPanel
│ └── style.css # Styles (CSS variables, thèmes, responsive)
├── data/ # Données persistantes (créé au démarrage)
│ ├── users.json # Utilisateurs (hashés Argon2id)
│ └── secret.key # Clé secrète JWT (512 bits)
├── Dockerfile # Multi-stage, healthcheck, non-root
├── docker-compose.yml # Déploiement avec healthcheck et auth env vars
├── 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
- Issues : git.dracodev.net/Projets/ObsiGate/issues
- Documentation : git.dracodev.net/Projets/ObsiGate/wiki
- Auteur : Bruno Beloeil
📝 Changelog
v1.4.0 (2026)
Authentification & Contrôle d'accès
- Système d'authentification JWT (HS256) optionnel — désactivé par défaut, activation via
OBSIGATE_AUTH_ENABLED=true - Hachage des mots de passe Argon2id (paramètres OWASP 2024 : time_cost=2, mem=64MB)
- Sessions avec access token (1h) + refresh token (7j, HttpOnly cookie) et révocation
- Contrôle d'accès par vault : chaque utilisateur accède uniquement à ses vaults assignées
- Bootstrap automatique du compte admin au premier démarrage (mot de passe généré et affiché dans les logs)
- CLI de gestion des utilisateurs :
python backend/create_admin.py create|list|delete - Interface d'administration dans la SPA : création/modification/suppression d'utilisateurs avec sélection de vaults
- Protection brute-force : verrouillage 15 min après 5 tentatives échouées
- Réponses en temps constant sur le login pour éviter l'énumération d'utilisateurs
- Token de rafraîchissement révocable (persisté dans
data/revoked_tokens.json) - Clé secrète JWT auto-générée (512 bits) et persistée dans
data/secret.key
Sécurité (headers)
Content-Security-Policysur toutes les réponsesX-Frame-Options: SAMEORIGINX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockReferrer-Policy: strict-origin-when-cross-origin
Frontend
- Écran de connexion avec glassmorphism (avant chargement de l'app si auth activée)
- Menu utilisateur dans le header (nom affiché, bouton admin, déconnexion)
- Rafraîchissement silencieux de l'access token (via cookie refresh)
- Compatibilité totale :
OBSIGATE_AUTH_ENABLED=false→ comportement identique à v1.3.x
v1.3.0 (2025)
Synchronisation temps réel
- Surveillance automatique des fichiers via
watchdogavec fallback polling automatique - Mise à jour incrémentale de l'index : ajout, modification, suppression et déplacement de fichiers sans rebuild complet
- Server-Sent Events (SSE) : endpoint
/api/eventspour notifications temps réel vers le frontend - Badge de synchronisation dans le header avec indicateur visuel (connecté/déconnecté/syncing)
- Panel d'événements récents accessible en cliquant sur le badge
- Reconnexion SSE automatique avec backoff exponentiel
- Toast informatif à chaque mise à jour détectée
- Rafraîchissement automatique de la sidebar et du fichier courant si affecté
Gestion dynamique des vaults
POST /api/vaults/add: ajouter une vault à chaud sans redémarrageDELETE /api/vaults/{name}: supprimer une vault de l'indexGET /api/vaults/status: statut détaillé (fichiers, tags, état de surveillance)- Les vaults ajoutées sont automatiquement surveillées par le watcher
Configuration watcher
- Nouveaux paramètres dans
config.json:watcher_enabled,watcher_use_polling,watcher_polling_interval,watcher_debounce - Section « Synchronisation automatique » dans la modal de configuration frontend
- Toggles pour activer/désactiver la surveillance et le mode polling
v1.2.0 (2025)
Performance (critique)
- Réécriture du moteur
advanced_search(): retrieval par set-intersection sur l'index inversé (O(k × postings) au lieu de O(N)) - Prefix matching par recherche binaire sur liste triée de tokens (O(log V + k) au lieu de O(V))
- Offload des fonctions de recherche CPU-bound via
ThreadPoolExecutor(2 workers par défaut) - Pré-calcul des expansions de préfixe pour éviter les recherches binaires répétées
- Fix du bug de staleness :
is_stale()utilise un compteur de génération au lieu deid(index)
Frontend
- Guard contre les race conditions :
currentSearchIdvérifié après chaquefetchavant rendu - Barre de progression animée pendant la recherche
- Timeout de recherche configurable (30s par défaut)
- Longueur minimale de requête configurable (2 caractères par défaut)
- Affichage du temps de requête serveur (
query_time_ms) dans les résultats - Pagination ajoutée sur l'endpoint legacy
/api/search(paramslimit/offset)
Configuration & Diagnostics
- Nouveaux endpoints
GET/POST /api/configpour la configuration persistante (config.json) - Nouveau endpoint
GET /api/diagnostics(stats index, mémoire, moteur de recherche) - Page de configuration étendue : paramètres frontend (debounce, résultats/page, timeout) et backend (workers, boosts, expansions)
- Panel de diagnostics intégré dans la modal de configuration
- Boutons « Forcer réindexation » et « Réinitialiser » dans les paramètres
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é viarequestAnimationFrameAbortControllersur 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_eventdéprécié parlifespan
Infrastructure
- Endpoint
/api/healthpour monitoring - Healthcheck Docker (Dockerfile + docker-compose)
build.shamé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.4.0 | Dernière mise à jour : 2026