Der Schlüssel, der doch noch da war

Inhaltsverzeichnis

Der Schlüssel, der doch noch da war

Der rote Faden dieser Woche war nicht ein einzelnes Projekt, sondern ein wiederkehrendes Muster: Mehrfach war der erste Eindruck falsch oder unvollständig, und erst ein zweiter, genauerer Blick brachte die eigentliche Wahrheit ans Licht. Ein Signierschlüssel, von dem ich einen Tag lang überzeugt war, dass es ihn nie gab. Ein E-Book, dessen ZIP-Integritätstest grün war, während das eigentliche Buch auf dem Zielgerät kaputt ankam. Docker-Container, die “unhealthy” gemeldet wurden, obwohl sie nur noch beim Hochfahren waren. Und eine Sync-Lösung, für die ich eine neue Verbindung bauen wollte — bis sich herausstellte, dass die halbe Infrastruktur dafür schon existierte, nur niemand hatte sie verbunden.

Hufpflege: Der Signierschlüssel, der angeblich nie existierte

Auf einer frischen Arch-Linux-Installation musste ich die komplette Android-Build-Kette für die Hufpflege-App neu aufsetzen — Flutter, Java, Android SDK, alles von null. Dabei kam eine unangenehme Wahrheit ans Licht: Die App lief die gesamte Beta-Zeit über nie mit einem echten Release-Schlüssel, sondern mit dem generischen Debug-Signing, das jede Flutter-Installation automatisch erzeugt. Google Play Protect blockiert Installationen bei Beta-Testern deshalb inzwischen hart — kein Warnhinweis, ein echter Stopp. Die Ursache: Debug-Signing ist der stille Standardfall bei Flutter. Wer nicht explizit einen eigenen Schlüssel einrichtet, verteilt am Ende unbemerkt mit dem Entwickler-Wegwerf-Key.

Also einen echten Release-Schlüssel erzeugt — aber vorher noch eine alte Backup-Festplatte komplett durchsucht, in der Hoffnung, dort einen früher schon “eingespielten” Schlüssel wiederzufinden, den man weiterverwenden könnte. Ergebnis der Suche: nichts. Schlussfolgerung: Es gab nie einen echten Release-Key, weder für Hufpflege noch für andere eigene Flutter-Apps.

Am nächsten Tag die Korrektur: Die alte Installation noch einmal eingebunden — diesmal nicht als Backup-Image, sondern als eigenes, vollständig zugängliches Verzeichnis. Dort lag der tatsächlich genutzte Signaturschlüssel doch. Fingerprint-Abgleich bestätigte: genau dieser Schlüssel steckt in den APKs, die aktuell bei den Testern installiert sind. “Ergebnislos gesucht” hatte sich als “nicht gründlich genug gesucht” entpuppt, nicht als Beweis der Nichtexistenz. Die Build-Kette ließ sich damit so reparieren, dass Updates auf bereits installierte Apps wieder durchlaufen, statt bei jedem Tester eine komplette Neuinstallation zu erzwingen. Der saubere, dedizierte Release-Key liegt trotzdem bereit — der Umstieg darauf ist jetzt eine bewusste, spätere Entscheidung, weil er alle bestehenden Installationen zu einer Neuinstallation zwingen würde.

Aus dem laufenden Beta-Einsatz kamen direkt im Anschluss noch zwei konkrete Bug-Meldungen. Ein Screenshot aus der Praxis zeigte den Namen eines Pferdes komplett senkrecht, Buchstabe für Buchstabe untereinander — ein verlässliches Warnsignal in Flutter dafür, dass eine benachbarte Komponente ohne Breitenbegrenzung der eigentlich flexiblen Spalte den ganzen Platz wegnimmt. Fix: beide Seiten der Zeile bekamen ein festes Größenverhältnis. Und das Dashboard aktualisierte sich nicht von selbst — vier Provider waren als dauerhaft gecacht angelegt, ohne dass irgendwo ein Invalidieren stattfand. Für Bildschirme, die über eine Tab-Leiste erreicht werden, ist automatisches Entsorgen beim Verlassen der robustere Ansatz als manuelles Invalidieren nach jeder Datenänderung — es gibt schlicht keinen zentralen Punkt, an dem man das sonst triggern könnte.

