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

9.0 KiB
Raw Blame History

#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) Effort : 8-12 jours | Impact : 🟡 | Framework : Tauri v2 (Rust + Webview) Références : Roadmap · Guide de build & releases

  • 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)

  • Toolchain : tauri-cli 2.11.4 / rustc 1.94.1
  • Projet Tauri v2 dans desktop/ (Cargo.toml, build.rs)
  • tauri.conf.json : fenêtre 1200×800 (min 800×600), titre "ObsiGate"
  • Build : cibles .msi/.nsis (Windows), .deb/.AppImage (Linux)
  • 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)

  • Bundle Python : desktop/python-embed/ (python3.11-embed + site-packages, validé par validate-structure.sh)
  • Lancement backend : spawn_backend() Rust lance python-embed -m uvicorn backend.main:app (équivalent sidecar), logs dans %APPDATA%/ObsiGate/logs/backend.log
  • main.rs : spawn processus fils, health check (GET /api/health, 30 essais × 2s), kill propre (SIGTERM→wait→kill)
  • Menu tray (voir section C ✅)
  • 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É

  • Sélecteur de dossier : pick_vault_folder via tauri_plugin_dialog → ajoute le vault dans config.json
  • Thème système : get_system_theme lit le thème OS → appliqué automatiquement
  • Notifications natives : tauri-plugin-notification intégré — remplace le service worker Push API
  • Associations de fichiers : .md → « Ouvrir avec ObsiGate » dans tauri.conf.json
  • Menu natif : Fichier (Nouvelle fenêtre, Fermer, Quitter) / Édition (Annuler, Rétablir, Couper, Copier, Coller, Tout sélectionner) / Aide (À propos)
  • Raccourcis clavier : Ctrl+N, Ctrl+W, Ctrl+Q, Ctrl+Z, Ctrl+Shift+Z, Ctrl+X/C/V/A
  • Tray icon : menu contextuel (Ouvrir, À propos, Quitter) + toggle fenêtre au clic gauche
  • Single instance : tauri-plugin-single-instance — deuxième lancement focus la fenêtre existante
  • Auto-update : tauri-plugin-updater configuré → vérifie les releases Gitea
  • Pas de terminal visible : #![windows_subsystem = "windows"] + CREATE_NO_WINDOW sur le processus Python
  • Persistance fenêtre : position/taille sauvegardée dans config.json

D. Build et distribution (2 jours) — ✅ COMPLÉTÉ

  • 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
  • Build Windows local : cargo build --release vérifié (rustc 1.94.1) — cargo tauri build --bundles msi prêt
  • Build Linux local : workflow CI couvre .deb, .rpm, .AppImage
  • Auto-update : tauri-plugin-updater configuré → vérifie https://git.dracodev.net/api/v1/repos/Projets/ObsiGate/releases/latest
  • 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).
  • 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)
  • 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
  • Page de release : README desktop existe (desktop/README.md)

E. Expérience utilisateur (1 jour) — ✅ COMPLÉTÉ

  • É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
  • Gestion des erreurs : backend crash → showBackendCrashBanner() appelé par le monitor loop toutes les 5s
  • Sauvegarde des préférences desktop : position/taille fenêtre sauvées dans %APPDATA%/ObsiGate/config.json au close + restauration au startup
  • Première expérience : config par défaut auto-créée au premier lancement (vault ~/voute_obsidian, dir ~USERPROFILE)
  • 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é
  • Jumplist vaults récents dans le menu Démarrer (desktop/src/jumplist.rs, Windows)

F. Tests (1 jour) — ✅ COMPLÉTÉ

  • 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

  • Build debug + release vérifié (rustc 1.94.1, tauri-cli 2.11.4)

  • 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 : 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)

  • 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.
  • 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.
  • Jump list rafraîchie après chaque ajout/retrait de vault (refresh_jumplist()).
  • 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).
  • Tests : tests/frontend/desktop-roots.test.mjs (4 — helpers purs + gating hors desktop), inscrit au CI ; suites frontend/JSDOM vertes, cargo test 25 passed.