# ObsiGate
**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.
[]()
[](https://opensource.org/licenses/MIT)
[](https://www.docker.com/)
[](https://www.python.org/)
[](https://git.dracodev.net/Projets/ObsiGate/actions)

> ObsiGate web interface: multi-vault sidebar, global search, dashboard stats and shortcuts.
---
## π Guides
Step-by-step **user guides** live in [`docs/GUIDES/`](docs/GUIDES/):
| Guide | What it covers |
|---|---|
| π [Getting Started](docs/GUIDES/PRISE_EN_MAIN.md) | First run, interface, navigation, vaults, shortcuts |
| π [Search, PDF, Excel & Excalidraw](docs/GUIDES/RECHERCHE_PDF_EXCALIDRAW.md) | Query syntax, semantic search, PDF/Excel viewers, diagrams |
| π€ [AI Assistant & Forge](docs/GUIDES/ASSISTANT_IA_FORGE.md) | Providers, AI editor, BooksLM, Forge, `@` / `/` commands |
| π [Editing & Collaboration](docs/GUIDES/COLLABORATION.md) | Simultaneous editing, remote cursors, persistence |
| π± [PWA & Offline](docs/GUIDES/PWA_HORS_LIGNE.md) | Install as an app, offline cache, sync queue, push |
| π [REST API](docs/GUIDES/API_REST.md) | Authentication, API keys, endpoints, `curl` examples, SSE |
| 𧩠[MCP Server](docs/GUIDES/MCP.md) | Connect Claude Desktop, Cursor, Cline⦠to your vaults |
| π [Auth & Security](docs/GUIDES/AUTHENTIFICATION_SECURITE.md) | Users, MFA, per-vault permissions, hardening |
| π³ [Docker Deployment](docs/GUIDES/DEPLOIEMENT_DOCKER.md) | `docker-compose`, volumes, reverse proxy, updates |
| π₯οΈ [Desktop (Tauri)](docs/GUIDES/DESKTOP.md) | Install, first run, build from source, troubleshooting |
> All guides are currently written in **French**. See the full index:
> [`docs/GUIDES/README.md`](docs/GUIDES/README.md).
---
## π Table of Contents
- β¨ [Features](#features)
- π [Guides](#guides)
- π [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)
- πΌοΈ [Obsidian Image Rendering](#obsidian-image-rendering)
- π₯οΈ [Desktop (Tauri) β Native Application](#desktop-tauri--native-application)
- π [Usage](#usage)
- π₯ [Real-time Collaboration](#real-time-collaboration)
- π [API](#api)
- π [Advanced Search](#advanced-search)
- π‘οΈ [Security](#security)
- β‘ [Performance](#performance)
- π§ [Troubleshooting](#troubleshooting)
- ποΈ [Tech Stack](#tech-stack)
- π [Architecture](#architecture)
- π [Development](#development)
- π [License](#license)
- π€ [Support](#support)
- π [Changelog](#changelog)
---
## β¨ Features
- **π€ 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
- **π§© MCP Server & AI Agent** β Built-in Model Context Protocol server (`/mcp`) and tool-calling assistant: read, search and edit your vaults from Claude Desktop, Cursorβ¦ with two-step confirmations, per-vault permissions, rate limiting and secret redaction ([guide](docs/GUIDES/MCP.md))
- **π₯ Real-time Collaboration** β Simultaneous editing of the same document (Yjs/CRDT): colored remote cursors, presence indicator, conflict-free merge, automatic reconnection and server-side persistence ([details](docs/features/collaboration.md))
- **π Built-in User Guide** β Complete FR/EN help from the Options menu: interface, navigation, search, files, AI, security, API & integrations (OpenAPI, MCP), offline, collaboration, desktop, plus an **Architecture** section with a Mermaid diagram; downloadable as **Markdown** and **PDF** in the current language ([details](docs/features/guide-coverage-105.md))
- **π± Native Mobile Editor** β Touch-optimised editing: floating Markdown toolbar (bold/italic/code/list/link), persistent Paste button (iOS workaround), pinch-zoom font & adjustable height, swipe shortcuts (backlinks / table of contents) and a full-screen reading mode with page navigation ([details](docs/features/mobile-editor.md))
- **πΊοΈ 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 β plus an optional **semantic search** (embeddings via `all-MiniLM-L6-v2`, hybrid TF-IDF + RRF fusion) toggled with `~` ([details](docs/features/semantic-search.md))
- **π‘ 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
- **π¬ Audio & video** : Built-in HTML5 players (`.mp3 .wav .flac .mp4 .webm`β¦) with HTTP Range streaming (play, seek, fullscreen) and **persistent playback** (floating mini-player / mini video window, return to media or stop anytime, lock-screen controls via Media Session), falling back to download when the format is not playable in the browser
- **π¨ Excalidraw Diagrams** : Native viewer/editor for `.excalidraw` and `.excalidraw.md` files (sandboxed iframe, autosave, dark/light theme, diagram text indexed for search)
- **π Excel Spreadsheets** : `.xlsx` and `.xlsm` files open in a dedicated viewer β one table per sheet with tabs, A1 headers and inline cell editing (`PUT /api/file/{vault}/xlsx/save`, automatic backup, atomic write), plus download of the original file. The viewer renders fonts, colors, merged cells and frozen panes, offers keyboard navigation, a formula bar, sort/filter/find, CSV export, sheet & row/column structure editing and a workbook dashboard (named ranges, charts/pivot detection, per-sheet stats); `.csv` is edited in the same grid (RFC 4180) while `.xls` and `.ods` open read-only. Workbooks holding elements ObsiGate cannot preserve (cached values, slicers, form controls, signatureβ¦) show a **warning** and ask for confirmation before saving; a value starting with `=` or `@` is stored as text unless the `f(x)` toggle is enabled. The AI assistant can list sheets, dump a bounded table to its context, update cells and append rows
- **π¨ 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
---
## π Prerequisites
### System Requirements
- **Docker** >= 20.10
- **docker-compose** >= 2.0
- **Disk space** : ~200MB for the Docker image
### Supported Systems
- Linux (Ubuntu, Debian, CentOS, etc.)
- macOS (Intel and Apple Silicon)
- Windows (with Docker Desktop)
- Docker-compatible NAS (Synology, QNAP, etc.)
---
## β‘ Quick Installation
### 1. Clone the Repository
```bash
git clone https://git.dracodev.net/Projets/ObsiGate.git
cd ObsiGate
```
### 2. Configure Your Vaults and Secrets
Edit the `docker-compose.yml` file to add your Obsidian vaults:
```yaml
volumes:
- /absolute/path/to/your/vault:/vaults/YourVaultName:ro
```
> **Important** : The path must be absolute and the volume must be read-only (`:ro`)
Create your `.env` file for authentication and secrets:
```bash
cp .env.example .env
# Edit .env to configure your passwords and options
```
> **Never commit `.env`!** It is in `.gitignore`. Use `.env.example` as a reference.
### 3. Launch the Application
```bash
# Make the script executable (once)
chmod +x build.sh
# Build + deploy in one command
./build.sh
```
> **That's it!** `build.sh` checks Docker, validates your volumes, builds the image, and starts the container automatically.
>
> Useful options: `./build.sh --help` for help, `./build.sh --cache` for a faster rebuild, `./build.sh --build-only` to build without starting.
### 4. Access the Interface
Open your browser at: **http://localhost:2020**
---
## βοΈ Detailed Configuration
### Step 1: Prepare Your Vaults
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
### Step 2: Configure docker-compose.yml
Here's a complete example:
```yaml
services:
obsigate:
build:
context: .
image: obsigate:latest
container_name: obsigate
restart: unless-stopped
ports:
- "2020:8080" # Local port 2020 β Container port 8080
volumes:
# 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-Personal:/vaults/Personal:ro
# Auth data persistence
- ./data:/app/data
environment:
# Vault configuration
- VAULT_1_NAME=Recipes
- VAULT_1_PATH=/vaults/Recipes
- VAULT_2_NAME=IT
- VAULT_2_PATH=/vaults/IT
- 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 # Contains OBSIGATE_ADMIN_PASSWORD and other secrets
```
### Step 3: Build & Deploy
```bash
# Use the automated build script (recommended)
chmod +x build.sh
./build.sh
```
The `build.sh` script handles everything: prerequisite checks, volume validation, image building, and startup.
**Manual alternative:**
```bash
docker compose build --no-cache
docker compose up -d
```
> **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.
---
## π Environment Variables
Vaults are configured using pairs of `VAULT_N_NAME` / `VAULT_N_PATH` variables (N = 1, 2, 3β¦):
| Variable | Description | Example |
|----------|-------------|---------|
| `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` |
**Naming rules:**
- Use only letters, numbers, and hyphens
- No spaces or special characters
- The name must match the path inside the container
---
## π Authentication
> **Disabled by default** β Compatible with all existing installations.
ObsiGate supports an optional authentication system based on **JWT + Argon2id** with per-vault access control.
### Enable Authentication
1. **Copy the `.env` template** :
```bash
cp .env.example .env
```
2. **Edit `.env`** and uncomment/configure the variables :
```bash
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. **In `docker-compose.yml`**, make sure you have :
```yaml
env_file:
- .env
```
> **Never put passwords in `docker-compose.yml`!** Always use `.env`.
### First Startup
If no user exists, ObsiGate automatically creates an admin account and **displays the password in the logs** :
```bash
docker-compose logs obsigate | grep -A4 "FIRST"
```
```
============================================================
FIRST STARTUP β Admin account created automatically
Username : admin
Password : xK9mQ3pLr7wN2jT5
CHANGE THIS PASSWORD on first login!
============================================================
```
### User Management via CLI
```bash
# Create a user
docker exec obsigate python backend/create_admin.py create alice MyPassword --role user --vaults Recipes IT
# Create an admin with full access
docker exec obsigate python backend/create_admin.py create bob SecretPass --role admin --vaults "*"
# List users
docker exec obsigate python backend/create_admin.py list
# Delete a user
docker exec obsigate python backend/create_admin.py delete alice
```
### Admin Interface
When an **admin** account is logged in, a π‘οΈ icon appears in the header. Clicking it opens the admin panel allowing you to:
- List all users
- Create / edit / delete users
- Assign accessible vaults per user
- Enable/disable accounts
### Per-Vault Access Control
| vaults value | Access |
|--------------|--------|
| `["*"]` | All vaults (including future ones) β admin default |
| `["Recipes", "IT"]` | Only these vaults |
| `[]` | No access |
### Auth Environment Variables
| 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_ACCOUNT_MAX_ATTEMPTS` | Max login attempts per account | `10` |
| `OBSIGATE_LOGIN_WINDOW_SECONDS` | Rate limiting window (seconds) | `900` |
| `OBSIGATE_TRUST_PROXY` | Trust `X-Forwarded-For` for the client IP (reverse proxy) | `false` |
| `OBSIGATE_WEBHOOK_ALLOW_HTTP` | Allow non-HTTPS webhook targets | `false` |
| `OBSIGATE_WEBHOOK_ALLOW_PRIVATE` | Allow webhooks to private/loopback addresses | `false` |
| `OBSIGATE_PDF_MAX_SIZE_MB` | Max PDF size for text extraction | `50` |
| `OBSIGATE_MEDIA_MAX_INLINE_MB` | Max size for inline audio/video playback (above: download) | `500` |
| `OBSIGATE_PDF_EXTRACT_TIMEOUT` | PDF extraction timeout (seconds) | `30` |
| `OBSIGATE_TAVILY_API_KEY` / `OBSIGATE_BRAVE_API_KEY` / `OBSIGATE_SERPAPI_API_KEY` / `OBSIGATE_EXA_API_KEY` | Keyed web-search providers (tried before SearXNG) | β |
| `OBSIGATE_WEB_PROVIDERS` | Search provider order (e.g. `brave,searxng`) | β |
| `OBSIGATE_WEB_RETRY` | Web tools network retries (house-made backoff) | `1` |
| `OBSIGATE_WEB_CACHE_TTL` | SQLite cache TTL for web results (seconds, `0` = off) | `900` |
| `OBSIGATE_GITEA_URL` / `OBSIGATE_GITEA_TOKEN` | Gitea connected source (`git_list_repos`β¦) | β |
| `OBSIGATE_GITHUB_TOKEN` | GitHub token (`git_list_repos`β¦) | β |
> These keys can also be entered **from the UI** (menu β Configurations β
> "Connected sources & search"): the stored value goes to `data/api_keys.json`
> and takes precedence over the environment variable.
>All these variables are documented in `.env.example`.
### Volume for Persistence
Auth data (`users.json`, `secret.key`) is stored in `/app/data`. Add a volume to persist it:
```yaml
volumes:
# vaults...
- ./data:/app/data # Persist users and JWT key
```
---
## β Adding a New Vault
### Method 1: Direct Editing
1. **Stop the container** :
```bash
docker-compose down
```
2. **Add a volume** in `docker-compose.yml` :
```yaml
volumes:
- /new/vault/path:/vaults/NewVault:ro
```
3. **Add the environment variables** :
```yaml
environment:
- VAULT_4_NAME=NewVault
- VAULT_4_PATH=/vaults/NewVault
```
4. **Restart** :
```bash
./build.sh
```
### Method 2: Hot-reload (recommended)
1. **Add the volume and variables** as above
2. **Apply the changes** :
```bash
./build.sh
```
3. **Reload the index** via the interface or the API :
```bash
curl http://localhost:2020/api/index/reload
```
### Method 3: Dynamic API (without restart)
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": "NewVault", "path": "/vaults/NewVault"}'
```
Remove a vault:
```bash
curl -X DELETE http://localhost:2020/api/vaults/NewVault
```
---
## π¨ Build & Deployment with build.sh
The `build.sh` script is the recommended way to build and deploy ObsiGate.
### Basic Usage
```bash
chmod +x build.sh # once
./build.sh # build from scratch + start
```
### Available Options
| Option | Description |
|--------|-------------|
| `--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 |
### What the Script Does
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
### Examples
```bash
# Clean build + start (recommended after code changes)
./build.sh
# Fast rebuild with cache (minor frontend changes only)
./build.sh --cache
# Test the build without starting (useful for pre-prod testing)
./build.sh --build-only
# Verbose output to debug a build failure
./build.sh --progress=plain
```
### Stopping / Restarting
```bash
docker compose down # Stop the container
docker compose up -d # Restart without rebuild
docker compose logs -f # View logs
```
---
## πΌοΈ Obsidian Image Rendering
ObsiGate supports **all Obsidian image syntaxes** with an intelligent multi-strategy resolution system.
### Supported Syntaxes
1. **Standard Markdown with HTML attributes** (Obsidian-compatible) :
```markdown
[
](https://example.com)
```
2. **Wiki-link embed with full path** :
```markdown
![[06_Toolbox/6.2_Attachments/image.svg]]
```
3. **Wiki-link embed with filename only** :
```markdown
![[image.svg]]
```
4. **Standard Markdown** :
```markdown

```
### Intelligent Path Resolution
ObsiGate uses 7 resolution strategies in order of priority:
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]`
### Viewer & file tree
Images are first-class vault files: they appear in the tree, are indexed (name +
metadata, **never the bytes**) and open in a **dedicated viewer** β wheel zoom
0.1Γβ8Γ, drag pan, double-click to reset, β/β navigation between images in the
same folder (WebP thumbnail filmstrip), metadata panel, full-screen lightbox,
open original and download. The `ext:png`/`ext:jpg` search filter is available.
Decodable formats: PNG, JPEG, GIF, WebP, BMP, ICO, SVG (SVG served with a
`sandbox` CSP). **HEIC/HEIF** (iPhone) is not decodable by browsers and is not
supported.
### Configuration
To optimize resolution, configure the attachments folder for each vault:
```yaml
environment:
- 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)
```
### Manual Rescan
To rescan images in a vault after adding/removing:
```bash
curl -X POST http://localhost:2020/api/attachments/rescan/MyVault
```
---
## π₯οΈ Desktop (Tauri) β Native Application
> π Full guide: [Desktop (Tauri)](docs/GUIDES/DESKTOP.md)
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 β binaries are being stabilized.** For now, building from source is recommended.
### Native Desktop Features
| Feature | Web | Desktop |
|---|---|---|
| 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) |
### Download (Pre-built Binaries)
Releases are published on [Gitea](https://git.dracodev.net/Projets/ObsiGate/releases) :
| Platform | Format |
|---|---|
| **Linux** | `.deb` + `.AppImage` |
| **Windows** | `.msi` + `.exe` (NSIS) |
#### Linux
```bash
# .deb (Debian/Ubuntu/Deepin)
sudo dpkg -i obsigate_2.0.0_amd64.deb
# Launch : ObsiGate from the applications menu or `obsigate-desktop`
# .AppImage (any distro)
chmod +x ObsiGate_2.0.0_amd64.AppImage
./ObsiGate_2.0.0_amd64.AppImage
```
#### Windows
```cmd
:: Double-click ObsiGate_2.0.0_x64.msi
:: Or launch ObsiGate from the Start menu
```
### Getting Started
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 from Source
Detailed guide: [desktop/README.md](./desktop/README.md).
#### Common Prerequisites
| Tool | Version | Installation |
|---|---|---|
| Rust (cargo) | β₯ 1.75 | `rustup` |
| Tauri CLI | β₯ 2.0 | `cargo install tauri-cli` |
| Git | β | β |
| Linux system dependencies | β | `sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev` |
> **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 Prerequisites (via Scoop) : rustup, curl, git
scoop install rustup curl git
rustup default stable
cargo install tauri-cli
cd desktop
build-windows.bat
```
Script steps:
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. Copies `python-embed` next to the executable (`target\x86_64-pc-windows-msvc\release\`) for local dev mode
7. Cleans the staged folders
β **Artifact :** `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
```
Script steps:
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. Copies the runtime (`python-embed/`, `backend/`, `frontend/`) next to the executable
β **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`
### π€ CI/CD Builds β Automatic Artifacts
**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 | Artifacts (retained 30 days) |
|---|---|---|
| `build-windows` | `[self-hosted, windows, desktop]` | `desktop/target/release/bundle/msi/*.msi` |
| `build-linux` | `[self-hosted, linux, desktop]` | `*.AppImage` + `*.deb` |
- 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.
### Desktop Architecture
```
ββββββββββββββββββββββββββββββββββββββββββββββ
β Tauri (Rust) β
β ββ Webview (system webview) β
β β ββ Frontend (HTML/JS/CSS) β
β ββ Sidecar Python β
β ββ uvicorn backend.main:app β
β ββ port 127.0.0.1:17890 β
ββββββββββββββββββββββββββββββββββββββββββββββ
```
Lifecycle: Tauri spawns the Python backend β health check β opens the webview. On close: SIGTERM β clean shutdown β cleanup.
---
## π Usage
### Web Interface
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
### Keyboard Shortcuts
| Action | Shortcut |
|--------|----------|
| Search | `Ctrl + K` or `/` |
| Toggle theme | `Ctrl + T` |
| Focus search | `Esc` |
---
## π₯ Real-time Collaboration
> π Full guide: [Editing & Collaboration](docs/GUIDES/COLLABORATION.md)
Multiple users can edit the same markdown document simultaneously (Google Docs style):
- **Conflict-free merge** via Yjs (CRDT): two people can type in the same place, no change is lost.
- **Colored remote cursors** and visible selections in CodeMirror, labelled with each user's name.
- **Presence indicator** in the editor header (avatars + connection status).
- **Automatic reconnection** (exponential backoff): state is merged on return.
- **Server-side persistence**: the document is written to disk 2 s after the last change.
- **Transport**: WebSocket `ws(s):///ws/collab/{vault}/{path}`, authenticated via the
`access_token` cookie (or `?token=`) and subject to per-vault access control.
No configuration is required: open the same file in two browsers (or two windows) to see it live.
---
## π API
> π Full guide: [REST API](docs/GUIDES/API_REST.md) Β· [MCP Server](docs/GUIDES/MCP.md)
ObsiGate exposes a complete REST API :
| 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 (+ `semantic=true` for hybrid) | 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/media/{vault}/thumb?path=&size=` | WebP thumbnail (disk cache) | GET | Yes |
| `/api/config` | Read / write configuration | GET/POST | Yes/Admin |
| `/api/diagnostics` | Index and memory statistics | GET | Admin |
> When `OBSIGATE_AUTH_ENABLED=false`, all endpoints are accessible without a token.
> All endpoints expose documented Pydantic schemas. Interactive docs are available at `/docs` (Swagger UI).
**Usage Example :**
```bash
# Health check
curl http://localhost:2020/api/health
# List vaults
curl http://localhost:2020/api/vaults
# Simple search (legacy)
curl "http://localhost:2020/api/search?q=recipe&vault=all"
# 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"
# Title autocomplete
curl "http://localhost:2020/api/suggest?q=piz&vault=all"
# Tag autocomplete
curl "http://localhost:2020/api/tags/suggest?q=rec&vault=all"
# Get a file
curl "http://localhost:2020/api/file/Recipes?path=pizza.md"
```
## π Advanced Search
> π Full guide: [Search, PDF, Excel & Excalidraw](docs/GUIDES/RECHERCHE_PDF_EXCALIDRAW.md)
### Query Syntax
| 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"` |
Extension filter examples: `ext:sh` for bash scripts, `ext:py` for Python scripts, `ext:md` for Markdown files, `ext:pdf` for PDF documents, `ext:excalidraw` for Excalidraw diagrams (text-extracted content is indexed).
### PDF support
PDF files in your vaults are rendered inline in the browser via the native PDF viewer (iframe + `