Ein E-Book, das nur auf dem Papier fehlerfrei war

Für ein interaktives Buchprojekt wollte ich eine EPUB-Fassung bauen und automatisch auf meinen E-Reader synchronisieren. Der erste Test sah sauber aus: gültiges ZIP, korrekte Kapitel-Sortierung. Auf dem Gerät ließ sich aber nur die erste Seite öffnen, der Rest des Buchs ließ sich nicht indexieren.

Der eigentliche Fehler steckte tiefer, als ein ZIP-Integritätstest je zeigen kann: Der Markdown-zu-XHTML-Export erzeugte typografische Anführungszeichen und Auslassungspunkte als benannte HTML-Entities — gültiges HTML5, aber ungültiges XML ohne DTD. Die Titelseite war handgeschrieben ohne solche Entities und öffnete deshalb klaglos; jede echte Kapitelseite enthielt sie und ließ den XML-Parser des Readers stolpern. Beim genaueren Prüfen fiel dazu noch ein zweiter Fehler auf: fünf tote interne Links, weil das Export-Skript blind jeden Wikilink in einen Sprunglink verwandelte, auch wenn das Ziel gar keine Buchseite war.

Die eigentliche Lehre: “Gültiges ZIP” heißt nicht “gültiges EPUB”. Der aussagekräftige Test ist, jede erzeugte Datei einzeln gegen einen strikten XML-Parser laufen zu lassen — genau die Prüfung, die ein ressourcenbeschränkter E-Reader beim Indexieren intern ohnehin macht. Nach dem Fix alle Dateien gegengeprüft, keine Fehler mehr, Buch läuft.

Wenn “unhealthy” nur “noch am Hochfahren” bedeutet

Nach einem Docker-Pull mit anschließendem Neustart meines Cloud-Server-Stacks (Nextcloud, Immich, Paperless-ngx, Collabora) meldeten plötzlich zwei Container “unhealthy”, dazu zeigte Nextcloud kurzzeitig einen 502 Bad Gateway. Erster Reflex: irgendwas ist kaputt. Tatsächlich: kein einziger echter Ausfall.

Paperless-ngx lief nach dem Versionswechsel gerade DB-Migrationen, eine SHA-256-Neuberechnung für 166 vorhandene Dokumente und OCR-Nachverarbeitung — der Webserver war schlicht noch nicht hochgefahren. Collabora musste sämtliche LibreOffice-Erweiterungen neu in den Container-Dateibaum verlinken, sichtbar an hunderten Logzeilen. Beide liefen nach wenigen Minuten stabil. Der 502 bei Nextcloud hatte eine eigene, interessante Ursache: Das Image hatte im Entrypoint automatisch ein Versionsupdate angestoßen, dafür kurz den Wartungsmodus aktiviert — genau in diesem Fenster lief der Health-Check des Reverse Proxys ins Leere.

Ein zusätzlicher Fund dabei: Collaboras eingebauter Docker-Healthcheck prüft grundsätzlich per HTTPS gegen sich selbst — läuft der Container aber bewusst mit externer TLS-Terminierung durch einen vorgeschalteten Reverse Proxy, schlägt der interne Check bei jedem Neustart kurz fehl, obwohl der Dienst über Klartext-HTTP korrekt antwortet. Ein reiner False Positive, der bei jedem Neustart für unnötige Verunsicherung sorgen kann, wenn man ihn nicht kennt. Die Lektion, die sich durch den ganzen Vorfall zieht: vor jeder Fehlersuche erst prüfen, ob der Container noch aktiv initialisiert — “unhealthy” heißt nicht automatisch “kaputt”.

Der Akku-Umweg, der eine halb fertige Brücke aufdeckte

Mein Obsidian-Vault synct seit Wochen per Syncthing zwischen PC, Chromebook und Handy — bis mir auffiel, dass sich der Akku meines Handys seit der Installation spürbar schneller entlädt. Die naheliegende Idee: komplett auf meine eigene Nextcloud-Instanz umsteigen. Die Recherche zeigte aber: Der offizielle Nextcloud-Android-Client bietet bis heute keinen verlässlichen bidirektionalen Ordner-Sync — eine seit Jahren offene Baustelle im Client selbst, kein Detail, das man mal eben fixt.

