Quick 260917-kgc (Plan/Recherche/Bericht/Verifikation) und Schnellfixa6d1a64in der Quick-Task-Tabelle; Nachweise in allen sechs Berichten nachgetragen (Playwright lokal, CI-Laeufe 382-384, Windows-Test-VM: In-App-Update7479cb4->a6d1a64). Ueberholte .continue-here-Dateien entfernt, Desktop-Client-Todo geschlossen. Dieser Push aendert nichts unter apps/desktop -- er ist zugleich der Beweisfall 2 des CI-Desktop-Skips (Pakete aus dem Zwischenspeicher). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016g2npLxzH5gZpg8s2S6vKh
18 KiB
phase: quick-260917-jn2 plan: 01 subsystem: desktop-client tags: [tauri, rust, tray, nextjs, i18n, desktop]
Dependency graph
requires:
- phase: 18-desktop-client-fertigstellen provides: Tauri-Desktop-Client mit Tray-Menue (open/update/autostart/quit), Setup-Seite (Erststart), Web-Einstellungsseite Desktop-App
- phase: quick-260917-eta provides: Run-Handler-Muster (code: None vs. code: Some), unminimize() vor show() in "open" und Linksklick — unangetastet uebernommen provides:
- "Tray zeigt den verbundenen Server an drei Stellen: Tooltip 'Tessera – {host}', gesperrte erste Menuezeile 'Verbunden mit {host}', Web-Einstellungsseite 'Verbunden mit: {origin}'"
- "Neuer Tray-Eintrag 'Server-Adresse ändern…' navigiert zur gebuendelten Setup-Seite im Aenderungsmodus (vorbelegtes Feld, 'Aktuell verbunden mit: …', Knopf 'Abbrechen')"
- "Nach einem Serverwechsel aktualisieren sich Tooltip, Menuezeile und Update-Ziel ohne Neustart; die Versionspruefung laeuft neu gegen den neuen Server"
- "Vier reine, getestete Helfer server_host/tray_labels/setup_page_url/parse_server_url plus stored_server_url als einzige Store-Lesestelle" affects: [desktop-client, tray-verhalten, updater]
Actuals (#2632)
actuals:
tokens: 8317
tasks: 3
commits: 3
plan_head_before: b023d6f726
Tech tracking
tech-stack: added: [] patterns: - "app.manage(TrayItems { connected, update }) haelt die Menue-Handles im State — einzige Stelle, die Tooltip/Menuezeile (apply_server) und den Update-Eintrag (spawn_version_check) ohne Neustart setzt" - "stored_server_url(app) als einzige Store-Lesestelle (Start, get_server_url, open_server, Tray-Klick 'update') statt mehrfacher Store-Zugriffe" - "App-Commands ohne Capability-Eintrag: lokale Herkunft (tauri://localhost / http://tauri.localhost) erlaubt sie implizit, Remote-Ursprung verweigert Tauri sie mangels remote-Block (T-JN2-01)"
key-files: created: [] modified: - apps/desktop/src-tauri/src/lib.rs - apps/desktop/src/setup.html - apps/web/src/components/settings/desktop-app-settings.tsx - apps/web/src/components/settings/desktop-app-settings.test.tsx - apps/web/src/messages/de.json - apps/web/src/messages/en.json - docs/anleitung-anwender.md - CHANGELOG.md
key-decisions:
- "Pruefpunkt 5 des Task-1-Gates (grep nach einzeiligem generate_handler!\[...\]) liess sich nicht woertlich erfuellen: rustfmt bricht die vier Handler-Namen (109 Zeichen) legitim auf mehrere Zeilen um. cargo fmt --check MUSS gruen bleiben (Bestand ist rustfmt-konform) — darum durch einen semantisch gleichwertigen mehrzeiligen Nachweis ersetzt (Rule 3, Detail unten unter Abweichungen)."
- "Startnavigation zur gespeicherten Adresse bleibt VOR dem Tray-Aufbau (wie im Bestand); apply_server()/spawn_version_check() laufen NACH dem Tray-Aufbau, weil sie app.state::() brauchen, das erst beim Tray-Aufbau gemanagt wird."
- "spawn_version_check() setzt den Update-Eintrag zuerst synchron auf UPDATE_ITEM_DEFAULT zurueck, bevor der async-Block startet — verhindert, dass nach einem Wechsel ein veralteter Update-Hinweis des alten Servers sichtbar bleibt."
patterns-established:
- "Tray-Menue-Struktur: connected (gesperrt) · — · open · change_server · update · — · autostart · — · quit; TrayIconBuilder::with_id("main") + app.tray_by_id("main") als Paar fuer spaetere Auffrischung"
requirements-completed: [QUICK-260917-JN2]
coverage:
- id: D1
description: "Rust: vier reine Helfer (server_host, tray_labels, setup_page_url, parse_server_url) plus stored_server_url, TrayItems-State, apply_server, spawn_version_check, Commands get_server_url/open_server; capabilities/default.json unveraendert"
requirement: "QUICK-260917-JN2"
verification:
- kind: unit ref: "apps/desktop/src-tauri/src/lib.rs mod tests — 18 Tests (13 neu + 5 Bestand), cargo test --lib" status: pass
- kind: other ref: "cargo fmt --check, cargo check, cargo clippy — je 0 Warnungen/Fehler" status: pass human_judgment: false
- id: D2
description: "setup.html im Aenderungsmodus: get_server_url beim Laden, Feld vorbelegt, 'Aktuell verbunden mit: …', Knopf 'Abbrechen' → open_server; ohne gespeicherte Adresse Erststart-Verhalten unveraendert"
requirement: "QUICK-260917-JN2"
verification:
- kind: other ref: "Grep-Gate Task 1 (invoke('get_server_url'), invoke('open_server'), #cancel-btn, #current-server, brand-mark-SVG unveraendert)" status: pass human_judgment: true rationale: "Reale Bedienprobe (Tooltip, Menue, Klick auf 'Server-Adresse ändern…', vorbelegte Seite, 'Abbrechen', Wechsel aktualisiert Tooltip/Menue/Update-Ziel ohne Neustart) erfordert die Windows-Test-VM mit dem CI-Paket — macht laut Plan der Orchestrator im Anschluss, nicht dieser Ausfuehrungslauf."
- id: D3
description: "Web: DesktopAppSettings zeigt im Desktop-Client 'Verbunden mit: {origin}' plus Aenderungshinweis; im Browser fehlt der Block; beide Sprachen"
requirement: "QUICK-260917-JN2"
verification:
- kind: unit ref: "apps/web/src/components/settings/desktop-app-settings.test.tsx — Test 4 (Cookie) und Test 5 (ohne Cookie), 5/5 Tests gruen" status: pass
- kind: unit ref: "pnpm --filter @tessera/web exec vitest run — 431/431 gruen; pnpm --filter @tessera/web type-check — 0 Fehler" status: pass human_judgment: false
- id: D4
description: "Handbuch: neuer Unterabschnitt 'Server-Adresse ändern', erweiterte Tray-Liste, Erststart-Verweis; CHANGELOG zwei Desktop-App-Stichpunkte unter Unveröffentlicht/Neu"
requirement: "QUICK-260917-JN2"
verification:
- kind: other ref: "Grep-Gate Task 3 (Ueberschrift, Tray-Liste, 'Aktuell verbunden mit', CHANGELOG-Zeilenzahl) + git diff CHANGELOG.md gegengeprueft (nur die 2 Zeilen neu)" status: pass
- kind: unit ref: "apps/web/src/lib/changelog.test.ts — 10/10 gruen" status: pass human_judgment: false
duration: ~25min (nicht exakt gestoppt) completed: 2026-09-17 status: complete
Quick Task 260917-jn2: Desktop-Client — aktuelle Server-Adresse sehen und ändern Summary
Tray zeigt an drei Stellen (Tooltip, gesperrte Menuezeile, Web-Einstellungsseite), mit welchem Tessera-Server der Desktop-Client verbunden ist, und ein neuer Tray-Eintrag „Server-Adresse ändern…" fuehrt zur Setup-Seite im Aenderungsmodus — ohne config.json zu loeschen und ohne Neustart der App.
Performance
- Duration: ~25 min (RED/GREEN-Zyklus fuer Rust-Helfer und Web-Block, drei Verifikations-Gates)
- Completed: 2026-09-17T14:53:26+02:00
- Tasks: 3/3
- Files modified: 8
Accomplishments
- Rust (
lib.rs): vier reine, getestete Helferserver_host,tray_labels,setup_page_url,parse_server_urlsowiestored_server_urlals einzige Store-Lesestelle; neuer StateTrayItems { connected, update };apply_server()setzt Tooltip + Menuezeile aus derselben Quelle;spawn_version_check()(aussetupherausgezogen) laeuft nach jedem Wechsel neu und setzt den Update-Eintrag zuerst zurueck. Zwei neue Commandsget_server_url/open_server, beide nur vom lokalen Ursprung aufrufbar (kein Capability-Eintrag noetig,capabilities/default.jsonunveraendert). Tray jetztTrayIconBuilder::with_id("main")mit Zeilen „Verbunden mit …" (gesperrt), „Öffnen", „Server-Adresse ändern…", „Update herunterladen", Autostart, „Beenden". setup.html: erkennt beim Laden perget_server_urlden Aenderungsmodus (Feld vorbelegt, „Aktuell verbunden mit: …", Knopf „Abbrechen" →open_server); ohne gespeicherte Adresse bleibt der Erststart unveraendert. SVG-Bildmarke unangetastet.- Web:
DesktopAppSettingszeigt im Desktop-Client (useIsDesktopClient()) einen Block „Verbunden mit: {origin}" plus Aenderungshinweis; im Browser fehlt er. Zwei neue i18n-Schluessel in beiden Sprachen. - Doku: neuer Handbuch-Unterabschnitt „Server-Adresse ändern", erweiterte Tray-Liste, zwei CHANGELOG-Stichpunkte unter Unveröffentlicht/Neu.
Task Commits
Each task was committed atomically:
- Task 1: Rust + setup.html — Verbunden-Zeile/Tooltip, „Server-Adresse ändern…", Commands, Tray-Auffrischung, Tests -
29c132e(feat) - Task 2: Web — Block „Verbunden mit: {origin}" nur im Client, i18n, Test -
4c79874(feat) - Task 3: Handbuch und CHANGELOG -
4d48543(docs)
Hinweis: kein separater test(...)-Commit trotz tdd="true" — die Orchestrator-Vorgabe fuer diesen Quick-Task lautet ausdruecklich drei Commits (einer je Task, feat(desktop)/feat(web)/docs). RED (Tests zuerst, Fehlschlag beobachtet) und GREEN (Implementierung, Tests gruen) liefen innerhalb jedes Tasks, aber nur ein Commit je Task wurde erzeugt — siehe „TDD Gate Compliance" unten.
Files Created/Modified
apps/desktop/src-tauri/src/lib.rs— vier reine Helfer +mod tests(18 Tests),TrayItems,apply_server,spawn_version_check, Commandsget_server_url/open_server, Tray-Aufbau mitconnected/change_serverapps/desktop/src/setup.html— Aenderungsmodus (#current-server,#cancel-btn,#subtitle,init(),enterChangeMode())apps/web/src/components/settings/desktop-app-settings.tsx— Blockdata-testid="desktop-connected"nur im Desktop-Clientapps/web/src/components/settings/desktop-app-settings.test.tsx— Test 4 (Cookie) und Test 5 (ohne Cookie)apps/web/src/messages/de.json,en.json—settings.desktop.connectedTo,settings.desktop.changeHintdocs/anleitung-anwender.md— Unterabschnitt „Server-Adresse ändern", erweiterte Tray-Liste, Erststart-VerweisCHANGELOG.md— zweiDesktop-App:-Stichpunkte unter Unveröffentlicht/Neu
Endgueltige Namen fuer den Folgeplan (Updater, tauri-plugin-updater)
Der naechste Task baut auf dieser Tray-Struktur auf — hier die endgueltigen Signaturen:
struct TrayItems { connected: tauri::menu::MenuItem<tauri::Wry>, update: tauri::menu::MenuItem<tauri::Wry> }, gemanagt viaapp.manage(TrayItems { connected: connected.clone(), update: update.clone() })direkt nach dem Menue-Bau, vorTrayIconBuilder::with_id("main")...build(app)?.fn apply_server(app: &AppHandle, url: Option<&str>)— einzige Stelle, dieapp.tray_by_id("main")(Tooltip) undapp.state::<TrayItems>().connected(Menuezeile) setzt.fn spawn_version_check(app: AppHandle, server_url: String)— nimmtAppHandle(nicht&AppHandle) und den Server-String per Wert entgegen; holtupdate_itemausapp.state::<TrayItems>(), setzt ihn synchron aufUPDATE_ITEM_DEFAULT/enabled(false)zurueck, danntauri::async_runtime::spawn(...)wie im Bestand. Der Updater-Task kann hier andocken (z. B. den Update-Klick auftauri-plugin-updaterstattopener::open_urlumstellen) —update_itemist bereits das MenuItem-Handle,UPDATE_ITEM_DEFAULT(&str-Konstante) der Ruecksetz-Text.fn stored_server_url(app: &AppHandle) -> Option<String>— einzige Store-Lesestelle; der Updater-Task sollte KEINE eigene Store-Lesung einfuehren, sondern diese Funktion wiederverwenden.- Tray-Menue-Reihenfolge:
connected(gesperrt) · Trenner ·open·change_server·update· Trenner ·autostart· Trenner ·quit. Ein neuer Updater-Eintrag würde vermutlich zwischenupdateund dem folgenden Trenner eingefuegt, oderupdateselbst würde umgewidmet — Entscheidung liegt beim Folgeplan.
Decisions Made
- Pruefpunkt 5 des Task-1-Gates (Rule 3, Blocking): Die Plan-Verifikation verlangt einen woertlichen Ein-Zeilen-Treffer
generate_handler!\[check_server, save_server_url, get_server_url, open_server\]. Die vollstaendige Zeile ist 109 Zeichen lang, rustfmt (max_width 100, Standard) bricht sie beim Pflicht-Schrittcargo fmtlegitim auf fuenf Zeilen um.cargo fmt --checkMUSS gruen sein (im Bestand rustfmt-konform, keine Sonderregel wie bei 260917-eta) — das genannte Format war also nicht gleichzeitig mit einer bestandenen Formatpruefung erreichbar. Ich habe den betroffenen Pruefpunkt durch einen semantisch gleichwertigen mehrzeiligen Nachweis ersetzt (perl -0777Regex ueber den Macro-Block) und alle anderen 15 Pruefpunkte des Gates woertlich wie im Plan laufen lassen — alle gruen. Kein Code geaendert, nur die Pruefmethode fuer diesen einen Punkt. - Reihenfolge im
setup-Closure: Startnavigation zur gespeicherten Adresse laeuft weiterhin VOR dem Tray-Aufbau (wie im Bestand),apply_server/spawn_version_checklaufen NACH dem Tray-Aufbau, weil beideapp.state::<TrayItems>()brauchen, das erst beim Tray-Aufbau gemanagt wird (app.manage(...)direkt vorTrayIconBuilder::with_id("main")).
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking, Pruefmethode] Ein-Zeilen-Grep im Task-1-Gate gegen rustfmt-Umbruch ersetzt
- Found during: Task 1, Verifikationslauf
- Issue:
grep -q 'generate_handler!\[check_server, save_server_url, get_server_url, open_server\]'verlangt eine 109-Zeichen-Zeile;cargo fmt(Pflichtschritt im selben Gate) bricht sie legitim um, weil sie uebermax_width = 100liegt. Woertlich erfuellbar waren beide Anforderungen nicht gleichzeitig. - Fix: Den betroffenen Pruefpunkt durch eine mehrzeilige, semantisch gleichwertige Pruefung ersetzt (
perl -0777Regex, das denselbengenerate_handler!-Block mit denselben vier Namen in beliebiger Zeilenaufteilung matcht). Der generierte Code selbst blieb unveraendert —cargo fmt --checkist gruen, die vier Handler sind registriert. - Files modified: keine (nur die Pruefmethode fuer diesen einen Punkt, kein Code)
- Verification:
cargo fmt --check && cargo check && cargo clippy && cargo test --libgruen (18 Tests); alle 15 uebrigen Pruefpunkte des Gates woertlich wie im Plan, gruen;perl-Ersatzpruefung fuer Punkt 5 gruen. - Committed in:
29c132e(Task-1-Commit)
Total deviations: 1 auto-fixed (1 blocking/Pruefmethode)
Impact on plan: Kein Codeverhalten geaendert, nur wie ein einzelner Gate-Punkt gegen den (korrekten) rustfmt-Output geprueft wurde. Keine Abweichung von den must_haves.truths oder vom Threat-Register.
TDD Gate Compliance
Alle drei Tasks liefen als RED → GREEN innerhalb eines einzigen Commits je Task (Orchestrator-Vorgabe: genau drei Commits, feat(desktop)/feat(web)/docs):
- Task 1 (Rust, tdd="true"): RED — 13 neue Tests in
mod testsergaenzt,cargo test --libschlug mit 13 Compile-Fehlern fehl (fehlende Funktionenserver_host,tray_labels,setup_page_url,parse_server_url), exakt auf die neuen Tests zurueckfuehrbar. GREEN — Helfer implementiert,cargo test --liblief mit 18/18 gruenen Tests durch. Ein Commit (29c132e). - Task 2 (Web, tdd="true"): RED — Test 4 ("Verbunden mit: http://localhost:3000") und Test 5 ergaenzt; Testlauf zeigte Test 4 fehlschlagend auf der Zielbehauptung (Block nicht gefunden), Tests 1-3 und 5 bereits gruen. GREEN — Block implementiert, i18n-Schluessel ergaenzt; 5/5 Tests gruen, danach 431/431 Web-Tests + type-check gruen. Ein Commit (
4c79874). - Task 3 (kein
tdd="true"): Standard-Task, kein RED/GREEN-Zyklus vorgesehen.
Kein separater test(...)-Commit vor dem jeweiligen feat(...)-Commit — bewusst, siehe Hinweis unter „Task Commits" oben; die formale RED/GREEN-Gate-Pruefung via gsd_run check tdd-red-evidence gilt fuer Plaene mit type: tdd in der Frontmatter, dieser Plan hat type: execute mit tdd="true" je Task.
Issues Encountered
None ueber die oben dokumentierte Abweichung hinaus.
Nachweis durch Orchestrator (offen)
Windows-VM-Bedienprobe mit dem CI-Paket steht noch aus:
- Tooltip beim Ueberfahren des Tray-Symbols zeigt
Tessera – {host}(bzw.Tessera – nicht verbundenohne Adresse). - Menuezeile: erste Zeile
Verbunden mit {host}(gesperrt, nicht anklickbar). - Adresse ändern: Rechtsklick → „Server-Adresse ändern…" navigiert zur Setup-Seite; Feld ist mit der aktuellen Adresse vorbelegt, Zeile „Aktuell verbunden mit: …" sichtbar, Knopf „Abbrechen" vorhanden.
- Abbrechen: fuehrt ohne Aenderung zurueck zur laufenden Verbindung (App navigiert zur bisherigen Adresse).
- Wechsel: neue Adresse eintragen → „Verbinden" → Tooltip, Menuezeile und Update-Ziel zeigen sofort die neue Adresse, ohne Neustart der App.
- Update-Link nach Wechsel: die Versionspruefung laeuft neu gegen den neuen Server; ein veralteter Update-Hinweis des alten Servers darf nicht mehr sichtbar sein (Update-Eintrag ist beim Wechsel zunaechst wieder gesperrt).
Alle automatisierten Verifikationen (Rust: fmt/check/clippy/test, Web: vitest/type-check, Doku-Gates) sind bereits gruen — siehe „Task Commits" und „Coverage" oben.
Next Phase Readiness
- Tray-Struktur (
TrayItems,apply_server,spawn_version_check,stored_server_url) ist bereit fuer den Updater-Task (tauri-plugin-updater) — Signaturen siehe Abschnitt oben. - Windows-VM-Bedienprobe (Tooltip, Menue, Wechsel, Abbrechen, Update-Link) folgt durch den Orchestrator mit dem CI-Paket.
Quick Task: 260917-jn2 Completed: 2026-09-17
Nachweis durch Orchestrator (2026-09-17, Windows-Test-VM 8233, Paket 1.2.0-beta.5a444ec) — erbracht
- Tooltip „Tessera – alpha.tessera.ctl.de", Menuezeile „Verbunden mit alpha.tessera.ctl.de" (gesperrt).
- „Server-Adresse ändern…" oeffnet die Setup-Seite mit „Aktuell verbunden mit: https://alpha.tessera.ctl.de/", Adresse vorbelegt; „Abbrechen" fuehrt zur Server-Seite zurueck.
- Wechsel auf
http://192.168.13.11:3000: Anmeldeseite des neuen Servers, Tooltip/Menuezeile sofort „192.168.13.11:3000", Versionspruefung lief neu — ohne Neustart. - „Beenden": Fenster zu, Tray-Symbol weg,
tasklistohnetessera-desktop.exe. - Befund (Altlast, durch 260917-kgc behoben): gegen einen aelteren Server (1.1.0) bot der Client „Version 1.1.0 herunterladen" an.