- 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.
126 lines
10 KiB
Markdown
126 lines
10 KiB
Markdown
# #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.
|
||
|
||
## H. Premier lancement & section Configuration harmonisée — #160 — ✅ livré (2026-10-02, v2.51.0)
|
||
|
||
- [x] `default_first_run_config(home)` (pure, testée) : `<home>/ObsiGate`
|
||
monté comme vault « ObsiGate » ET comme `vault_path`, racine home nommée
|
||
d'après son dernier segment — remplace `voute_obsidian` + le « bruno »
|
||
codé en dur ; les champs fenêtre de la config existante sont préservés.
|
||
- [x] `Prise en main.md` : contenu embarqué (`include_str!("prise_en_main.md")`),
|
||
écrit au premier lancement **si absent** (jamais d'écrasement).
|
||
- [x] Section `cfg-desktop-roots` refondue : markup à classes (zéro style
|
||
inline), bloc CSS `#160` sur variables (`desktop-roots-*`, motif
|
||
`webauthn-key-item`), boutons `.config-btn-sm` (primaire/secondaire),
|
||
override mobile 44px dans le bloc `#config-modal`.
|
||
- [x] Tests : `test_default_first_run_config`, `test_welcome_doc_embedded`
|
||
— `cargo test` 28 passed ; suites frontend vertes (validate-imports,
|
||
unit, config-mobile, desktop-roots, settings-order) + E2E locale.
|