- Premier lancement : %USERPROFILE%\ObsiGate créé et monté comme vault de
démarrage « ObsiGate » (remplace voute_obsidian), vault_path dessus,
racine home nommée d'après son dernier segment (fin du « bruno » codé en
dur), champs de fenêtre préservés.
- Document « Prise en main.md » embarqué dans le binaire
(include_str!) et écrit dans ce répertoire si absent — jamais écrasé.
- Section « 🖥️ Vaults & dossiers (Desktop) » refondue : markup à classes
(zéro style inline), bloc CSS desktop-roots-* sur variables (motif
webauthn-key-item), boutons .config-btn-sm primaire/secondaire,
cibles tactiles 44px en mobile.
- Tests : test_default_first_run_config, test_welcome_doc_embedded
(cargo test 28 passed), suites frontend vertes, E2E 123/123.
10 KiB
#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 lancepython-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é (commitc066b2c, 3 tests Rust)
C. Fonctionnalités desktop natives (2-3 jours) — ✅ COMPLÉTÉ
- Sélecteur de dossier :
pick_vault_folderviatauri_plugin_dialog→ ajoute le vault dans config.json - Thème système :
get_system_themelit le thème OS → appliqué automatiquement - Notifications natives :
tauri-plugin-notificationintégré — remplace le service worker Push API - Associations de fichiers :
.md→ « Ouvrir avec ObsiGate » danstauri.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-updaterconfiguré → vérifie les releases Gitea - Pas de terminal visible :
#![windows_subsystem = "windows"]+CREATE_NO_WINDOWsur 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 surmain(sidesktop/modifié), upload des artefacts.msi/.AppImage/.deben release - Build Windows local :
cargo build --releasevérifié (rustc 1.94.1) —cargo tauri build --bundles msiprêt - Build Linux local : workflow CI couvre
.deb,.rpm,.AppImage - Auto-update :
tauri-plugin-updaterconfiguré → vérifiehttps://git.dracodev.net/api/v1/repos/Projets/ObsiGate/releases/latest - Signature de l'updater Tauri (gratuite, ≠ signature Windows) : paire de clés
minisigngénérée, clé publique dansplugins.updater.pubkey,bundle.createUpdaterArtifacts: true, secrets GiteaTAURI_SIGNING_PRIVATE_KEY/_PASSWORDexposés au CI (build non signé en repli si le secret est absent). - Manifeste
latest.json: généré parscripts/updater_manifest.py(et automatiquement parpublish_release.py), endpoint de l'updater pointé surraw/branch/main/desktop/latest.json. Builds locaux signés viaobsigate-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-splashdansindex.html, retiré quandapp.jssignale 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.jsonau 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_donedansconfig.json) pour ne pas réapparaître après un choix ou un clic « Plus tard », même si lelocalStoragede 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
- Rust ≥ 1.75 (stable) — installé via
G. Gestion des vaults & dossiers — #159 — ✅ livré (2026-10-02, v2.50.0)
- Retrait vault/dossier racine par menu contextuel (
ContextMenuManager, branchevault, gateisTauriEnv()) →removeRoot()dansdesktop.js: résolution vault/dossier vialist_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 Rustpick_folder— sélecteur sans effet de bord, contrairement àpick_vault_folderré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 danspermissions/commands.toml). - Tests :
tests/frontend/desktop-roots.test.mjs(4 — helpers purs + gating hors desktop), inscrit au CI ; suites frontend/JSDOM vertes,cargo test25 passed.
H. Premier lancement & section Configuration harmonisée — #160 — ✅ livré (2026-10-02, v2.51.0)
default_first_run_config(home)(pure, testée) :<home>/ObsiGatemonté comme vault « ObsiGate » ET commevault_path, racine home nommée d'après son dernier segment — remplacevoute_obsidian+ le « bruno » codé en dur ; les champs fenêtre de la config existante sont préservés.Prise en main.md: contenu embarqué (include_str!("prise_en_main.md")), écrit au premier lancement si absent (jamais d'écrasement).- Section
cfg-desktop-rootsrefondue : markup à classes (zéro style inline), bloc CSS#160sur variables (desktop-roots-*, motifwebauthn-key-item), boutons.config-btn-sm(primaire/secondaire), override mobile 44px dans le bloc#config-modal. - Tests :
test_default_first_run_config,test_welcome_doc_embedded—cargo test28 passed ; suites frontend vertes (validate-imports, unit, config-mobile, desktop-roots, settings-order) + E2E locale.