--- phase: 18-desktop-client-fertigstellen plan: 04 subsystem: infra tags: [tauri, rust, desktop-client, opener-plugin, autostart] # Dependency graph requires: - phase: 18-desktop-client-fertigstellen (Plan 01) provides: "GET /desktop/latest (@Public), DesktopLatestResponse-Form, Basislinie 1.1.0" - phase: 18-desktop-client-fertigstellen (Plan 03) provides: "Route /settings/general/desktop, GET /desktop/latest ueber /api-proxy/* im Web-Container" provides: - "Rust-Kommandos check_server/save_server_url fuer die Erststart-Seite (kein Modul-Import mehr)" - "Versionspruefung gegen /api-proxy/desktop/latest mit Benachrichtigung + Tray-Update-Eintrag" - "Tray-Menue: Öffnen · Update herunterladen · Autostart-Haken · Beenden, echte Umlaute" - "Echtes App-Icon (Tessera-Zeichen) in allen Bundle-Groessen" - "Lokal gebautes AppImage (Tessera-1.1.0.AppImage) als D-16-Beweis" affects: [18-05-windows-cross-bau-pipeline-beweis, 18-06-freigabe-release-anhang] actuals: tokens: 4547 tasks: 2 commits: 2 plan_head_before: 82312ef691c86dedd08f3c71225d3b8be63630df tech-stack: added: - "tauri-plugin-opener 2.5.5 (offizielles Tauri-Plugin, Legitimitaet in 18-RESEARCH.md geprueft: OK)" patterns: - "api_url(server, path) als einzige Stelle, die den Next.js-Rewrite-Praefix /api-proxy kennt — alle Rust-seitigen API-Aufrufe (check_server, Versionspruefung) laufen ausschliesslich darueber" - "Erststart-Seite spricht nur noch ueber window.__TAURI__.core.invoke() mit Rust-Kommandos statt ueber einen ES-Modul-Import eines Tauri-Plugins — vermeidet den 'Failed to resolve module specifier'-Fehler im gebauten Client (kein Bundler/keine Importmap vorhanden)" key-files: created: [] modified: - apps/desktop/src-tauri/src/lib.rs - apps/desktop/src-tauri/Cargo.toml - apps/desktop/src-tauri/Cargo.lock - apps/desktop/src-tauri/capabilities/default.json - apps/desktop/src-tauri/tauri.conf.json - apps/desktop/src/setup.html - apps/desktop/src-tauri/icons/icon.png - apps/desktop/src-tauri/icons/icon.ico - apps/desktop/src-tauri/icons/128x128.png - apps/desktop/src-tauri/icons/128x128@2x.png - apps/desktop/src-tauri/icons/32x32.png key-decisions: - "cargo add tauri-plugin-opener@2 ausgefuehrt statt Cargo.toml/Cargo.lock von Hand zu pflegen — Cargo.lock bleibt damit fuer den echten Dependency-Graphen konsistent (Cargo hat zusaetzlich open, is-docker, is-wsl als transitive Abhaengigkeiten des Plugins aufgeloest)." - "Autostart-Umschaltung setzt den Haken im Fehlerfall bewusst auf den vor dem Klick gemessenen Ist-Zustand zurueck (set_checked(currently_on) statt eines optimistischen Toggles), damit der Haken nie eine falsche Systemwahrheit anzeigt, wenn enable()/disable() fehlschlaegt." - "Versionspruefung liest die Zieladresse jetzt ausschliesslich ueber die neue api_url()-Hilfsfunktion, damit /health/version (im Kommando check_server) und /desktop/latest (im Setup-Block) denselben Rewrite-Praefix garantiert konsistent verwenden." patterns-established: [] requirements-completed: [DESK-01, DESK-02, DESK-05] coverage: - id: D1 description: "Versionspruefung gegen /api-proxy/desktop/latest mit Benachrichtigung 'Neue Version X.Y.Z verfuegbar' und freigeschaltetem, umbenanntem Tray-Eintrag 'Update herunterladen', der die Einstellungsseite im Systembrowser oeffnet" requirement: "DESK-05" verification: - kind: other ref: "grep-Batterie (fn api_url, /desktop/latest, settings/general/desktop, tauri_plugin_opener::init()) + cargo check/cargo clippy gruen" status: pass human_judgment: true rationale: "Das tatsaechliche Ausloesen der Benachrichtigung und das Umschalten des Tray-Eintrags laesst sich nur gegen einen laufenden Server mit abweichender Version und einer grafischen Sitzung beobachten — beides stand in dieser Ausfuehrungsumgebung nicht zur Verfuegung (kopflos, kein Display). Die Bedienprobe macht der Nutzer laut Plan-Verifikation Punkt 4 in 18-06." - id: D2 description: "Erststart-Seite prueft die Adresse ueber das Rust-Kommando check_server (kein Modul-Import mehr), speichert sie ueber save_server_url und fuehrt zur Tessera-Anmeldung; Sie-Form, Tessera-Farben/-Zeichen, kein vorbelegter Wert" requirement: "DESK-02" verification: - kind: other ref: "grep-Batterie (SETUP-OK: __TAURI__.core, invoke('check_server'/'save_server_url'), kein import, kein unpkg.com, keine vorbelegte Adresse, Label vorhanden)" status: pass human_judgment: true rationale: "Der volle Ablauf (Adresse eingeben, echten Server erreichen, zur Anmeldeseite navigieren) braucht ein gestartetes AppImage mit grafischer Sitzung und einen laufenden Tessera-Server — nicht Teil dieses Plans (kein Pflichtschritt laut Action-Abschnitt), Bedienprobe folgt in 18-06." - id: D3 description: "Tray-Menue in der Reihenfolge Öffnen · Update herunterladen · Autostart-Haken (Windows: 'Mit Windows starten', sonst 'Beim Anmelden starten') · Beenden, mit echten Umlauten; Autostart-Haken spiegelt beim Start den Systemzustand" requirement: "DESK-05" verification: - kind: other ref: "grep-Batterie (\"Öffnen\", \"Mit Windows starten\", CheckMenuItemBuilder::with_id(\"autostart\") je genau 1 Treffer) + cargo check/cargo clippy gruen" status: pass human_judgment: true rationale: "Die sichtbare Tray-Darstellung (Reihenfolge, Umlaute im echten Rendering, Haken-Zustand) laesst sich nur in einer grafischen Sitzung mit laufender App pruefen, nicht headless. Bedienprobe folgt in 18-06." - id: D4 description: "Client traegt das Tessera-Zeichen als App-/Fenster-Icon in allen Bundle-Groessen (512 PNG, 128/128@2x/32 PNG, ICO 16-256); cargo check, cargo clippy und ein lokaler AppImage-Bau laufen durch" requirement: "DESK-05" verification: - kind: other ref: "cargo check/cargo clippy (Finished, 0 Warnungen) + magick identify (icon.png 512x512, icon.ico 6 Groessen) + lokaler Bau pnpm --filter @tessera/desktop exec tauri build --bundles appimage + desktop-collect.sh --require linux (Tessera-1.1.0.AppImage im Manifest)" status: pass human_judgment: false duration: 9min completed: 2026-09-16 status: complete --- # Phase 18 Plan 04: Client-Fertigstellung — Update-Hinweis, Tray-Autostart, Erststart-Seite, echtes Icon Summary **`lib.rs` bekommt zwei neue Rust-Kommandos (`check_server`/`save_server_url`) fuer eine modul-import-freie Erststart-Seite, die Versionspruefung laeuft jetzt ueber `/api-proxy/desktop/latest` mit Benachrichtigung und einem sich selbst umbenennenden Tray-Eintrag, das Tray traegt echte Umlaute und einen Autostart-Haken, und der Client hat erstmals ein echtes Tessera-Icon statt der flachen gelben Platzhalter-Quadrate — ein frischer lokaler AppImage-Bau (103 MB) beweist, dass alles zusammen kompiliert und buendelt.** ## Performance - **Duration:** 9 min - **Started:** 2026-09-16T14:32:35Z - **Completed:** 2026-09-16T14:41:21Z - **Tasks:** 2 - **Files modified:** 15 (davon 4 durch `git rm -r` entfernt) ## Accomplishments - `lib.rs`: `tauri-plugin-opener` eingebunden, neue Hilfsfunktion `api_url()` als einzige Stelle mit dem `/api-proxy`-Rewrite-Praefix, zwei neue Kommandos `check_server` (prueft `/api-proxy/health/version` mit 8s-Zeitlimit, deutsche Sie-Form-Fehlermeldungen) und `save_server_url` (normalisiert, speichert im Store, navigiert das Fenster); beide ueber `invoke_handler` registriert. - Versionspruefung beim Start laeuft jetzt gegen `/api-proxy/desktop/latest` statt `/health/version`; bei Abweichung erscheint die Benachrichtigung "Tessera-Update" / "Neue Version X.Y.Z verfuegbar – Download ueber das Symbol im Infobereich." und der Tray-Eintrag "Update herunterladen" wird umbenannt ("Version X.Y.Z herunterladen") und freigeschaltet. - Tray-Menue neu geordnet: Öffnen · Update herunterladen · — · Autostart-Haken (Windows: "Mit Windows starten", sonst "Beim Anmelden starten") · — · Beenden — mit echten Umlauten (vorher "Oeffnen"/"Beenden"). Der Update-Eintrag oeffnet `{server}/settings/general/desktop` per `tauri-plugin-opener` im Systembrowser; der Autostart-Haken spiegelt beim Start `autolaunch().is_enabled()` und schaltet bei Klick um, faellt bei einem Fehlschlag von `enable()`/`disable()` auf den tatsaechlichen Zustand zurueck. - `setup.html` spricht nur noch ueber `window.__TAURI__.core.invoke` (kein `