diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index c63b3a5..e1b4ad4 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -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)* diff --git a/.planning/STATE.md b/.planning/STATE.md index 990117d..55f41e3 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -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 diff --git a/.planning/phases/18-desktop-client-fertigstellen/18-03-SUMMARY.md b/.planning/phases/18-desktop-client-fertigstellen/18-03-SUMMARY.md new file mode 100644 index 0000000..5400a38 --- /dev/null +++ b/.planning/phases/18-desktop-client-fertigstellen/18-03-SUMMARY.md @@ -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 -> '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-`` 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 `` 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-`` Punkt 4, ausserhalb dieses Plans). diff --git a/.planning/state.json b/.planning/state.json index 9edf8ed..ee605e5 100644 --- a/.planning/state.json +++ b/.planning/state.json @@ -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" }