Der bessere Weg lag eine Ebene höher: nur das Handy auf ein Obsidian-Plugin umstellen, das sich direkt per WebDAV mit Nextcloud verbindet und den Sync innerhalb der App erledigt. PC und Chromebook bleiben bei Syncthing, wo es hervorragend funktioniert. Für die Server-Brücke dazwischen wollte ich schon eine neue Verbindung bauen — bis ein kurzer Blick zeigte, dass der Server, auf dem meine Nextcloud läuft, bereits seit Wochen selbst ein Peer im Syncthing-Netz war, mit einem eigenen, längst synchronisierten Ordner auf der Platte. Nur Nextcloud wusste nichts davon.

Ein zusätzlicher Volume-Mount machte den Ordner für den containerisierten Nextcloud sichtbar. Der nächste Stolperstein: Der Nextcloud-Prozess läuft im Container unter einem anderen Benutzer als dem, dem der Ordner auf dem Host gehört — Lesen ging sofort, Schreiben schlug fehl, ein klassisches Docker-Bind-Mount-Problem. Und selbst danach blieb eine Lücke: Nextcloud aktualisiert seinen internen Datei-Index nur, wenn es selbst eine Datei ändert, nicht wenn Syncthing im Hintergrund schreibt. Ein kleiner Cronjob stößt seitdem alle paar Minuten einen erneuten Scan an. End-to-End in beide Richtungen getestet, bevor ich das Handy tatsächlich umgestellt habe — und der Akku hält seitdem wieder länger.

Ein ERP-Konzept, das noch am selben Tag zum klickbaren Prototyp wurde

Aus einer einzelnen Frage — “gibt es für Nextcloud eigentlich ERP-Erweiterungen?” — wurde im Lauf eines Nachmittags ein vollständiges Architektur-Konzept: Termine über die Kalender-App, Kunden und Lieferanten über die Kontakte-App, Versand über die Mail-App, nur die eigentliche Geschäftslogik (Projekte, Artikel, Preise, Auswertungen) neu gebaut, statt alles doppelt zu speichern. Fünf Mockup-Screens später — Dashboard, Projekt-Auswertung, Artikelstamm, Angebots-Editor, Berechtigungsmatrix — stand noch am selben Tag ein klickbarer Prototyp: Go, HTMX, SQLite, bewusst wegwerfbar, aber mit echter Logik statt Fake-Zahlen.

Die Gewinn/Verlust-Auswertung eines Testprojekts ist eine echte SQL-Aggregation aus erfassten Stunden (bewertet mit dem individuellen Stundensatz jedes Mitarbeiters) und verbrauchtem Material — von Hand nachgerechnet, stimmte exakt mit der Programmausgabe überein. Die im Konzept diskutierte Preisbindung bei Angeboten ist ebenfalls real umgesetzt: Nach dem Versenden lässt sich ein Angebot nicht mehr bearbeiten, unabhängig davon, ob sich der zugrundeliegende Artikelpreis später ändert. Der pragmatische Kniff dahinter: Jede Angebotsposition speichert ihren Preis schon beim Anlegen fest, statt ihn bei jedem Aufruf neu vom aktuellen Artikelpreis abzuleiten — dasselbe Ergebnis, deutlich einfachere Umsetzung als ein “live bis zum Versand”-Mechanismus.

Fazit

Vier von diesen Geschichten laufen auf dieselbe Erkenntnis hinaus: Der erste, schnelle Blick reicht nicht. “Ergebnislos gesucht” war keine Bestätigung, dass ein Schlüssel nicht existiert. “ZIP ist gültig” war keine Garantie, dass das Buch funktioniert. “Unhealthy” war keine Bestätigung, dass etwas kaputt ist. Und “wir brauchen eine neue Verbindung” war keine korrekte Diagnose, wenn die halbe Verbindung längst existierte. Die eigentliche Fähigkeit, die sich durch die ganze Woche zieht, ist nicht Debugging im engeren Sinn — es ist die Bereitschaft, dem eigenen ersten Ergebnis zu misstrauen und noch einmal genauer hinzusehen.