Mit dem Cargo-Zwischenspeicher wuerde ein einmal einkompilierter Stempel
sonst veralten und der Beta-Update-Hinweis dauerhaft erscheinen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Alle vier Critical/Warning-Befunde aus 18-REVIEW.md sind behoben (CR-01
0d5c80f, WR-01 1b2f803, WR-02 579e24b, WR-03 a8964f1); die beiden Info-Befunde
bleiben laut Auftrag unbearbeitet (dokumentiert als uebersprungen). Status auf
clean gesetzt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
desktop-collect.sh vergibt fuer den Beta-Kanal (main) jedem Commit dieselbe
X.Y.Z-Version aus dem letzten Freigabe-Tag (D-07) -- der bisherige Vergleich
nur ueber `version` liess Nutzer zwischen zwei Tags nie eine neuere
Beta-Version sehen, obwohl manifest.json ein neues `commit`-Feld traegt.
build.rs bettet jetzt per `git rev-parse --short=7 HEAD` denselben
Commit-Stempel, den desktop-collect.sh fuer manifest.json schreibt, als
APP_COMMIT zur Kompilierzeit ein; lib.rs vergleicht bei channel == "beta"
zusaetzlich den Commit. Fuer den Live-Kanal bleibt es beim reinen
Versionsvergleich, D-07 (X.Y.Z in tauri.conf.json/Cargo.toml) bleibt
unveraendert. cargo check + cargo clippy -- -D warnings sind sauber.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Die CSP erlaubte 'unsafe-eval' und Wildcard-Quellen (connect-src/img-src/
font-src/style-src *), obwohl setup.html -- die einzige lokale Seite der App --
kein eval() nutzt, keine externen Schriften/Bilder laedt und ausschliesslich
ueber die Tauri-IPC-Bruecke (window.__TAURI__.core.invoke) mit dem Rust-Teil
spricht. Diese CSP gilt nur fuer vom App-eigenen Protokoll ausgelieferte
Seiten; nach save_server_url() navigiert das Hauptfenster auf die
Server-Adresse, und diese Navigation wird von der CSP der Zielseite selbst
bestimmt, nicht mehr von dieser Konfiguration. Verengt auf
default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self'
'unsafe-inline'; img-src 'self' data:; connect-src 'self'.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Die Zeichen-Whitelist /^[A-Za-z0-9._-]+$/ liess Namen wie ".." durch, weil
Punkt und Bindestrich erlaubte Zeichen sind -- path.join(desktopDistDir, '..')
loest aber in den Elternordner auf und unterlaeuft genau die Verteidigung in
der Tiefe (T-18-02), die diese Zeile laut Kommentar herstellen soll. Jetzt
werden "." und ".." explizit abgelehnt UND der aufgeloeste Pfad zusaetzlich
gegen desktopDistDir geprueft (haelt auch kuenftige Varianten ab, falls die
Whitelist anderswo wiederverwendet wird). Neue Testfaelle fuer manifest-Eintraege
namens "..", "." und "../manifest.json".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Ein kaputter Plattform-Eintrag (z. B. fehlendes name-Feld oder ungueltiger
sha256) fiel bisher erst spaeter unbemerkt durch -- entry.name === undefined
wurde zu "undefined" gecoerct und als Dateiname gesucht. getManifest()
prueft jetzt jeden vorhandenen Plattform-Eintrag (name: string, size: number,
sha256: 64-stelliger Hex-String) und behandelt ein kaputtes Manifest wie ein
fehlendes (404 + Warn-Log), statt die kaputte Form durchzureichen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Coverage-Block, Manuelle-Abnahme-Abschnitt mit Bedienprobe-Schrittfolge und
den zwei auf den naechsten Freigabe-Tag vertagten Punkten, Self-Check PASSED.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Neuer Abschnitt "Phase 18 — Desktop-Client fertigstellen" mit DESK-01..05
(DESK-01/02 aus Phase 6 fortgefuehrt, DESK-03..05 neu aus 18-CONTEXT.md)
- Traceability-Tabelle um fuenf DESK-Zeilen ergaenzt, Coverage-Satz aktualisiert
- Alle Gesamtlaeufe gruen: API 1086/1086, Web 365/365, beide Typpruefungen
fehlerfrei, cargo check Finished
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Betriebshandbuch: neues Kapitel 10 (Pipeline-Herkunft, Ablageort im Abbild,
Release-Anhaenge, DESKTOP_DIST_DIR, Fehlerbilder-Tabelle); Kapitel 9 um
Satz zu Desktop-Paketen im Freigabe-Tag ergaenzt
- CI/CD-Runbook: aus drei werden vier Jobs, Job desktop ausfuehrlich
beschrieben (Cross-Bau, Cache-Reihenfolge, Cache-vs-upload-artifact-
Begruendung), Fehlerbehebung um drei Unterabschnitte ergaenzt
(Job desktop, cache miss, Release-Upload 413)
- Entwicklungshandbuch: apps/desktop ist kein Grundgeruest mehr, neuer
Abschnitt "Desktop-App lokal bauen", Testabschnitt um vitest src/desktop
und cargo check/clippy ergaenzt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Neues Kapitel "Desktop-App" (9 Unterabschnitte: Was es ist, Herunterladen,
Installation Windows/Linux, Erster Start, Infobereich/Beenden, Automatischer
Start, Neue Version, Fehlerbilder), Inhaltsverzeichnis um Punkt 8 ergaenzt
- CHANGELOG-Stichpunkt unter Unveroeffentlicht/Neu im Wortlaut von D-17
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Job desktop, Schritt "Rust pruefen": `cargo clippy` scheiterte mit
"'cargo-clippy' is not installed for the toolchain 'stable-x86_64-unknown-linux-gnu'"
(minimal-Profil enthaelt clippy nicht). `rustup component add clippy` direkt
nach der Toolchain-Installation ergaenzt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Baut nach dem AppImage zusaetzlich den Windows-Installer per Cross-Bau auf
dem Linux-Runner (cargo-xwin, NSIS aus dem Ubuntu-Paket), cached SDK und
NSIS-Plugins, und sammelt beide Dateien mit --require linux,windows ein.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- setup.html spricht nur noch über window.__TAURI__.core.invoke (kein
Modul-Import mehr, der im gebauten Client ohnehin scheiterte), prüft die
Adresse über check_server und speichert sie über save_server_url
- Sie-Form-Texte, Tessera-Zeichen als inline-SVG, Markengelb/-Olive,
keine vorbelegte Server-Adresse
- CSP ohne Fremdhost (unpkg.com entfernt), da nichts mehr von außen geladen wird
- Icon-Satz aus apps/web/src/app/icon.svg neu erzeugt (512, 128, 128@2x, 32,
ICO mit 16-256) statt der bisherigen flachen gelben Quadrate
- Versehentlich verschachteltes apps/desktop/src-tauri/apps/ entfernt
- Lokaler AppImage-Bau (Tessera-1.1.0.AppImage, ~103 MB) erfolgreich, von
desktop-collect.sh eingesammelt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- tauri-plugin-opener@2 hinzugefügt (Legitimität in RESEARCH geprüft)
- Neue Rust-Kommandos check_server/save_server_url für die Erststart-Seite,
Adressen laufen über api_url() ausschließlich über /api-proxy/*
- Versionsprüfung gegen /api-proxy/desktop/latest statt /health/version,
schaltet den Tray-Eintrag "Update herunterladen" frei und benennt ihn um
- Tray-Menü: Öffnen · Update herunterladen · Autostart-Haken · Beenden,
echte Umlaute, Update-Eintrag öffnet die Download-Seite im Systembrowser
- capabilities/default.json: opener:allow-open-url für http/https
- cargo check und cargo clippy grün
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Neue Route /settings/general/desktop (DesktopSettingsPage)
- DesktopAppSettings: Version, zwei Primaerknoepfe mit Plattform-Symbol,
Dateiname/Groesse je Knopf, Beta-Kanal-Hinweis, vier erklaerende Saetze,
Hinweistext wenn keine Pakete hinterlegt sind
- Seitenleiste: Eintrag "Desktop-App" unter "Allgemein"
- de/en: settings.categoryDesktopApp, settings.desktop.*
- umlaut-dictionary.ts: "neuere" zur Allowlist ergaenzt (Rule 1 —
Waechter-Test brach an einer bereits korrekten Umlautschreibung, die
zufaellig die Buchstabenfolge "ue" enthaelt)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- apps/web/src/lib/desktop.ts: loadDesktopLatest (memoisiert, still bei
Fehler), desktopDownloadUrl, formatFileSize (lokalisierte MB-Werte)
- DesktopDownloadLinks: unauffaelliger Link-Block, rendert nichts ohne
Daten; Windows fuehrt, Linux als Kurzlink wenn beide Pakete vorliegen
- Anmeldeseite bindet den Block nach dem Formular ein (D-12)
- de/en: auth.desktopDownload.* ergaenzt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- upload_asset() nach dem bestehenden GET-then-PATCH/POST-Idempotenzmuster:
GET .../assets -> vorhandene Datei gleichen Namens per DELETE entfernen ->
frisch per POST multipart (Feld attachment) hochladen
- Zweite Header-Datei HDR_AUTH (nur Authorization, kein JSON-Content-Type) fuer
den multipart-Upload; Token bleibt in Header-Dateien, nie als Argument (T-18-03)
- Nach Release-Anlage/-Aktualisierung wird jede Datei aus desktop-dist/manifest.json
hochgeladen; fehlt das Manifest bei einem Freigabe-Tag, bricht das Skript hart ab
- --dry-run listet zusaetzlich die geplanten Uploads aus dem Manifest, ohne Netzaufruf
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Neuer CI-Job desktop nach test, laeuft auf main und bei Tags v* (Systemabhaengigkeiten,
Rust-Toolchain per rustup, Cargo-Zwischenspeicher, Version setzen, cargo check/clippy,
alte Bundles entfernen, Linux-AppImage bauen, desktop-collect.sh --require linux,
Uebergabe per actions/cache/save mit Schluessel desktop-dist-${{ gitea.sha }})
- publish haengt jetzt an desktop (needs: desktop) statt an test, holt die Pakete per
actions/cache/restore mit fail-on-cache-miss: true und prueft das Manifest hart
- publish-images.sh bricht im echten Baupfad ohne desktop-dist/manifest.json ab
(zweites Netz gegen einen Cache-Fehlschlag, D-08/Pitfall 1)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SUMMARY: 8 gruene Spec-Tests, Typpruefung fehlerfrei, lokaler Stack
liefert /desktop/latest und /desktop/download/linux auf Basislinie
1.1.0 aus. Ein Deviation-Eintrag (Rule 3): @Inject(DesktopService)
explizit noetig, da Vitest ueber esbuild ohne emitDecoratorMetadata
transpiliert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
desktop-version.sh (D-07): schreibt die reine X.Y.Z-Form des letzten
Freigabe-Tags in tauri.conf.json und Cargo.toml; --print nur zur
Anzeige, keine Vorab-/Metadatenform wird je geschrieben (Pitfall 2 —
NSIS-Ressourcen sind rein numerisch). Negativproben (v1.2.3-beta
abgelehnt, v2.0.0 akzeptiert aber ungeschrieben) bestehen.
Basislinie 1.1.0 (aktueller Tag v1.1.0) in tauri.conf.json, Cargo.toml,
Cargo.lock (cargo check) und package.json eingecheckt — die Wahrheit im
CI bleibt der Tag, dies ist nur die Vorgabe fuer lokale Baue.
Frischer AppImage-Bau mit der Basislinie bestaetigt: desktop-collect.sh
liefert jetzt Tessera-1.1.0.AppImage samt Manifest.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Die duenne Strecke Skript -> Abbild -> API beweisen (D-08, D-10):
- desktop-collect.sh sammelt AppImage/exe ein, schreibt manifest.json
(Version, Kanal, Commit, Groesse, SHA-256) ohne Secrets
- apps/api/src/desktop/: neues Modul mit GET /desktop/latest und
GET /desktop/download/:platform, beide @Public(); Plattform-Whitelist
vor jedem Dateisystemzugriff, Dateiname ausschliesslich aus dem
Manifest (T-18-01, T-18-02)
- packages/shared: DesktopPlatform/-Manifest(File)/-Latest(Response)
Typen
- Dockerfile kopiert desktop-dist/ in die runner-Stufe; desktop-dist/
per .gitkeep + .gitignore versioniert (leeres Verzeichnis, Pakete
bleiben ungetrackt)
- HTTP-Durchstich-Spec (8 Tests) via NestFactory, kein fs-Mock; echtes
Temp-Verzeichnis + unabhaengig berechneter SHA-256
Abweichung: DesktopController braucht @Inject(DesktopService) explizit
— Vitest transpiliert ueber esbuild, das emitDecoratorMetadata nicht
abbildet, sonst bleibt desktopService bei einem echten NestFactory-Bau
undefined (Rule 3, Blocker).
Lokal bewiesen: neu gebautes API-Abbild liefert /desktop/latest (200)
und /desktop/download/linux (200, attachment) aus, auch ueber
/api-proxy/ des Web-Containers.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cargo-xwin/NSIS-Toolchain gegen Cargo.lock und offizielle Tauri-Doku geprueft, act_runner-Cache-Server live bestaetigt (Docker-Inspektion), Paket-Legitimitaet fuer tauri-plugin-opener/cargo-xwin gecheckt, bestehende Codebase-Muster (DkvService-Pfadschutz, app-version.ts, @Public()) als Vorlage fuer das neue Desktop-Modul dokumentiert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Plaketten-Wrapper calendar-day-badges rendert buildDayBadges(day.events) statt der alten Einzel-Plakette
- Ein Kalender: unveraendert eine Plakette in Kalenderfarbe/Akzentfarbe (Tests 3/3b/3c bleiben gruen)
- Zwei/drei Kalender: je ein kleiner Kreis pro Kalender in Startreihenfolge (Test 3d)
- Vier oder mehr Kalender: zwei Kreise plus grauer Restkreis bg-muted-foreground/text-background mit Summe (Test 3e)
- CHANGELOG-Stichpunkt erweitert (mehrere Kalender am selben Tag)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- groupDayBySource gruppiert Tagestermine nach sourceId (nicht Farbe), Reihenfolge = erstes Auftreten, Farbe = Farbe des ersten Termins der Gruppe
- buildDayBadges baut daraus bis zu drei Plaketten-Kreise, ab dem vierten Kalender einen grauen Restkreis mit Summe
- Tests 8/9 in calendar-month.test.ts (TDD: RED bestaetigt vor Implementierung)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Tailwind-Preflight setzt list-style: none in @layer base, markdown.css stellt es nicht wieder her
- Ungeschichteter CSS-Block in globals.css schlaegt die Layer-Regel fuer .wmde-markdown ul/ol
- Aufgabenlisten mit Kaestchen bleiben ohne Punkt
- CHANGELOG.md: zwei Stichpunkte unter Unveroeffentlicht ergaenzt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- groupEventsByDate sortiert jede Tagesgruppe jetzt nach Start aufsteigend
- Zaehl-Plakette im Monatsraster traegt die Farbe des Kalenders des fruehesten Termins (weisse Schrift), ohne Farbe unveraendert bg-primary
- Tooltip-Zeilen bekommen denselben Farbpunkt wie die Liste "Naechste Termine" (Rueckfall var(--muted-foreground))
- 3 neue Tests: calendar-month Test 2b, calendar-widget Test 3b/3c
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Vorlage aus dem Auftragsordner uebernommen (28 Stichpunkte, 3 Versionen)
- Sachlich unveraendert, nur Fassung gestrafft
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- useTheme (next-themes) + mounted-Guard wie changelog-view.tsx
- data-color-mode am Wurzel-Div folgt resolvedTheme statt fest 'auto'
- zwei neue Tests (dark/light) via vi.hoisted-Themenzustand
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Titel-Span im Tooltip: min-w-0 break-words statt truncate
- Breite (288px) und Rand-Klemmung aus TOOLTIP_WIDTH_PX/TOOLTIP_EDGE_PX
- Test 4c: belegt Klassen und Tooltip-Breite
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>