934 lines
41 KiB
Markdown
934 lines
41 KiB
Markdown
# ObsiGate
|
||
|
||
> **Version française** — ce document est le miroir synchronisé de [README.md](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.
|
||
|
||
[]()
|
||
[](https://opensource.org/licenses/MIT)
|
||
[](https://www.docker.com/)
|
||
[](https://www.python.org/)
|
||
[](https://git.dracodev.net/Projets/ObsiGate/actions)
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ [🔍 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](#fonctionnalites)
|
||
- [Prérequis](#prerequis)
|
||
- [Installation rapide](#installation-rapide)
|
||
- [Configuration détaillée](#configuration-detaillee)
|
||
- [Variables d'environnement](#variables-denvironnement)
|
||
- [🔒 Authentification](#authentification)
|
||
- [Ajouter une nouvelle vault](#ajouter-une-nouvelle-vault)
|
||
- [Build & déploiement avec build.sh](#build-deploiement-avec-buildsh)
|
||
- [Rendu d'images Obsidian](#rendu-dimages-obsidian)
|
||
- [Desktop (Tauri) — Application native](#desktop-tauri-application-native)
|
||
- [Utilisation](#utilisation)
|
||
- [API](#api)
|
||
- [Recherche avancée](#recherche-avancee)
|
||
- [Dépannage](#depannage)
|
||
- [Performance](#performance)
|
||
- [Sécurité](#securite)
|
||
- [Stack technique](#stack-technique)
|
||
- [Architecture](#architecture)
|
||
- [Développement](#developpement)
|
||
- [Licence](#licence)
|
||
- [Changelog](#changelog)
|
||
|
||
---
|
||
|
||
## ✨ 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](docs/MCP_GUIDE.md))
|
||
- **👥 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](docs/features/collaboration.md))
|
||
- **📱 É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](docs/features/mobile-editor.md))
|
||
- **🗺️ 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](docs/features/semantic-search.md))
|
||
- **💡 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
|
||
|
||
```bash
|
||
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 :
|
||
|
||
```yaml
|
||
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 :
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```yaml
|
||
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
|
||
|
||
```bash
|
||
chmod +x build.sh
|
||
./build.sh
|
||
```
|
||
|
||
**Alternative manuelle :**
|
||
|
||
```bash
|
||
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` :
|
||
```bash
|
||
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** :
|
||
|
||
```bash
|
||
docker-compose logs obsigate | grep -A4 "PREMIER"
|
||
```
|
||
|
||
### Gestion des utilisateurs via CLI
|
||
|
||
```bash
|
||
# 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` |
|
||
| `OBSIGATE_TAVILY_API_KEY` / `OBSIGATE_BRAVE_API_KEY` / `OBSIGATE_SERPAPI_API_KEY` / `OBSIGATE_EXA_API_KEY` | Fournisseurs de recherche web à clé (essayés avant SearXNG) | — |
|
||
| `OBSIGATE_WEB_PROVIDERS` | Ordre des fournisseurs de recherche (ex. `brave,searxng`) | — |
|
||
| `OBSIGATE_WEB_RETRY` | Réessais réseau des outils web (backoff maison) | `1` |
|
||
| `OBSIGATE_WEB_CACHE_TTL` | Durée du cache SQLite des résultats web (secondes, `0` = off) | `900` |
|
||
| `OBSIGATE_GITEA_URL` / `OBSIGATE_GITEA_TOKEN` | Source connectée Gitea (outil `git_list_repos`…) | — |
|
||
| `OBSIGATE_GITHUB_TOKEN` | Jeton GitHub (outil `git_list_repos`…) | — |
|
||
|
||
> Ces clés peuvent aussi être saisies **depuis l'interface** (menu → Configurations →
|
||
> « Sources connectées & recherche ») : la valeur saisie est stockée dans `data/api_keys.json`
|
||
> et prime sur la variable d'environnement.
|
||
|
||
### Volume pour la persistance
|
||
|
||
Les données d'auth (`users.json`, `secret.key`) sont stockées dans `/app/data` :
|
||
|
||
```yaml
|
||
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)
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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** : ``
|
||
|
||
### 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
|
||
|
||
```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
|
||
|
||
```bash
|
||
curl -X POST http://localhost:2020/api/attachments/rescan/MonVault
|
||
```
|
||
|
||
---
|
||
|
||
## 🖥️ Desktop (Tauri) — Application native
|
||
|
||
ObsiGate Desktop est une application native construite avec [Tauri](https://tauri.app/) (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](https://git.dracodev.net/Projets/ObsiGate/releases) :
|
||
|
||
| Plateforme | Format |
|
||
|---|---|
|
||
| **Linux** | `.deb` + `.AppImage` |
|
||
| **Windows** | `.msi` + `.exe` (NSIS) |
|
||
|
||
```bash
|
||
# 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
|
||
```
|
||
|
||
```cmd
|
||
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](./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`
|
||
|
||
```cmd
|
||
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`
|
||
|
||
```bash
|
||
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`](./.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`](./.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 :**
|
||
|
||
```bash
|
||
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](docs/features/semantic-search.md).
|
||
|
||
---
|
||
|
||
## 🔧 Dépannage
|
||
|
||
**Port déjà utilisé :**
|
||
|
||
```bash
|
||
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 :**
|
||
|
||
```bash
|
||
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 :**
|
||
|
||
```bash
|
||
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.
|
||
|
||
```bash
|
||
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](./docs/CONTRIBUTING.md) pour les standards de code et
|
||
[docs/DELIVERY_WORKFLOW.md](./docs/DELIVERY_WORKFLOW.md) pour la méthode de livraison obligatoire.
|
||
|
||
---
|
||
|
||
## 📄 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)
|
||
|
||
---
|
||
|
||
## 📝 Changelog
|
||
|
||
Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v2.11.2).
|
||
|
||
---
|
||
|
||
*Projet : ObsiGate | Version : 2.11.2 | Dernière mise à jour : Juin 2026*
|