Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
22 KiB
phase, verified, status, score, covered_files, covered_digest, behavior_unverified, behavior_unverified_items, overrides_applied, human_verification
| phase | verified | status | score | covered_files | covered_digest | behavior_unverified | behavior_unverified_items | overrides_applied | human_verification | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 18-desktop-client-fertigstellen | 2026-09-16T17:50:00Z | passed | 9/10 must-haves verified (Windows-Bedienprobe 2026-09-17 bestanden; Release-Anhang + Update-Hinweis bewusst auf den naechsten Freigabe-Tag vertagt, siehe 18-UAT.md) |
|
v1:sha256:d489cb5b094aba560b96f3d6ce7537d67fe83a2827906d554c4cccae996e091c | 2 |
|
0 |
|
Phase 18: Desktop-Client fertigstellen Verification Report
Phase Goal: Anwender koennen den Tessera-Desktop-Client als fertigen Windows-Installer (und Linux-AppImage) direkt aus Tessera herunterladen und installieren; die Pipeline baut die Pakete bei jedem Freigabe-Tag und haengt sie an das Gitea-Release; der Client traegt die Freigabe-Version, fragt die Server-Adresse weiterhin beim ersten Start ab und weist bei einer neueren Client-Version mit Download-Link hin.
Verified: 2026-09-16T17:50:00Z Status: human_needed Re-verification: No — initial verification
Goal Achievement
Observable Truths
| # | Truth | Status | Evidence |
|---|---|---|---|
| 1 | GET /desktop/latest (200 mit Version/Kanal/Dateiliste, 404 ohne Manifest) und GET /desktop/download/:platform (attachment-Stream, Whitelist vor Dateisystemzugriff, 400 fuer unbekannte Plattform) sind oeffentlich (@Public()) |
✓ VERIFIED | pnpm --filter @tessera/api exec vitest run src/desktop — 13/13 gruen (inkl. CR-01/WR-03-Regressionstests); lokaler curl: GET /desktop/latest → 200 mit Manifest, GET /desktop/download/linux → 200 mit Content-Disposition: attachment, GET /desktop/download/nonsense → 400 |
| 2 | desktop-collect.sh/desktop-version.sh schreiben kanonische Dateinamen, manifest.json (Version/Kanal/Commit/Groesse/SHA-256) und reine X.Y.Z-Versionen aus dem Freigabe-Tag |
✓ VERIFIED | Skripte vorhanden (156/53 Zeilen), von CI-Lauf 367 tatsaechlich benutzt (siehe Truth 4); Code-Review fand keine Beanstandung außer IN-01 (Info, nicht behoben, kein Sicherheitsproblem) |
| 3 | API-Abbild traegt die Pakete unter /app/desktop-dist/ und liefert sie aus, ohne dass Live-Server Gitea-Zugang brauchen (D-08) |
✓ VERIFIED | apps/api/Dockerfile enthaelt COPY desktop-dist; lokaler Docker-Stack liefert /desktop/latest und /desktop/download/linux tatsaechlich aus (curl-Beweis oben; Hinweis: das laufende lokale Abbild ist ein aelterer Baustand, siehe Anmerkung unten) |
| 4 | CI-Job desktop baut auf dem Linux-Runner sowohl Tessera-X.Y.Z.AppImage als auch Tessera-Setup-X.Y.Z.exe (Cross-Bau, cargo-xwin/NSIS) und uebergibt sie per actions/cache an publish, das ohne Manifest hart abbricht |
✓ VERIFIED | Gitea CI/CD Lauf 367 (Commit 742fb5c), Job "Desktop-Pakete bauen" gruen, erzeugte Tessera-Setup-1.1.0-beta.742fb5c.exe (2.775.663 Bytes) und Tessera-1.1.0-beta.742fb5c.AppImage (82.479.608 Bytes); .gitea/workflows/ci.yml enthaelt cargo-xwin, --require linux,windows, fail-on-cache-miss: true, needs: desktop; publish-images.sh bricht ohne desktop-dist/manifest.json hart ab (Code-Inspektion, Zeile 63-64) |
| 5 | publish haengt Pakete ins API-/Web-Abbild; Job publish von Lauf 367 pushte Abbilder mit den Paketen |
✓ VERIFIED | 18-05-SUMMARY.md: Lauf 367 — alle vier Jobs gruen, publish pushte Abbilder mit Etiketten beta/latest |
| 6 | publish-release.sh haengt bei Tags jede Manifest-Datei idempotent (GET/DELETE/POST) als Release-Anhang an; Token verlaesst nie die Kommandozeile |
✓ VERIFIED (Code + Trockenlauf) | .gitea/scripts/publish-release.sh enthaelt upload_asset(), HDR_AUTH (nur Authorization-Header), kein GITEA_TOKEN in einer curl-Zeile (grep bestaetigt); --dry-run --tag v1.1.0 nennt laut 18-02-SUMMARY.md den erwarteten Zielpfad — der echte Upload bei einem Tag ist aber noch nicht gelaufen (siehe Truth 7) |
| 7 | Ein Freigabe-Tag haengt beide Dateien tatsaechlich als Release-Anhang an den Gitea-Release (ROADMAP-SC1, zweite Haelfte) | ⚠️ PRESENT_BEHAVIOR_UNVERIFIED | Code/Skript vorhanden und per Trockenlauf geprueft, aber kein echter v*-Tag wurde seit den Phase-18-Aenderungen gepusht (Lauf 367 war ein main-Push) — der reale API-Roundtrip ist unbewiesen. Siehe behavior_unverified_items |
| 8 | Anmeldeseite zeigt einen unauffaelligen "Desktop-App herunterladen (Windows)"-Link mit Linux-Kurzlink und Version nur wenn /desktop/latest antwortet; Einstellungen → Allgemein → Desktop-App zeigt Version, zwei Download-Knoepfe, Dateigroesse, Erklaerung; alle Downloads laufen ueber API_URL (ROADMAP-SC2) |
✓ VERIFIED | apps/web/src/app/(auth)/login/page.tsx importiert/rendert DesktopDownloadLinks; settings-sidebar.tsx verlinkt /settings/general/desktop; pnpm --filter @tessera/web exec vitest run src/lib/desktop.test.ts src/components/desktop src/components/settings/desktop-app-settings.test.tsx — 11/11 gruen; volle Web-Suite 365/365 gruen; desktopDownloadUrl() baut Adressen ausschliesslich aus API_URL + relativem url-Feld |
| 9 | Client fragt die Server-Adresse beim ersten Start ab, prueft sie echt (check_server//health/version), speichert sie, navigiert zur Tessera-Anmeldung; Tray behaelt Oeffnen/Schliessen-ins-Tray/Autostart aus Phase 6 und traegt zusaetzlich einen Update-Eintrag mit echten Umlauten; Versionspruefung gegen /desktop/latest inkl. Commit-Vergleich fuer Beta (WR-02-Fix) |
⚠️ PRESENT_BEHAVIOR_UNVERIFIED | Code vollstaendig vorhanden und verdrahtet: check_server/save_server_url-Kommandos, api_url()-Helfer, Tray-Eintraege "Öffnen"/"Update herunterladen"/Autostart-Haken/"Beenden" mit korrektem Label je Plattform, is_newer-Vergleich inkl. channel == "beta" && info.commit != app_commit (WR-02, build.rs embeds APP_COMMIT via TESSERA_COMMIT-Env aus der Pipeline); cargo check/cargo clippy sauber. Das tatsaechliche Verhalten in einer grafischen Sitzung (echtes Rendering, echter Serverwechsel, echte Benachrichtigung) ist in dieser kopflosen Umgebung nicht beobachtbar — Bedienprobe steht laut 18-06-SUMMARY.md aus. Siehe behavior_unverified_items |
| 10 | Anwender-, Betriebs- und Entwicklungshandbuch beschreiben Installation, Erststart, Tray, Pipeline, Release-Dateien und Umgebungsvariablen (ROADMAP-SC4) | ✓ VERIFIED | docs/anleitung-anwender.md Kapitel ## Desktop-App (Zeile 161) mit den geforderten Unterabschnitten; docs/anleitung-betrieb.md Kapitel ## 10. Desktop-App: Pakete und Release-Dateien (Zeile 552) mit DESKTOP_DIST_DIR; docs/anleitung-entwicklung.md enthaelt ### Desktop-App lokal bauen und keinen Treffer mehr fuer "Tauri-Grundgerüst"; docs/ci-cd-setup.md beschreibt den Job desktop; CHANGELOG.md traegt den D-17-Stichpunkt |
Score: 8/10 truths verified (2 present, behavior-unverified)
Anmerkung zum lokalen Docker-Stack
Der laufende lokale API-Container liefert /desktop/latest mit "channel":"dev","commit":"ae8fecb" — das ist ein aelterer, lokal gebauter Stand aus 18-01, nicht der aktuelle Code mit den Review-Fixes (CR-01/WR-01/WR-02/WR-03). Dieser Befund bestaetigt nur, dass die Route/das Streaming-Verhalten funktioniert (Truth 1/3) — er ist keine Evidenz dafuer, dass die Review-Fixes in einem laufenden Abbild aktiv sind. Die Review-Fixes selbst sind stattdessen ueber den frisch ausgefuehrten vitest run src/desktop (13/13, inkl. der neuen Test 7a/7b/7c und Test 9/10) sowie cargo check/cargo clippy bewiesen, wie vom Auftraggeber vorgegeben.
Required Artifacts
| Artifact | Expected | Status | Details |
|---|---|---|---|
apps/api/src/desktop/desktop.service.ts |
Manifest lesen, Plattform-Whitelist, Datei-Stream, Pfad-Traversal-Schutz | ✓ VERIFIED | 176 Zeilen; PLATFORMS-Whitelist vor Dateisystemzugriff; CR-01-Fix (./..-Ablehnung + startsWith(resolvedRoot)) und WR-03-Fix (isValidManifestFileEntry) beide im Code vorhanden und getestet |
apps/api/src/desktop/desktop.controller.ts |
GET /desktop/latest, GET /desktop/download/:platform, beide @Public() |
✓ VERIFIED | 37 Zeilen, @Inject(DesktopService) explizit gesetzt (Vitest/esbuild-Workaround) |
.gitea/scripts/desktop-collect.sh / desktop-version.sh |
Pakete einsammeln, Version aus Tag | ✓ VERIFIED | 156/53 Zeilen, in CI-Lauf 367 tatsaechlich benutzt |
apps/api/Dockerfile |
COPY desktop-dist |
✓ VERIFIED | COPY desktop-dist ./desktop-dist vor USER nestjs (18-01-SUMMARY.md, curl-Beweis bestaetigt Auslieferung) |
.gitea/workflows/ci.yml |
Job desktop, Windows-Cross-Bau, Cache-Uebergabe an publish |
✓ VERIFIED | cargo-xwin, --target x86_64-pc-windows-msvc --bundles nsis, --require linux,windows, TESSERA_COMMIT-Env, fail-on-cache-miss: true, needs: desktop alle vorhanden |
.gitea/scripts/publish-release.sh |
Idempotenter Release-Datei-Upload | ✓ VERIFIED (Code) / ⚠️ Realer Upload nicht beobachtet | upload_asset(), HDR_AUTH, kein Token in curl-Zeile |
apps/web/src/lib/desktop.ts + Komponenten |
Fetch-Helfer, Login-Link, Einstellungsseite | ✓ VERIFIED | 67/66/122 Zeilen, verdrahtet in login/page.tsx und settings-sidebar.tsx, 11/11 Tests gruen |
apps/desktop/src-tauri/src/lib.rs + build.rs |
Versionspruefung, Tray, Erststart-Kommandos, Commit-Stempel | ✓ VERIFIED (Code) / ⚠️ Kein grafischer Beweis | 246/35 Zeilen, cargo check/clippy sauber, WR-02-Fix verdrahtet |
apps/desktop/src-tauri/icons/* |
Echtes Tessera-Icon statt Platzhalter | ✓ VERIFIED | 5 Dateien vorhanden (icon.ico 105.724 Bytes, icon.png 33.721 Bytes — keine 105-Byte-Platzhalter mehr) |
docs/anleitung-anwender.md, docs/anleitung-betrieb.md, docs/anleitung-entwicklung.md, docs/ci-cd-setup.md, CHANGELOG.md |
Handbuecher + Changelog | ✓ VERIFIED | Alle geforderten Kapitel-Anker gefunden |
.planning/REQUIREMENTS.md |
DESK-01..05 mit Traceability | ✓ VERIFIED | 5/5 Eintraege, 5/5 Traceability-Zeilen, DESK-01/02 Complete, DESK-03/04/05 bewusst Pending bis Bedienprobe |
Key Link Verification
| From | To | Via | Status | Details |
|---|---|---|---|---|
.gitea/scripts/desktop-collect.sh |
apps/api/src/desktop/desktop.service.ts |
manifest.json |
✓ WIRED | Manifest-Form stimmt mit DesktopManifest-Typ und Service-Lesecode ueberein; curl-Beweis bestaetigt reales Ausliefern |
apps/api/Dockerfile |
apps/api/src/desktop/desktop.service.ts |
COPY desktop-dist |
✓ WIRED | desktopDistDir zeigt auf /app/desktop-dist, curl liefert reale Datei |
.gitea/workflows/ci.yml (desktop) |
.gitea/workflows/ci.yml (publish) |
actions/cache Schluessel desktop-dist-${{ gitea.sha }} |
✓ WIRED | Bestaetigt durch gruenen Lauf 367 (alle vier Jobs gruen) |
apps/web/src/lib/desktop.ts |
apps/api/src/desktop/desktop.controller.ts |
fetch(${API_URL}/desktop/latest) |
✓ WIRED | loadDesktopLatest() ruft /desktop/latest; Unit-Tests decken Erfolg/Fehler ab |
apps/web/src/components/settings/settings-sidebar.tsx |
apps/web/src/app/(portal)/settings/general/desktop/page.tsx |
Link href=/settings/general/desktop |
✓ WIRED | grep bestaetigt genau 1 Treffer, aria-current analog "Konto" |
apps/desktop/src-tauri/src/lib.rs (Tray "update") |
apps/web/.../settings/general/desktop/page.tsx |
opener().open_url({server}/settings/general/desktop) |
✓ WIRED | Zeile 153 in lib.rs baut exakt diese URL |
.gitea/scripts/publish-release.sh |
desktop-dist/manifest.json |
jq -r '.files[].name' |
✓ WIRED (Code) | Upload-Schleife iteriert Manifest-Dateien; realer Netzaufruf am naechsten Tag noch offen |
Behavioral Spot-Checks
| Behavior | Command | Result | Status |
|---|---|---|---|
| API liefert Manifest oeffentlich | curl -s localhost:3001/desktop/latest |
200, Manifest mit files.linux |
✓ PASS |
| API streamt Datei mit attachment-Header | curl -sI localhost:3001/desktop/download/linux |
200, Content-Disposition: attachment |
✓ PASS |
| Unbekannte Plattform vor Dateisystemzugriff abgewiesen | curl -s localhost:3001/desktop/download/nonsense |
400 "Unknown platform" | ✓ PASS |
| API-Modul-Tests (inkl. Review-Fix-Regressionen) | pnpm --filter @tessera/api exec vitest run src/desktop |
13/13 gruen | ✓ PASS |
| Web-Suite komplett | pnpm --filter @tessera/web exec vitest run |
365/365 gruen | ✓ PASS |
| Desktop-spezifische Web-Tests | pnpm --filter @tessera/web exec vitest run src/lib/desktop.test.ts src/components/desktop src/components/settings/desktop-app-settings.test.tsx |
11/11 gruen | ✓ PASS |
| API Typpruefung | pnpm --filter @tessera/api exec tsc --noEmit |
fehlerfrei | ✓ PASS |
| Web Typpruefung | pnpm --filter @tessera/web exec tsc --noEmit |
fehlerfrei | ✓ PASS |
| Rust-Client kompiliert | cargo check (apps/desktop/src-tauri) |
Finished |
✓ PASS |
| Windows-Cross-Bau real in CI | — | Gitea Lauf 367 (bereits vom Auftraggeber gemessen, nicht erneut ausgefuehrt) | ✓ PASS (uebernommene Evidenz) |
Requirements Coverage
| Requirement | Source Plan(s) | Description | Status | Evidence |
|---|---|---|---|---|
| DESK-01 | 18-01, 18-02, 18-04, 18-05, 18-06 | Tauri-Wrapper Windows+Linux (Phase 6, fortgefuehrt) + Pipeline | ✓ SATISFIED | Code+CI-Lauf 367, REQUIREMENTS.md Complete |
| DESK-02 | 18-04, 18-06 | Server-Adresse beim ersten Start (Phase 6, fortgefuehrt) | ✓ SATISFIED (Code) / Bedienprobe offen | check_server/save_server_url verdrahtet; REQUIREMENTS.md fuehrt DESK-02 als Complete (aus Phase 6, unveraendert) |
| DESK-03 | 18-01, 18-03, 18-06 | Installer in Tessera herunterladbar | ✓ SATISFIED (Code+Tests) / REQUIREMENTS.md bewusst Pending | Login-Link/Einstellungsseite verdrahtet und getestet; Statuswechsel auf Complete an Bedienprobe geknuepft |
| DESK-04 | 18-02, 18-05, 18-06 | Freigabe-Tag baut beide Pakete, haengt sie an den Release | ⚠️ TEILWEISE | Bau-Haelfte bewiesen (Lauf 367); Release-Anhang-Haelfte nur per Trockenlauf, kein echter Tag in diesem Zyklus |
| DESK-05 | 18-01, 18-04, 18-06 | Client traegt Freigabe-Version, Update-Hinweis mit Link | ✓ SATISFIED (Code) / Bedienprobe offen | Versionspruefung inkl. WR-02-Commit-Vergleich verdrahtet, cargo check/clippy sauber; grafischer Beweis aussteht |
Keine verwaisten Requirements. REQUIREMENTS.md bildet alle 5 DESK-Eintraege korrekt auf Phase 18 ab (DESK-01/02 aus Phase 6 fortgefuehrt); keine zusaetzliche Phase-18-Zuordnung fehlt.
Anti-Patterns Found
Keine. grep auf TODO|FIXME|XXX|TBD|HACK|PLACEHOLDER|not yet implemented|coming soon in allen 18 neuen/geaenderten Kerndateien (API-Modul, Skripte, Web-Komponenten, Rust-Client, CI-Workflow) ergab 0 Treffer.
Code-Review-Status
18-REVIEW.md: 1 Critical (CR-01, Pfad-Traversal-Verteidigung), 3 Warnings (WR-01 CSP, WR-02 Beta-Update-Vergleich, WR-03 Manifest-Validierung), 2 Info (beide bewusst uebersprungen, keine Sicherheitswirkung). Alle 4 Critical/Warning-Funde sind laut 18-REVIEW-FIX.md behoben und per Commit nachgewiesen (a8964f1, 0d5c80f, 1b2f803, 579e24b) — durch eigenes Code-Lesen und vitest/cargo-Laeufe in diesem Verifizierungslauf bestaetigt. Ein fuenfter, in REVIEW-FIX.md nicht dokumentierter Nachfolge-Commit (72e488e) behebt einen Cache-bedingten Folgefehler des WR-02-Fixes (Commit-Stempel wuerde mit warmem Cargo-Cache veraltet bleiben) — inhaltlich konsistent und ebenfalls durch Code-Lesen bestaetigt.
Human Verification Required
-
Release-Anhang am naechsten Freigabe-Tag
- Test: Naechsten
v*-Tag setzen/pushen, Jobdesktop+publishbeobachten, danach den Gitea-Release des Tags oeffnen. - Expected:
Tessera-Setup-X.Y.Z.exeundTessera-X.Y.Z.AppImagesind als Anhaenge vorhanden und herunterladbar. - Why human:
publish-release.shlaeuft nur bei einem echten Tag-Push; in diesem Verifizierungszyklus (Lauf 367) war kein Tag gesetzt. Nur per Trockenlauf geprueft.
- Test: Naechsten
-
Windows-Bedienprobe (Erststart, Tray, Anmeldung, Einstellungsseite)
- Test: 18-06-SUMMARY.md "Manuelle Abnahme (ausstehend)", Schritte 1-11.
- Expected: Installation mit SmartScreen-Hinweis, Erststart fuehrt zur Tessera-Anmeldung im App-Fenster, Tray (Oeffnen/Update/Autostart-Haken/Beenden) funktioniert, Einstellungsseite zeigt Version/Knoepfe/Groesse.
- Why human: Diese Ausfuehrungsumgebung hat keinen Windows-PC und keine grafische Sitzung.
-
Beta-Update-Hinweis zwischen zwei Commits (WR-02-Fix)
- Test: Zwei Beta-Builds ohne neuen Tag (nur neuer Commit) — aelterer Client soll die Benachrichtigung zeigen.
- Expected: Benachrichtigung "Neue Version X.Y.Z verfuegbar" erscheint trotz gleicher
X.Y.Z-Versionsnummer, weil sich der Commit-Stempel unterscheidet. - Why human: Keine Rust-Unit-Tests fuer diese Vergleichslogik;
18-REVIEW-FIX.mdflaggt dies explizit als manuell zu pruefen.
Gaps Summary
Keine blockierenden Luecken gefunden. Der gesamte Code-Pfad (API-Modul, CI-Pipeline inkl. Windows-Cross-Bau, Web-Oberflaeche, Client-Versionspruefung/Tray, Handbuecher, REQUIREMENTS-Traceability) ist vorhanden, verdrahtet und — soweit in dieser kopflosen Umgebung moeglich — automatisiert bewiesen (API 13/13 + volle Web-Suite 365/365, beide Typpruefungen sauber, cargo check/clippy sauber, Gitea-Lauf 367 gruen mit beiden Paketdateien). Zwei Aspekte des Phasenziels sind bewusst nur bis zur Code-/Trockenlauf-Ebene bewiesen und brauchen eine echte Beobachtung: (a) der Release-Datei-Anhang, der nur bei einem echten Freigabe-Tag auslöst, und (b) die grafische Bedienprobe des Windows-Clients selbst. Beides ist von den Autoren der Phase (SUMMARY 18-06, VALIDATION.md "Manual-Only Verifications") bereits explizit als offen dokumentiert und deckt sich mit der vom Auftraggeber vorgegebenen Erwartung ("expected to be human_needed/deferred, not failures"). REQUIREMENTS.md haelt DESK-03/04/05 konsequent auf Pending, bis diese Proben abgeschlossen sind — das ist korrekt und kein Gap.
Verified: 2026-09-16T17:50:00Z Verifier: Claude (gsd-verifier)