diff --git a/README.fr.md b/README.fr.md index ee58737..b117430 100644 --- a/README.fr.md +++ b/README.fr.md @@ -756,6 +756,67 @@ Configurables via l'interface (Settings) ou l'API `/api/config`. ## 📝 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 ``` diff --git a/README.md b/README.md index a92adb2..fabdafe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 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. +**Ultra-light web gateway for your Obsidian vaults** — Access, browse, and search all your Obsidian notes from any device via a modern, responsive web interface. [![Version](https://img.shields.io/badge/Version-1.7.0-blue.svg)]() [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) @@ -10,12 +10,12 @@ ``` ┌─────────────────────────────────────────────────────────┐ -│ [🔍 Recherche...] [☀/🌙 ThĂšme] ObsiGate │ +│ [🔍 Search...] [☀/🌙 Theme] ObsiGate │ â”œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”Źâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ │ SIDEBAR │ CONTENT AREA │ -│ â–Œ Recettes │ 📄 Titre du fichier │ -│ 📁 Soupes │ Tags: #recette #rapide │ -│ 📄 Pizza │ [Contenu Markdown rendu] │ +│ â–Œ Recipes │ 📄 File Title │ +│ 📁 Soups │ Tags: #recipe #quick │ +│ 📄 Pizza │ [Rendered Markdown Content] │ │ â–Œ IT │ │ │ 📁 Docker │ │ │ Tags Cloud │ │ @@ -24,128 +24,128 @@ --- -## 📋 Table des matiĂšres +## 📋 Table of Contents -- [FonctionnalitĂ©s](#fonctionnalites) +- [Features](#features) - [Architecture](#architecture) -- [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) -- [Desktop (Tauri) — Application native](#desktop-tauri-application-native) -- [Utilisation](#utilisation) +- [Prerequisites](#prerequisites) +- [Quick Installation](#quick-installation) +- [Detailed Configuration](#detailed-configuration) +- [Environment Variables](#environment-variables) +- [🔒 Authentication](#authentication) +- [Adding a New Vault](#adding-a-new-vault) +- [Build & Deployment with build.sh](#build--deployment-with-buildsh) +- [Desktop (Tauri) — Native Application](#desktop-tauri--native-application) +- [Usage](#usage) - [API](#api) - [Performance](#performance) -- [DĂ©pannage](#depannage) -- [Stack technique](#stack-technique) +- [Troubleshooting](#troubleshooting) +- [Tech Stack](#tech-stack) - [Changelog](#changelog) --- -## ✹ FonctionnalitĂ©s +## ✹ Features -- **đŸ€– 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 +- **đŸ€– Integrated AI Editor** — CodeMirror 6 editor with AI toolbar: improve, correct, translate, generate, custom rewrite, toolbox (list, table, frontmatter, canvas) — multi-provider DeepSeek/OpenRouter/Gemini +- **đŸ—ș Interactive Graph View** — Canvas force-directed with Barnes-Hut O(n log n), filters (tag, type), depth, focus mode, navigation history ←→↑, export PNG, preview on hover (Ctrl+click) +- **đŸ—‚ïž Multi-vault** : View multiple Obsidian vaults simultaneously +- **🌳 Tree Navigation** : Browse your folders and files in the sidebar +- **🔍 Advanced Search** : TF-IDF search engine with French stemming, accent normalization, highlighted snippets, facets, pagination, and sorting +- **💡 Smart Autocomplete** : Suggestions for files, tags, and history with keyboard navigation +- **đŸ§© Query Syntax** : Operators `tag:`, `#`, `vault:`, `title:`, `path:`, `ext:` with visual chips +- **📜 Search History** : Persisted in localStorage (max 50 entries, LIFO, deduplicated) +- **đŸ·ïž Tag Cloud** : Filtering by tags extracted from YAML frontmatters +- **🔗 Wikilinks** : `[[internal links]]` from Obsidian are clickable +- **đŸ–Œïž Obsidian Images** : Full support for all Obsidian image syntaxes with intelligent resolution +- **🎹 Syntax Highlight** : Syntax highlighting for code blocks +- **🌓 Light/Dark Theme** : Toggle persisted in localStorage +- **📡 Real-time Sync** : Automatic file monitoring via watchdog with incremental index updates +- **📡 Server-Sent Events** : SSE notifications for index changes with automatic reconnection +- **➕ Dynamic Vault Management** : Add/remove vaults via API without restart +- **🐳 Multi-platform Docker** : linux/amd64, linux/arm64, linux/arm/v7, linux/386 +- **🔒 Authentication** : JWT + Argon2id, persistent sessions, per-vault access control +- **đŸ›Ąïž Security** : Rate limiting, audit log, automatic backup, secret redaction, CSP headers, path traversal protection, non-root user +- **⚡ Performance** : GZip compression, Cache-Control immutable, incremental inverted index, search with no disk I/O +- **❀ Healthcheck** : `/api/health` endpoint integrated for Docker and monitoring --- -## 🚀 PrĂ©requis +## 🚀 Prerequisites -### SystĂšme requis +### System Requirements - **Docker** >= 20.10 - **docker-compose** >= 2.0 -- **Espace disque** : ~200MB pour l'image Docker +- **Disk space** : ~200MB for the Docker image -### SystĂšmes supportĂ©s +### Supported Systems - Linux (Ubuntu, Debian, CentOS, etc.) -- macOS (Intel et Apple Silicon) -- Windows (avec Docker Desktop) -- NAS compatibles Docker (Synology, QNAP, etc.) +- macOS (Intel and Apple Silicon) +- Windows (with Docker Desktop) +- Docker-compatible NAS (Synology, QNAP, etc.) --- -## ⚡ Installation rapide +## ⚡ Quick Installation -### 1. Cloner le dĂ©pĂŽt +### 1. Clone the Repository ```bash git clone https://git.dracodev.net/Projets/ObsiGate.git cd ObsiGate ``` -### 2. Configurer vos vaults et vos secrets +### 2. Configure Your Vaults and Secrets -Éditez le fichier `docker-compose.yml` pour ajouter vos vaults Obsidian : +Edit the `docker-compose.yml` file to add your Obsidian vaults: ```yaml volumes: - - /chemin/absolu/vers/votre/vault:/vaults/NomDeVotreVault:ro + - /absolute/path/to/your/vault:/vaults/YourVaultName:ro ``` -> **Important** : Le chemin doit ĂȘtre absolu et le volume en lecture seule (`:ro`) +> **Important** : The path must be absolute and the volume must be read-only (`:ro`) -CrĂ©ez votre fichier `.env` pour l'authentification et les secrets : +Create your `.env` file for authentication and secrets: ```bash cp .env.example .env -# Éditez .env pour configurer vos mots de passe et options +# Edit .env to configure your passwords and options ``` -> **Ne committez jamais `.env` !** Il est dans `.gitignore`. Utilisez `.env.example` comme rĂ©fĂ©rence. +> **Never commit `.env`!** It is in `.gitignore`. Use `.env.example` as a reference. -### 3. Lancer l'application +### 3. Launch the Application ```bash -# Rendre le script exĂ©cutable (une seule fois) +# Make the script executable (once) chmod +x build.sh -# Build + dĂ©ploiement en une commande +# Build + deploy in one command ./build.sh ``` -> **C'est tout !** `build.sh` vĂ©rifie Docker, contrĂŽle vos volumes, construit l'image et dĂ©marre le conteneur automatiquement. +> **That's it!** `build.sh` checks Docker, validates your volumes, builds the image, and starts the container automatically. > -> 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. +> Useful options: `./build.sh --help` for help, `./build.sh --cache` for a faster rebuild, `./build.sh --build-only` to build without starting. -### 4. AccĂ©der Ă  l'interface +### 4. Access the Interface -Ouvrez votre navigateur sur : **http://localhost:2020** +Open your browser at: **http://localhost:2020** --- -## ⚙ Configuration dĂ©taillĂ©e +## ⚙ Detailed Configuration -### Étape 1 : PrĂ©paration des vaults +### Step 1: Prepare Your 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 +1. **Locate your Obsidian vaults** on your system +2. **Note the absolute paths** to each `.obsidian` folder +3. **Check permissions** : Docker must be able to read these folders -### Étape 2 : Configuration docker-compose.yml +### Step 2: Configure docker-compose.yml -Voici un exemple complet : +Here's a complete example: ```yaml services: @@ -156,369 +156,370 @@ services: container_name: obsigate restart: unless-stopped ports: - - "2020:8080" # Port local 2020 → Port conteneur 8080 + - "2020:8080" # Local port 2020 → Container port 8080 volumes: - # Exemples de vaults (adaptez Ă  vos chemins) - - /home/user/Documents/Obsidian-Recettes:/vaults/Recettes:ro + # Vault examples (adapt to your paths) + - /home/user/Documents/Obsidian-Recipes:/vaults/Recipes:ro - /home/user/Documents/Obsidian-IT:/vaults/IT:ro - - /home/user/Documents/Obsidian-Perso:/vaults/Perso:ro - # Persistance des donnĂ©es d'auth + - /home/user/Documents/Obsidian-Personal:/vaults/Personal:ro + # Auth data persistence - ./data:/app/data environment: - # Configuration des vaults - - VAULT_1_NAME=Recettes - - VAULT_1_PATH=/vaults/Recettes + # Vault configuration + - VAULT_1_NAME=Recipes + - VAULT_1_PATH=/vaults/Recipes - VAULT_2_NAME=IT - VAULT_2_PATH=/vaults/IT - - VAULT_3_NAME=Perso - - VAULT_3_PATH=/vaults/Perso - # Auth (les secrets sont dans .env) + - VAULT_3_NAME=Personal + - VAULT_3_PATH=/vaults/Personal + # Auth (secrets are in .env) - OBSIGATE_AUTH_ENABLED=true - OBSIGATE_ADMIN_USER=admin env_file: - - .env # Contient OBSIGATE_ADMIN_PASSWORD et autres secrets + - .env # Contains OBSIGATE_ADMIN_PASSWORD and other secrets ``` -### Étape 3 : Build & dĂ©ploiement +### Step 3: Build & Deploy ```bash - # Utilisez le script de build automatisĂ© (recommandĂ©) + # Use the automated build script (recommended) 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. + The `build.sh` script handles everything: prerequisite checks, volume validation, image building, and startup. - **Alternative manuelle :** + **Manual alternative:** ```bash 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. +> **Docker Compatibility** : The image uses the minimal `uvicorn` variant and a compatible `fastapi` version (`0.110.3`) to avoid certain optional native dependencies (`watchfiles`, `uvloop`, `httptools`, `fastapi-cli`, etc.) that may fail to build on some platforms like Alpine, ARM, or i386. --- -## 🌍 Variables d'environnement +## 🌍 Environment Variables -Les vaults sont configurĂ©es par paires de variables `VAULT_N_NAME` / `VAULT_N_PATH` (N = 1, 2, 3
) : +Vaults are configured using pairs of `VAULT_N_NAME` / `VAULT_N_PATH` variables (N = 1, 2, 3
): -| Variable | Description | Exemple | +| Variable | Description | Example | |----------|-------------|---------| -| `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` | +| `VAULT_1_NAME` | Display name of the vault | `Recipes` | +| `VAULT_1_PATH` | Path inside the container | `/vaults/Obsidian-RECIPES` | +| `VAULT_1_ATTACHMENTS_PATH` | Relative path to the attachments folder (optional) | `06_Toolbox/6.2_Attachments` | +| `VAULT_1_SCAN_ATTACHMENTS` | Enable image scanning on startup (optional, default: true) | `true` | +| `VAULT_2_NAME` | Display name of the vault | `IT` | +| `VAULT_2_PATH` | Path inside the container | `/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 +**Naming rules:** +- Use only letters, numbers, and hyphens +- No spaces or special characters +- The name must match the path inside the container --- -## 🔒 Authentification +## 🔒 Authentication -> **DĂ©sactivĂ©e par dĂ©faut** — Compatible avec toutes les installations existantes. +> **Disabled by default** — Compatible with all existing installations. -ObsiGate supporte un systĂšme d'authentification optionnel basĂ© sur **JWT + Argon2id** avec contrĂŽle d'accĂšs par vault. +ObsiGate supports an optional authentication system based on **JWT + Argon2id** with per-vault access control. -### Activer l'authentification +### Enable Authentication -1. **Copiez le template `.env`** : +1. **Copy the `.env` template** : ```bash cp .env.example .env ``` -2. **Éditez `.env`** et dĂ©commentez/configurez les variables : +2. **Edit `.env`** and uncomment/configure the variables : ```bash - 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 + OBSIGATE_AUTH_ENABLED=true + OBSIGATE_ADMIN_USER=admin + OBSIGATE_ADMIN_PASSWORD=your_password # Leave empty = auto-generated (see logs) + # OBSIGATE_SECURE_COOKIES=false # true if behind HTTPS ``` -3. **Dans `docker-compose.yml`**, assurez-vous d'avoir : +3. **In `docker-compose.yml`**, make sure you have : ```yaml env_file: - .env ``` -> **Ne mettez jamais de mot de passe dans `docker-compose.yml` !** Utilisez toujours `.env`. +> **Never put passwords in `docker-compose.yml`!** Always use `.env`. -### Premier dĂ©marrage +### First Startup -Si aucun utilisateur n'existe, ObsiGate crĂ©e automatiquement un compte admin et **affiche le mot de passe dans les logs** : +If no user exists, ObsiGate automatically creates an admin account and **displays the password in the logs** : ```bash -docker-compose logs obsigate | grep -A4 "PREMIER" +docker-compose logs obsigate | grep -A4 "FIRST" ``` ``` ============================================================ -PREMIER DÉMARRAGE — Compte admin créé automatiquement - Utilisateur : admin - Mot de passe : xK9mQ3pLr7wN2jT5 -CHANGEZ CE MOT DE PASSE dĂšs la premiĂšre connexion ! +FIRST STARTUP — Admin account created automatically + Username : admin + Password : xK9mQ3pLr7wN2jT5 +CHANGE THIS PASSWORD on first login! ============================================================ ``` -### Gestion des utilisateurs via CLI +### User Management via CLI ```bash -# CrĂ©er un utilisateur -docker exec obsigate python backend/create_admin.py create alice MonMotDePasse --role user --vaults Recettes IT +# Create a user +docker exec obsigate python backend/create_admin.py create alice MyPassword --role user --vaults Recipes IT -# CrĂ©er un admin avec accĂšs total +# Create an admin with full access docker exec obsigate python backend/create_admin.py create bob SecretPass --role admin --vaults "*" -# Lister les utilisateurs +# List users docker exec obsigate python backend/create_admin.py list -# Supprimer un utilisateur +# Delete a user docker exec obsigate python backend/create_admin.py delete alice ``` -### Interface d'administration +### Admin Interface -Lorsqu'un compte **admin** est connectĂ©, une icĂŽne đŸ›Ąïž apparaĂźt dans le header. Cliquer dessus ouvre le panneau d'administration permettant de : +When an **admin** account is logged in, a đŸ›Ąïž icon appears in the header. Clicking it opens the admin panel allowing you to: -- Lister tous les utilisateurs -- CrĂ©er / modifier / supprimer des utilisateurs -- Assigner les vaults accessibles par utilisateur -- Activer/dĂ©sactiver des comptes +- List all users +- Create / edit / delete users +- Assign accessible vaults per user +- Enable/disable accounts -### ContrĂŽle d'accĂšs par vault +### Per-Vault Access Control -| Valeur vaults | AccĂšs | -|---------------|-------| -| `["*"]` | Toutes les vaults (y compris futures) — dĂ©faut admin | -| `["Recettes", "IT"]` | Uniquement ces vaults | -| `[]` | Aucun accĂšs | +| vaults value | Access | +|--------------|--------| +| `["*"]` | All vaults (including future ones) — admin default | +| `["Recipes", "IT"]` | Only these vaults | +| `[]` | No access | -### Variables d'environnement d'auth +### Auth Environment Variables -| 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` | +| Variable | Description | Default | +|----------|-------------|---------| +| `OBSIGATE_AUTH_ENABLED` | Enable authentication | `false` | +| `OBSIGATE_ADMIN_USER` | Auto-created admin username | `admin` | +| `OBSIGATE_ADMIN_PASSWORD` | Admin password (empty = auto-generated) | *(auto)* | +| `OBSIGATE_SECURE_COOKIES` | `Secure` cookie (HTTPS only) | `false` | +| `OBSIGATE_ACCESS_TOKEN_TTL` | JWT token lifetime (seconds) | `3600` | +| `OBSIGATE_REFRESH_TOKEN_TTL` | Refresh token lifetime (seconds) | `2592000` | +| `OBSIGATE_LOGIN_MAX_ATTEMPTS` | Max login attempts per IP | `10` | +| `OBSIGATE_LOGIN_WINDOW_SECONDS` | Rate limiting window (seconds) | `900` | ->Toutes ces variables sont documentĂ©es dans `.env.example`. +>All these variables are documented in `.env.example`. -### Volume pour la persistance +### Volume for Persistence -Les donnĂ©es d'auth (`users.json`, `secret.key`) sont stockĂ©es dans `/app/data`. Ajoutez un volume pour les persister : +Auth data (`users.json`, `secret.key`) is stored in `/app/data`. Add a volume to persist it: ```yaml volumes: # vaults... - - ./data:/app/data # Persistance des utilisateurs et clĂ© JWT + - ./data:/app/data # Persist users and JWT key ``` --- -## ➕ Ajouter une nouvelle vault +## ➕ Adding a New Vault -### MĂ©thode 1 : Édition directe +### Method 1: Direct Editing -1. **ArrĂȘtez le conteneur** : +1. **Stop the container** : ```bash docker-compose down ``` -2. **Ajoutez un volume** dans `docker-compose.yml` : +2. **Add a volume** in `docker-compose.yml` : ```yaml volumes: - - /nouveau/chemin/vault:/vaults/NouvelleVault:ro + - /new/vault/path:/vaults/NewVault:ro ``` -3. **Ajoutez les variables d'environnement** : +3. **Add the environment variables** : ```yaml environment: - - VAULT_4_NAME=NouvelleVault - - VAULT_4_PATH=/vaults/NouvelleVault + - VAULT_4_NAME=NewVault + - VAULT_4_PATH=/vaults/NewVault ``` -4. **RedĂ©marrez** : +4. **Restart** : ```bash ./build.sh ``` -### MĂ©thode 2 : Hot-reload (recommandĂ©) +### Method 2: Hot-reload (recommended) -1. **Ajoutez le volume et les variables** comme ci-dessus -2. **Appliquez les changements** : +1. **Add the volume and variables** as above +2. **Apply the changes** : ```bash ./build.sh ``` -3. **Rechargez l'index** via l'interface ou l'API : +3. **Reload the index** via the interface or the API : ```bash curl http://localhost:2020/api/index/reload ``` -### MĂ©thode 3 : API dynamique (sans redĂ©marrage) +### Method 3: Dynamic API (without restart) -Ajoutez une vault Ă  chaud via l'API (le volume doit dĂ©jĂ  ĂȘtre montĂ©) : +Add a vault on the fly via the API (the volume must already be mounted): ```bash curl -X POST http://localhost:2020/api/vaults/add \ -H "Content-Type: application/json" \ - -d '{"name": "NouvelleVault", "path": "/vaults/NouvelleVault"}' + -d '{"name": "NewVault", "path": "/vaults/NewVault"}' ``` -Supprimez une vault : +Remove a vault: ```bash -curl -X DELETE http://localhost:2020/api/vaults/NouvelleVault +curl -X DELETE http://localhost:2020/api/vaults/NewVault ``` --- -## 🔹 Build & dĂ©ploiement avec build.sh +## 🔹 Build & Deployment with build.sh -Le script `build.sh` est la mĂ©thode recommandĂ©e pour construire et dĂ©ployer ObsiGate. +The `build.sh` script is the recommended way to build and deploy ObsiGate. -### Utilisation de base +### Basic Usage ```bash -chmod +x build.sh # une seule fois -./build.sh # build from scratch + dĂ©marrage +chmod +x build.sh # once +./build.sh # build from scratch + start ``` -### Options disponibles +### Available Options | 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 | +| `--help`, `-h` | Display full help | +| `--build-only` | Build the image without starting the container | +| `--no-cache` | Full rebuild without Docker cache **(default)** | +| `--cache` | Use Docker cache (faster if few changes) | +| `--progress=plain` | Verbose output (recommended for debugging) | +| `--progress=tty` | Interactive output with progress bars | -### Ce que fait le script +### What the Script Does -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 +1. **Checks** that Docker and Docker Compose are installed (with version numbers) +2. **Validates** the presence and syntax of the `docker-compose.yml` file +3. **Checks each mounted volume** : warns if a source directory does not exist +4. **Builds** the Docker image via `docker compose build` (multi-stage, ~180MB) +5. **Starts** the container via `docker compose up -d` +6. **Displays** the container status then real-time logs -### Exemples +### Examples ```bash -# Build propre + dĂ©marrage (recommandĂ© aprĂšs changement de code) +# Clean build + start (recommended after code changes) ./build.sh -# Rebuild rapide avec cache (changements mineurs frontend uniquement) +# Fast rebuild with cache (minor frontend changes only) ./build.sh --cache -# VĂ©rifier le build sans dĂ©marrer (pratique pour tester avant mise en prod) +# Test the build without starting (useful for pre-prod testing) ./build.sh --build-only -# Sortie verbeuse pour dĂ©bugger un Ă©chec de build +# Verbose output to debug a build failure ./build.sh --progress=plain ``` -### ArrĂȘter / redĂ©marrer +### Stopping / Restarting ```bash -docker compose down # ArrĂȘter le conteneur -docker compose up -d # RedĂ©marrer sans rebuild -docker compose logs -f # Voir les logs +docker compose down # Stop the container +docker compose up -d # Restart without rebuild +docker compose logs -f # View logs ``` --- -## ïżœïž Rendu d'images Obsidian +## đŸ–Œïž Obsidian Image Rendering -ObsiGate supporte **toutes les syntaxes d'images Obsidian** avec un systĂšme de rĂ©solution intelligent multi-stratĂ©gies. +ObsiGate supports **all Obsidian image syntaxes** with an intelligent multi-strategy resolution system. -### Syntaxes supportĂ©es +### Supported Syntaxes -1. **Standard Markdown avec attributs HTML** (compatible Obsidian) : +1. **Standard Markdown with HTML attributes** (Obsidian-compatible) : ```markdown [](https://example.com) ``` -2. **Wiki-link embed avec chemin complet** : +2. **Wiki-link embed with full path** : ```markdown - ![[06_Boite_a_Outils/6.2_Attachments/image.svg]] + ![[06_Toolbox/6.2_Attachments/image.svg]] ``` -3. **Wiki-link embed avec nom de fichier uniquement** : +3. **Wiki-link embed with filename only** : ```markdown ![[image.svg]] ``` -4. **Markdown standard** : +4. **Standard Markdown** : ```markdown ![alt text](path/to/image.png) ``` -### RĂ©solution intelligente des chemins +### Intelligent Path Resolution -ObsiGate utilise 7 stratĂ©gies de rĂ©solution par ordre de prioritĂ© : +ObsiGate uses 7 resolution strategies in order of priority: -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]` +1. **Absolute path** : If the path is absolute and exists +2. **Configured attachments folder** : Via `VAULT_N_ATTACHMENTS_PATH` +3. **Startup index (unique match)** : Search by filename in the index +4. **Same directory** : Relative to the current markdown file +5. **Vault root** : Relative to the vault root +6. **Startup index (closest match)** : If multiple files have the same name +7. **Fallback** : Display a styled placeholder `[image not found: filename.ext]` ### Configuration -Pour optimiser la rĂ©solution, configurez le dossier d'attachements de chaque vault : +To optimize resolution, configure the attachments folder for each vault: ```yaml environment: - - VAULT_1_NAME=MonVault - - VAULT_1_PATH=/vaults/MonVault - - VAULT_1_ATTACHMENTS_PATH=Assets/Images # Chemin relatif - - VAULT_1_SCAN_ATTACHMENTS=true # Activer le scan (dĂ©faut) + - VAULT_1_NAME=MyVault + - VAULT_1_PATH=/vaults/MyVault + - VAULT_1_ATTACHMENTS_PATH=Assets/Images # Relative path + - VAULT_1_SCAN_ATTACHMENTS=true # Enable scanning (default) ``` -### Rescan manuel +### Manual Rescan -Pour rescanner les images d'un vault aprĂšs ajout/suppression : +To rescan images in a vault after adding/removing: ```bash -curl -X POST http://localhost:2020/api/attachments/rescan/MonVault +curl -X POST http://localhost:2020/api/attachments/rescan/MyVault ``` --- -## đŸ–„ïž Desktop (Tauri) — Application native +## đŸ–„ïž Desktop (Tauri) — Native Application -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. +ObsiGate Desktop is a native application built with [Tauri](https://tauri.app/) (Rust + system webview). It embeds the Python backend and frontend in a standalone executable — zero Docker, zero command line. -> 🚧 **Version 2.0.0 — binaires en cours de stabilisation.** Pour l'instant, le build depuis les sources est recommandĂ©. +> 🚧 **Version 2.0.0 — binaries are being stabilized.** For now, building from source is recommended. -### FonctionnalitĂ©s desktop natives +### Native Desktop Features -| FonctionnalitĂ© | Web | Desktop | +| Feature | 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) | +| Local file access | Via upload | Native (folder picker) | +| System theme | Manual | Auto (follows OS dark/light) | +| Notifications | Service Worker | Native OS | +| `.md` associations | ❌ | ✅ "Open with ObsiGate" | +| Tray icon | ❌ | ✅ Taskbar | +| Auto-update | ❌ | ✅ Checks Gitea releases | +| Offline mode | Limited | Full (local backend) | -### TĂ©lĂ©chargement (binaires prĂ©-buildĂ©s) +### Download (Pre-built Binaries) -Les releases sont publiĂ©es sur [Gitea](https://git.dracodev.net/Projets/ObsiGate/releases) : +Releases are published on [Gitea](https://git.dracodev.net/Projets/ObsiGate/releases) : -| Plateforme | Format | +| Platform | Format | |---|---| | **Linux** | `.deb` + `.AppImage` | | **Windows** | `.msi` + `.exe` (NSIS) | @@ -528,9 +529,9 @@ Les releases sont publiĂ©es sur [Gitea](https://git.dracodev.net/Projets/ObsiGat ```bash # .deb (Debian/Ubuntu/Deepin) sudo dpkg -i obsigate_2.0.0_amd64.deb -# Lancer : ObsiGate depuis le menu applications ou `obsigate-desktop` +# Launch : ObsiGate from the applications menu or `obsigate-desktop` -# .AppImage (toute distrib) +# .AppImage (any distro) chmod +x ObsiGate_2.0.0_amd64.AppImage ./ObsiGate_2.0.0_amd64.AppImage ``` @@ -538,39 +539,39 @@ chmod +x ObsiGate_2.0.0_amd64.AppImage #### Windows ```cmd -:: Double-cliquer sur ObsiGate_2.0.0_x64.msi -:: Ou lancer ObsiGate depuis le menu DĂ©marrer +:: Double-click ObsiGate_2.0.0_x64.msi +:: Or launch ObsiGate from the Start menu ``` -### DĂ©marrage +### Getting Started -1. **Lance l'application** depuis le menu ou la ligne de commande -2. Le backend Python dĂ©marre automatiquement sur `127.0.0.1:17890` -3. La fenĂȘtre s'ouvre et charge l'interface ObsiGate -4. **Premier lancement** : sĂ©lectionne le dossier de tes vaults Obsidian via le sĂ©lecteur natif -5. Pour fermer : icĂŽne tray → Quitter (arrĂȘt propre du backend) +1. **Launch the application** from the menu or command line +2. The Python backend starts automatically on `127.0.0.1:17890` +3. The window opens and loads the ObsiGate interface +4. **First launch** : select your Obsidian vaults folder via the native picker +5. To close : tray icon → Quit (clean backend shutdown) -### Build depuis les sources +### Build from Source -Guide dĂ©taillĂ© : [desktop/README.md](./desktop/README.md). +Detailed guide: [desktop/README.md](./desktop/README.md). -#### PrĂ©requis communs +#### Common Prerequisites -| Outil | Version | Installation | +| Tool | 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` | +| Linux system dependencies | — | `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 ». +> **Important — staging :** `tauri.conf.json` embeds `backend/**` and `frontend/**` **from the `desktop/` folder**. +> The build scripts automatically copy `../backend` and `../frontend` into `desktop/` before `cargo tauri build`. +> Without this staging, the build fails with "glob pattern backend/**/* path not found". #### đŸȘŸ Windows — `build-windows.bat` ```cmd -REM PrĂ©requis (via Scoop) : rustup, curl, git +REM Prerequisites (via Scoop) : rustup, curl, git scoop install rustup curl git rustup default stable cargo install tauri-cli @@ -579,17 +580,17 @@ cd desktop build-windows.bat ``` -Étapes du script : +Script steps: -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\` +1. Kills residual Python processes (`taskkill /F /IM python.exe`) +2. Downloads **Python 3.11 embed** (python.org) → `desktop\python-embed\` + enables pip (`python311._pth`) +3. `pip install -r ..\backend\requirements.txt` in the embed +4. **Staging** : copies `..\backend` and `..\frontend` to `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 +6. Copies `python-embed` next to the executable (`target\x86_64-pc-windows-msvc\release\`) for local dev mode +7. Cleans the staged folders -→ **Artefact :** `desktop\target\x86_64-pc-windows-msvc\release\bundle\nsis\ObsiGate_2.0.0_x64-setup.exe` +→ **Artifact :** `desktop\target\x86_64-pc-windows-msvc\release\bundle\nsis\ObsiGate_2.0.0_x64-setup.exe` #### 🐧 Linux — `build-linux.sh` @@ -599,38 +600,38 @@ chmod +x build-linux.sh ./build-linux.sh ``` -Étapes du script : +Script steps: -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/` +1. Checks Rust + Tauri CLI, installs system dependencies (apt) +2. Creates a Python venv `desktop/python-embed/venv` + `pip install -r ../backend/requirements.txt` +3. **Staging** : copies `../backend` and `../frontend` to `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 +5. Copies the runtime (`python-embed/`, `backend/`, `frontend/`) next to the executable -→ **Artefacts :** +→ **Artifacts :** - `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 +### đŸ€– CI/CD Builds — Automatic Artifacts -**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** : +**Yes** — the workflow [`.gitea/workflows/desktop-build.yml`](./.gitea/workflows/desktop-build.yml) builds desktop binaries on every push to `main` touching `desktop/**`, `frontend/**`, or `backend/**` (and manually via `workflow_dispatch`), on **self-hosted runners** : -| Job | Runner | Artefacts (conservĂ©s 30 jours) | +| Job | Runner | Artifacts (retained 30 days) | |---|---|---| | `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. +- Artifacts are downloadable from the **Actions** page of the Gitea run. +- Publishing to **Gitea Release** is planned for tags `v*` (`Publish to Gitea Release` step). +- The web workflow [`.gitea/workflows/ci.yml`](./.gitea/workflows/ci.yml) separately handles lint → tests → security → Docker build → e2e Playwright. -### Architecture Desktop +### Desktop Architecture ``` ┌────────────────────────────────────────────┐ │ Tauri (Rust) │ -│ ├─ Webview (webview systĂšme) │ +│ ├─ Webview (system webview) │ │ │ └─ Frontend (HTML/JS/CSS) │ │ └─ Sidecar Python │ │ └─ uvicorn backend.main:app │ @@ -638,246 +639,249 @@ chmod +x build-linux.sh └────────────────────────────────────────────┘ ``` -Cycle de vie : Tauri spawn le backend Python → health check → ouvre la webview. À la fermeture : SIGTERM → arrĂȘt propre → nettoyage. +Lifecycle: Tauri spawns the Python backend → health check → opens the webview. On close: SIGTERM → clean shutdown → cleanup. --- -## ïżœđŸ“– Utilisation +## 📖 Usage -### Interface web +### Web Interface -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 🌙/☀ +1. **Navigation** : Click on vaults in the sidebar to expand them +2. **Search** : Use the search bar to search across all vaults +3. **Tags** : Click on tags to filter content +4. **Wikilinks** : `[[page]]` links are clickable and navigable +5. **Images** : All Obsidian image syntaxes are rendered automatically +6. **Theme** : Toggle between light/dark theme with the 🌙/☀ icon -### Raccourcis clavier +### Keyboard Shortcuts -| Action | Raccourci | -|--------|-----------| -| Recherche | `Ctrl + K` ou `/` | -| Toggle thĂšme | `Ctrl + T` | -| Focus recherche | `Esc` | +| Action | Shortcut | +|--------|----------| +| Search | `Ctrl + K` or `/` | +| Toggle theme | `Ctrl + T` | +| Focus search | `Esc` | --- ## 🔌 API -ObsiGate expose une API REST complĂšte : +ObsiGate exposes a complete REST API : -| 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 | +| Endpoint | Description | Method | Auth | +|----------|-------------|--------|------| +| `/api/health` | Health check (status, version, stats) | GET | No | +| `/api/auth/status` | Auth status (enabled, users present) | GET | No | +| `/api/auth/login` | Login (returns access token + refresh cookie) | POST | No | +| `/api/auth/refresh` | Refresh access token via refresh cookie | POST | Cookie | +| `/api/auth/logout` | Logout + revoke refresh token | POST | Yes | +| `/api/auth/me` | Current user info | GET | Yes | +| `/api/auth/change-password` | Change password | POST | Yes | +| `/api/auth/admin/users` | List / create users | GET/POST | Admin | +| `/api/auth/admin/users/{u}` | Modify / delete a user | PATCH/DELETE | Admin | +| `/api/vaults` | List vaults (filtered by permissions) | GET | Yes | +| `/api/browse/{vault}?path=` | Browse folders | GET | Yes | +| `/api/file/{vault}?path=` | Rendered content of a file | GET | Yes | +| `/api/file/{vault}/raw?path=` | Raw content of a file | GET | Yes | +| `/api/file/{vault}/download?path=` | Download a file | GET | Yes | +| `/api/file/{vault}/save?path=` | Save a file | PUT | Yes | +| `/api/file/{vault}?path=` | Delete a file | DELETE | Yes | +| `/api/search/advanced` | Advanced TF-IDF search | GET | Yes | +| `/api/suggest` / `/api/tags/suggest` | Autocomplete | GET | Yes | +| `/api/tags?vault=` | Unique tags with counters | GET | Yes | +| `/api/index/reload` | Force a rescan of vaults | GET | Admin | +| `/api/events` | Real-time SSE stream | GET | Yes | +| `/api/vaults/add` / `/api/vaults/{name}` | Dynamic vault management | POST/DELETE | Admin | +| `/api/image/{vault}?path=` | Serve an image | GET | Yes | +| `/api/config` | Read / write configuration | GET/POST | Yes/Admin | +| `/api/diagnostics` | Index and memory statistics | GET | Admin | -> Quand `OBSIGATE_AUTH_ENABLED=false`, tous les endpoints sont accessibles sans token. +> When `OBSIGATE_AUTH_ENABLED=false`, all endpoints are accessible without a token. -> Tous les endpoints exposent des schĂ©mas Pydantic documentĂ©s. La doc interactive est disponible sur `/docs` (Swagger UI). +> All endpoints expose documented Pydantic schemas. Interactive docs are available at `/docs` (Swagger UI). -**Exemple d'utilisation :** +**Usage Example :** ```bash # Health check curl http://localhost:2020/api/health -# Lister les vaults +# List vaults curl http://localhost:2020/api/vaults -# Recherche simple (legacy) -curl "http://localhost:2020/api/search?q=recette&vault=all" +# Simple search (legacy) +curl "http://localhost:2020/api/search?q=recipe&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" +# Advanced search with TF-IDF, facets, and pagination +curl "http://localhost:2020/api/search/advanced?q=recipe%20tag:cuisine&vault=all&limit=20&offset=0&sort=relevance" -# AutocomplĂ©tion de titres +# Title autocomplete curl "http://localhost:2020/api/suggest?q=piz&vault=all" -# AutocomplĂ©tion de tags +# Tag autocomplete 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 +# Get a file +curl "http://localhost:2020/api/file/Recipes?path=pizza.md" +``` -### Syntaxe de requĂȘte +## 🔍 Advanced Search -| OpĂ©rateur | Description | Exemple | -|-----------|-------------|---------| -| `tag:` | Filtrer par tag | `tag:recette docker` | -| `#` | Raccourci tag | `#linux serveur` | -| `vault:` | Filtrer par vault | `vault:IT kubernetes` | -| `title:` | Filtrer par titre | `title:pizza` | -| `path:` | Filtrer par chemin | `path:recettes/soupes` | -| `ext:` | Filtrer par type de fichier | `ext:md kubernetes` | -| `"phrase exacte"` | Recherche de phrase | `tag:"multi mots"` | +### Query Syntax -Exemples de filtre par extension : `ext:sh` pour les scripts bash, `ext:py` pour les scripts Python, `ext:md` pour les fichiers Markdown. +| Operator | Description | Example | +|----------|-------------|---------| +| `tag:` | Filter by tag | `tag:recipe docker` | +| `#` | Tag shortcut | `#linux server` | +| `vault:` | Filter by vault | `vault:IT kubernetes` | +| `title:` | Filter by title | `title:pizza` | +| `path:` | Filter by path | `path:recipes/soups` | +| `ext:` | Filter by file type | `ext:md kubernetes` | +| `"exact phrase"` | Phrase search | `tag:"multiple words"` | -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. +Extension filter examples: `ext:sh` for bash scripts, `ext:py` for Python scripts, `ext:md` for Markdown files. -### Raccourcis clavier +Operators are combinable: `tag:linux vault:IT ext:md server web` searches for "server web" in Markdown files of the IT vault with the linux tag. -| 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 | +### Keyboard Shortcuts -### FonctionnalitĂ©s +| Shortcut | Action | +|----------|--------| +| `Ctrl+K` / `Cmd+K` | Focus search bar | +| `/` | Focus search (outside text fields) | +| `↑` / `↓` | Navigate suggestions | +| `Enter` | Select active suggestion or launch search | +| `Escape` | Close suggestions / exit search | -- **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 `` 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 +### Features + +- **TF-IDF** : Scoring based on term frequency weighted by inverse document frequency +- **Title boost** : Title matches receive 3× higher score +- **Accent normalization** : `resume` finds `rĂ©sumĂ©`, `elephant` finds `Ă©lĂ©phant` +- **Highlighted snippets** : Found terms are wrapped in `` in excerpts +- **Facets** : Counters by vault and by tag in results +- **Pagination** : Page navigation with 50 results per page +- **Sorting** : By relevance (TF-IDF) or modification date +- **Visual chips** : Active filters are shown as removable colored chips +- **History** : Last 50 searches are stored in localStorage --- -## 🔧 DĂ©pannage +## 🔧 Troubleshooting -### ProblĂšmes courants +### Common Issues -**Port dĂ©jĂ  utilisĂ© :** +**Port already in use:** ```bash -# VĂ©rifier qui utilise le port +# Check who is using the port sudo netstat -tulpn | grep 2020 -# Changer le port dans docker-compose.yml +# Change the port in 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 +**Vault not found:** +- Verify paths are absolute +- Ensure read permissions +- Restart the container after modifications -**Build Ă©choue :** +**Build fails:** ```bash -# Nettoyer le cache Docker et rebuild +# Clean Docker cache and rebuild docker system prune -f docker compose down ./build.sh --progress=plain -# Si l'Ă©chec persiste, vĂ©rifier les logs de build +# If failure persists, check build logs ./build.sh --progress=plain 2>&1 | tee build.log ``` -**Logs pour debugging :** +**Logs for debugging:** ```bash -# Logs en temps rĂ©el +# Real-time logs docker compose logs -f obsigate -# Logs dĂ©taillĂ©s +# Detailed logs 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Ă© | +| Metric | Estimate | +|--------|----------| +| **Indexing** | ~1–2s for 1,000 markdown files | +| **Advanced Search** | < 10ms for most queries (inverted index + TF-IDF) | +| **Wikilink Resolution** | O(1) via lookup table | +| **Memory** | ~80–150MB per 1,000 files (content capped at 100 KB/file) | +| **Docker Image** | ~180MB (multi-stage, no build tools) | +| **CPU** | Non-blocking; search offloaded to dedicated thread pool | -### ParamĂštres recommandĂ©s par taille de vault +### Recommended Settings by Vault Size -| 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 | +| Size | Files | `search_workers` | `prefix_max_expansions` | `max_content_size` | +|------|-------|------------------|--------------------------|---------------------| +| Small | < 500 | 1 | 50 | 100,000 | +| Medium | 500–5,000 | 2 | 50 | 100,000 | +| Large | 5,000+ | 4 | 30 | 50,000 | -Ces paramĂštres sont configurables via l'interface (Settings) ou l'API `/api/config`. +These parameters are configurable via the interface (Settings) or the `/api/config` API. -### Optimisations clĂ©s (v1.2.0) +### Key Optimizations (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 +- **Inverted index with set-intersection** : Search uses posting lists for O(k × postings) retrieval instead of O(N) full scan +- **Prefix matching by binary search** : O(log V + k) instead of O(V) linear vocabulary scan +- **ThreadPoolExecutor** : CPU-bound search functions are offloaded from the asyncio event loop +- **Race condition guard** : `currentSearchId` + `AbortController` prevent stale result rendering +- **Progress bar** : Animated progress bar during search +- **Search timeout** : Automatic abort after 30s (configurable) +- **Query time display** : Server time shown in results (`query_time_ms`) +- **Staleness detection fix** : Generation counter instead of `id(index)` to detect index changes -### Optimisations v1.5.0 (Quick Wins 2026-05-27) +### Optimizations 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 +- **GZip Compression** : FastAPI middleware compresses all responses >1KB (~70% bandwidth saved) +- **Cache-Control immutable** : Static assets (`/static/*`) are cached by the browser for 1 year +- **`.dockerignore`** : Minimal Docker build context (no `.git`, `docs/`, `*.md`, `__pycache__`) +- **Incremental InvertedIndex** : `add_document`/`remove_document` hooks, no more O(N) rebuild on every mutation -### Optimisations v1.1.0 +### Optimizations 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` +- **Search without I/O** : File content is cached in memory index +- **Multi-factor scoring** : exact title (+20), partial title (+10), path (+5), tag (+3), content frequency (x1 per occurrence, capped at 10) +- **Markdown renderer singleton** : The mistune renderer is instantiated once +- **AbortController** : Stale search requests are aborted client-side +- **Debounced icon rendering** : `lucide.createIcons()` is batched via `requestAnimationFrame` --- -## đŸ›Ąïž SĂ©curitĂ© +## đŸ›Ąïž Security -- **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 +- **Path traversal** : All file endpoints validate that the resolved path stays within the vault +- **Rate limiting** : 10 login attempts max per IP over 15 minutes + per-account lockout (5 attempts) +- **Audit log** : All writes, deletions, and config changes are logged in `data/audit.log` (JSON lines, 10 MB rotation) +- **Automatic backup** : Every file modification or deletion is saved in `.obsigate-backup/` with timestamp +- **Secret redaction** : Automatic masking of JWTs, API keys, tokens, and connection strings in previews +- **Non-root user** : The Docker container runs under user `obsigate` (UID 1000) +- **Read-only volumes** : Vaults are mounted as `:ro` by default in docker-compose +- **Secrets in `.env`** : Passwords and tokens are never in `docker-compose.yml` +- **Atomic writes** : Data files (users.json, shares.json, webhooks.json) use tmp+replace --- -## đŸ—ïž Stack technique +## đŸ—ïž Tech Stack - **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 +- **Security** : Rate limiting (IP + account lockout), audit logging, secret redaction, atomic writes +- **File Watcher** : watchdog 4.x (native inotify + fallback polling) +- **Frontend** : Vanilla JS + HTML + CSS (zero framework, zero build) +- **Markdown Rendering** : 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 +- **Compression** : GZip middleware (FastAPI), Cache-Control immutable for assets +- **Docker Image** : python:3.11-slim (multi-stage), `.dockerignore` for minimal context +- **User Storage** : Local JSON (`data/users.json`) — no database +- **Architecture** : SPA + REST API + SSE --- @@ -885,7 +889,7 @@ Ces paramĂštres sont configurables via l'interface (Settings) ou l'API `/api/con ``` ┌─────────────────┐ ┌─────────────────────────────────────────┐ -│ Navigateur │◄───â–ș│ FastAPI (backend/main.py) │ +│ Browser │◄───â–ș│ FastAPI (backend/main.py) │ │ (SPA) │ REST │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ app.js │ │ │ indexer.py │ │ search.py │ │ @@ -895,70 +899,131 @@ Ces paramĂštres sont configurables via l'interface (Settings) ou l'API `/api/con │ └──────┬───────┘ │ │ │ │ │ ┌────────┮─────────┐ │ - │ │ Index en mĂ©moire │ │ - │ │ (fichiers, tags, │ │ - │ │ contenu, lookup)│ │ + │ │ In-Memory Index │ │ + │ │ (files, tags, │ │ + │ │ content, lookup)│ │ │ └──────────────────┘ │ └─────────────────────────────────────────┘ ┌───────────────────────────────┐ - │ Filesystem (vaults montĂ©es) │ - │ /vaults/Recettes (ro) │ + │ Filesystem (mounted vaults) │ + │ /vaults/Recipes (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 +**Data Flow:** +1. On startup, `indexer.py` scans all vaults in parallel (thread pool) +2. Content, tags (YAML + inline), and metadata are cached in memory +3. An O(1) lookup table is built for wikilink resolution +4. `watcher.py` starts file monitoring (native watchdog or polling) +5. Detected changes trigger incremental index updates +6. Changes are notified to the frontend via Server-Sent Events (SSE) +7. Search queries use the in-memory index (zero disk I/O) +8. The SPA frontend communicates via REST + SSE and manages state client-side --- -## 📝 DĂ©veloppement +## 📝 Development -### Structure du projet +### đŸ§Ș Tests and CI — Mandatory Rules (Before Each Push) + +> ⚠ **Absolute rule — human contributors and AI agents**: never `git push` +> without having **locally** executed the entire sequence below with **100 % +> success**. Push is not meant to discover failures: CI is a safety net, not a +> diagnostic tool. + +#### Local Checks Before Commit + +| Step | Command | Equivalent CI Job | +|---|---|---| +| Backend lint | `ruff check backend/` | `lint` | +| Frontend import validation | `node tests/frontend/validate-imports.mjs` | `lint` | +| Frontend unit tests | `node tests/frontend/unit.test.mjs` | `lint` | +| Backend tests | `pytest tests/ -q` | `test` | +| **E2E Playwright** | `npm run test:e2e` (~5 min) | `e2e` | + +#### Local E2E Tests (`npm run test:e2e`) + +The `scripts/run-e2e-local.sh` script faithfully reproduces the `e2e` CI job +conditions (`.gitea/workflows/ci.yml`): + +- backend started natively (venv `.venv-e2e`, Python 3.11 via `uv`) ; +- authentication disabled (`OBSIGATE_AUTH_ENABLED=false`) ; +- fixtures `test_vault` (TestVault) and `test_dir` (TestDir) ; +- port `2029` (baseURL from `playwright.config.ts`) ; +- Playwright project `chromium-desktop` only (same as CI). + +Prerequisites: `uv`, Node.js ≄ 20, Playwright browsers +(`npx playwright install chromium`). The venv is created automatically on +first run. Docker is not required. + +```bash +npm run test:e2e # full suite +bash scripts/run-e2e-local.sh --headed # visible browser +bash scripts/run-e2e-local.sh -g "reset panes" # filter on a test +``` + +The suite must end with **all tests passing** (60 currently), with no failure +or reliance on retries. In case of failure: fix and re-run locally until 100 %, +then only commit. + +#### Test Writing Rules (Lesson Learned) + +- **Check every selector in the actual DOM** before using it in a test. Real + bug encountered: a test was targeting `#cp-input` while the command palette + input only has the `.cp-input` class (no id) — the test could not pass in any + environment. +- Any new or modified test must be **run locally** (at least with + `-g "test name"`) before push. +- No workarounds that mask flakiness (arbitrary `waitForTimeout`, + silent fallbacks): fix the root cause. + +#### Commits and Push + +- Commit message: imperative subject ≀ 50 chars; body (72 col.) only if it + adds useful information. +- One commit = one logical change (do not mix fix and refactor). +- Push only when all 5 local steps are green. CI pipeline: + `lint → test → security → build → e2e`. + +### Project Structure ``` 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 +├── backend/ # FastAPI API +│ ├── main.py # Endpoints, Pydantic models, markdown rendering +│ ├── indexer.py # Vault scanning, in-memory index, lookup table +│ ├── search.py # Full-text search engine with scoring +│ ├── watcher.py # File monitoring (watchdog + debounce) +│ ├── auth/ # Authentication module │ │ ├── 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 +│ │ ├── jwt_handler.py # JWT tokens + revocation +│ │ ├── user_store.py # users.json CRUD (atomic) +│ │ ├── middleware.py # FastAPI auth dependencies +│ │ └── router.py # /api/auth/* endpoints +│ ├── create_admin.py # User management CLI │ └── 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) +├── frontend/ # Web interface (Vanilla JS, zero framework) +│ ├── index.html # SPA page + login screen +│ ├── app.js # SPA logic, AuthManager, AdminPanel +│ └── style.css # Styles (CSS variables, themes, responsive) +├── data/ # Persistent data (created on startup) +│ ├── users.json # Users (Argon2id hashed) +│ └── secret.key # JWT secret key (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 +├── docker-compose.yml # Deployment with healthcheck and auth env vars +├── build.sh # Automated build & deployment (docker compose build + up) +└── CONTRIBUTING.md # Contribution guide ``` -### Contribuer +### Contributing -Voir [CONTRIBUTING.md](CONTRIBUTING.md) pour les dĂ©tails. +See [CONTRIBUTING.md](CONTRIBUTING.md) for details. --- -## 📄 Licence +## 📄 License -Ce projet est sous licence **MIT** - voir le fichier [LICENSE](LICENSE) pour les dĂ©tails. +This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details. --- @@ -966,14 +1031,14 @@ Ce projet est sous licence **MIT** - voir le fichier [LICENSE](LICENSE) pour les - **Issues** : [git.dracodev.net/Projets/ObsiGate/issues](https://git.dracodev.net/Projets/ObsiGate/issues) - **Documentation** : [git.dracodev.net/Projets/ObsiGate/wiki](https://git.dracodev.net/Projets/ObsiGate/wiki) -- **Auteur** : Bruno Beloeil +- **Author** : Bruno Beloeil --- ## 📝 Changelog -Consultez le [CHANGELOG.md](./CHANGELOG.md) pour l'historique complet de toutes les versions (v1.0.0 → v1.7.0). +See [CHANGELOG.md](./CHANGELOG.md) for the complete version history (v1.0.0 → v1.7.0). --- -*Projet : ObsiGate | Version : 1.7.0 | DerniĂšre mise Ă  jour : Mai 2026* +*Project: ObsiGate | Version: 1.7.0 | Last updated: May 2026*