docs(18-03): complete Web-Oberflaeche fuer Desktop-App plan

This commit is contained in:
2026-09-16 16:32:35 +02:00
parent e96d460b8e
commit 82312ef691
4 changed files with 202 additions and 10 deletions
+2 -2
View File
@@ -666,7 +666,7 @@ Plans (Wellenstruktur — streng nacheinander, alle drei fassen Schema, Controll
3. Der installierte Client zeigt nach Eingabe der Server-Adresse die Tessera-Anmeldung, laeuft mit Tray/Schliessen-ins-Tray/Autostart wie in Phase 6 und meldet eine neuere Client-Version mit Link zur Download-Seite
4. Anwender- und Betriebshandbuch beschreiben Installation, Erststart, Tray-Verhalten, Pipeline, Release-Dateien und Umgebungsvariablen
**Plans:** 2/6 plans executed
**Plans:** 3/6 plans executed
Plans:
**Wave 1**
@@ -676,7 +676,7 @@ Plans:
**Wave 2** *(blocked on Wave 1 completion)*
- [x] 18-02-PLAN.md — Pipeline (Welle 2): CI-Job desktop (Linux-AppImage mit Tag-Version) + Uebergabe an publish per actions/cache mit hartem Abbruch, Release-Upload (idempotent) in publish-release.sh
- [ ] 18-03-PLAN.md — Web (Welle 2): lib/desktop.ts, Download-Link auf der Anmeldeseite, Seite Einstellungen → Allgemein → Desktop-App, Seitenleiste, i18n de/en, Tests
- [x] 18-03-PLAN.md — Web (Welle 2): lib/desktop.ts, Download-Link auf der Anmeldeseite, Seite Einstellungen → Allgemein → Desktop-App, Seitenleiste, i18n de/en, Tests
- [ ] 18-04-PLAN.md — Client (Welle 2): lib.rs mit check_server/save_server_url, Versionspruefung gegen /api-proxy/desktop/latest, Tray mit Update-Eintrag und Autostart-Haken (Umlaute), tauri-plugin-opener, Erststart-Seite in Sie-Form/Tessera-Gestalt, echter Icon-Satz, lokaler AppImage-Beweis
**Wave 3** *(blocked on Wave 2 completion)*
+9 -7
View File
@@ -4,16 +4,16 @@ milestone: v1.2
current_phase: 18
current_phase_name: desktop-client-fertigstellen
status: verified
stopped_at: Completed 18-02-PLAN.md
last_updated: "2026-09-16T14:23:19.503Z"
stopped_at: Completed 18-03-PLAN.md
last_updated: "2026-09-16T14:32:05.734Z"
last_activity: 2026-09-16
last_activity_desc: Quick 260910-jab — drei zu kurz greifende RLS-Regeln geschlossen (GroupMembership beide Seiten, ModuleGrant beide Ziele, TenderRssFeedSource Lese-/Schreibsplit), listForUser gebunden, Aktenstand kohaerent
state_head: ab75911b720a388adbabf829aae9a240495a04f9
state_head: e96d460b8ecd8cbeab8a78f415976ea6de31bb0e
progress:
total_phases: 18
completed_phases: 15
total_plans: 89
completed_plans: 84
completed_plans: 85
milestone_name: Plattform-Berechtigungen
---
@@ -29,7 +29,7 @@ See: .planning/PROJECT.md (updated 2026-07-17)
## Current Position
Phase: 18 (desktop-client-fertigstellen) — IN PROGRESS
Plan: 2 of 6 (18-02 abgeschlossen)
Plan: 3 of 6 (18-02 abgeschlossen)
Status: 18-02 (CI-Job desktop, Cache-Uebergabe an publish, Release-Anhaenge) fertig; 18-03 (Web-Oberflaeche), 18-04 (Client-Updatepruefung), 18-05 (Windows-Cross-Bau + Pipeline-Beweis), 18-06 (Freigabe) stehen aus
Last activity: 2026-09-16 - 18-02: Job desktop (Linux-AppImage, actions/cache) vor publish, Manifest-Pruefung in publish-images.sh, idempotenter Release-Anhang-Upload in publish-release.sh
@@ -125,6 +125,7 @@ Progress: [███░░░░░░░] 33%
| Phase quick-260914-eym P01 | 1 Sitzung | 3 tasks | 29 files |
| Phase 18 P01 | 13min | 2 tasks | 15 files |
| Phase 18 P02 | 8 min | 2 tasks | 3 files |
| Phase 18-desktop-client-fertigstellen P03 | 20 min | 2 tasks | 12 files |
## Accumulated Context
@@ -311,6 +312,7 @@ Recent decisions affecting current work:
- [Phase 17]: [quick-260914-eym]: forSystem(prisma) als Schwesterhelfer (eigene Detektor-Erkennungsform, Umkehrung der 3b-Begruendung); system_read_policy FOR SELECT auf fuenf Tabellen, SmtpConfig nicht (Mail-Startpfad entfernt, Transport je Versand nach Mandant); DKV-Planer Auftrag je Mandant (promote); Single-Flight-Riegel bleibt prozessweit -> WINDOWS #37
- [Phase 18]: [18-01]: DesktopController braucht @Inject(DesktopService) explizit, da Vitest ueber esbuild ohne emitDecoratorMetadata transpiliert (sonst desktopService=undefined im echten NestFactory-HTTP-Durchstich).
- [Phase 18]: 18-02: Cross-Job-Uebergabe per actions/cache (save/restore, Schluessel exakt am gitea.sha) statt upload-/download-artifact, da diese auf der Gitea-Instanz unzuverlaessig sind. — Pitfall 1 aus 18-RESEARCH.md; publish bricht bei Cache-Fehlschlag hart ab (fail-on-cache-miss + explizite Manifest-Pruefung in Workflow und Skript).
- [Phase 18]: Desktop-Download-Link/Einstellungsseite lesen GET /desktop/latest memoisiert und blenden sich ohne Pakete aus — Wiederverwendung des app-version.ts-Musters (Modul-Ebene-Promise, still bei Fehler)
### Pitfalls & Anti-Patterns
@@ -463,8 +465,8 @@ sind. Kein Anlass, sie vorher erneut vorzulegen.
## Session Continuity
Last session: 2026-09-16T14:23:19.237Z
Last session: 2026-09-16T14:32:05.422Z
Resumed: 2026-09-14 — Sitzung ueber /gsd-resume-work fortgesetzt; #29 und 3c als /gsd-quick --validate mit voller Kette durchgefuehrt.
Stopped at: Completed 18-02-PLAN.md
Stopped at: Completed 18-03-PLAN.md
Resume file: None
Last activity: 2026-09-16 - Completed quick task 260916-k2z: Mehrfach-Kreise je Kalender am Tag; Browser-Pruefung + Push ausstehend
@@ -0,0 +1,190 @@
---
phase: 18-desktop-client-fertigstellen
plan: 03
subsystem: ui
tags: [next-intl, react, desktop-distribution, i18n]
# Dependency graph
requires:
- phase: 18-01
provides: "GET /desktop/latest, GET /desktop/download/:platform (beide @Public()), DesktopLatestResponse-Form"
provides:
- "apps/web/src/lib/desktop.ts (loadDesktopLatest, desktopDownloadUrl, formatFileSize)"
- "DesktopDownloadLinks — unauffaelliger Link-Block auf der Anmeldeseite (D-12)"
- "DesktopAppSettings + Route /settings/general/desktop — Version, Download-Knoepfe, Dateigroesse, Erklaerung"
- "Seitenleisteneintrag Desktop-App unter Allgemein"
affects: [18-04-client-updateprüfung, 18-06-browser-gegenprobe]
actuals:
tokens: 6993
tasks: 2
commits: 2
plan_head_before: 2164cd537a8645f39a055bfa3cff77b8ef02822d
tech-stack:
added: []
patterns:
- "memoisiertes Single-Promise-Laden (Modul-Ebene), still bei Fehler -> null, konsumiert per useEffect+useState mit active-Schutz (Muster app-version.ts/AppVersionBadge, jetzt zweimal wiederverwendet: Login-Link und Einstellungsseite)"
- "Linkziel immer aus API_URL plus relativem url-Feld gebaut, nie eine absolute Adresse aus der Antwort uebernommen (T-18-07)"
key-files:
created:
- apps/web/src/lib/desktop.ts
- apps/web/src/lib/desktop.test.ts
- apps/web/src/components/desktop/desktop-download-links.tsx
- apps/web/src/components/desktop/desktop-download-links.test.tsx
- "apps/web/src/app/(portal)/settings/general/desktop/page.tsx"
- apps/web/src/components/settings/desktop-app-settings.tsx
- apps/web/src/components/settings/desktop-app-settings.test.tsx
modified:
- "apps/web/src/app/(auth)/login/page.tsx"
- apps/web/src/components/settings/settings-sidebar.tsx
- apps/web/src/messages/de.json
- apps/web/src/messages/en.json
- apps/web/src/messages/umlaut-dictionary.ts
key-decisions:
- "useLocale() aus der Anmeldeseiten-Komponente entfernt (Plan-Text erwaehnte es, aber der Link-Block zeigt keine Dateigroesse — nur die Einstellungsseite braucht locale fuer formatFileSize); vermeidet eine ungenutzte Variable."
- "'neuere' zur UMLAUT_ALLOWLIST ergaenzt — der bestehende Waechter-Test flaggte das Wort faelschlich, weil es zufaellig die Buchstabenfolge 'ue' enthaelt, obwohl die Schreibweise bereits korrekt ist (kein Substitutionsfehler)."
patterns-established: []
requirements-completed: [DESK-03]
coverage:
- id: D1
description: "Anmeldeseite zeigt Download-Link(s) nur wenn /desktop/latest antwortet, Windows fuehrt, Linux als Kurzlink bei beiden Paketen"
requirement: "DESK-03"
verification:
- kind: unit
ref: "apps/web/src/lib/desktop.test.ts#Test 1-5"
status: pass
- kind: unit
ref: "apps/web/src/components/desktop/desktop-download-links.test.tsx#Test 1-3"
status: pass
human_judgment: false
- id: D2
description: "Einstellungsseite Desktop-App: Version, zwei Primaerknoepfe mit Symbol, Dateiname/Groesse, Beta-Hinweis, vier erklaerende Saetze, Hinweistext ohne Pakete"
requirement: "DESK-03"
verification:
- kind: unit
ref: "apps/web/src/components/settings/desktop-app-settings.test.tsx#Test 1-3"
status: pass
human_judgment: false
- id: D3
description: "Seitenleiste zeigt den Eintrag Desktop-App unter Allgemein mit aria-current auf der Route"
requirement: "DESK-03"
verification:
- kind: other
ref: "grep -c 'href=\"/settings/general/desktop\"' apps/web/src/components/settings/settings-sidebar.tsx (=1)"
status: pass
human_judgment: false
- id: D4
description: "de/en vollstaendig fuer auth.desktopDownload.* und settings.desktop.*/categoryDesktopApp, deutsche Texte mit echten Umlauten"
requirement: "DESK-03"
verification:
- kind: other
ref: "node i18n-Paritaets-/Umlautskript aus 18-03-PLAN.md <verify> -> 'i18n OK'"
status: pass
- kind: unit
ref: "apps/web/src/messages/umlaut-guard.spec.ts"
status: pass
human_judgment: false
- id: D5
description: "Alle Downloads laufen ueber die Tessera-API (API_URL + relatives url-Feld), keine feste Server-/Firmenadresse im Code"
requirement: "DESK-03"
verification:
- kind: unit
ref: "apps/web/src/lib/desktop.test.ts#Test 4 (desktopDownloadUrl)"
status: pass
- kind: other
ref: "grep -v '^\\s*//' apps/web/src/lib/desktop.ts | grep -c 'process.env.NEXT_PUBLIC_API_URL' (=1)"
status: pass
human_judgment: true
rationale: "Der End-zu-Ende-Beweis (Browser klickt echten Download bis zum tatsaechlichen Dateidownload) ist die geplante Browser-Gegenprobe am Phasenende (18-06) — hier nur die Unit-/Text-Ebene automatisiert bewiesen."
duration: 20min
completed: 2026-09-16
status: complete
---
# Phase 18 Plan 03: Desktop-App in der Web-Oberflaeche Summary
**Unauffaelliger Download-Link auf der Anmeldeseite und eine vollstaendige Einstellungsseite "Desktop-App" (Version, zwei Primaerknoepfe mit Plattform-Symbol, Dateigroesse, Beta-Hinweis, vier erklaerende Saetze) — beide lesen `GET /desktop/latest` und blenden sich ohne Pakete aus.**
## Performance
- **Duration:** 20 min (geschaetzt)
- **Started:** 2026-09-16T14:10:00Z (geschaetzt)
- **Completed:** 2026-09-16T14:30:47Z
- **Tasks:** 2
- **Files modified:** 12
## Accomplishments
- `apps/web/src/lib/desktop.ts`: `loadDesktopLatest()` memoisiert (ein Fetch je Modulinstanz, still bei Fehler -> `null`, kein `credentials: 'include'` — die Anmeldeseite hat noch kein Cookie), `desktopDownloadUrl()` (baut die Adresse ausschliesslich aus `API_URL` plus dem relativen `url`-Feld, T-18-07), `formatFileSize()` (lokalisierte MB-Werte, `Intl.NumberFormat`).
- `DesktopDownloadLinks` auf der Anmeldeseite: rendert nichts ohne Daten oder ohne Plattform in `files`; Windows fuehrt als Hauptlink, Linux folgt als kleiner Zusatzlink, wenn beide Pakete vorliegen; darunter die Versionszeile.
- `DesktopAppSettings` unter `/settings/general/desktop`: vier erklaerende Saetze in Sie-Form (Was ist die App, Erststart, Tray-Verhalten, Update-Hinweis), Versionszeile, Beta-Kanal-Zusatzhinweis mit Commit, zwei Primaerknoepfe (`bg-primary`, inline-SVG-Plattformsymbol, `download`-Attribut) mit Dateiname+Groesse darunter, und ein Hinweistext statt der Knoepfe, wenn die API `null` liefert.
- Seitenleiste: neuer Eintrag "Desktop-App" unter "Allgemein" mit identischem `aria-current`-Muster wie "Konto".
- `de.json`/`en.json`: `auth.desktopDownload.*` und `settings.desktop.*`/`settings.categoryDesktopApp` vollstaendig, deutsche Texte mit echten Umlauten.
## Task Commits
Each task was committed atomically:
1. **Task 1: Fetch-Helfer und der Download-Link auf der Anmeldeseite** - `026d9c3` (feat)
2. **Task 2: Einstellungsseite "Desktop-App" mit Knoepfen, Groesse und Erklaerung** - `e96d460` (feat)
**Plan metadata:** commit pending (this SUMMARY + STATE.md/ROADMAP.md/REQUIREMENTS.md)
## Files Created/Modified
- `apps/web/src/lib/desktop.ts` - `DesktopPlatform`/`DesktopFileInfo`/`DesktopLatestInfo`, `loadDesktopLatest`, `desktopDownloadUrl`, `formatFileSize`
- `apps/web/src/lib/desktop.test.ts` - 5 Tests (memoisiert, still bei ok=false/Netzfehler, URL-Bau, Groessenformatierung)
- `apps/web/src/components/desktop/desktop-download-links.tsx` - Link-Block der Anmeldeseite
- `apps/web/src/components/desktop/desktop-download-links.test.tsx` - 3 Tests (leer, beide Plattformen, nur Linux)
- `apps/web/src/app/(auth)/login/page.tsx` - `DesktopDownloadLinks` nach dem Formular eingebaut
- `apps/web/src/app/(portal)/settings/general/desktop/page.tsx` - Route, delegiert an `DesktopAppSettings`
- `apps/web/src/components/settings/desktop-app-settings.tsx` - Version, Knoepfe, Groesse, Saetze, Hinweisfall
- `apps/web/src/components/settings/desktop-app-settings.test.tsx` - 3 Tests (beide Plattformen, Beta-Hinweis, keine Pakete)
- `apps/web/src/components/settings/settings-sidebar.tsx` - Eintrag "Desktop-App" ergaenzt
- `apps/web/src/messages/de.json` / `en.json` - `auth.desktopDownload.*`, `settings.desktop.*`, `settings.categoryDesktopApp`
- `apps/web/src/messages/umlaut-dictionary.ts` - `neuere` zur Allowlist ergaenzt (Deviation, siehe unten)
## Decisions Made
- `useLocale()` in `DesktopDownloadLinks` weggelassen: der Link-Block der Anmeldeseite zeigt keine Dateigroesse, nur die Version — `formatFileSize` wird ausschliesslich auf der Einstellungsseite gebraucht. Eine ungenutzte Variable haette keinen Wert gehabt.
- Die vier erklaerenden Saetze und die Download-Bloecke bleiben eine einzige Client-Komponente (`DesktopAppSettings`) statt mehrerer Unterkomponenten — passend zur Groesse des Inhalts und zum bestehenden `account`/`smtp`-Seitenmuster (eine Komponente pro Einstellungsseite).
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 1 - Bug] Umlaut-Waechter-Test schlug auf "neuere" fehl**
- **Found during:** Task 2 (voller `pnpm --filter @tessera/web exec vitest run` nach dem i18n-Block)
- **Issue:** `src/messages/umlaut-guard.spec.ts` flaggte `settings.desktop.update: "neuere"` als vermeintlich falsche ASCII-Umschrift, weil das Wort die Buchstabenfolge "ue" enthaelt (n-e-**ue**-r-e) — die Schreibweise ist aber bereits korrektes Deutsch, keine Substitution noetig.
- **Fix:** `neuere` zur `UMLAUT_ALLOWLIST` in `apps/web/src/messages/umlaut-dictionary.ts` ergaenzt (neben den bereits vorhandenen `neue`/`neuen`/`Neue`/`Neues`).
- **Files modified:** `apps/web/src/messages/umlaut-dictionary.ts`
- **Verification:** `pnpm --filter @tessera/web exec vitest run` — vollstaendige Suite gruen (365/365).
- **Committed in:** `e96d460` (Task 2 commit)
---
**Total deviations:** 1 auto-fixed (1 bug)
**Impact on plan:** Reine Testinfrastruktur-Korrektur, kein Verhaltensunterschied im Produktionscode. Keine Ausweitung des Umfangs.
## Issues Encountered
None.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- Die Web-Oberflaeche liest `GET /desktop/latest` an beiden vorgesehenen Stellen (Anmeldeseite, Einstellungen) und blendet sich korrekt aus, wenn keine Pakete hinterlegt sind — 18-04 (Client-Versionspruefung) kann auf demselben Endpunkt aufbauen, ohne die Web-Seite zu beruehren.
- Die Browser-Gegenprobe (echter Klick, echter Download) ist bewusst auf 18-06 verschoben (siehe Plan-`<verification>` Punkt 4); alle automatisierten Ebenen (Unit-Tests, Typpruefung, i18n-Paritaet/Umlaute, volle Web-Suite) sind gruen.
- Kein Blocker.
---
*Phase: 18-desktop-client-fertigstellen*
*Completed: 2026-09-16*
## Self-Check: PASSED
All created files verified on disk (`apps/web/src/lib/desktop.ts`, `desktop.test.ts`, `apps/web/src/components/desktop/desktop-download-links.tsx`, `desktop-download-links.test.tsx`, `apps/web/src/app/(portal)/settings/general/desktop/page.tsx`, `apps/web/src/components/settings/desktop-app-settings.tsx`, `desktop-app-settings.test.tsx`). Both task commits found in `git log` (`026d9c3`, `e96d460`). All plan-level `<verification>` items re-run and passing: `pnpm --filter @tessera/web exec vitest run` (365/365 green, baseline 354 + 11 new), `pnpm --filter @tessera/web type-check` (clean), i18n parity/umlaut script -> `i18n OK`. Browser-Gegenprobe bleibt fuer 18-06 (Plan-`<verification>` Punkt 4, ausserhalb dieses Plans).
+1 -1
View File
@@ -94,5 +94,5 @@
"label": "Advance to the next step (verify)",
"reason": "Phase 18 of 18 · ready to verify"
},
"updated_at": "2026-09-16T13:56:53.376Z"
"updated_at": "2026-09-16T14:31:50.856Z"
}