Ein Office-Dokument öffnete am Telefon als gewandeltes PDF, weil OnlyOffices
Oberfläche auf 400 Pixeln nichts vom Dokument übrig lässt. Die Begründung war
falsch: Die Ermittlungsliste bietet zu jeder Endung mehrere Aktionen an, und
OnlyOffice/Euro-Office führen neben `edit` auch `mobileEdit` – dieselbe
Adresse mit `?mobile=1`, dahinter eine für kleine Schirme gebaute Oberfläche.
`EditURL` kannte nur `edit` und `view`; die Handy-Fassung lag die ganze Zeit
in der Tabelle und wurde nie abgerufen.
Entschieden wird am Zeigegerät, nicht an der Fensterbreite – ein schmales
Fenster auf dem Schreibtisch ist immer noch eine Maus.
Mit dem Anlass fällt die Notlösung: preview.go (229 Zeilen), convert.go (271)
samt Test, files.preview_version (Migration 000026), die Sonderabfrage im GC,
die Route und dreizehn Fundstellen im Frontend. convert.go hatte keinen
anderen Aufrufer – die gesamte Umwandlung nach PDF existierte allein für
diese Ansicht. Wer ein PDF braucht, exportiert es im Editor. Die Dateien
unter previews/ sammelt der GC ein.
Zwei Fehler, die dabei sichtbar wurden:
fix(history): „Edit" schloss die Datei, statt den Editor zu öffnen. Beim
Wechsel räumt React erst die alte Ansicht ab; der Aufräumer von useBackClose
ruft history.back(), das verzögert wirkt und deshalb den Eintrag verbrauchte,
den der Editor gerade angelegt hatte. Ein Zähler für selbst ausgelöste
Schritte verschluckt genau diese popstate.
fix(filetypes): `.txt` ging gar nicht auf. Es stand in officeExtensions und
lief damit in den Office-Zweig statt in den eingebauten Text-Editor – am
Telefon in die PDF-Umwandlung, die daran scheiterte. `md`, `log` und `rst`
standen nie drin; das war die Asymmetrie.
Dazu Euro-Office als Compose-Profil (Abbild 6,99 GB, nachgemessen – die
Ankündigung nennt 5) und die Android-App als Idee.
Geprüft: go build/vet sauber, tsc sauber, 37 Vitest-Tests, alle 234
Prüfungen der sieben Selbsttest-Suiten grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Vorschaubild entstand in einer nackten Goroutine. Chis Recoverer haengt
am Anfragebehandler und sieht davon nichts -- eine Panik im Bilddekodierer
nahm den ganzen Go-Prozess mit, ausgeloest durch einen gewoehnlichen
Upload. Die Bibliothek ist seit ef60497 aktuell; das schloss **diese**
Luecke. Dies hier schliesst die **Gattung**.
pkg/bg mit zwei Funktionen, und der Unterschied ist keine Feinheit:
* bg.Go(name, fn) -- Goroutine, die eine Panik ueberlebt
* bg.Run(name, fn) -- dasselbe ohne eigene Goroutine, fuer Schleifen
Faengt man eine Panik um den **ganzen** Arbeiter ab, ueberlebt der Prozess
-- aber der Arbeiter ist tot, und von da an wird still keine Datei mehr
erkannt. Der OCR-Arbeiter sichert deshalb jeden **Auftrag** einzeln ab.
Umgestellt: Vorschaubild, Bestand nachtragen, Freigabe-Zaehler,
Speicherbereinigung, OCR-Arbeiter. Eine nackte Goroutine bleibt mit
Begruendung im Code -- die Signalbehandlung; ein recover braechte dort
nichts, weil main ohnehin wartete.
Aufgefangene Paniken werden mit Stapel und Herkunft protokolliert. Vier
Tests, darunter der wichtige: Eine Schleife laeuft nach einer Panik im
dritten Durchgang weiter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Am Finger öffnet ein Office-Dokument jetzt das gewandelte PDF im eigenen
Betrachter; "Edit" daneben führt trotzdem in den Editor. Mit Maus ändert
sich nichts.
Der Web-Editor ist eine vollständige Textverarbeitung – zwischen seinen
Leisten bleibt auf 400 Pixeln vom Dokument ein Rechteck. Collabora und
OnlyOffice verhalten sich gleich; deshalb kein besserer Bedienmodus,
sondern ein anderes Werkzeug. Gewandelt wird von dem Server, der auch
bearbeitet: Sonst sähe man unterwegs ein LibreOffice-Layout eines
Dokuments, für das man OnlyOffice gewählt hat.
Je Dokument gibt es GENAU EIN PDF, und das ist keine Frage des
Aufräumens, sondern des Schlüssels: previews/<id>.pdf trägt die Fassung
nicht im Namen, eine neue Fassung überschreibt. files.preview_version
sagt, ob das Abgelegte noch passt.
Sicherheit: Die Adresse, die OnlyOffice zurückgibt, wird von uns
abgerufen – der Wähler des Transports lässt nur OFFICE_ALLOWED_HOSTS zu,
zusätzlich eine ausdrückliche Prüfung mit Test. JWT-Signatur (HS256) für
die eigene API des Dokumentenservers. Fremde Kennung 404, ohne Anmeldung
401. Das Ergebnis muss mit %PDF- beginnen, sonst landete eine
Fehlerseite im Zwischenspeicher.
Gemessen gegen einen echten OnlyOffice-Server im Docker-Netz:
erster Abruf 1,05 s -> zweiter 0,009 s
erneut hochgeladen -> Fassung 2, preview_version 2, weiterhin 1 Datei
GC: herrenloses PDF von vorgestern weg, echtes bleibt
endgültig gelöscht -> PDF weg; Papierkorb -> PDF bleibt
ohne Anmeldung 401, fremde Kennung 404, Nicht-Office 415
Dazu im Admin-Bereich neu: Platzbedarf der abgeleiteten Daten
(Vorschaubilder, PDFs, Profilbilder). Sie zählen gegen kein Kontingent –
ein Ordner, der wächst, ohne dass ihn jemand sieht, ist eine stille
Überraschung.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Schickt der Anbieter ein `picture`, wird es bei der Anmeldung geholt,
mittig auf 256x256 zugeschnitten und oben rechts angezeigt. Fehlt es
oder scheitert das Holen, bleibt es beim Buchstabenkreis - die
Anmeldung selbst hängt nicht davon ab.
Die Bildadresse kommt aus einem Token, also von außen. Erlaubt ist
deshalb ausschließlich der Ursprung aus OIDC_ISSUER, Weiterleitungen
eingeschlossen; dazu 4 MB und 5 Sekunden als Deckel. Ohne das wäre es
eine Aufforderung an den Server, für einen Fremden beliebige Adressen
im internen Netz anzufragen.
Neu: Migration 000019 (avatar_key/-source/-updated_at), Paket
internal/avatar, Route GET /api/v1/users/{id}/avatar. Der GC durchsucht
"avatars/" mit und kennt die Schlüssel - sonst räumte er die Bilder
nach einem Tag weg.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA.
Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb,
Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming,
Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office
(Collabora/OnlyOffice).
Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort)
sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>