Bruno Charest 34d89706be
Some checks failed
CI / lint (push) Failing after 6s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / security (push) Successful in 10s
feat: 6 nouvelles commandes palette — créer/supprimer fichiers/dossiers, éditer, pop-out
2026-06-02 15:08:30 -04:00

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 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
  • 🗺️ 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
  • 💡 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
  • 🎨 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é : 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 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)

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

# Rendre le script exécutable (une seule fois)
chmod +x build.sh

# Build + déploiement en une commande
./build.sh

C'est tout ! build.sh vérifie Docker, contrôle vos volumes, construit l'image et démarre le conteneur automatiquement.

Options utiles : ./build.sh --help pour l'aide, ./build.sh --cache pour un rebuild plus rapide, ./build.sh --build-only pour 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 .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
      # Persistance des données d'auth
      - ./data:/app/data
    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
      # Auth (les secrets sont dans .env)
      - OBSIGATE_AUTH_ENABLED=true
      - OBSIGATE_ADMIN_USER=admin
    env_file:
      - .env  # Contient OBSIGATE_ADMIN_PASSWORD et autres secrets

Étape 3 : Build & déploiement

# Utilisez le script de build automatisé (recommandé)
chmod +x build.sh
./build.sh

Le script build.sh gère tout : vérification des prérequis, validation des volumes, construction de l'image et démarrage.

Alternative manuelle :

docker compose build --no-cache
docker compose up -d

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

🔒 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

  1. Copiez le template .env :

    cp .env.example .env
    
  2. Éditez .env et décommentez/configurez les variables :

    OBSIGATE_AUTH_ENABLED=***   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, assurez-vous d'avoir :

    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 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
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_LOGIN_WINDOW_SECONDS Fenêtre de rate limiting (secondes) 900

Toutes ces variables sont documentées dans .env.example.

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

  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 :

    ./build.sh
    

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

  1. Ajoutez le volume et les variables comme ci-dessus
  2. Appliquez les changements :
    ./build.sh
    
  3. 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 & déploiement avec build.sh

Le script build.sh est la méthode recommandée pour construire et déployer ObsiGate.

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 que Docker et Docker Compose sont installés (avec numéros de version)
  2. Valide la présence et la syntaxe du fichier docker-compose.yml
  3. Vérifie chaque volume monté : avertit si un répertoire source n'existe pas
  4. Construit l'image Docker via docker compose build (multi-stage, ~180MB)
  5. Démarre le conteneur via docker compose up -d
  6. Affiche le statut du conteneur puis les logs en temps réel

Exemples

# Build propre + démarrage (recommandé après changement de code)
./build.sh

# Rebuild rapide avec cache (changements mineurs frontend uniquement)
./build.sh --cache

# Vérifier le build sans démarrer (pratique pour tester avant mise en prod)
./build.sh --build-only

# Sortie verbeuse pour débugger un échec de build
./build.sh --progress=plain

Arrêter / redémarrer

docker compose down      # Arrêter le conteneur
docker compose up -d     # Redémarrer sans rebuild
docker compose logs -f   # Voir les logs

<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

  1. Standard Markdown avec attributs HTML (compatible Obsidian) :

    [<img width="180" height="60" src="path/to/image.svg"/>](https://example.com)
    
  2. Wiki-link embed avec chemin complet :

    ![[06_Boite_a_Outils/6.2_Attachments/image.svg]]
    
  3. Wiki-link embed avec nom de fichier uniquement :

    ![[image.svg]]
    
  4. Markdown standard :

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

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

  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 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` |
| `ext:<type>` | Filtrer par type de fichier | `ext:md kubernetes` |
| `"phrase exacte"` | Recherche de phrase | `tag:"multi mots"` |

Exemples de filtre par extension : `ext:sh` pour les scripts bash, `ext:py` pour les scripts Python, `ext:md` pour les fichiers Markdown.

Les opérateurs sont combinables : `tag:linux vault:IT ext:md serveur web` recherche "serveur web" dans les fichiers Markdown du 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** : `resume` trouve `résumé`, `elephant` trouve `é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é :**
```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 :

# Nettoyer le cache Docker et rebuild
docker system prune -f
docker compose down
./build.sh --progress=plain

# Si l'échec persiste, vérifier les logs de build
./build.sh --progress=plain 2>&1 | tee build.log

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 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 ~80150MB 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 5005 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 + AbortController empê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.5.0 (Quick Wins 2026-05-27)

  • Compression GZip : middleware FastAPI compresse toutes les réponses >1KB (~70% de bande passante économisée)
  • Cache-Control immutable : les assets statiques (/static/*) sont cachés 1 an par le navigateur
  • .dockerignore : contexte de build Docker minimal (pas de .git, docs/, *.md, __pycache__)
  • InvertedIndex incrémental : hooks add_document/remove_document, plus de rebuild O(N) à chaque mutation

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é via requestAnimationFrame

🛡️ 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 : toutes les écritures, suppressions et changements de config sont journalisés dans data/audit.log (JSON lines, rotation 10 MB)
  • Backup automatique : chaque modification ou suppression de fichier est sauvegardée dans .obsigate-backup/ avec timestamp
  • Secret redaction : masquage automatique des JWT, clés API, tokens et connection strings dans les aperçus
  • Utilisateur non-root : le conteneur Docker tourne sous l'utilisateur obsigate (UID 1000)
  • Volumes read-only : les vaults sont montées en :ro par défaut dans docker-compose
  • Secrets dans .env : les mots de passe et tokens ne sont jamais dans docker-compose.yml
  • Atomic writes : les fichiers de données (users.json, shares.json, webhooks.json) utilisent tmp+replace

🏗️ Stack technique

  • Backend : Python 3.11 + FastAPI 0.110 + Uvicorn
  • Auth : python-jose (JWT HS256) + argon2-cffi (Argon2id)
  • Security : rate limiting (IP + account lockout), audit logging, secret redaction, atomic writes
  • 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+
  • Compression : GZip middleware (FastAPI), Cache-Control immutable pour les assets
  • Image Docker : python:3.11-slim (multi-stage), .dockerignore pour contexte minimal
  • 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 :

  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. watcher.py démarre la surveillance des fichiers (watchdog natif ou polling)
  5. Les modifications détectées déclenchent une mise à jour incrémentale de l'index
  6. Les changements sont notifiés au frontend via Server-Sent Events (SSE)
  7. Les requêtes de recherche utilisent l'index en mémoire (zéro I/O disque)
  8. 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 & déploiement automatisé (docker compose build + up)
└── 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

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


Projet : ObsiGate | Version : 1.7.0 | Dernière mise à jour : Mai 2026

Description
Porte d'entrée vers vos vaults Obsidian
Readme 12 MiB
Languages
JavaScript 52.9%
Python 28.8%
HTML 9.5%
CSS 8.3%
Shell 0.4%
Other 0.1%