Files
ObsiGate/docs/features/desktop-tauri.md
T
bruno d2734dc8ce
CI / lint (push) Successful in 3m2s
CI / security (push) Successful in 2m2s
CI / test (push) Successful in 4m42s
CI / build (push) Successful in 1m52s
CI / e2e (push) Successful in 15m54s
feat: gestion desktop des vaults & dossiers — retrait par menu contextuel et ajout en configuration #159
2026-10-02 21:04:17 -04:00

110 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# #77 — Application Desktop native — Tauri (Windows / Linux / macOS)
> **Statut :** 🔵 En cours — livré : A/B/C/D/E/F ; reste la signature de code Windows (optionnelle, non retenue) et l'exécution des 6 tests E2E **manuels** ([protocole](../DESKTOP_E2E_CHECKLIST.md))
> **Effort :** 8-12 jours | **Impact :** 🟡 | **Framework :** Tauri v2 (Rust + Webview)
> **Références :** [Roadmap](../ROADMAP.md) · [Guide de build & releases](../DEVELOPMENT_AND_RELEASES.md)
- **Description :** Packager ObsiGate en application desktop native autonome. L'utilisateur télécharge un `.exe` (Windows) ou un `.AppImage` (Linux), l'installe, et lance ObsiGate comme n'importe quelle app — sans Docker, sans terminal, sans navigateur. Le backend Python est embarqué, le frontend s'affiche dans une webview native. L'expérience est identique à l'application web, avec des capacités supplémentaires (accès fichiers natif, notifications OS, tray icon).
- **Architecture :**
```
ObsiGate.exe (Tauri shell ~5 Mo)
├── python-embed/ ← Python 3.11 embarqué (~30 Mo)
│ ├── backend/ ← Code FastAPI existant
│ └── site-packages/ ← Dépendances gelées
├── frontend/ ← HTML/CSS/JS (identique au web)
└── obsigate-desktop ← Binaire Rust (lance Python + ouvre webview)
```
- **Pourquoi Tauri plutôt qu'Electron ?**
- Binaire de ~35-40 Mo contre ~180 Mo pour Electron (pas de Chromium embarqué)
- RAM idle ~50 Mo contre ~200 Mo — la webview utilise le moteur du navigateur système
- Rust gère le cycle de vie du backend Python (spawn, health check, kill propre)
- Signature de code native Windows/macOS pour éviter les faux positifs antivirus
- Auto-update natif via le mécanisme de Tauri (vérifie un endpoint JSON)
- **Sous-tâches :**
## A. Initialisation du projet Tauri (1 jour) — ✅ livré (vérifié 2026-09)
- [x] Toolchain : tauri-cli 2.11.4 / rustc 1.94.1
- [x] Projet Tauri v2 dans `desktop/` (Cargo.toml, build.rs)
- [x] `tauri.conf.json` : fenêtre 1200×800 (min 800×600), titre "ObsiGate"
- [x] Build : cibles `.msi`/`.nsis` (Windows), `.deb`/`.AppImage` (Linux)
- [x] Icônes desktop dans `desktop/icons/` (.ico, .icns, .png)
## B. Intégration du backend Python (2-3 jours) — ✅ livré (variante : uvicorn spawné directement, pas de sidecar.py)
- [x] Bundle Python : `desktop/python-embed/` (python3.11-embed + site-packages, validé par validate-structure.sh)
- [x] Lancement backend : `spawn_backend()` Rust lance `python-embed -m uvicorn backend.main:app` (équivalent sidecar), logs dans `%APPDATA%/ObsiGate/logs/backend.log`
- [x] `main.rs` : spawn processus fils, health check (`GET /api/health`, 30 essais × 2s), kill propre (SIGTERM→wait→kill)
- [x] Menu tray (voir section C ✅)
- [x] Gestion du port : `pick_free_port()` scan 17890..17899 si occupé (commit c066b2c, 3 tests Rust)
## C. Fonctionnalités desktop natives (2-3 jours) — ✅ COMPLÉTÉ
- [x] **Sélecteur de dossier** : `pick_vault_folder` via `tauri_plugin_dialog` → ajoute le vault dans config.json
- [x] **Thème système** : `get_system_theme` lit le thème OS → appliqué automatiquement
- [x] **Notifications natives** : `tauri-plugin-notification` intégré — remplace le service worker Push API
- [x] **Associations de fichiers** : `.md` → « Ouvrir avec ObsiGate » dans `tauri.conf.json`
- [x] **Menu natif** : Fichier (Nouvelle fenêtre, Fermer, Quitter) / Édition (Annuler, Rétablir, Couper, Copier, Coller, Tout sélectionner) / Aide (À propos)
- [x] **Raccourcis clavier** : `Ctrl+N`, `Ctrl+W`, `Ctrl+Q`, `Ctrl+Z`, `Ctrl+Shift+Z`, `Ctrl+X/C/V/A`
- [x] **Tray icon** : menu contextuel (Ouvrir, À propos, Quitter) + toggle fenêtre au clic gauche
- [x] **Single instance** : `tauri-plugin-single-instance` — deuxième lancement focus la fenêtre existante
- [x] **Auto-update** : `tauri-plugin-updater` configuré → vérifie les releases Gitea
- [x] **Pas de terminal visible** : `#![windows_subsystem = "windows"]` + `CREATE_NO_WINDOW` sur le processus Python
- [x] **Persistance fenêtre** : position/taille sauvegardée dans `config.json`
## D. Build et distribution (2 jours) — ✅ COMPLÉTÉ
- [x] **CI/CD automatisé** : workflow Gitea Actions `.gitea/workflows/desktop-build.yml` — build Windows + Linux à chaque push sur `main` (si `desktop/` modifié), upload des artefacts `.msi`/`.AppImage`/`.deb` en release
- [x] **Build Windows local** : `cargo build --release` vérifié (rustc 1.94.1) — `cargo tauri build --bundles msi` prêt
- [x] **Build Linux local** : workflow CI couvre `.deb`, `.rpm`, `.AppImage`
- [x] **Auto-update** : `tauri-plugin-updater` configuré → vérifie `https://git.dracodev.net/api/v1/repos/Projets/ObsiGate/releases/latest`
- [x] **Signature de l'updater Tauri** (gratuite, ≠ signature Windows) : paire de clés `minisign` générée, clé publique dans `plugins.updater.pubkey`, `bundle.createUpdaterArtifacts: true`, secrets Gitea `TAURI_SIGNING_PRIVATE_KEY` / `_PASSWORD` exposés au CI (build non signé en repli si le secret est absent).
- [x] **Manifeste `latest.json`** : généré par `scripts/updater_manifest.py` (et automatiquement par `publish_release.py`), endpoint de l'updater pointé sur `raw/branch/main/desktop/latest.json`. Builds locaux signés via `obsigate-updater.key` ([guide](../DEVELOPMENT_AND_RELEASES.md#2bis-signature-des-mises-à-jour-updater-tauri))
- [ ] **Signature de code Windows** : non retenue (pas de certificat) — alternatives : livrer non signé, SignPath.io (OSS gratuit), Certum Open Source, Azure Trusted Signing, certificat EV
- [x] **Page de release** : README desktop existe (`desktop/README.md`)
## E. Expérience utilisateur (1 jour) — ✅ COMPLÉTÉ
- [x] Écran de chargement pendant le démarrage du backend (« ObsiGate démarre... » avec spinner) — splash inline `#boot-splash` dans `index.html`, retiré quand `app.js` signale le boot ; statut mis à jour depuis Rust
- [x] Gestion des erreurs : backend crash → `showBackendCrashBanner()` appelé par le monitor loop toutes les 5s
- [x] Sauvegarde des préférences desktop : position/taille fenêtre sauvées dans `%APPDATA%/ObsiGate/config.json` au close + restauration au startup
- [x] Première expérience : config par défaut auto-créée au premier lancement (vault `~/voute_obsidian`, dir `~USERPROFILE`)
- [x] Bannière de premier lancement « Choisissez votre vault » (`frontend/js/desktop.js`) — non bloquante ; l'état est persisté côté Rust (`wizard_done` dans `config.json`) pour ne pas réapparaître après un choix ou un clic « Plus tard », même si le `localStorage` de la webview est vidé
- [x] Jumplist vaults récents dans le menu Démarrer (`desktop/src/jumplist.rs`, Windows)
## F. Tests (1 jour) — ✅ COMPLÉTÉ
- [x] 24 tests Rust unitaires : config roundtrip, JSON parsing (empty/partial/corrupted/legacy), `wizard_done`, vault dedup, dir remove, backend URL, paths, branding, jumplist args, edge cases
- [x] Build debug + release vérifié (rustc 1.94.1, tauri-cli 2.11.4)
- [x] CI desktop workflow existant (desktop-build.yml)
- [ ] **6 tests E2E manuels** — protocole détaillé (prérequis, étapes, résultat
attendu) dans [docs/DESKTOP_E2E_CHECKLIST.md](../DESKTOP_E2E_CHECKLIST.md) :
installation → 1er lancement → wizard → ouverture fichier ; tray ; notifications
natives ; association `.md` ; auto-update ; désinstallation propre. À exécuter
et cocher par un humain sur un build release.
- **Prérequis techniques :**
- Rust ≥ 1.75 (stable) — installé via `rustup`
- Tauri CLI ≥ 2.0 — `cargo install tauri-cli`
- Python 3.11 embed — téléchargé depuis python.org
- NSIS (Windows) — pour le générateur d'installateur `.exe`
- AppImageKit (Linux) — pour le packaging portable
## G. Gestion des vaults & dossiers — #159 — ✅ livré (2026-10-02, v2.50.0)
- [x] Retrait vault/dossier racine par menu contextuel (`ContextMenuManager`,
branche `vault`, gate `isTauriEnv()`) → `removeRoot()` dans `desktop.js` :
résolution vault/dossier via `list_vaults`/`list_dirs`, confirmation i18n,
`remove_vault`/`remove_dir` + `restart_backend` + reload — déregistration
seule, zéro suppression disque.
- [x] Section Configuration `cfg-desktop-roots` (+ entrée TOC i18n FR/EN) :
liste des roots injectés, retrait par ligne, ajout vault
(`pickAndAddVault`, existant) et ajout dossier (nouvelle commande Rust
`pick_folder` — sélecteur sans effet de bord, contrairement à
`pick_vault_folder` réservé au wizard). Section masquée hors desktop.
- [x] Jump list rafraîchie après chaque ajout/retrait de vault
(`refresh_jumplist()`).
- [x] i18n FR/EN (7 clés `config.*`/`desktop.*`), garde-fou ACL automatique
(`test_frontend_invokes_are_acl_allowed` : toute commande invoquée par le
frontend doit figurer dans `permissions/commands.toml`).
- [x] Tests : `tests/frontend/desktop-roots.test.mjs` (4 — helpers purs +
gating hors desktop), inscrit au CI ; suites frontend/JSDOM vertes,
`cargo test` 25 passed.