Files
tessera-ctl/.planning/quick/260917-jn2-desktop-client-aktuelle-server-adresse-s/260917-jn2-SUMMARY.md
T
schalli efbd6e8974
Tessera CI/CD / Lint & Type Check (push) Successful in 53s
Tessera CI/CD / Tests (push) Successful in 1m5s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 18s
Tessera CI/CD / Build & Publish Images (push) Successful in 4m22s
docs(quick-260917-kgc): Aktenstand — Update in der Desktop-App, alle Nachweise erbracht, Wiedereinstieg bereinigt
Quick 260917-kgc (Plan/Recherche/Bericht/Verifikation) und Schnellfix a6d1a64
in der Quick-Task-Tabelle; Nachweise in allen sechs Berichten nachgetragen
(Playwright lokal, CI-Laeufe 382-384, Windows-Test-VM: In-App-Update
7479cb4 -> 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
2026-09-18 11:29:14 +02:00

18 KiB
Raw Blame History


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 Helfer server_host, tray_labels, setup_page_url, parse_server_url sowie stored_server_url als einzige Store-Lesestelle; neuer State TrayItems { connected, update }; apply_server() setzt Tooltip + Menuezeile aus derselben Quelle; spawn_version_check() (aus setup herausgezogen) laeuft nach jedem Wechsel neu und setzt den Update-Eintrag zuerst zurueck. Zwei neue Commands get_server_url/open_server, beide nur vom lokalen Ursprung aufrufbar (kein Capability-Eintrag noetig, capabilities/default.json unveraendert). Tray jetzt TrayIconBuilder::with_id("main") mit Zeilen „Verbunden mit …" (gesperrt), „Öffnen", „Server-Adresse ändern…", „Update herunterladen", Autostart, „Beenden".
  • setup.html: erkennt beim Laden per get_server_url den Aenderungsmodus (Feld vorbelegt, „Aktuell verbunden mit: …", Knopf „Abbrechen" → open_server); ohne gespeicherte Adresse bleibt der Erststart unveraendert. SVG-Bildmarke unangetastet.
  • Web: DesktopAppSettings zeigt 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:

  1. Task 1: Rust + setup.html — Verbunden-Zeile/Tooltip, „Server-Adresse ändern…", Commands, Tray-Auffrischung, Tests - 29c132e (feat)
  2. Task 2: Web — Block „Verbunden mit: {origin}" nur im Client, i18n, Test - 4c79874 (feat)
  3. 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, Commands get_server_url/open_server, Tray-Aufbau mit connected/change_server
  • apps/desktop/src/setup.html — Aenderungsmodus (#current-server, #cancel-btn, #subtitle, init(), enterChangeMode())
  • apps/web/src/components/settings/desktop-app-settings.tsx — Block data-testid="desktop-connected" nur im Desktop-Client
  • apps/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.changeHint
  • docs/anleitung-anwender.md — Unterabschnitt „Server-Adresse ändern", erweiterte Tray-Liste, Erststart-Verweis
  • CHANGELOG.md — zwei Desktop-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 via app.manage(TrayItems { connected: connected.clone(), update: update.clone() }) direkt nach dem Menue-Bau, vor TrayIconBuilder::with_id("main")...build(app)?.
  • fn apply_server(app: &AppHandle, url: Option<&str>) — einzige Stelle, die app.tray_by_id("main") (Tooltip) und app.state::<TrayItems>().connected (Menuezeile) setzt.
  • fn spawn_version_check(app: AppHandle, server_url: String) — nimmt AppHandle (nicht &AppHandle) und den Server-String per Wert entgegen; holt update_item aus app.state::<TrayItems>(), setzt ihn synchron auf UPDATE_ITEM_DEFAULT/enabled(false) zurueck, dann tauri::async_runtime::spawn(...) wie im Bestand. Der Updater-Task kann hier andocken (z. B. den Update-Klick auf tauri-plugin-updater statt opener::open_url umstellen) — update_item ist 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 zwischen update und dem folgenden Trenner eingefuegt, oder update selbst 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-Schritt cargo fmt legitim auf fuenf Zeilen um. cargo fmt --check MUSS 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 -0777 Regex 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_check laufen NACH dem Tray-Aufbau, weil beide app.state::<TrayItems>() brauchen, das erst beim Tray-Aufbau gemanagt wird (app.manage(...) direkt vor TrayIconBuilder::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 ueber max_width = 100 liegt. Woertlich erfuellbar waren beide Anforderungen nicht gleichzeitig.
  • Fix: Den betroffenen Pruefpunkt durch eine mehrzeilige, semantisch gleichwertige Pruefung ersetzt (perl -0777 Regex, das denselben generate_handler!-Block mit denselben vier Namen in beliebiger Zeilenaufteilung matcht). Der generierte Code selbst blieb unveraendert — cargo fmt --check ist 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 --lib gruen (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 tests ergaenzt, cargo test --lib schlug mit 13 Compile-Fehlern fehl (fehlende Funktionen server_host, tray_labels, setup_page_url, parse_server_url), exakt auf die neuen Tests zurueckfuehrbar. GREEN — Helfer implementiert, cargo test --lib lief 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 verbunden ohne 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, tasklist ohne tessera-desktop.exe.
  • Befund (Altlast, durch 260917-kgc behoben): gegen einen aelteren Server (1.1.0) bot der Client „Version 1.1.0 herunterladen" an.