Ctrl K
ComunidadGuías…

CHANGELOG.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Changelog

## 3.8.3 – Oktober 2026

### Sicherheit
- 🔒 **Zugriff ohne Portfreigabe: stumme Verbindungen gehen wieder zu.**
  Ein Gerät, das sich über den Vermittler meldet, aber den verschlüsselten
  Handschlag nicht schickt, hielt bisher seinen Platz, solange es wollte.
  Weil der Vermittler je Instanz nur acht Geräte gleichzeitig zulässt,
  konnte so jemand alle Plätze besetzen, und die eigenen Geräte kamen nicht
  mehr hinein. Jetzt schließt Nupplo jede Verbindung, die nach zehn Sekunden
  noch keinen Handschlag hat. Gekoppelte Geräte merken davon nichts, ihr
  Handschlag dauert Millisekunden.

## 3.8.2 – Oktober 2026

### Geändert
- 🔒 **Der Figurenkatalog kommt verschlüsselt.** Die Beschreibungen, mit
  denen die Suche Figuren nach ihrem Aussehen findet, standen bisher als
  Klartext in `katalog/index.ndjson` – und damit unter der MIT-Lizenz des
  Repos, also für jeden frei nehmbar. Sie sind aber eigene Arbeit des
  Projekts und sollen nur in Nupplo genutzt werden. Jetzt lädt Nupplo
  `katalog/index.nupplo`, Zeile für Zeile verschlüsselt, und der Ordner
  `katalog/` hat eine eigene Lizenz (`katalog/LIZENZ.md`): Nutzung nur in
  Nupplo. Der Schlüssel steht in Nupplo selbst – jede Installation bekommt
  den Katalog weiter ohne Anmeldung und ohne Hub. Die Verschlüsselung ist
  bewusst ein Schild, keine Festung: Wer sie umgeht, weiß, dass der Inhalt
  nicht für ihn bestimmt ist. Ein paar Kontrollzeilen machen eine Kopie
  erkennbar; Nupplo übergeht sie. Das Format steht in
  `docs/KATALOG-FORMAT.md`.
- 📣 **Ältere Fassungen bitten ums Update.** An der alten Stelle liegt nur
  noch ein Hinweis. Wer nicht aktualisiert, findet bei der Suche nach
  Aussehen statt Figuren die Bitte, Nupplo zu aktualisieren – mit dem
  Grund dafür. Nach dem Update verschwinden diese Hinweise von selbst, und
  jede Beschreibung kommt aus der neuen Datei zurück. Wer die alte Adresse
  als Katalogquelle eingetragen hatte, wird still auf die neue umgelenkt.
- 🇩🇪 **Beschreibungen werden beim Abruf eingedeutscht**, nicht nur einmal
  beim Start. Sonst wären alle Beschreibungen, die nach dem Hinweis neu
  kommen, englisch geblieben, und „gelber Kopf“ fände nichts mehr.

Sonst ändert sich nichts – dieses Update bringt nur die neue Katalogdatei
und ihren Schlüssel.

## 3.8.1 – Oktober 2026

### Geändert
- 📘 **Der Verweis auf die Bauanleitungen steht nicht mehr in der
  Hauptansicht.** Beim Set in der Sammlung liegt er im Steckbrief unter
  **Mehr → Nachschlagen**, neben Preisverlauf und BrickLink; im
  Katalogfenster hinter **Mehr ▾** neben „Bei BrickLink ansehen“. Das 📘
  neben den Sets einer Figur ist weg – wer die Anleitung sucht, öffnet das
  Set und findet sie dort unter „Mehr“.

## 3.8.0 – Oktober 2026

### Neu
- 📘 **Verweis auf die Bauanleitungen bei LEGO.** Bei Sets – in der
  Sammlung und im Katalog – und bei Figuren in der Liste „in Sets“ führt
  ein Verweis zu LEGOs Seite mit den Bauanleitungen zur Setnummer.
  **Optional und ausgeschaltet voreingestellt:** Unter *Mehr → 📘
  Bauanleitungen* wählst du, ob er nur in der Browseransicht, nur in der
  Handyansicht oder in beiden erscheint. Artikelseiten verlinken wir
  nicht – die gibt es bei LEGO nur für Sets, die gerade verkauft werden.

## 3.7.4 – Oktober 2026

### Behoben
- 🔎 **„Badehose Stormtrooper" findet den Stormtrooper in Badehose.** Für
  diese Anfrage hatte sich die Instanz früher eine Übersetzung vom Modell
  gemerkt (`stormtrooper helmet`), und die ging der Liste vor – auch
  nachdem die Liste „Badehose" kannte. Jetzt stehen die Fassungen der
  Liste vorn, das Gelernte dahinter, und gesucht wird mit allen.
- 🔎 **Die eigene Sammlung findet auch über die Bildbeschreibung.** Bisher
  verglich der zweite Anlauf dort nur Namen. Eine Figur, deren Badehose
  nur in der Beschreibung steht, fand die Katalogsuche, die eigene
  Sammlung aber nicht.

## 3.7.3 – Oktober 2026

### Behoben
- 🔎 **„Badehose" findet etwas.** Das Wort fehlte im mitgelieferten
  Wörterbuch, und ein unbekanntes Wort zählt als Pflichtwort – die Suche
  lief leer, obwohl eine Figur in Badehose im Katalog steht. Ergänzt sind
  Badehose, Whirlpool, Bademantel, Schlafanzug, Trainingsanzug, Laborkittel,
  Fliege, Schlittschuhe, Rettungsring und weitere Alltagswörter rund um
  Kleidung und Freizeit.
- 🔎 **Ein unbekannter Wortteil leert die Suche nicht mehr.** Kennt die
  Liste den vorderen Teil eines zusammengesetzten Worts nicht, gilt
  wenigstens der hintere – eine „Quatschhose" ist eine Hose. Namen wie
  Skywalker oder Dumbledore bleiben unangetastet.

## 3.7.2 – Oktober 2026

### Geändert
- 📣 **„Meine Mitteilungen vom Hub-Admin“ erscheint nur, wenn etwas drin
  ist.** Bisher stand der Kasten im Tausch-Tab auch leer da – obwohl man den
  Hub-Admin von dort gar nicht anschreiben kann. Sind alle Mitteilungen
  gelöscht, verschwindet er.

## 3.7.1 – Oktober 2026

### Sicherheit (externer Zugriff ohne Portfreigabe)
- 🔒 **Gelöschte Benutzer nehmen ihre gekoppelten Geräte mit.** Bisher
  blieben die Geräte stehen und kamen weiter bis zur Anmeldeseite. Jetzt
  verschwinden sie samt offenen Kopplungscodes, und bestehende Verbindungen
  werden sofort getrennt.
- 🔒 **Eine kaputte Nachricht trifft nur ihre eigene Verbindung.** Ein
  gekoppeltes Gerät konnte mit einer fehlerhaften Nachricht die Leitung für
  alle Geräte kurz abreißen lassen. Außerdem sind Anfragen je Verbindung auf
  160 MB begrenzt; darüber gibt es „413“.
- 🔒 **Die Herkunft kommt nie aus Kopfzeilen des Geräts.** Fehlte die
  Adresse vom Vermittler, zählte die Bremse gegen Passwortraten nach der
  vom Gerät gesetzten Absender-Kopfzeile. Solche Kopfzeilen werden jetzt
  verworfen; ohne Adresse zählt eine feste Kennung je Gerät.

## 3.7.0 – Oktober 2026

### Neu
- 🗑 **Mitteilungen vom Hub-Admin löschen.** Unter „Meine Mitteilungen vom
  Hub-Admin“ hat jeder Eintrag jetzt „Löschen“. Die Mitteilung verschwindet
  nur bei dir und gilt als gelesen; der Hub-Admin behält sie in seinem
  Verlauf. Braucht Hub 1.27.0.

## 3.6.0 – Oktober 2026

### Neu
- 🚫 **Zur Sperre selbst Stellung nehmen.** Im Kasten „Zugang gesperrt“
  stand bisher nur, dass und warum gesperrt ist – widersprechen ließ sich
  nicht. Jetzt steht darunter „Stellung nehmen“ (bis 2000 Zeichen, nur der
  Hub-Admin liest es; erneutes Senden ersetzt die frühere Stellungnahme).
- 🚫 **Auch ohne Mitgliedskonto.** Lehnt der Hub schon den Beitritt ab, weil
  die Installation gesperrt ist, sagt das jetzt *Mehr → Tausch-Netzwerk*
  samt Grund – und bietet dieselbe Stellungnahme an. Dann spricht die
  Installation mit ihrer Kennung statt mit einem Konto. Braucht Hub 1.26.0.

## 3.5.0 – Oktober 2026

### Neu
- 📣 **Zu einer Mitteilung des Hub-Admins Stellung nehmen.** Bisher blieb
  eine Verwarnung ohne Gegenrede im Verlauf stehen – man konnte sie nur mit
  „Verstanden“ wegdrücken. Jetzt steht daneben „Stellung nehmen“: ein Feld
  für bis zu 2000 Zeichen, das nur der Hub-Admin liest. Erneutes Senden
  ersetzt die frühere Stellungnahme. Braucht Hub 1.25.0.
- 📣 **Meine Mitteilungen vom Hub-Admin.** Im Tausch-Tab stehen alle
  Mitteilungen an dich, auch bestätigte, mit deiner Stellungnahme.
  Zurückgenommene bleiben durchgestrichen mit Datum und Begründung stehen.
- 🚫 **Auch gesperrt kann man Stellung nehmen.** Der Hub beantwortet die
  eigenen Mitteilungen auch während einer Sperre; die Liste ist dann gleich
  aufgeklappt. Das Lesen hebt den Sperrhinweis nicht auf – bisher galt jede
  erfolgreiche Antwort des Hubs als Freischaltung.

## 3.4.4 – Oktober 2026

### Behoben
- 🎨 **„rote Beine" findet jetzt, was der Name sagt.** Die Farbsuche schaute
  bisher nur in die Farbliste der Bildanalyse. Nannte der BrickLink-Name
  „… Red Legs", fehlte Rot aber in der Liste, fiel die Figur heraus – und
  umgekehrt kam „Red Torso, Blue Legs" herein, weil Rot irgendwo stand.
  Jetzt liest Nupplo SE aus dem Namen, welches Teil welche Farbe hat
  (`backend/namensfarben.py`): Fragt jemand nach einem Teil, entscheidet
  der Name; ohne Teil holt er eine Figur nur noch herein, hinter die
  Treffer der Farbliste („roter Droide" bleibt R-3PO).
- Gelesen wird nur „<Farbe> <Teil>" – Details wie „Short Red Stripes"
  machen weiter keinen roten Droiden. Und es bleibt **lokal**: Die Namen
  holt jede Instanz über ihren eigenen BrickLink-Zugang, weitergegeben
  wird nichts.

## 3.4.3 – Oktober 2026

### Geändert
- 📚 **Der Katalog-Abzug hat eine eigene Karte.** Bisher stand er samt
  Stand („… Figuren und … Sets · zuletzt geholt am …“) unten in der Karte
  „Lokale KI für die Suche“ – dort sucht ihn niemand. Jetzt unter
  **Mehr → 📚 Katalog-Abzug**. Die Zahlen im Erklärtext stimmen wieder
  (gut 19.000 Figuren, gut 6 MB).

### Neu
- 🔄 **Beim Öffnen der App wird der Katalog-Abzug nachgesehen** – wie bei
  den übrigen Nupplo-Oberflächen, statt bis zu zwölf Stunden auf den
  nächsten Hintergrundlauf zu warten. Geholt wird nur, was sich geändert
  hat, höchstens alle 15 Minuten, ohne BrickLink-Kontingent (die Namen
  schlägt weiter der Hintergrundlauf nach). Die Karte zeigt dazu
  „Zuletzt nachgesehen: …“.

## 3.4.2 – Oktober 2026

### Behoben
- 🐞 **Fehlerliste: kopierter Text und Issue nennen jetzt auch die jüngste
  Fassung.** Bisher stand dort nur die Version vom ersten Auftreten – ein
  heute wieder aufgetretener Fehler sah so aus, als käme er von einer Seite,
  die seit Tagen nicht neu geladen wurde. Jetzt steht dort wie in der Karte
  „2.92.0 → 3.4.0 (zuerst → zuletzt)“.

## 3.4.1 – Oktober 2026

### Behoben
- 🤝 **Angebote ziehen nach dem Abgleich selbst nach.** Wurde eine im
  Tausch-Netzwerk angebotene Figur über externen Zugriff verkauft oder
  geändert, stand das alte Angebot weiter im Netz – neu veröffentlichen
  durfte nur ein Admin. Jetzt veröffentlicht die Instanz nach so einem
  Abgleich im Hintergrund neu, wie nach einem Tausch (nur, wenn schon einmal
  veröffentlicht wurde).

## 3.4.0 – Oktober 2026

### Neu
- 🤝 **Verkaufslisten im Tausch-Netzwerk.** Unter einer Verkaufsliste steht
  „🤝 Im Netz anbieten“: Die offenen Artikel erscheinen im Netzwerk als
  Verkauf, so viele Stück wie auf der Liste, **mit Preis je Stück** (aus dem
  Preisfeld der Liste, sonst Ø-Marktwert). „Aus dem Netz nehmen“ zieht sie
  zurück; angebotene Artikel tragen „🤝 im Netz“.
- **Liste und Netzwerk wissen voneinander:** Auf der Liste als verkauft
  abgehakt → raus aus dem Angebot. Über das Netzwerk verkauft und
  ausgetragen → die Liste hakt den Artikel von selbst ab, ohne die Sammlung
  ein zweites Mal anzufassen.
- 💶 **Preise an Angeboten.** Wer mit Preis anbietet, bei dem steht er an
  der Karte – unter Angebote, in Entdecken und im Profil. Braucht Hub 1.24.0.

## 3.3.3 – Oktober 2026

### Behoben
- ↩︎ **Rückgängig bei Verkäufen aus der App.** Was in der iOS-App verkauft
  wurde, trägt keinen Schnappschuss des alten Stands. „Rückgängig“ in der
  Web-App setzte dann nur den Haken zurück, die Stücke fehlten weiter in
  der Sammlung. Jetzt sagt sie „In der App verkauft – bitte dort
  zurücknehmen“ und lässt alles, wie es ist.

## 3.3.2 – Oktober 2026

### Behoben
- 🏷️ **„ab … €“ passt zum Zustand.** Die Angebotsmarke in Einkaufs- und
  Verkaufslisten (und bei den Doppelten) zeigte immer den billigsten
  **gebrauchten** Preis, auch bei Artikeln im Zustand Neu. Jetzt steht dort
  „ab … neu“ bzw. „ab … gebraucht“, passend zum Artikel. Weiterhin eine
  Abfrage je Zeile – das BrickLink-Tageslimit wird nicht stärker belastet.

## 3.3.1 – Oktober 2026

### Verbessert
- 💰 **Gesamterlös auf Verkaufslisten.** „💰 Gesamtpreis“ verteilt einen
  Betrag anteilig nach Marktwert auf die offenen Artikel – auf einer
  Verkaufsliste heißt das Feld jetzt „Gesamterlös“, und der Vorschlag ist
  der volle Marktwert statt des Angebots-Anteils (60 %), der fürs Einkaufen
  gedacht ist.

## 3.3.0 – Oktober 2026

### Neu
- 💰 **Verkaufslisten.** Über den Stift ✏️ an einer Liste lässt sich jetzt
  auch die Art wählen: Einkaufs- oder Verkaufsliste. Eine Verkaufsliste tut
  beim Abhaken das Gegenteil – **„✔ Verkauft – raus aus der Sammlung“**
  nimmt die Stücke aus der Sammlung, das Kaufbuch geht mit, und die letzten
  Stücke nehmen die Zeile mit. Im Preisfeld steht der Erlös; er zählt nicht
  als Einkauf. „Rückgängig“ legt Menge, Kaufbuch und Notiz genau zurück.
- Das Listen-PDF schlägt für Verkaufslisten gleich die Verkaufsfassung vor.

### Geändert
- Der Stift an einer Liste öffnet jetzt einen Dialog mit Name und Art statt
  einer Zeile nur zum Umbenennen.

## 3.2.1 – Oktober 2026

### Verbessert
- 📄 **Listen-PDF kommt fertig vom Server.** Bisher lief es über den
  Druckdialog des Browsers – am iPhone ohne „Als PDF sichern“, mit Rändern
  und Skalierung nach Gutdünken. Jetzt baut die Instanz das PDF selbst
  (gleiches Aussehen überall, Nunito wie in der App, Seitenzahlen). Am
  Handy geht danach das Teilen-Menü auf (In Dateien sichern, AirDrop,
  Mail), am Rechner wird die Datei heruntergeladen – als
  „Verkaufsliste ‹Name›.pdf“ bzw. „Einkaufsliste ‹Name›.pdf“.

### Für Betreiber
- Neue Abhängigkeit **fpdf2** (reines Python). Wer das Image zieht oder
  mit `update.sh` baut, muss nichts tun.

## 3.2.0 – Oktober 2026

### Neu
- 📄 **Listen als PDF.** Unter jeder Einkaufsliste steht „📄 PDF“, zur
  Auswahl in zwei Fassungen:
  - **🛒 Einkaufsliste** – alle Artikel mit Bild, Zustand, Menge, Ø-Preis,
    Summe, eingetragenen Einkaufspreisen und einem Kästchen zum Abhaken.
  - **💰 Verkaufsliste** – für den Käufer: nur die offenen Artikel, ein
    Preis je Stück (auf Wunsch ein Anteil vom Marktwert, z. B. 90 %) und
    die Summe – **ohne** eigene Einkaufspreise.
  Oben Wortmarke, Listenname und Eckdaten; gedruckt bzw. gesichert über den
  Druckdialog des Browsers („Als PDF sichern“).

## 3.1.3 – Oktober 2026

### Neu
- 🎬 **Neues Startbild.** Die Wortmarke steht größer da, die
  Steine fallen von weit oben ein und federn nach, „Nupp“ und „o“ gleiten
  weiter heran. Darunter steigen ein **Gruß zur Tageszeit** („Guten
  Morgen, Mia!“, ohne Anmeldung schlicht „Guten Morgen!“) und der Spruch
  auf. Der Name der Sammlung steht dort nicht mehr – er bleibt bei der
  Anmeldung.
- Der Gruß in der Kopfleiste spricht jetzt genauso wie das Startbild:
  „Guten Morgen“ bis 11 Uhr, „Hallo“ bis 18 Uhr, „Guten Abend“ bis 23 Uhr,
  danach „Noch wach?“.

## 3.1.2 – Oktober 2026

### Neu
- 🔐 **„Nur mit zweitem Faktor“** für den Zugriff ohne Portfreigabe
  (*Mehr → Nach außen*, Admin). Dann kommt über den Vermittler nur herein,
  wer die Zwei-Faktor-Anmeldung eingerichtet hat; im Heimnetz ändert sich
  nichts.

### Warum
- Gemeldet: Über den Vermittler kam keine Code-Abfrage. Das Konto hatte
  keinen zweiten Faktor – gefragt hatte bisher Cloudflare Access vor der
  Web-App, und dieser Weg führt nicht durch Access.
- **Geprüft wird bei jeder Anfrage, nicht nur beim Anmelden.** Ein Gerät
  meldet sich zu Hause oft direkt an und geht erst unterwegs über den
  Vermittler; eine Prüfung nur beim Anmelden hätte diese Sitzung
  durchgelassen.

## 3.1.1 – Oktober 2026

### Neu
- 🧱 **„Jede Noppe zählt.“** – der neue Spruch unter der Wortmarke im
  Startbild und bei der Anmeldung (englisch „Every stud counts.“). Nupplo
  kommt von „Noppe“.

### Doku
- Neue Bildschirmfotos in der README: Scannen, Sammlung, Einkaufsliste,
  Statistik, eigene Fotos und Sicherung – mit der Nupplo-Kopfleiste und
  erfundenen Beispieldaten.

## 3.1.0 – Oktober 2026

### Neu
- 📡 **Zugriff ohne Portfreigabe.** Nupplo SE kann von sich aus eine
  Verbindung zu einem Vermittler (`connect.nupplo.com`) aufbauen und offen
  halten. Externe Geräte erreichen die Instanz darüber, ohne dass am Router
  etwas freigegeben wird – ohne Domain, ohne Tunnel, ohne zweiten
  Container. Aus, bis ein Admin es unter *Mehr → Nach außen* einschaltet.
  **Im Aufbau:** Der Vermittler nimmt vorerst nur freigeschaltete
  Instanzen an.
- 🔐 **Ende zu Ende verschlüsselt** mit dem Noise-Protokoll (IK). Der
  Vermittler reicht nur durch und kann nichts lesen. Geprüft gegen die
  offiziellen Testvektoren.
- 📱 **Geräte koppeln per QR-Code** im Profil: Einmalcode, zehn Minuten
  gültig. **Nur gekoppelte Geräte kommen durch** – ein fremdes Gerät sieht
  nicht einmal die Anmeldeseite. Entkoppeln beendet auch eine gerade offene
  Verbindung. Angemeldet wird danach wie immer.
- „Von außen genutzt“ in den Einstellungen zum zweiten Faktor kennt den
  neuen Weg und meldet ihn nicht als „ohne Zugangsschutz“.

### Warum so gebaut
- **Anfragen gehen im Prozess an den Server**, nicht über eine
  HTTP-Bibliothek an 127.0.0.1. Im Probelauf hängte eine solche Bibliothek
  von sich aus `Accept-Encoding: gzip` an, und Fotos kamen gepackt an,
  obwohl niemand danach gefragt hatte. Kopfzeilen gehen jetzt unverändert
  durch; ein Test hält das fest.
- **Die Absenderadresse des Geräts** gibt der Verbinder als Client-Adresse
  weiter. Sonst hätte die Sperre gegen Passwortraten („je Herkunft“) alle
  Geräte gemeinsam gebremst.
- **Die Anmeldung beim Vermittler trägt eine Zufallszahl.** Ed25519
  unterschreibt gleichen Inhalt immer gleich; eine Instanz, die sich in
  derselben Sekunde neu verbindet, wäre sonst als Wiederholung abgewiesen
  worden (beim Bau bemerkt).
- Der Schlüssel liegt als `connect.key` neben dem Geheimnis, nicht in der
  Datenbank – Sicherungen wandern herum.

## 3.0.1 – Oktober 2026

**Das Repository heißt jetzt [Melle79/nupplo](https://github.com/Melle79/nupplo).**
Die alte Adresse leitet weiter – Links, `git`, `update.sh` und die
Katalogdatei kommen dort weiter an.

### Neu
- 👋 **Gruß in der Kopfleiste** statt des Namens über der Wortmarke:
  „Guten Morgen“, „Guten Abend“ … mit dem eigenen Benutzernamen, passend
  zur Tageszeit. Der Name der Sammlung steht weiter im Startbild und bei
  der Anmeldung.

### Behoben
- **Update-Hinweis nach dem Umzug.** Die Prüfung liest, wohin
  `…/releases/latest` weiterleitet. Seit dem Umzug steht davor eine zweite
  Weiterleitung – vom alten auf den neuen Namen –, und der folgte sie
  nicht. Jetzt folgt sie bis zu drei Sprüngen, nur innerhalb von GitHub.
  **Wer 3.0.0 oder älter betreibt, bekommt den Hinweis auf diese Fassung
  deshalb nicht angezeigt** und aktualisiert einmal von Hand.
- Fehler melden legt die Issues im neuen Repository an; ein noch auf
  `Melle79/brickfolio` gesetztes `GITHUB_REPO` gilt als der neue Name.

## 3.0.0 – Oktober 2026

**Brickfolio heißt jetzt Nupplo SE** – SE steht für *Server Edition*, die
Fassung, die man selbst betreibt. Gleiche App, neuer Name – bestehende
Installationen laufen ohne Umstellung weiter.

### Neu
- 🧱 **Neuer Name und neues Logo.** Die Wortmarke „Nupplo“, deren l ein Turm
  aus vier Steinen ist – oben gelb, dann rot, blau, unten grün. Sie steht im
  Startbild, bei der Anmeldung und in der Kopfleiste, mit einem kleinen
  „SE“ daneben, und nimmt die Farben jedes Designs an.
- 🎬 **Startbild:** Der Turm baut sich Stein für Stein auf, dann gleiten die
  Buchstaben heran. Wer „Bewegung reduzieren“ eingestellt hat, sieht alles
  sofort.
- 📲 **Neues App-Symbol:** der Steinturm auf Gelb, mit dem Namen der Instanz
  darüber, wenn einer eingestellt ist. Auf dem Startbildschirm erscheint es
  beim nächsten Hinzufügen.
- 🔔 Nach dem Update sagt ein einmaliger Hinweis, dass Brickfolio jetzt
  Nupplo SE heißt.

### Für Betreiber
- **Nichts umstellen nötig.** Datenbank (`data/brickfolio.db`), tägliche
  Sicherungen und JSON-Sicherungen behalten ihre Namen und ihr Format –
  Sicherungen lassen sich weiter in ältere Instanzen einspielen.
- **Docker-Image:** Neu ist `ghcr.io/melle79/nupplo` (und `melle79/nupplo`
  auf Docker Hub). Das bisherige `…/brickfolio` bekommt während eines
  Übergangs von etwa drei Monaten dieselben Fassungen; wer es in seiner
  `docker-compose.yml` stehen hat, muss nichts tun, sollte aber bei
  Gelegenheit auf `nupplo` wechseln.
- Die Umgebungsvariable für den Anzeigenamen heißt jetzt `NUPPLO_NAME`;
  `BRICKFOLIO_NAME` gilt weiter.
- Die Verbindung zum Tausch-Netzwerk und dessen Verschlüsselung bleiben
  unverändert.

## 2.92.1 – September 2026

### Verbessert
- 🔎 **Das Suchwörterbuch kennt jetzt auch die Wörter der Setnamen** – rund
  450 neue Stichwörter quer durch alle Themen: City, Friends, Ninjago,
  Harry Potter, Castle, Pirates, Technic, Creator, Duplo, Disney,
  Marvel/DC, Minecraft, Jurassic World, Super Mario, Botanicals. Gemessen
  worden war bisher nur an Figurennamen; dort deckte die Liste 80 % der
  Wörter, in den 21.669 Setnamen aber nur 37 %. „Bahnhof", „Bagger",
  „Garage", „Tempel" oder „Adventskalender" (allein 1.931 Sets) fanden
  nichts. Jetzt sind es 59 % – der Rest sind Eigennamen und Marken, die man
  so tippt, wie sie im Katalog stehen.
- **Häufige Zusammensetzungen mit eigenem Eintrag.** Zerlegt wurde
  „Feuerwache" zu `fire` + `guard` und traf Wachen aller Art; jetzt ist es
  `fire station`. Ebenso „Polizeiwache", „Feuerwehrauto", „Todesstern".
- **Deutsche Namen, die anders lauten:** „Schneewittchen", „Aschenputtel",
  „Dornröschen", „Arielle", „Todesstern", „Sternzerstörer",
  „Kopfgeldjäger", „Besen", „Zaubertrank" und andere.
- Aufgenommen ist nur, was im Katalog auch vorkommt – ein Ziel, das in
  keinem Namen steht, fände nichts.

### Behoben
- **Fehlende Bedeutungen:** „Pony" war nur die Frisur (jetzt auch das
  Tier), „Motorrad" zerfiel in `motor` + `wheel`, „Anhänger" war nur der
  Schmuck (jetzt auch der Anhänger am Auto), „Steine" nur Edelsteine, „See"
  nur das Meer. Die bisherige Bedeutung bleibt jeweils vorn.

## 2.92.0 – September 2026

### Neu
- 📚 **Der Katalog für externen Zugriff** (`/api/sync/katalog`). Wer die
  Sammlung mit eigener Datenbank führt, soll auch dann nachschlagen können,
  wenn die Instanz gerade nicht erreichbar ist – nach Name, Nummer oder
  Beschreibung. Dafür gibt die Instanz ihren Katalog heraus: Figuren und
  Sets mit Bild, Jahr und Beschreibung, dazu Kategorien, Setinhalte und die
  BrickLink-Nummern.
- **Mit den Namen, ohne die Schlüssel.** Der öffentliche Abzug hat keine
  Namen; jede Instanz trägt sie über ihren eigenen BrickLink-Zugang nach.
  Wer den Katalog von hier holt, bekommt sie mit. Die BrickLink-Schlüssel
  verlassen die Instanz dabei nicht.
- Geholt wird nur, was sich seit dem letzten Mal geändert hat, in Seiten zu
  5.000 Einträgen und gepackt: Der ganze Figurenkatalog (gut 19.000) ist
  rund 1 MB.

## 2.91.0 – September 2026

### Neu
- 🔄 **Abgleich für externen Zugriff mit eigener Datenbank.** Wer von
  außen zugreift und seine Daten selbst mitführt, kann jetzt holen, was sich
  seit seinem letzten Stand geändert hat, und schicken, was bei ihm geändert
  wurde (`/api/sync/info`, `/pull`, `/push`). Das betrifft Sammlung,
  Kaufbuch, Wunschliste, Einkaufslisten und Preisverlauf. Konflikte
  entscheidet die neueste Änderung je Eintrag. Doppelt erfasste Artikel
  werden zusammengeführt, statt dass einer verloren geht.
- Dafür bekommt jede dieser Zeilen eine feste Kennung und einen Stand.
  **Nachgezogen wird über Trigger in der Datenbank**, nicht an den rund 90
  Stellen, an denen die Instanz schreibt: So zählt jeder Schreibweg mit,
  auch einer, der später dazukommt. Gelöschtes hinterlässt einen Vermerk,
  sonst käme es beim nächsten Abgleich wieder zurück.

### Rechte wie in der Web-App
- **Kaufpreise und Kaufbuch nur für Sammlerprofis.** Standard-Konten bekommen
  sie beim Abholen nicht, und was sie schicken, wird dort ignoriert.
- **Einkaufslisten** anlegen und ändern nur Profis. Standard-Konten dürfen
  Artikel verbuchen. Das Archiv gibt es für sie auch im Abgleich nicht.
- Werte werden geprüft wie in der Web-App: kein `1e999` als Preis, keine
  unbekannten Zustände.

### Geändert
- ↩️ **Nach dem Zurückspielen einer Sicherung** (JSON oder Tagesstand)
  beginnt jeder externe Zugriff mit eigener Datenbank von vorn. Mit einem
  Tagesstand kommt auch der alte Zählerstand zurück, und wer schon weiter
  war, hätte sonst Änderungen übersehen.

## 2.90.22 – September 2026

### Neu
- 🔎 **Steckbriefe in der Tauschbörse.** Ein Tipp auf Name oder Nummer eines
  Artikels öffnet seinen Steckbrief – in Angeboten, Entdecken, „Ich biete
  an“, im Profil eines anderen, im Anfrage-Fenster und im Kopf eines
  Gesprächs. Die Knöpfe behalten ihre Aufgabe.
- 🎨 **Kopf des Tausch-Netzwerks als eigene Karte:** größeres Bild, Name
  fett, „Mein Profil“ und „Freund einladen“ als Knöpfe; die freien
  Einladungen stehen als Zahl im Einladen-Knopf.
- 👑 **Hub-Admins laden ohne Kontingent ein** (mit Hub 1.23.0).

### Geändert
- 👤 **„Benutzername ändern“** statt „Anzeigename ändern“ im Profil – das
  Feld ändert den Anmeldenamen.
- 🔒 **Nummern übernehmen, doppelte Nummern zusammenführen und Themen
  nachladen** dürfen nur noch Admins und Sammlerprofis. Standard-Konten
  sehen den Hinweis weiter, ohne die Knöpfe.
- 💬 **Rückfragen im eigenen Fenster** statt der Browser-Kästen
  (`confirm`/`alert`); Löschen und Entfernen mit rotem Knopf.
- 🔢 **Sortierung „Nummer“** zählt Zahlen als Zahlen: 3001 vor 10179-1.
- 🌍 **Englisch:** die übrigen Absätze in den Einstellungen (Jedipedia,
  Katalog-Abzug, Gelernte Begriffe, Tausch-Netzwerk, Diagnose, Quellen &
  Rechtliches) und die restlichen Texte aus dem Code übersetzt.

### Behoben
- 🐞 **Ausfälle von BrickLink & Co. landen nicht mehr als Fehler** mit
  großem Hinweis und Push – die App hat sie abgefangen und sagt es.
- 📉 **„Größte Wertverluste“** zählt keine Artikel ohne Marktpreis mehr.
- 💬 **Dialoge schließen nicht mehr bei falscher Eingabe** („Weiterer Kauf“
  mit Buchstaben, zu kurzes Passwort) – sie sagen, was fehlt.
- 🧾 **Kaufbuch** zeigt den Betrag des Postens statt des gerundeten
  Stückpreises („2× 9,99 €“ statt „2× 5,00 €“).
- ✏️ **Kleinigkeiten:** das × in Suchfeldern stimmt auch nach „Filter
  zurücksetzen“; der Stift in der Bezahlt-Kachel wird nicht abgeschnitten;
  Listen-Reiter und Fußzeile einzeilig; Schilder über mehrere Zeilen stoßen
  nicht an die Rundung; das Preis-Protokoll ist am Handy lesbar; der
  Zwei-Faktor-Schlüssel bricht nur zwischen den Vierergruppen um;
  „Fehlerbericht öffnen“ springt an den Anfang der Karte; der Listenpreis
  lässt sich leeren; der Minus-Knopf wechselt nach einem Kauf sein Zeichen;
  der Steckbrief nimmt Preise von Wunsch- und Einkaufsliste; „Modelle
  laden“ ohne Adresse sagt es; „Nichts zu tun“ nur, wenn wirklich nichts
  offen ist; „Alle auf die Wunschliste“ verschwindet, wenn schon alle
  gemerkt sind; Netzwerkfehler als Satz statt Python-Meldung; nach dem
  Abmelden keine Abfragen mehr; der Hinweistitel wechselt mit der Sprache;
  die Hilfe verweist auf „Manuell erfassen“ statt auf eine Suche, die es
  dort nicht gibt.
- 🤝 **Tausch-Netzwerk:** Der Ungelesen-Zähler verpasst keine Antwort mehr
  in derselben Sekunde; „Ich biete an“ gleicht Nummer *und* Zustand ab;
  der Stand einer Meldung kommt nach dem Absenden sofort.
- 🛡️ **Schnittstelle:** Die Anmeldebremse glaubt Proxy-Kopfzeilen nur aus
  dem eigenen Netz; die Ersteinrichtung legt auch bei gleichzeitigen
  Aufrufen nur einen Admin an; eine neue Nummer verwirft die alten Preise;
  eine CSV-Datei mit offenem Anführungszeichen meldet die Zeile.

## 2.90.21 – September 2026

Ergebnis eines Gesamttests: alle 181 Schnittstellen, die ganze Oberfläche
(Handy und Desktop, drei Designs, Deutsch und Englisch) und das
Tausch-Netzwerk mit zwei Instanzen und einem örtlichen Hub.

### Behoben – Sammlung, Listen, Kaufpreise
- 💥 **Ein unendlicher Preis legte die App lahm.** `1e999` als Kaufpreis
  wurde angenommen; danach gaben Sammlung, Statistik und Sicherung nur noch
  Fehler. Unendlich und NaN werden jetzt überall abgelehnt, auch im
  CSV-Import.
- ↩️ **„Rückgängig“ in der Einkaufsliste nimmt den Wareneingang zurück** –
  Menge und Kaufposten. Bisher blieb beides stehen, und wer den Artikel noch
  einmal annahm, hatte ihn doppelt. Nach „Ersetzen“ bleibt es beim Hinweis,
  die Sammlung von Hand anzupassen.
- 🔒 **Kaufpreise nur für Sammlerprofis – auch in der Schnittstelle.** Die
  Oberfläche blendete sie für Standard-Benutzer aus, geliefert und
  angenommen wurden sie trotzdem (Sammlung, Kaufbuch, Statistik, Listen).
- 📉 **Weniger Stück heißt weniger bezahlt.** Menge verringern ließ den
  ganzen Kaufpreis an der Zeile stehen; jetzt geht das Kaufbuch mit.
- 🧹 **Gelöschter Kaufpreis bleibt gelöscht.** Nach dem Neuladen war er
  wieder da.
- ☑️ **Haken in der Katalogliste entfernen löscht keine Einträge mit
  Kaufpreis mehr** – und räumt Kaufbuch und Fotos mit auf.
- 🔢 **Neue Nummer übernehmen** führt zusammen, wenn es die Nummer schon
  gibt, statt mit einem Serverfehler abzubrechen.
- 👤 **Benutzer löschen** klappt auch, wenn er ein Foto angehängt hat.
- 🤝 **„Doppelte übernehmen“ bietet nur den Überschuss an** – nicht mehr das
  Exemplar zum Behalten und die Figuren aus eigenen Sets.
- ⭐ **Wunschliste:** Besitz neu *und* gebraucht wird zusammengezählt.
- 📈 **Wertverlauf** berücksichtigt beide Zustände einer Figur.
- 💶 **Gesamtangebot:** kein Anteil mehr mit −0,01 €.
- 📄 **CSV:** Der Export enthält Thema und (für Profis) Bezahlt, der Import
  liest beides und versteht „1,234.56“ wie „1.234,56“.
- 🔐 **Falsches Passwort beim Einrichten der Zwei-Faktor-Anmeldung meldet
  nicht mehr ab.**
- 🤖 **Der Ollama-Test fragt wirklich das Modell** – vorher antwortete das
  eingebaute Wörterbuch, und der Test meldete „verbunden“ ohne Dienst.
- 🧩 **Steckbrief:** „Steckt in diesen Sets“ zeigt wieder Name und Anzahl
  statt „…|2“.
- 🛒 **Manuell erfassen → Liste** übernimmt den Einkaufspreis.
- 🔁 **Zustand im Karten-Fenster umstellen** aktualisiert Wert und Gewinn
  sofort.
- Kleinigkeiten: Katalog ohne Abzug meldet „noch nicht geladen“,
  „Lukas' Brickfolio“ statt „Lukas's“, „1 Figur fehlt“, keine doppelten
  Fehlergründe, sichere Suche mit `%` und `_`, Push-Geräte ohne Schlüssel
  werden abgewiesen, Sicherungen mit kaputtem Aufbau bekommen eine klare
  Meldung, 422-Antworten wiederholen keine Eingaben (auch keine
  Passwörter), der Update-Vergleich versteht Anhänge wie `-rc1`.

### Behoben – Tausch-Netzwerk
- 📨 **Nachrichten an ein gesperrtes Gegenüber gehen raus** (und kommen nach
  der Freischaltung an), statt mit „Mitglied nicht gefunden“ zu scheitern.
- 📦 **Löscht das Gegenüber ein schon angenommenes Gespräch, bleibt es
  buchbar.**
- 🗂 **Nach Abmelden und Wiederbeitritt** stehen alte Gespräche als
  „frühere Mitgliedschaft“ da, nicht als „vom Gegenüber gelöscht“.
- 🔁 **Dasselbe Angebot lässt sich nach einem abgeschlossenen Tausch wieder
  anfragen**; der Zustand (neu/gebraucht) zählt dabei.
- 🚦 **Statuswechsel werden geprüft** – die eigene Anfrage annehmen oder ein
  abgeschlossenes Gespräch wieder öffnen geht nicht mehr.
- 🚪 **Zweimal beitreten** legt kein zweites Mitglied mehr an.
- 🔌 **Vom Hub-Admin entfernt?** Die App sagt es und zeigt den Weg zum
  Neubeitritt, statt überall „Token ungültig“ zu melden.
- 🐞 **Absagen des Hubs sind keine Fehler mehr.** Sperre, Kontingent,
  benutzte Einladung landeten als 502 im Fehlerbericht.
- ⚖️ **Gleichzeitiges Austragen** bucht Menge und Kaufbuch sauber
  nacheinander.
- Kleinigkeiten: „nicht mehr angeboten“ nur, solange nichts zugesagt ist;
  der Sperrhinweis sagt nicht „bis auf Weiteres“ neben einem Enddatum;
  „Freund einladen“ verschwindet bei Sperre; leere Nachrichten werden
  abgewiesen.

### Geändert – Darstellung
- 📱 **Sammlung am Handy:** Die Suche hat eine eigene Zeile, „Alle Typen“
  und „Zuletzt erfasst“ werden nicht mehr abgeschnitten.
- 📱 **Kacheln am Handy:** Große Beträge passen nebeneinander, auch in der
  Wunschliste.
- 🎨 **Galaxy und Nova:** Ausgewählte Zustands-Pillen und das
  Wunschlisten-Schild haben dunkle Schrift auf Gelb bzw. Hellblau.
- 🌍 **Englisch:** gut 60 fehlende Übersetzungen im Tausch-Netzwerk
  (Entdecken, Profil, Einstieg) ergänzt.

## 2.90.20 – September 2026

### Behoben
- 🔌 **Vereinzelte „502“ mitten im Betrieb.** Hinter einem Tunnel wie
  Cloudflare schloss der Server ruhende Verbindungen schon nach 5 Sekunden,
  der Tunnel hielt sie aber bis zu 90 Sekunden für die nächste Anfrage
  bereit. Traf eine Anfrage genau diesen Moment, kam sie mit „502“ zurück –
  ohne dass der Server neu startete. Er hält Verbindungen jetzt 120 Sekunden
  offen. Wirkt nach dem Update, weil der Startbefehl im Image steckt.

## 2.90.19 – September 2026

### Behoben
- 💰 **„Gesamtangebot“ in Einkaufslisten geht wieder.** Seit die Knöpfe
  einer Liste in der eigenen Fußzeile stehen (2.88.37), suchte der Knopf
  noch den alten Rahmen, fand ihn nicht und brach ohne Meldung ab – es
  passierte einfach nichts.
- 📱 **Tausch-Netzwerk am Handy aufgeräumt.** Unter dem eigenen Namen stehen
  „Mein Profil“, „Freund einladen“ und die freien Einladungen jetzt in einer
  eigenen, eingerückten Zeile, statt links unter das Bild zu rutschen.
- 📱 **„Ich biete an“:** „Entfernen“ sitzt jetzt klein unten rechts neben der
  Menge. Bisher nahm der Knopf neben dem Titel fast die halbe Breite ein und
  quetschte lange Namen auf fünf Zeilen.
- 🎨 **Keine blaue Schrift mehr auf dem iPhone.** Safari färbt Knöpfe und
  Auswahllisten ohne eigene Farbe systemblau – betroffen waren etwa die
  Reiter im Tausch-Netzwerk und die Mengenauswahl. Sie übernehmen jetzt die
  Textfarbe des Themas. In den dunklen Themen ist die Schrift auf gelb
  bzw. blau hinterlegten, ausgewählten Reitern und Umschaltern wieder dunkel.

## 2.90.18 – September 2026

### Geändert
- 📱 **Preiszeilen brechen sauber um.** Das gelbe Schild steht links, alles
  andere in einer eigenen Spalte daneben – was umbricht, bleibt unter dem
  Preis eingerückt. Bisher rutschte „· 13× verkauft 🇩🇪“ auf dem Handy an
  den linken Rand unter das Schild. Ist die Zeile schmal (Handy,
  Katalogfenster), steht die Verkaufszahl grundsätzlich in einer eigenen,
  eingerückten Zeile; ist sie breit, bleibt alles in einer. Angaben wie
  „1× verkauft 🇩🇪“ werden nie mehr mittendrin getrennt.

## 2.90.17 – September 2026

### Geändert
- 💶 **Das Katalogfenster zeigt jetzt auch Preise** – wie der Steckbrief,
  mit Spanne, Verkaufszahl, Gebietsfahne und den Angebotspreisen, wenn
  eingeschaltet. Bisher standen dort nur Bild, Name und die Knöpfe. Das
  Fenster ist dafür etwas breiter geworden.
- Die Gebietsfahne hängt an der Angabe davor und rutscht nicht mehr allein
  in die nächste Zeile.

## 2.90.16 – September 2026

### Geändert
- 💶 **Auch das Info-Fenster aus Listen, Sets und Katalog zeigt die Preise
  wie der Steckbrief** – mit Spanne, Verkaufszahl, Gebietsfahne und den
  Angebotspreisen, wenn eingeschaltet. Wie beim Suchtreffer (2.90.15) steht
  die Kurzzeile sofort da, die vollen Angaben folgen.

## 2.90.15 – September 2026

### Geändert
- 💶 **Das Infofenster eines Suchtreffers zeigt die Preise wie der
  Steckbrief.** Bisher stand dort nur „Ø neu … · Ø gebr. …“. Jetzt kommen
  neu und gebraucht mit Spanne, Verkaufszahl und Gebietsfahne, darunter die
  Angebotspreise, wenn eingeschaltet. Die Kurzzeile steht sofort da, die
  vollen Angaben folgen einen Moment später.

## 2.90.14 – September 2026

### Neu
- ✉️ **Meine Einladungen.** Unter „Freund einladen“ stehen die eigenen
  Einladungen: offene mit ihrem Code – noch einmal kopieren, teilen oder
  zurückziehen –, eingelöste mit Name und Datum (vier Wochen lang). Bisher
  war ein Code nach dem Schließen des Fensters weg, obwohl die Einladung
  verbraucht war, und ob er eingelöst wurde, sah man nirgends. Den Code
  merkt sich die eigene Instanz, der Hub kennt nur seine Prüfsumme. Braucht
  Hub 1.22.0.

## Hub 1.22.0 – September 2026

### Neu
- `GET /v1/invites` liefert die eigenen Einladungen mit Stand (Prüfsumme als
  Kennung, ohne Code), `DELETE /v1/invites/:prüfsumme` zieht eine offene
  zurück.

### Behoben
- Abgelaufene, nie eingelöste Einladungen zählten für immer gegen das
  Kontingent. Jetzt zählen nur noch offene und eingelöste.

## 2.90.13 – September 2026

### Geändert
- ✉️ **Einladen mit eigenem Fenster.** Der Code stand bisher als rohe
  Zeile unter dem Zähler. Jetzt öffnet „Freund einladen“ ein Fenster mit dem
  Code in groß, „Kopieren“ und – wo das Gerät es kann – „Teilen“, dazu drei
  Schritte, was der Freund damit macht. Wie viele Einladungen noch frei
  sind, steht als kleine Marke direkt am Knopf.
- 📝 README und Handbuch: Der Tausch-Abschnitt sagt jetzt gleich oben, dass
  das Netzwerk von Haus aus aus ist und nur geteilt wird, was man
  ausdrücklich auswählt. Die Flaggen-Beschreibung passt zu 2.90.12.

## 2.90.12 – September 2026

### Geändert
- 🇩🇪 **Jede Preiszeile im Steckbrief zeigt ihr Gebiet.** Bisher stand die
  Fahne nur, wenn die App auf ein größeres Gebiet ausweichen musste. Dann
  sah man etwa bei „Gebraucht“ die EU-Fahne und bei „Neu“ nichts. Jetzt
  steht auch die Fahne des eingestellten Gebiets dahinter, bei Verkaufs-
  wie Angebotspreisen, und der Tooltip sagt, woher der Preis kommt. Die
  kurze Zeile auf der Karte bleibt, wie sie war.

## Hub 1.21.0 – September 2026

### Neu
- **Instanz ganz entfernen:** `DELETE /v1/admin/instances/:id` löscht die
  Instanz samt aller Konten, die je darüber beigetreten sind, und allem, was
  an ihnen hängt. Für Testinstanzen und verwaiste Installationen – wer nur
  nicht zurücksoll, bekommt weiter „Neubeitritt sperren“. Instanzen mit
  Admin-Konto bleiben stehen. In der Konsole unter *Instanzen → Entfernen*.

## 2.90.11 – September 2026

### Neu
- 💬 **Rückfragen zu Meldungen.** Der Hub-Admin kann beim Meldenden
  nachfragen. Die Frage steht unter der Meldung im Gespräch, es kommt ein
  Hinweis, und man antwortet gleich dort.
- 📣 **Maßnahmen, die der Betroffene sieht.** Hinweis und Verwarnung des
  Hub-Admins stehen oben im Tausch-Tab, bis man „Verstanden“ drückt. Der
  Sperrhinweis nennt Grund und Ende einer Sperre. Wer gemeldet hat, steht
  nirgends.
- ✔ **Der Meldende sieht, was aus seiner Meldung wurde** – die Maßnahme,
  wenn der Admin sie freigibt, sonst nur „bearbeitet“.

Braucht Hub 1.20.0.

## Hub 1.20.0 – September 2026

### Neu
- **Rückfragen:** `report_messages`; der Admin schreibt über
  `POST /v1/admin/reports/:id/messages`, der Meldende über
  `POST /v1/reports/:id/messages` (öffnet eine erledigte Meldung wieder).
  Beide Seiten bekommen den Austausch mit den Meldungen geliefert.
- **Maßnahmen beim Erledigen:** `massnahme` (`keine`, `hinweis`,
  `verwarnung`, `sperre_zeit` mit `tage`, `sperre`), Text an den
  Gemeldeten, `ergebnis_sichtbar` für den Meldenden. Hinweise landen in
  `member_notices` und über `/v1/me` beim Betroffenen, bestätigt mit
  `POST /v1/notices/:id/ack`. Sperren setzen `blocked_until`/`block_reason`,
  befristete heben sich beim nächsten Besuch nach Ablauf selbst auf. Der
  403 einer Sperre nennt Grund und Ende.
- **Archiv:** erledigte Meldungen und entschiedene Einladungsanfragen lassen
  sich archivieren (`POST …/archive`, Liste mit `?archiv=1`) oder löschen.
- Die Meldungsliste der Verwaltung nennt beim Gemeldeten, wie oft er schon
  gemeldet wurde und welche Maßnahmen es gab. Die Mitgliederliste zeigt
  Meldungen, Maßnahmen und Sperrgrund.

## 2.90.10 – September 2026

### Neu
- ⚑ **Die eigene Meldung bleibt sichtbar.** Bisher kam nach dem Melden nur
  eine kurze Bestätigung, danach fand man die Meldung nirgends wieder. Jetzt
  steht im Gespräch, wann man gemeldet hat und ob mit Verlauf, in der
  Gesprächsliste die Marke „⚑ gemeldet“. Hat ein Hub-Admin die Meldung
  erledigt, steht das dort ebenfalls, und es kommt ein Hinweis. Braucht
  Hub 1.19.0.

## Hub 1.19.0 – September 2026

### Neu
- `POST /v1/reports` gibt die Nummer der Meldung zurück, `GET /v1/reports`
  liefert die eigenen Meldungen mit Stand (`open`/`handled`) und Datum. Die
  Notiz des Admins und der offengelegte Verlauf gehen dabei nicht mit.

## 2.90.9 – September 2026

### Behoben
- ✉️ **„Freund einladen“ war kaum zu finden.** Der Knopf stand im Reiter
  „Angebote“ neben „Aktualisieren“. Seit „Entdecken“ der Startreiter ist,
  sah man ihn gar nicht mehr. Jetzt steht er oben im Tausch-Tab neben „Mein
  Profil“, samt Einladungszähler, und ist von jedem Reiter aus erreichbar.

## 2.90.8 – September 2026

### Behoben
- 🧱 **Kompakte Ansicht nach Thema sortiert zeigte Riesenkacheln.** Auf
  breiten Bildschirmen standen statt der kleinen Kacheln drei 400 px breite
  Kästen je Reihe. Schuld war die Spaltenregel der Listenansicht: Sie
  traf auch die kompakte Ansicht und stand später in der Datei. Jetzt gilt
  sie nur noch für die Liste, und ein Test hält das fest.

## 2.90.7 – September 2026

### Neu
- ↕️ **Nach Kaufpreis und Gewinn sortieren** (nur Sammlerprofis):
  „Bezahlt (hoch → niedrig)“, „Gewinn (hoch → niedrig)“ und „Gewinn
  (niedrig → hoch)“ – letztere zeigt die Verluste zuerst. „Wert“ bleibt der
  Marktwert. Einträge ohne Kaufpreis stehen am Ende. Für alle anderen
  bleiben die Sortierungen unsichtbar und greifen auch nicht, denn schon
  die Reihenfolge verriete, was bezahlt wurde.

## 2.90.6 – September 2026

### Behoben
- 📒 **Ein leer gelassenes „Bezahlt (optional)“ wurde als 0 € gebucht.**
  Beim Übernehmen eines Tauschs landete damit „0 € bezahlt“ im Kaufbuch
  statt „kein Preis“, und der Gewinn der Zeile stimmte nicht. Leer heißt
  jetzt wieder: keine Angabe.

## 2.90.5 – September 2026

### Behoben
- 🔁 **Ein Neustart beim Ausrollen ging manchmal als Fehler in die Liste.**
  Nach einem 502 fragte die App genau einmal nach 20 Sekunden, ob der
  Server frisch gestartet ist. Dauerte der Austausch länger, lief die
  Nachfrage ins Leere, und „502 bei GET /api/update/status“ landete als
  Fehler im Bericht. Jetzt fragt sie bis zu zwei Minuten lang nach.
  Gemeldet wird nur, wenn der Server schon lange läuft oder nach zwei
  Minuten immer noch weg ist.

## 2.90.4 – September 2026

### Behoben
- 📬 **Neue Nachrichten erschienen erst nach bis zu einer Minute.**
  Außerhalb eines Gesprächs sah die App nur einmal pro Minute beim Hub
  nach. Wer vorher neu lud, sah die Nachricht sofort und hielt das
  Nachladen für kaputt. Jetzt alle 20 Sekunden (in der Nachrichtenliste
  alle 15, im offenen Gespräch weiter alle 8) und zusätzlich sofort, wenn
  man in den Tab oder ins Fenster zurückkommt.

## 2.90.3 – September 2026

### Behoben
- Eine Nachricht an jemanden, der das Netzwerk verlassen hat, scheiterte
  mit „502 – Mitglied nicht gefunden“. Jetzt heißt es gleich „Das Gegenüber
  hat das Tausch-Netzwerk verlassen“. In der Oberfläche war das Eingabefeld
  dort schon ausgeblendet, es betraf nur den direkten Aufruf.

## 2.90.2 – September 2026

### Neu
- 🚪 **Hinweis, wenn das Gegenüber das Netzwerk verlassen hat.** Bisher
  konnte man in so ein Gespräch weiterschreiben, aber es kam nie etwas an.
  Jetzt steht im Gespräch „hat das Tausch-Netzwerk verlassen", das
  Eingabefeld verschwindet, und der Verlauf bleibt lesbar. Ist das
  Gegenüber gesperrt, sagt ein Hinweis, dass Nachrichten erst nach einer
  Freischaltung ankommen.

### Geändert
- 📝 Der Text zum Tausch-Netzwerk unter *Mehr* stammte noch aus der Zeit,
  als nur Abgebbares geteilt wurde. Jetzt sagt er, was wirklich geteilt
  wird: Angebote, Profil und, wenn man will, die Wunschliste.

Braucht Hub 1.18.0.

## Hub 1.18.0 – September 2026

### Neu
- `/v1/trades` liefert `from_status`/`to_status` (`active`, `left`,
  `disabled`, `gone` für gelöschte Mitglieder). Nachrichten an Abgemeldete
  lehnt der Hub mit 410 ab – sie würden nie abgeholt.

### Geändert
- Beim Abmelden geht auch das Profil (Über mich, Gegend, Themen). Es
  bleiben nur Name und Eckdaten, damit die Verwaltung den Austritt sieht
  und die Gegenseite ihre Gespräche behält.

## 2.90.1 – September 2026

### Neu
- 🚪 **Abmelden heißt jetzt auch abmelden.** Bisher vergaß beim Trennen nur
  die eigene Instanz die Verbindung. Im Hub blieben Angebote und Wünsche
  stehen, andere fragten bei jemandem an, der nie antworten würde. Jetzt
  meldet sich die App beim Hub ab, der nimmt alles heraus, und in der
  Verwaltung steht „abgemeldet am …". Der Knopf heißt „Aus dem Netzwerk
  abmelden", und die Rückfrage sagt, was passiert.
- ⏸ **Pause bei Inaktivität.** Wer länger nicht im Netzwerk war (Standard
  30 Tage), dessen Angebote und Wünsche blendet der Hub aus, bis er
  wiederkommt. Dann sind sie von selbst zurück, und die App sagt, von wann
  bis wann sie pausiert waren – als Hinweis und zwei Wochen lang im
  Tausch-Tab.

### Behoben
- 📒 **Austragen nach einem Tausch ließ das Kaufbuch stehen.** Es sank nur
  die Stückzahl, und bei einer Figur standen danach „10,37 € für 5 Stück"
  bei nur noch 4 in der Sammlung. Einkauf und Gewinn der Zeile stimmten
  nicht mehr. Jetzt gehen die weggegebenen Stücke im Buch mit hinaus, vom
  jüngsten Kauf her, denn abgegeben wird meist der zuletzt dazugekommene
  Doppelte.

Braucht Hub 1.17.0.

## Hub 1.17.0 – September 2026

### Neu
- `POST /v1/leave`: Das Mitglied bekommt `status = 'left'` und `left_at`,
  Angebote und Wünsche werden gelöscht, der Token gilt nicht mehr. Der Name
  ist danach wieder frei.
- **Pause bei Inaktivität:** `hub_settings.inaktiv_tage` (Standard 30, 0 =
  aus, über `GET/PUT /v1/admin/settings`). Angebote und Wünsche von
  Mitgliedern, deren letzter Besuch länger zurückliegt, fehlen in
  `/v1/offers` und `/v1/wants`, ihr Profil trägt `pausiert`. Kommt jemand
  zurück, hält der Hub `pause_von`/`pause_bis` fest, und `/v1/me` meldet sie
  zusammen mit `inaktiv_tage`.
- Verwaltung: `/v1/admin/overview` zählt `paused` und `left`,
  `/v1/admin/members` liefert `left_at`, `paused_since`, `pause_von` und
  `pause_bis`.

## 2.90.0 – September 2026

### Neu
- 🏷 **Angebotspreise: was die Figur gerade *kostet*.** Bisher stand überall
  der Ø-Verkaufspreis – was zuletzt tatsächlich bezahlt wurde, also was die
  Figur *wert* ist. Neu daneben: **ab wie viel sie zu haben ist**. Zwei
  verschiedene Fragen, und für den Flohmarkt ist die zweite oft die
  nützlichere.
  - In der **Detailansicht** unter dem Verkaufspreis, für neu und gebraucht,
    mit der Zahl der angebotenen Stücke.
  - In **Wunsch- und Einkaufslisten** als kleine Marke an der Zeile
    („ab 6,70 € gebraucht").
  - **Zuschaltbar unter *Mehr → Angebotspreise*, voreingestellt aus.** Die
    gewohnte Ansicht bleibt, wie sie war, und die zusätzlichen
    BrickLink-Abrufe zahlt niemand ungefragt.
  - Dieselbe Schnittstelle, dieselben Zugangsdaten – nur ein anderer
    Parameter. Keine neue Quelle.
  - **Angebote werden nicht gespeichert.** Was heute zu haben ist, ist morgen
    weg; der Wert deiner Sammlung beruht weiter auf Verkäufen.

### Intern
- Listen holen ihre Angebote in **einem** Abruf statt einem je Zeile
  (höchstens 60 Nummern; der 20-Minuten-Speicher fängt Wiederholungen ab).
  Fällt eine Figur aus, reißt sie die anderen nicht mit.
- Beim Rückfall auf ein breiteres Preisgebiet entscheidet bei Angeboten die
  **Stückzahl**, nicht der Durchschnitt: BrickLink meldet in einem leeren
  Gebiet `0.0000` statt nichts.

## 2.89.4 – September 2026

### Neu
- 🏁 **Tausche schließen sich selbst ab.** Bisher blieb ein fertiger Tausch
  für immer auf „angenommen". Jetzt meldet jede Seite ihre Buchung
  (ausgetragen bzw. übernommen) an den Hub, und sobald beide gebucht haben,
  steht er auf „abgeschlossen". Die Schrittleiste endet mit „🏁
  Abgeschlossen". Wer seinen Teil noch nicht gebucht hat, behält den Knopf.
  Schon gebuchte Tausche schließen sich beim nächsten Abgleich nach.

### Behoben
- 🆕 **Bei „🤝 Anbieten" wurde „gebraucht" vorgeschlagen, auch für neue
  Stücke.** Der Zustand ging nicht mit. Jetzt schickt die abgebende Seite
  ihn mit, und die bekommende übernimmt ihn als Vorschlag. Beim Austragen
  ist das Stück im passenden Zustand vorgewählt.

Braucht Hub 1.16.0.

## Hub 1.16.0 – September 2026

### Neu
- `given_at` und `taken_at` an `trades`: `POST /v1/trades/:id/progress`
  kennt dafür die Schritte `given` (abgebende Seite) und `taken`
  (bekommende). Stehen beide, setzt der Hub den Status auf `closed`. Gebucht
  werden darf auch nach dem Abschluss noch.
- `trades.condition` (`new`/`used`) – beim Anlegen mitgeschickt, in der
  Vorgangsliste zurück.

## 2.89.3 – September 2026

### Neu
- 📦 **Verschickt → angekommen → übernehmen.** Nach dem Annehmen ging es
  bisher direkt ans Buchen, ob das Päckchen schon unterwegs oder da war,
  stand nirgends. Jetzt führt das Gespräch durch Schritte, sichtbar als
  Leiste: Wer abgibt, meldet **„verschickt / übergeben"** (mit einer
  vorbelegten Nachricht, gern samt Sendungsnummer) und trägt danach aus.
  Wer bekommt, bestätigt **„angekommen"** und übernimmt dann in die
  Sammlung. Gebucht wird erst nach dem eigenen Schritt. Von Hand zu Hand
  geht die Ankunft auch ohne „verschickt". In der Gesprächsliste steht, was
  ansteht. Braucht Hub 1.15.0; ältere App-Fassungen merken davon nichts.

## Hub 1.15.0 – September 2026

### Neu
- **Tauschschritte** `shipped_at` und `arrived_at` samt
  `POST /v1/trades/:id/progress` (`step`: `shipped` oder `arrived`).
  „Verschickt" darf nur die abgebende Seite melden, „angekommen" nur die
  bekommende, beides nur bei angenommenem Tausch. Der Status bleibt
  `accepted`.

## 2.89.2 – September 2026

### Behoben
- 🤫 **Die Mahnung beim Betreiber-Feld ist wieder weg.** 2.89.0 meldete
  „BrickLink ist eingerichtet, aber es steht keine Kontaktadresse da" –
  jeder Instanz, immer. Für die allermeisten ist das Unsinn: Wenn außer
  der eigenen Familie niemand die Instanz benutzt, gibt es keine Fremden,
  die jemanden erreichen müssten. Eine Auflage, die im Regelfall ins Leere
  läuft, gehört nicht als Dauerhinweis in die Einstellungen. Das Feld
  bleibt, die Mahnung geht.
- 📝 **Und der Hinweis sagt jetzt, wann man es überhaupt braucht:** bei
  einem Zugang für jemanden außerhalb des Haushalts oder einer öffentlich
  erreichbaren Instanz. Sonst: leer lassen.

## 2.89.1 – September 2026

### Behoben
- 📝 **Der Hinweis beim Betreiber-Feld sagte nicht, wofür die Adresse da
  ist.** Die naheliegende Rückfrage lautet: „Meine Adresse liegt BrickLink
  doch aus der Registrierung vor, und das Feld wird gar nicht dorthin
  übertragen – wozu dann?" Beides stimmt, nur geht die Auflage in eine
  andere Richtung: Die Adresse ist **nicht für BrickLink**, sondern für
  **Dritte, die deine Instanz benutzen**. Sie soll angezeigt werden, nicht
  gesendet. Steht jetzt so dort – und in beiden Handbüchern.
- 💬 Ein neues Gespräch zeigte bis zum ersten Abgleich „an ?" statt des
  Namens, und eine nie zugestellte Nachricht in einem gelöschten Gespräch
  stand ewig auf „unterwegs …".

## 2.89.0 – September 2026

BrickLinks Nutzungsbedingungen einmal gelesen statt überflogen – und dabei
drei Stellen gefunden, an denen Brickfolio sie nicht erfüllte.

### Neu
- 🔑 **Kontaktadresse des Betreibers** unter *Mehr → API-Schlüssel*.
  BrickLink verlangt eine sichtbare Kontaktadresse in der Anwendung.
  Gemeint ist die des **Betreibers**: Die Zugangsdaten registriert jede
  Instanz selbst, damit ist auch jeder Betreiber selbst der „Developer" im
  Sinne dieser Bedingungen – eine feste Projektadresse wäre dort schlicht
  falsch. Das Feld ist nicht maskiert, leeren heißt löschen, und ohne
  BrickLink-Zugang bleibt es ohne Wirkung.
- ⚖️ **Der vorgeschriebene BrickLink-Hinweis** steht jetzt unter
  *Mehr → Rechtliches* – im Wortlaut, wie verlangt, und auf Englisch auch
  in der deutschen Oberfläche. Er erscheint nur, wenn diese Instanz die
  API überhaupt benutzt. Ein Test vergleicht ihn Zeichen für Zeichen und
  ein zweiter stellt sicher, dass der Übersetzungslauf ihn nicht anfasst.

### Behoben
- 📄 **„Ein kostenloses Konto genügt" stimmte nicht.** Die Store-API steht
  nur Verkäufern offen: Im BrickLink-Konto muss einmal ein Shop eröffnet
  sein, der aber leer bleiben darf. Das Handbuch sagte es längst, die
  Projektseite nicht – dort stand es an drei Stellen falsch.

### Intern
- Die neue Einstellung ist als personenbezogen eingestuft und wird aus
  Fehlerberichten entfernt. Sichtbar in der eigenen Instanz heißt nicht
  sichtbar in einem öffentlichen Issue.

## 2.88.56 – September 2026

Gefunden beim Durchspielen von vier Tauschgesprächen zwischen zwei
Testinstanzen und einer echten.

### Behoben
- 🧹 **Nach einem Tausch blieb Veraltetes stehen.**
  - Wer ein Stück übernahm, behielt es auf der Wunschliste. Das Netzwerk
    zeigte deshalb weiter an, wer es hätte, und anderen, dass man es sucht.
    Jetzt verschwindet der Wunsch beim Übernehmen in die Sammlung (auf eine
    Einkaufsliste bleibt er stehen).
  - Wer ein Stück austrug, bot es im Netzwerk weiter in alter Stückzahl an,
    bis von Hand neu veröffentlicht wurde. Jetzt zieht die App die Angebote
    im Hintergrund nach – aber nur, wer schon einmal veröffentlicht hat.
- 🖼 **Ein erhaltenes Angebot kam ohne Bild in die Sammlung.** Der Hub
  liefert dem Empfänger kein Bild mit. Jetzt kommt es von der Wunschliste
  oder als Standardbild von BrickLink.
- 👻 **Vom Gegenüber gelöschte Gespräche standen ewig als „offen" da.**
  Antworten liefen ins Leere. Jetzt heißen sie „vom Gegenüber gelöscht",
  bleiben lesbar, und das Eingabefeld verschwindet.
- **Annehmen und Ablehnen** standen auch beim Fragenden, der so seine eigene
  Anfrage „annehmen" konnte. Jetzt sieht die Knöpfe nur, wer gefragt wurde,
  und nur, solange das Gespräch offen ist.

## 2.88.55 – September 2026

### Behoben
- 🤝 **Wer jemandem etwas anbietet, das er sucht**, bekam im Gespräch
  „⚠ Dieser Artikel wird nicht mehr angeboten" zu sehen: Der Hub suchte den
  Artikel in den Angeboten des *Gegenübers*, wo er nie stand. Gespräche
  tragen jetzt ihre Art – Anfrage oder Angebot. Die Warnung gibt es nur
  noch bei Anfragen, und nach dem Annehmen stimmt auch die Richtung: Wer
  angeboten hat, trägt aus, wer das Angebot bekommt, übernimmt. Bisher war
  es genau verkehrt herum. Braucht Hub 1.14.0.

## Hub 1.14.0 – September 2026

### Neu
- **Vorgänge tragen ihre Art** (`trades.kind`: `anfrage` oder `angebot`).
  Ältere App-Fassungen schicken nichts, das gilt als Anfrage. Bei einem
  Angebot meldet der Hub den Artikel immer als verfügbar. Bestehende
  Vorgänge, deren Empfänger den Artikel sucht und nicht selbst anbietet,
  stellt die Migration auf „angebot" um.

## Hub 1.13.0 – September 2026

### Neu
- 💶 **Angebote tragen ihre Art**: Tausch, Verkauf oder beides (neue Spalte
  `offers.deal`). Fehlt sie – bei älteren App-Fassungen –, gilt das Angebot
  als Tausch.

## Hub 1.12.0 – September 2026

### Neu
- 🧭 **Profile und freiwillig gezeigte Wunschlisten.** Zwei neue Tabellen
  (`member_profiles`, `wants`) und sechs Endpunkte: eigenes Profil lesen und
  speichern, fremdes Profil samt Tauschbilanz, Profilliste, eigene Wünsche
  ersetzen, gezeigte Wünsche der anderen. Wünsche nimmt der Hub nur an,
  solange „Wunschliste zeigen" gesetzt ist; beim Abschalten löscht er sie
  sofort. Die Sammlungsgröße speichert er gerundet und zeigt sie nur, wenn
  sie freigegeben ist. Beim Löschen eines Mitglieds gehen Profil und
  Wünsche mit.
- Ältere App-Fassungen fragen diese Wege nicht an und merken nichts davon.

## Hub 1.11.0 – September 2026

### Geändert
- 📚 **Nachtrag zur Beschreibung des Katalogwegs.** Der Eintrag zu Hub 1.8.0
  (weiter unten) beschreibt die Technik von damals; wie der Katalog *heute*
  entsteht, stand nirgends zusammenhängend. Deshalb hier in drei Schritten:

  1. **Angelegt und vervollständigt wird der Katalog im Katalogdienst** —
     Nummern der Reihe nach, dazu die Beschreibung des Katalogfotos. Dort
     liegen die BrickLink-Schlüssel dafür, und nur dort.
  2. **Ausgerollt wird über GitHub** — als Datei mit Nummer und
     Beschreibung, **ohne Namen**.
  3. **Die Namen holt sich jede Instanz selbst** über ihren eigenen
     BrickLink-Zugang, oder in Sekunden aus der Katalogdatei.

  Am 05.09.2026 nachgetragen, weil das Handbuch an zwei Stellen
  Verschiedenes sagte.

## Hub 1.8.0 – August 2026

### Neu
- 📚 **Der Katalogabzug liegt jetzt im Hub.** Bisher baute ihn jede Instanz
  selbst: Nummern der Reihe nach bei BrickLink abklappern (Tage, eigenes
  Kontingent) und danach jedes Bild von einem Sehmodell beschreiben lassen
  (rund 24 Stunden Grafikeinheit für 9.741 Figuren). Dieselbe Arbeit für
  dasselbe Ergebnis — der Katalog beschreibt BrickLinks Fotos, nicht die
  Sammlung von irgendwem.

  `POST /v1/katalog` nimmt Stapel zu 500 Zeilen entgegen, `GET /v1/katalog?seit=…`
  liefert nur, was sich seit dem eigenen Stand geändert hat. Im Normalbetrieb
  sind das null Zeilen — der Katalog ändert sich in der Größenordnung eines
  Dutzend Namen im Monat.

  **Schreiben braucht ein eigenes Recht (`can_katalog`), lesen nicht.** Das
  Recht hängt am Hub und nicht in der App, denn die Instanzen sind selbst
  gehostet: Wer seinen Container betreibt, kann dessen Code ändern, und eine
  Absprache wäre damit keine Regel, sondern eine Bitte. Der Schaden wäre auch
  nicht Unordnung, sondern Verschlechterung — eine schwächere Bildanalyse
  überschreibt eine bessere, und man sieht es der Beschreibung nicht an.

  Jede Zeile vermerkt, welches **Modell** die Beschreibung erzeugt hat. Ohne
  das wäre ein Modellwechsel ein stilles Umschreiben aller Zeilen, und
  niemand könnte zwei Beschreibungen daraufhin ansehen, ob sie überhaupt
  vergleichbar sind.

## 2.88.54 – September 2026

### Neu
- 💶 **Zum Tausch, zum Verkauf oder beides.** Unter „Ich biete an" wählst du
  je Artikel, wozu er angeboten wird; anfangs steht alles auf Tausch. Beim
  Gegenüber steht die Art an der Karte, unter „Angebote" lässt sich danach
  filtern, und bei reinem Verkauf schlägt die Anfrage einen Kauf vor statt
  eines Tauschs. Braucht Hub 1.13.0.

### Geändert
- Die Reiter im Tausch-Tab heißen jetzt **„💬 Nachrichten"** und **„📤 Ich
  biete an"**, der Knopf zum Veröffentlichen **„📤 Im Netzwerk anbieten"**.

## 2.88.53 – September 2026

### Neu
- 🧭 **Entdecken im Tausch-Netzwerk.** Der Tausch-Tab öffnet mit einem neuen
  Reiter und drei Abschnitten, alle auf der eigenen Instanz ausgerechnet:
  **„Hat, was du suchst"** (Angebote anderer, die auf deiner Wunschliste
  stehen – deine Wunschliste verlässt dafür die Instanz nicht), **„Sucht, was
  du übrig hast"** (gezeigte Wunschlisten anderer gegen deine Doppelten und
  Angebote, mit „🤝 Anbieten") und **„Passt zu dir"** (gleiche
  Lieblingsthemen).
- 👤 **Profile.** Ein Tipp auf einen Namen öffnet das Profil: Über mich,
  Gegend, Lieblingsthemen, Tauschbilanz, freiwillig die gerundete
  Sammlungsgröße, dazu was das Mitglied anbietet und – falls gezeigt – sucht.
  Was davon zu dir passt, ist gelb umrandet.
- ✏️ **Mein Profil** oben im Tab, ganz freiwillig. Zwei Schalter stehen
  anfangs auf aus: **„Meine Wunschliste im Netzwerk zeigen"** (wird bei jeder
  Änderung nachgezogen, beim Abschalten oder Trennen im Hub gelöscht) und
  **„Sammlungsgröße zeigen"**.
- 🤝 **Einrichtungsplaner nach dem Beitritt.** Sechs Schritte – Beitreten,
  Über dich, Themen, Sichtbarkeit, Angebote, Los –, jeder überspringbar,
  gespeichert nach jedem Schritt.
- Beitreten geht weiterhin nur mit Einladung, und ohne Beitritt bleibt der
  Tab verborgen.

### Geändert
- Die Reiter heißen kürzer: „💬 Vorgänge" und „📤 Auswahl", damit vier
  nebeneinander aufs Telefon passen.

## 2.88.52 – September 2026

### Intern
- 🤝 **Das Tausch-Netzwerk hat eigene Dateien.** Die 26 Endpunkte standen
  mitten in `main.py`, der Tausch-Tab mitten in `app.js`. Jetzt liegen sie in
  `backend/community.py` (als eigener Router) und `frontend/community.js`.
  `main.py` ist damit gut 700 Zeilen kürzer, `app.js` gut 800. Am Verhalten
  ändert sich nichts – die angemeldeten Routen sind vorher wie nachher
  dieselben 171. Grundlage für den Ausbau zur Community (Profile,
  Entdecken).
- Beitreten geht weiterhin **nur mit Einladungscode**, und ohne Beitritt
  bleibt der Tausch-Tab verborgen; ein Test hält beides fest.

## 2.88.51 – September 2026

### Geändert
- Im Zwei-Faktor-Abschnitt fällt der feste Satz „Empfehlenswert, sobald die
  App von außen erreichbar ist" weg, sobald die App weiß, wie sie genutzt
  wird. Direkt unter „nötig ist sie nicht" widersprach er sonst.

## 2.88.50 – September 2026

### Neu
- 🌐 **Die App merkt, ob sie von außen genutzt wird – und ob etwas davor
  steht.** Nicht durch einen Test von außen (dafür kennt sie ihre öffentliche
  Adresse nicht, und ein Aufruf aus dem eigenen Netz beweist nichts), sondern
  an den angemeldeten Anfragen selbst: Über Cloudflare kommen eigene
  Kopfzeilen mit, über Cloudflare Access zusätzlich dessen Anmeldenachweis,
  über einen Reverse Proxy mit Portfreigabe eine öffentliche Absenderadresse.
  Im Zwei-Faktor-Abschnitt steht dann „nur aus dem Heimnetz", „von außen,
  geschützt durch Cloudflare Access" oder „von außen – ohne Zugangsschutz
  davor".
- 🔔 **Im letzten Fall ein Hinweis für Admins ohne Zwei-Faktor** – einmal,
  mit „Zwei-Faktor einschalten". Mit Access davor drängt nichts: Dort steht
  mit dem Code per E-Mail schon ein zweiter Faktor vor der App.

### Behoben
- Hinweise auf dem Startbildschirm erscheinen jetzt auch auf Englisch
  übersetzt, wo es eine Übersetzung gibt.

## 2.88.49 – September 2026

### Behoben
- 🔐 **Rettungscodes ließen sich auf dem Handy nicht eintippen.** Das
  Code-Feld beim Anmelden holt den Ziffernblock – die Rettungscodes haben
  aber Buchstaben (a–f). Unter dem Feld steht jetzt **„Rettungscode
  eingeben"**, das die volle Tastatur holt. Außerdem gilt ein Rettungscode
  auch **ohne Bindestriche**; vorher hieß „3f9a0b12c7de" „Code stimmt
  nicht".

## 2.88.48 – September 2026

### Neu
- 🔐 **Zwei-Faktor schon bei der ersten Einrichtung.** Der Assistent hat
  einen Schritt „Absichern mit Zwei-Faktor" vor dem Abschluss (jetzt acht
  Schritte). Das Passwort vom Anlegen des Kontos ist schon eingetragen –
  QR-Code scannen, Code eintippen, Rettungscodes sichern, weiter. Es ist
  derselbe Block wie im Profil, nicht ein zweiter Nachbau; das Passwort
  liegt nur im Speicher der Seite und wird beim Ende des Assistenten
  vergessen. Überspringen geht wie bei jedem Schritt.

### Geändert
- Als Beispiel für den Anzeigenamen im Tausch-Netzwerk steht „Steinesammler"
  statt eines echten Vornamens.

## 2.88.47 – September 2026

### Behoben
- 🔐 **Der QR-Code für die Zwei-Faktor-Anmeldung ließ sich nicht scannen.**
  Er kam mit fester Größe (265 px) und ohne `viewBox`; die Oberfläche zeigt
  ihn in 200 px, und ein solches Bild wird dabei nicht verkleinert, sondern
  abgeschnitten – rechts und unten fehlte ein Drittel. Keine
  Authenticator-App konnte ihn lesen (gemeldet mit dem Google
  Authenticator). Jetzt skaliert er, hat den Rand, den die Norm verlangt,
  und einen weißen Grund im Bild selbst. Nachgeprüft mit der
  QR-Erkennung von macOS: der alte nicht lesbar, der neue fehlerfrei.

### Geändert
- 🔐 **Einschalten der Zwei-Faktor-Anmeldung beendet alle anderen
  Sitzungen.** Ein Gerät, das schon angemeldet war, blieb es bis zu 90 Tage
  – ohne je nach dem Code gefragt zu werden. Jetzt muss es sich neu
  anmelden; das Gerät, auf dem man einschaltet, bleibt angemeldet.

## 2.88.46 – September 2026

### Geändert
- 🛒 **„Verkaufsliste (Doppelte)" und „Fehlende Set-Figuren" stehen über dem
  Anlegen.** Das Feld für eine neue Einkaufsliste steht jetzt direkt über den
  Listen, zu denen sie gehört; die beiden Auswertungen rücken nach oben, und
  ihre Kästen klappen gleich unter den Knöpfen auf.
- **Feld und „Anlegen" in einer Zeile.** Vorher stand „Anlegen" als eigener
  grüner Balken über die volle Breite darunter. Der Platzhalter heißt dafür
  kürzer „Neue Liste, z. B. Flohmarkt" – der alte hätte auf dem Telefon
  292 px gebraucht, neben dem Knopf bleiben 210.

## 2.88.44 – September 2026

### Behoben
- ⭐ **Die Wunschliste frischt sich auf wie die Einkaufslisten.** Was ein
  anderes Gerät oder der Live-Scanner auf eine Einkaufsliste legte, erschien
  nach wenigen Sekunden von selbst – was er merkte oder wieder von der
  Wunschliste nahm, erst nach dem nächsten Neuladen. Die App verglich auf
  dem Listen-Tab nur den Stand der Einkaufslisten; jetzt zählt die
  Wunschliste mit.

## 2.88.43 – September 2026

### Geändert
- ⬆️ **Die Update-Prüfung fragt nicht mehr die GitHub-API.** Die erlaubt
  ohne Anmeldung nur 60 Abfragen je Stunde – für den ganzen
  Internetanschluss, geteilt mit jedem anderen Gerät dahinter. War das
  aufgebraucht, stand unter Mehr „GitHub gerade nicht erreichbar", und der
  Hinweis auf eine neue Fassung blieb aus. Jetzt liest die App die neueste
  Fassung aus der Weiterleitung der Release-Seite; die zählt nicht mit.
- Ein Fehlschlag wird eine halbe Stunde gemerkt. Vorher fragte jeder
  Aufruf des Mehr-Tabs erneut bei GitHub nach. „Jetzt prüfen" fragt
  weiterhin sofort.

## 2.88.42 – September 2026

### Geändert
- ✏️ **Die Suchvorschläge beim manuellen Erfassen in der neuen Handschrift.**
  Jeder Treffer trug vier gleich große Knöpfe – „✔ Übernehmen", „☆ Merken",
  „🛒 Liste", „BrickLink ↗". Jetzt derselbe Aufbau wie die Trefferkarte beim
  Scannen: **„✔ Übernehmen" breit und grün**, ☆ und 🛒 als Zeichen daneben,
  „Bei BrickLink ansehen ↗" als Verweis darunter.
- ⭐ **Der Stern ist gefüllt, wenn der Artikel schon auf der Wunschliste
  steht** – beim Scannen wie beim Suchen. Vorher erfuhr man das erst nach
  dem Tippen, als Zuruf „Steht schon auf der Wunschliste".
- „✔ Übernehmen" ist jetzt auch auf Englisch übersetzt.

## 2.88.41 – September 2026

### Geändert
- ✅ **„Da! Ab in die Sammlung" bestätigt sichtbar.** Bisher verschwand der
  Artikel einfach aus der Einkaufsliste, und die Meldung erschien unten am
  Rand – wer auf den Artikel schaute, bekam keine Rückmeldung. Jetzt bleibt
  die Zeile kurz stehen, links grün markiert und mit dem Schild
  „✔ In der Sammlung · Gebraucht" (beim Dazulegen „· jetzt 3×"), dasselbe
  Grün wie „schon in der Sammlung" auf der Wunschliste. Erst danach rückt
  sie zu den erledigten. Die Meldung unten nennt dazu den Namen.

### Behoben
- 🗓 **Das Jahr steht in den Suchvorschlägen nur noch einmal.** Beim
  manuellen Erfassen hieß es „sw0815 · 2017 · 2017 · Ø neu …": Der eigene
  Katalog gibt das Jahr gleich mit, und die Preisabfrage hängte es ein
  zweites Mal an.
- Beim Dazulegen hieß die Meldung noch „Einkaufspreis gemittelt" – seit
  2.88.40 wird addiert, wie es sich für ein Kaufbuch gehört.

## 2.88.40 – September 2026

### Behoben
- 🧾 **Käufe von der Einkaufsliste stehen jetzt im Kaufbuch.** „✔ Da! Ab in
  die Sammlung" schrieb den Preis direkt an den Eintrag, aber keinen Posten
  ins Kaufbuch – und der bezahlte Betrag ist die Summe dieser Posten. Kam
  danach ein weiteres Exemplar mit Preis dazu, wurde die Summe aus dem Buch
  neu gerechnet, und der Listenkauf fiel heraus: 5 € von der Liste plus 2 €
  gescannt ergaben 2 €. Beim nächsten Neustart zog die App fehlende Posten
  zwar nach, bis dahin aber stimmte die Summe nicht. Aufgefallen beim Test
  einer frisch aufgesetzten Instanz.

  Dabei auch behoben: „zusätzlich" **mittelte** den alten und den neuen
  Preis, statt sie zu addieren, und „überschreiben" ließ die alten Posten im
  Buch stehen. Im Kaufbuch steht als Herkunft jetzt der Name der Liste.

## 2.88.39 – September 2026

### Behoben
- ✅ **„✔ Da! Ab in die Sammlung" fragt nicht mehr alles noch einmal ab.**
  Für Profis öffnete der Knopf eine eigene Zeile mit „Preis [..] € – leer =
  BrickLink-Ø" und „✔ Gebraucht übernehmen" – dabei stehen Einkaufspreis und
  Zustand direkt darüber in derselben Karte. Jetzt nimmt ein Tipp, was dort
  steht: den Zustand aus der Pille, den Preis aus dem Einkaufsfeld (auch
  wenn er noch nicht mit ✓ gespeichert ist – man sieht ihn ja). Leer heißt
  wie bisher: BrickLink-Durchschnitt; das steht jetzt als Erklärung am Feld.

  Gefragt wird nur noch, wenn es wirklich etwas zu entscheiden gibt: Steht
  die Figur schon in diesem Zustand in der Sammlung, heißt es „zusätzlich
  oder überschreiben?" – mit rotem ✕ wie überall.

## 2.88.38 – September 2026

### Geändert
- 🧩 **Fehlende Set-Figuren ohne Knopfzeile.** Je Figur standen zwei gleich
  große Knöpfe, „☆ Merken" und „BrickLink ↗", bei gemerkten Figuren dazu ein
  gelbes Schild – bei 40 fehlenden Figuren viel Höhe für wenig. Jetzt wie im
  Katalog: **der Stern als Zeichen rechts an der Zeile**, gefüllt und gelb,
  wenn die Figur schon auf der Wunschliste steht; BrickLink als Verweis in
  der Nummernzeile. Im Fuß ist „☆ Alle auf die Wunschliste" die breite
  Hauptsache, CSV und Drucken stehen daneben.

### Behoben
- 🔄 **Ein Neustart erzeugte Fehlerberichte.** Beim Ausrollen ist die
  Instanz ein paar Sekunden weg; Cloudflared antwortet dann mit seiner
  eigenen HTML-Seite, und die Hintergrundabfragen (Tauschbörse jede Minute,
  Update-Wache) laufen genau hinein. So kam am 24.09. ein „502 bei POST
  /api/hub/trades/sync" an – das Tunnelprotokoll zeigte 17 Sekunden
  Neustart und mittendrin genau diese Anfrage.

  Verschwiegen wird so ein Fehler trotzdem nicht: Die App fragt nach 20
  Sekunden `/api/laufzeit`, seit wann der Server läuft. Ist er um den Fehler
  herum frisch gestartet, war es der Neustart; läuft er schon länger, war es
  ein echter Ausfall, und der wird gemeldet. Fehler der App selbst gehen wie
  bisher sofort ins Protokoll.

## 2.88.37 – September 2026

### Geändert
- 🧾 **Wunschliste, Einkaufsliste und „Auf eine Liste legen" sprechen
  dieselbe Sprache wie der Scan.** Überall dasselbe Muster: eine breite
  Hauptsache, Löschen und Abbrechen als rotes Zeichen, die Wege nach
  draußen als Verweise, eine Wahl als Pille.
  - **Wunschliste:** `[✔ Gekauft!] [🗑]` statt vier gleich großer Knöpfe
    im Raster; Preisverlauf und BrickLink als Verweise darunter. „Gekauft
    als" ist die Zeile `[Preis €] [Gebraucht] [Neu] [✕]` – „leer =
    BrickLink-Ø" steht als Erklärung am Feld statt als eigene Zeile.
  - **Einkaufsliste:** Einkaufspreis mit kleinem ✓ und daneben der Zustand
    als Pille – vorher zwei umrandete Zustandsknöpfe, einer gelb, und ein
    grüner ✓-Balken über die volle Breite. Im Fuß `[Gesamtangebot]
    [Archivieren] [🗑]` statt „Liste löschen" über die volle Breite.
  - **Auf eine Liste legen** (Trefferkarte, Suchtreffer, Formular):
    Einkaufspreis und Zustand in einer Zeile, die Listen als ruhige Knöpfe
    – im Formular war jede Liste ein grüner –, unten `[+ Neue Liste] [✕]`
    bzw. `‹`, wenn es zurück zur Listenwahl geht.
  - **Figurenliste im Set-Steckbrief:** Das ✕ im Zustands-Schritt war dort
    noch schwarz, als einzige Stelle der App.

### Behoben
- 🌐 **Texte, die an der Übersetzung vorbeiliefen.** „+ Zur Sammlung",
  „83 % sicher", „Auf welche Liste?", „Flohmarkt 24.09." und die Zurufe
  nach dem Aufnehmen standen als deutscher Text im Markup; zwei Zurufe
  wurden sogar aus deutschen Teilen zusammengesetzt. Wer die App auf
  Englisch nutzt, las dort Deutsch.

## 2.88.36 – September 2026

### Behoben
- 🌫 **Nach jedem Scan wurde die ganze Seite grau.** Der grüne „hier
  geschaut"-Rahmen auf dem Foto dunkelt mit einem riesigen Schatten das Foto
  um sich herum ab. Der Behälter schnitt aber nicht ab – seit **v1.78.0
  (31.07.)** lief der Schatten über die **ganze Seite**. Alles wurde um 28 %
  dunkler; nur was eine Ebene höher liegt – Kopfleiste, Trefferkarte – blieb
  hell. Das sah aus wie ein grauer Hintergrund, der nach dem Foto auftaucht.

  Der Behälter schneidet jetzt ab. Damit das Foto seinen eigenen
  Schlagschatten nicht verliert, trägt diesen jetzt der Behälter – dessen
  eigener Schatten wird vom Abschneiden nicht erfasst.

### Geändert
- 📏 **Der Zustands-Schritt steht in einer Zeile**, so breit wie die
  Knopfreihe, die er ersetzt: `[Bezahlt €] [Gebraucht] [Neu] [✕]`. In
  2.88.35 zog sich das Feld auf breiten Karten noch über 650 Pixel. Jetzt
  teilen sich die beiden Zustände den Platz, Feld und ✕ bleiben fest – die
  Karte springt beim Umschalten nicht. **Abbrechen ist ein rotes ✕**, in
  derselben Sprache wie „Letztes Exemplar löschen" in der Sammlung.

- 📝 **„Manuell erfassen" mit eigenen Bauteilen.** Das rohe „Datei
  auswählen | Keine Datei ausgewählt" des Systems ist weg: Das Bild ist eine
  Kachel mit Vorschau und ✕, daneben „Bild wählen" und „Vom Scan" in
  gleicher Größe. **Typ und Zustand sind Pillen** wie im Steckbrief statt
  Systemauswahl, die **Anzahl hat Plus und Minus**, und unten stehen die
  Knöpfe wie auf der Trefferkarte – ein breiter grüner, ☆ und 🛒 als
  Zeichen. Dabei ist auch „Zur Sammlung" endlich überall **grün**; im
  Formular war es gelb.

  Die alten Auswahlfelder bleiben unsichtbar als Quelle der Wahrheit
  stehen: `m-type` wird an elf Stellen gelesen – keine davon musste
  angefasst werden. Wo der Code den Wert direkt setzt, zeichnen sich die
  Pillen nach; ein Test hält fest, dass kein Setzen ohne das dazukommt.

## 2.88.35 – September 2026

### Geändert
- 🎯 **Die Trefferkarte im Scan hat eine Hauptsache.** Vorher standen dort
  vier gleich große Knöpfe mit demselben kräftigen Rahmen – obwohl sie sehr
  unterschiedlich wichtig sind: „Zur Sammlung" will man fast immer, „Liste"
  fast nie, und BrickLink führt aus der App heraus. Weil sie nicht
  nebeneinander passten, brach jede Beschriftung um („+ Zur / Sammlung").

  Jetzt derselbe Aufbau wie in der Katalogliste und im Steckbrief: **ein
  breiter Knopf** für die Sammlung, **Merken und Liste als Zeichen**
  daneben, **BrickLink als Verweis** darunter. Nach dem Merken füllt sich
  der Stern und das Zeichen wird gelb, statt dass „⭐ Gemerkt" den kleinen
  Knopf sprengt.

- ⚖️ **Der Zustands-Schritt ist ruhiger.** Ein Tipp auf „Gebraucht" oder
  „Neu" nimmt die Figur weiter sofort auf – das ist der schnellste Weg in
  die Sammlung, ein Zwischenschritt wäre ein Verlust. Geändert hat sich die
  Gewichtung: „Abbrechen" war so groß wie das Hinzufügen selbst. Jetzt teilen
  sich „Bezahlt" und „Abbrechen" eine Zeile, und Abbrechen ist ein Verweis –
  mit derselben Trefferfläche von 44 Pixeln wie jeder Knopf. **324 → 266 px.**

  Der Hinweis „wird sofort gespeichert" stand vorher ohne Übersetzung im
  Markup; auf Englisch stand dort Deutsch.

## 2.88.34 – September 2026

### Behoben
- 🚨 **Aus dem Scan liess sich nichts mehr aufnehmen.** „+ Zur Sammlung",
  „☆ Merken" und „🛒 Liste" taten **gar nichts** – keine Reaktion, keine
  Fehlermeldung, nichts im Protokoll. Betroffen seit **2.86.5 (22.09.)**,
  also zwei Tage.

  Dieselbe Zeile wie in 2.88.32, nur an der zweiten Stelle: `2.86.5` setzte
  `enrichSuggestions(items, meta.detailVon || 0)` in **zwei** Funktionen –
  in eine, die ein `meta` hat, und in die Scan-Ansicht, die keines hat. Dort
  flog die Ausnahme genau **zwischen** dem Zeichnen der Karte und dem
  Verdrahten der Knöpfe:

  ```
  enrichSuggestions(items, meta.detailVon || 0);   ← hier knallt es
  wireWantButtons(…);  wireCartButtons(…);          ← kommt nie an
  …forEach([data-add])                              ← kommt nie an
  ```

  Die Karte stand also vollständig da und sah richtig aus – sie war nur
  taub. Die Scan-Ergebnisse brauchen kein `meta`: Sie kommen in einem Stück,
  es gibt keine zweite Seite.

- 🛡 **Ein Wächter gegen genau diese Art Fehler.** Beide Zeilen sahen
  richtig aus – ein Test auf den Wortlaut hätte nichts gefunden. Der neue
  prüft den **Geltungsbereich**: Keine Funktion darf ein `meta` benutzen,
  das sie nicht hat. Kommentare und Zeichenketten bleiben dabei außen vor,
  sonst zählt jedes `<meta>` in einer Vorlage mit.

## 2.88.33 – September 2026

### Dokumentation
- 📖 **Das englische Handbuch war seit 2.87.0 stehen geblieben.** Nachgezogen
  sind die Kamera in der App (Livebild, Mediathek daneben, Zoom, der
  Sucherausschnitt und warum das Telefon jedes Mal nach der Freigabe fragt)
  und der Steckbrief mit Kopf und drei Reitern, samt Zeitspannen und
  Ablesen am Preisverlauf.

  Ein Kapitel zum Katalog-Durchblättern gibt es dort nicht – `MANUAL.md` ist
  eine gekürzte Fassung, kein Spiegel von `HANDBUCH.md`.

## 2.88.32 – September 2026

### Behoben
- 🔢 **Die Suche nach einer BrickLink-Nummer brach ab** (aus der App
  gemeldet, 24.09.2026): `Cannot read properties of undefined (reading
  'detailVon')`. Fand BrickLink zu einer eingetippten Nummer etwas, stürzte
  das Zeichnen der Trefferliste ab – die Treffer waren da, zu sehen war
  nichts.

  Die Zeichenfunktion nimmt die Treffer und freiwillig ein paar Angaben zur
  Seitenzahl. Drei der vier Aufrufer haben diese Angaben nicht; im Rumpf war
  eine Stelle darauf vorbereitet, eine zweite nicht. **Seit 2.86.5 drin.**

- 🙈 **Warum es drei Monate niemand bemerkt hat.** Der dritte dieser Wege –
  die Nummernsuche beim manuellen Erfassen – steht in einem Fangblock, der
  *jede* Ausnahme in einen Hinweistext verwandelt. Dort stand dann „Cannot
  read properties of undefined – der Eintrag behält die Rebrickable-Nummer",
  und das liest sich wie eine Meldung des Dienstes. Gemeldet wurde nichts.

  Ein `TypeError` ist kein Netzwerkfehler: Solche Ausnahmen gehen jetzt auch
  dort ins Fehlerprotokoll, statt nur als Text dazustehen.

## 2.88.31 – September 2026

### Geändert
- 🟡 **Die Marke im Kopf sieht aus wie überall sonst.** Die erste Noppe war
  dort weiß – als Einzige in der ganzen App. Der Grund war handfest: Die
  Kopfleiste ist gelb, eine gelbe Noppe darauf wäre unsichtbar. Der Preis
  war die Farbfolge, an der man die Marke erkennt.

  Statt die Farbe zu ändern, tragen jetzt **alle vier eine haarfeine
  Kante**. Sie hält die gelbe Noppe gegen den gelben Grund und lässt die
  anderen drei, wie sie sind – alle vier, weil ein Ring um genau eine von
  Nahem auffiele.

- 🌙 **In den dunklen Themen fällt die Ausnahme ganz weg.** Dort ist die
  Kopfleiste dunkel; die Noppe ist auch ohne Kante bestens zu sehen. Das
  Blaugrau, das da stand, war nur mitkopiert. In Nova nimmt die erste Noppe
  jetzt die Akzentfarbe des Themas an – dort ist das ein Blau, und das ist
  Absicht des Themas, nicht ein verlorenes Gelb.

## 2.88.30 – September 2026

### Behoben
- 🧩 **Absturz beim Nachladen der Sammlung** (aus der App gemeldet,
  24.09.2026): `NotFoundError: Failed to execute 'insertBefore' … not a
  child of this node`, aus dem Beobachter heraus.

  Die Sammlung lädt blockweise nach und fügt die Karten vor einer
  unsichtbaren Marke ein. Zeichnet sich die Liste neu – Suche, Filter,
  Sortierung –, wird der Nachschub beendet und die Liste geleert; eine
  beim Beobachter **bereits eingereihte Meldung** läuft aber trotzdem noch
  durch. Dann zeigt die Marke ins Leere. Nachgestellt und Wort für Wort
  derselbe Fehler; der Nachschub hält jetzt an, wenn die Marke nicht mehr
  zur Liste gehört.

  Nebenbei hätte das auch Karten aus dem **alten** Bestand in die neue
  Liste gesetzt, denn Daten und Zählstand gehörten noch zum vorigen Lauf.

- 🔇 **Und der stillere Fehler an derselben Stelle:** Der Beobachter lag in
  einer Variablen der Datei, nicht beim einzelnen Lauf. Räumte ein alter
  Lauf auf, beendete er damit den Beobachter des **neuen** – die Liste
  hörte lautlos auf nachzuladen, ohne Fehlermeldung. Jeder Lauf hat jetzt
  seinen eigenen.

## 2.88.29 – September 2026

### Geändert
- 🧱 **Der Platzhalter für fehlende Bilder trägt die heutige Handschrift.**
  Er war als Einziger noch im alten Stil: ein flächiger gelber Stein mit
  3 px schwarzer Kontur. Die App zeichnet Steine längst anders – weiche
  Ecken, keine Kontur, eine dunklere Unterkante als Tiefe. Jetzt sind es
  die **vier Steine des Ladezeichens**, in denselben Farben und derselben
  Reihenfolge: Gelb, Rot, Blau, Grün. Er steht an sechs Stellen und liest
  sich noch bei 28 Pixeln.

## 2.88.28 – September 2026

### Geändert
- 📚 **Die Artikel im Katalog sind endlich auseinanderzuhalten.** Der Name
  stand einzeilig in 162 Pixeln – nachgemessen an 80 Zeilen auf einem
  Telefon: **74 % abgeschnitten, und 14 Zeilenpaare sahen gleich aus.**
  BrickLink-Namen tragen die Identität vorn und das Unterscheidungsmerkmal
  hinten, also fiel genau der Teil weg, der zählt:

  ```
  Luke Skywalker - Pilot Suit, … Dark Gray Hips, Yellow Head
  Luke Skywalker - Pilot Suit, … Dark Bluish Gray Hips, Yellow Head
            beide sichtbar als →  „Luke Skywalker - Pilot Suit"
  ```

  In der Mitte zu kürzen half kaum (14 → 13 gleiche Paare) – die Namen
  teilen sich Kopf *und* Schwanz. Es half nur Platz:

  | | ganz lesbar |
  |---|---|
  | vorher | 23 % |
  | Name darf umbrechen (zwei Zeilen) | 57 % |
  | + Merkknopf raus, Namensfeld 196 px | **75 %** |

- ⭐ **Gemerkt wird jetzt im Steckbrief**, nicht mehr am Zeilenende. Dass
  eine Figur auf der Wunschliste steht, zeigt ein kleiner **Stern am
  Bild** – derselbe wie im Reiter „Wünsche"; der Katalog war die einzige
  Stelle mit einem Herz. Der Stern ist nur eine Anzeige, ein Tipp darauf
  öffnet den Steckbrief. „Hab ich" bleibt, wo es war: Das braucht man im
  Vorbeigehen.

- 🗂 **Die Artikel stehen auf weißen Karten**, je Hunderterblock eine, und
  die Blocknummer liegt dazwischen auf der grauen Fläche. Sie gliedert, sie
  ist kein Artikel. Bisher lag die ganze Liste ohne eigene Fläche auf dem
  Grau, und die weißen Bildchen wirkten darin wie Löcher.

### Behoben
- 🔌 **„Merken" im Steckbrief hätte lautlos aufgehört zu wirken.** Es
  schaltete nicht selbst, sondern suchte den passenden Knopf in der
  Katalogzeile und klickte ihn. Mit dem Herz wäre dieser Knopf verschwunden
  – und die Prüfung `if (knopf)` hätte den Fall kommentarlos verschluckt:
  keine Wirkung, keine Fehlermeldung. Beide Wege schalten jetzt über die
  Daten, und ein Fehlschlag nimmt die Anzeige wieder zurück.

## 2.88.27 – September 2026

### Geändert
- 🎚 **Die Zoomstufen versprechen nichts mehr über Objektive.** In 2.88.26
  hießen sie 1× / 2× / 5×, weil moderne iPhones dort einrasten. Das war
  eine Zusage, die die App nicht halten kann: Auf einem Modell **ohne
  Teleobjektiv** wäre die 5 rein gerechnet. Und umgekehrt genauso – auf
  einem Gerät *mit* 5×-Tele ist ein 3× eine Zwischenstufe. **Es gibt keine
  Leiter, die überall auf Rastpunkte trifft.**

  Der Grund liegt tiefer: Die Schnittstelle **unterscheidet Optik und
  Rechnung nicht**. Sie meldet einen durchgehenden Bereich, in dem der
  digitale Zoom mitzählt (beim iPhone bis 25×); welcher Faktor mit Glas
  entsteht, steht nirgends. Was sich nicht unterscheiden lässt, darf die
  Oberfläche auch nicht andeuten.

  Also wieder eine gleichmäßige Leiter **1× / 2× / 3×**, die nur sagt, wie
  viel näher es wird – und die Kneifgeste für alles dazwischen und
  darüber. Gefiltert wird weiterhin: Was der gemeldete Bereich nicht
  hergibt, erscheint nicht.

## 2.88.26 – September 2026

### Geändert
- 🔍 **Die Zoomstufen heißen jetzt 1× / 2× / 5×.** Vorher 1/2/3 – eine
  Zahlenreihe, die kein Telefon so hat. Ein iPhone 16 Pro Max rastet bei
  1×, 2× und 5× ein; ein 3× gibt es dort **nicht**, das läge zwischen zwei
  Objektiven und wäre gerechnet.

  Wo ein Gerät den Bereich nicht hergibt – kein Teleobjektiv –, fällt die 5
  von selbst weg. Und wo es den Gerätezoom gar nicht gibt, bleibt es bei
  1/2/3: Digital wird nur beschnitten, und bei 5× blieben von einem
  Sucherausschnitt von 599 Pixeln noch 120 übrig.

  **Die Zahlen benennen die Vergrößerung, nicht das Objektiv** – so wie
  Apples Beschriftung auch. Welches Glas dafür zum Einsatz kommt,
  entscheidet iOS.

  > **Warum eine feste Leiter und keine abgefragte:** Das Telefon gibt
  > seine Rastpunkte nicht heraus. Der Browser bekommt nur `{min, max,
  > step}`, also einen durchgehenden Bereich; die Umschaltpunkte kennt nur
  > AVFoundation intern. Aus `max` lässt sich der optische Endpunkt auch
  > nicht ablesen, weil dort der digitale Zoom mitzählt (bis 25×).

### Behoben
- 🔢 **Ein Zwischenwert aus der Kneifgeste fand seine Stufe nicht mehr.**
  Welche Stufe ihn anzeigt, wurde mit `Math.floor` bestimmt – das setzt
  die Reihe 1, 2, 3 voraus. Bei 1/2/5 käme für 3,4× eine 3 heraus, die es
  nicht gibt: Keine Stufe trüge den Wert, die Leiste zeigte weiter „2×".

## 2.88.25 – September 2026

### Geändert
- ↩️ **Die Objektivwahl aus 2.88.24 ist wieder raus.** Am Gerät sah man,
  warum: iOS bietet dort gar keine einzelnen Objektive an, sondern seine
  virtuellen Kombi-Kameras („Rückseitige Triple-Kamera", „Rückseitige
  Dual-Weitwinkelkamera") – und die Frontkamera gleich mit. Viel Auswahl,
  wenig Gewinn. Die Zoomstufen genügen.

### Behoben
- 🔍 **„1×" hätte am iPhone heraus gezoomt.** Der Gerätezoom wurde gegen
  den *kleinsten* Wert gerechnet, den die Kamera meldet. Bei einer
  Rückseite, die intern zwischen Ultraweitwinkel, Weitwinkel und Tele
  umschaltet, gehört dieser kleinste Wert zum **Ultraweitwinkel** – die
  Ansicht beim Öffnen liegt darüber. „1×" hätte also ein weiteres Bild
  gezeigt als das, was man gerade sieht, und „2×" wäre kaum mehr als
  normal gewesen.

  Bezugspunkt ist jetzt, was die Kamera beim Öffnen meldet: **Was du
  siehst, ist 1×.** Nachgemessen an einer Attrappe mit dem Verhalten einer
  Triple-Kamera (Bereich 1–15, Ausgangslage 2): 2× stellt 4, 3× stellt 6,
  und zurück auf 1× stellt wieder 2. Rein optisch, ohne Ausschnitt.

## 2.88.24 – September 2026

### Neu
- 🔭 **Die Objektive des Telefons stehen zur Wahl.** Über den Zoomstufen
  liegt jetzt eine Reihe mit den Kameras, die das Gerät hergibt –
  Weitwinkel, Ultraweitwinkel, Teleobjektiv. Wer eines davon wählt,
  bekommt **echte Optik** statt eines Ausschnitts.

  **Warum das nicht der Zoomregler tut:** Auf dem iPhone gibt es die
  Zoom-Schnittstelle nicht. WebKit reicht `zoom` in den Fähigkeiten einer
  Videospur nicht heraus, und weil alle Browser auf dem iPhone dieselbe
  Maschine benutzen, hilft auch kein anderer. Was es seit iOS 16.3 gibt:
  Die Rückkameras stehen **einzeln** in der Geräteliste. Über diesen Weg
  läuft die Wahl.

  Die Namen kommen vom Betriebssystem und sind übersetzt – darum werden
  sie angezeigt und nicht durchsucht. Welches Objektiv wofür taugt, weiß
  die App nicht: **Ein Teleobjektiv stellt oft erst ab einem halben Meter
  scharf** und ist für eine Figur auf dem Tisch womöglich das falsche.
  Also wählen lassen, nicht raten. Wo es nur eine Kamera gibt, bleibt die
  Reihe weg.

## 2.88.23 – September 2026

### Neu
- 🔍 **Zoom in der Kamera.** Über dem Auslöser stehen **1× / 2× / 3×**, und
  Kneifen mit zwei Fingern geht auch – stufenlos. Wo das Gerät es kann,
  zoomt der Sensor selbst (echte Details); sonst wird der Ausschnitt
  verkleinert. Die Stufen erscheinen nur, wo es etwas zu wählen gibt.

### Behoben
- 📷 **Aufgenommen wurde viel mehr, als der Sucher zeigte.** Das Livebild
  füllt den Bildschirm und ist dafür beschnitten – auf einem hochkanten
  Telefon sieht man **26 % der Bildbreite**. Das Foto nahm trotzdem das
  ganze Sensorbild. Wer eine Figur einrahmte, bekam sie also auf ein
  Viertel geschrumpft, und die Erkennung rechnet jedes Bild auf 1024 Pixel
  herunter.

  Der alte Grund dafür war, dass sonst der Rand fehle, an dem die Figur oft
  steht. Der Gedanke stimmt, die Größenordnung nicht: 74 % sind kein Rand.
  Jetzt wird der Sucherausschnitt genommen, **plus ein Fünftel
  Sicherheitsrand**. Nachgemessen: Die Figur kommt ohne Zoom mit **171
  statt 96 Pixeln** bei der Erkennung an, mit 3× mit **427**.

- 🔓 **Nicht mehr bei jedem Foto nach der Kamera fragen.** Bisher endete
  der Kamerastrom beim Schließen sofort; das nächste Foto fragte neu. Wer
  fünf Figuren hintereinander scannte, wurde fünfmal gefragt. Der Strom
  bleibt jetzt eine halbe Minute stehen – beim Tabwechsel und im
  Hintergrund endet er sofort, damit die Kameraanzeige des Geräts nicht
  ohne Grund leuchtet.

  **Das Fragen beim App-Start bleibt.** Für eine Web-App vom
  Startbildschirm merkt sich iOS die Kamerafreigabe nicht über den Start
  hinaus (WebKit-Fehler 215884) – daran kann keine App etwas ändern.

## 2.88.22 – September 2026

### Behoben
- 📐 **Der Update-Kasten brach mitten durch den Satz.** „Die App startet
  gleich / neu – bitte kurz warten." – der Umbruch riss das Verb
  auseinander, und in der zweiten Zeile las sich „neu" wie ein neuer
  Gedanke. Jetzt bricht er nach „neu –", wo der Satz auch atmet.

### Dokumentation
- 📖 **Handbuch und README beschreiben den Steckbrief, wie er heute
  aussieht.** Dort standen noch die vier Abschnitte von 2.69.0 und ein
  Themenfeld mit Stift, den es bei Katalogartikeln nicht mehr gibt. Neu
  beschrieben sind der Kopf (Bild über die volle Breite, Marken, die drei
  Kacheln) und die Reiter Exemplar / Preise / Mehr.
- 📖 **Die Kamera in der App steht jetzt im Handbuch** (Abschnitt 4.1):
  Livebild beim Antippen, Mediathek darin daneben, Licht nur wo das Gerät
  es kann – und der Hinweis, dass es über `http://` beim Dateidialog
  bleibt, weil das Livebild eine gesicherte Verbindung braucht.
- 📖 **Zeitspannen und Ablesen am Preisverlauf** sind beschrieben, samt dem
  Punkt, der leicht Fragen aufwirft: Die Spannen filtern im Browser und
  kosten keinen Abruf.

## 2.88.21 – September 2026

### Behoben
- 🧱 **Die Ladeanzeige im Katalog klebte unter der Filterleiste** und sagte
  nicht, worauf man wartet. Dort standen nur die vier Steine – ohne
  Abstand, ohne Beschriftung. Jetzt derselbe Block wie in Sammlung,
  Statistik und Tauschbörse: Luft darum und „Katalog wird geladen …"
  darunter.

## 2.88.20 – September 2026

### Geändert
- ↩️ **Die Schiebeschalter aus 2.88.17 und 2.88.19 sind zurückgenommen.**
  Sie kamen aus der Formensprache der Fenster und wirkten in den Listen
  geborgt: Die App lebt von kräftigen Konturen, ein weicher Schalter sieht
  darin aus wie aus einer anderen App hineinkopiert. Reiterreihen,
  Katalogfilter, Themenwahl und Suchfeld stehen wieder wie zuvor.

  Geblieben ist nur, was kein Geschmack ist: die Trefferfläche der Marken
  „Hab ich" und „Merken" im Katalog – 44 statt 35 Pixel, das Maß, das
  überall sonst gilt. Und die unsichtbare Vorsorge im Katalogkopf gegen das
  seitliche Verschieben.

## 2.88.19 – September 2026

### Geändert
- ↩️ **Zurückgenommen mit 2.88.20** – hier nur der Vollständigkeit halber,
  weil 2.88.20 darauf verweist: Die Schiebeschalter aus 2.88.17 waren auf
  alle Reiterreihen ausgeweitet worden (Wünsche/Einkaufen/Archiv/Katalog,
  Katalogfilter, Tauschbörse). Zwei Formensprachen übereinander sahen
  schlechter aus als eine, aber die richtige war die alte.

  Geblieben ist die Trefferfläche der Marken „Hab ich" und „Merken" im
  Katalog: 44 statt 35 Pixel, das Maß, das überall sonst gilt.

## 2.88.18 – September 2026

### Behoben
- 🔁 **„Bilder holen" lief endlos über dieselben Bilder.** Von BrickLink
  kommen die meisten Figurenbilder mit **400 Pixeln** – nachgemessen: von
  100 frisch geholten waren 91 genau 400 groß und acht 800. Die Ablage
  verkleinert nur, sie erfindet keine Pixel; ein solches Bild ist nach dem
  Holen genauso klein wie vorher und galt deshalb sofort wieder als offen.

  Neben jedem geholten Bild liegt jetzt eine Merkdatei mit der Zielgröße im
  Namen. Damit endet der Lauf – und wenn die Zielgröße später steigt, gilt
  sie nicht mehr und alles wird noch einmal versucht.

  **Was das für die Schärfe heißt:** Das große Bild im Steckbrief wird nur
  dort besser, wo BrickLink mehr als 400 Pixel liefert. Bei vielen Figuren
  ist 400 schlicht das Original.

- ↩️ **Der Text im Update-Fenster bricht ausgeglichen um.** „bitte kurz /
  warten." ließ das letzte Wort allein stehen.

## 2.88.17 – September 2026

### Geändert
- 📚 **Der Katalogkopf spricht dieselbe Sprache wie der Rest.** Die vier
  Filter („Alle", „Fehlt mir", „Hab ich", „Gemerkt") waren einzeln
  umrandete Knöpfe, einer davon gelb – das sah aus wie vier Aktionen, ist
  aber eine Wahl. Jetzt ein Schiebeschalter, dieselbe Form wie
  „Gebraucht/Neu" im Steckbrief. „Figuren/Sets" ebenso.

  Themenwahl und Suchfeld tragen die ruhige Fassung aus den Fenstern:
  weiche Kontur, Fläche statt Kasten, Rand erst beim Hineingehen.

- 🛡 **Dieselbe Vorsorge wie in der Sammlung.** Im Katalogkopf steht
  dasselbe Auswahlfeld in derselben Bauweise, an der Safari die Seite
  seitlich aufschob – der Kopf schneidet jetzt ab, bevor es dort dazu
  kommen kann.

## 2.88.16 – September 2026

### Geändert
- 🪟 **Auch Hilfe und Figuren-Steckbrief fahren jetzt auf.** Sie hängen an
  einer anderen Hülle als die übrigen Fenster und blieben deshalb beim
  Umbau zurück – sie sprangen herein, während alles daneben aufging. Der
  Schleier dahinter ist jetzt ebenfalls weichgezeichnet.

- 🔘 **Die Knöpfe im Katalogfenster haben dieselben Maße wie überall
  sonst** – mindestens 44 Pixel hoch, weiche Ecken. Am Telefon trifft man
  sie damit sicher.

## 2.88.15 – September 2026

### Geändert
- 🔍 **„Bilder holen" schärft die alten mit.** Bisher holte es nur, was ganz
  fehlte; die vor 2.88.0 abgelegten 400er blieben liegen und wurden erst
  scharf, wenn jemand den Artikel öffnete. Bei 780 Figuren dauert das seine
  Zeit. Sie gelten jetzt als offen und laufen in denselben Häppchen mit,
  samt Fortschrittsanzeige.

  **Richtigstellung:** In 2.88.3 und 2.88.13 stand, ein Sammellauf ginge
  gegen dasselbe BrickLink-Tageskontingent wie die Preise. Das ist falsch.
  Bilder kommen von den CDNs (`img.bricklink.com`, `cdn.rebrickable.com`),
  das Tageslimit von 5000 gilt für `api.bricklink.com`. Mit diesem falschen
  Argument war die bessere Lösung verworfen worden.

- 🪟 **Interesse, Melden und das Gespräch sehen aus wie der Rest.** Der
  Steckbrief hatte die ruhigere Sprache bekommen, der Dialog auch – diese
  drei blieben zurück und fielen nebeneinander auf. Sie sind gleich gebaut,
  also tragen sie jetzt dasselbe Kleid: weiche Felder, Abstand zum Rand,
  gleich breite Knöpfe.

- 🐞 **Ein wiederkehrender Fehler behält beides**, den ersten und den
  jüngsten Text. Gleichartige Meldungen werden zusammengefasst und behielten
  bisher nur den ersten; nach einer Behebung erhöhte ein Wiedersehen bloß
  den Zähler, und man sah dem Eintrag nicht an, ob er von vor oder nach der
  Änderung stammte. Genau daran ist am 23.09.2026 eine Runde
  verlorengegangen.

## 2.88.14 – September 2026

### Behoben
- 📈 **Am Telefon blieb der abgelesene Preis nicht stehen.** Beim Antippen
  der Kurve erschienen Datum und beide Preise – und verschwanden beim
  Loslassen wieder, also genau in dem Moment, in dem man sie lesen wollte.

  Am Zeiger ist das Ausblenden richtig: Die Maus fährt weiter, ein
  klebender Wert wäre dort falsch. Am Finger ist es andersherum, denn zum
  Ablesen muss man loslassen. Jetzt bleibt der Wert stehen, bis man die
  Kurve erneut antippt oder eine andere Zeitspanne wählt.

## 2.88.13 – September 2026

Diese Fassung bündelt alles seit 2.88.2. Die Zwischenschritte 2.88.3 bis
2.88.12 liefen nur auf einer Instanz und stehen unten einzeln – hier das
Wesentliche für alle.

### Geändert
- 🔍 **Zu klein abgelegte Bilder holen sich selbst nach**, sobald jemand die
  Figur oder das Set aufruft. Wer durch die Sammlung blättert, löst nichts
  aus.

  *(Hier stand zunächst, ein Sammellauf ginge gegen dasselbe
  BrickLink-Tageskontingent wie die Preise. Das war falsch – siehe 2.88.15.)*

- 🧹 **Die Fehlersuche-Abschnitte sind raus** – sowohl die Überstands-
  Messung, die eigens für die Jagd unten gebaut wurde, als auch das
  Abschalten einzelner Bausteine aus 2.73.0. Letzteres war für die
  Absturzsuche gedacht; die ist abgeschlossen, und was damals gelernt wurde,
  steht in den Proben. Wer Bausteine abgeschaltet hatte, bekommt sie damit
  automatisch zurück.

### Behoben
- ↔️ **Die Sammlung ließ sich seitlich schieben** – auf dem iPhone, nicht
  auf dem Prüfgerät. Der Rahmen um das Sortierfeld ist 98 Pixel breit, sein
  Inhalt meldete 175: Safari rechnet die Textbreite der `<option>`-Einträge
  in den Überlauf ein, obwohl diese Liste nie gezeichnet wird. Von dort
  wanderte es in die Filterleiste und bis zur Seite. Der Rahmen schneidet
  jetzt ab, und die Felder dürfen schrumpfen (`min-width: 0`).

  Sichtbar verschwindet dadurch nichts: Das Feld klippt seinen Text ohnehin,
  und die aufgeklappte Liste zeichnet das Betriebssystem außerhalb des
  Kastens.

## 2.88.12 – September 2026

### Geändert
- 🧹 **Die Überstands-Messung ist wieder raus.** Sie war für genau eine
  Jagd gebaut (2.88.4 bis 2.88.11) und hat sie erledigt: Ein Fehler, der
  sich auf keinem Prüfgerät nachstellen ließ, wurde dort gemessen, wo er
  auftrat. Was bleibt, sind die Proben und der Eintrag hier – das Werkzeug
  selbst muss niemand mit sich herumtragen.

## 2.88.11 – September 2026

### Behoben
- ↔️ **Das seitliche Schieben in der Sammlung – die Ursache.** Gemessen auf
  dem Gerät: Der Rahmen um das Sortierfeld ist 98 Pixel breit, sein Inhalt
  meldet 175 – und das Auswahlfeld darin nur 94. Die Differenz kommt von
  den `<option>`-Einträgen: Safari rechnet deren Textbreite („Wert (hoch →
  niedrig)") in den Überlauf ein, obwohl sie nie gezeichnet werden. Von
  dort wanderte sie weiter in die Filterleiste (+27) und bis zur Seite
  (+11).

  Der Rahmen schneidet jetzt ab. Sichtbar verschwindet dadurch nichts: Das
  Feld klippt seinen eigenen Text ohnehin, und die aufgeklappte Liste
  zeichnet das Betriebssystem außerhalb des Kastens.

  Chromium rechnet die Optionen nicht mit – deshalb war in der Nachbildung
  bei vier Bildschirmbreiten, allen Ansichten und 800 Einträgen nie etwas
  zu sehen. Gefunden hat es die Messung auf dem Gerät selbst.

## 2.88.10 – September 2026

### Behoben
- 📐 **Alte Überstands-Befunde gaben sich als neu aus.** Der gespeicherte
  Text blieb nach einem Update stehen, und die naheliegende Lesart war
  „nichts geändert" – zweimal geschehen. Jetzt sagt die Anzeige es, wenn
  der Befund aus einer älteren Fassung stammt.

  Dasselbe auf der Serverseite: Gleichartige Meldungen werden dort
  zusammengefasst und behalten den Text der **ersten**. Ein Wiedersehen
  nach einem Fix erhöhte damit nur den Zähler einer alten Zeile. Die
  Fassung steht jetzt in der Meldung, also bekommt jede ihre eigene.

## 2.88.9 – September 2026

### Behoben
- ↔️ **Das seitliche Schieben in der Sammlung – der zweite und
  wahrscheinlich letzte Grund.** Das Sortier- und das Typ-Feld standen mit
  175 Pixeln in einem 98 Pixel breiten Rahmen und schoben die Seite auf.

  Ein Flex-Kind schrumpft von sich aus **nicht** unter die Breite seines
  Inhalts – bei einem Auswahlfeld ist das die längste Option („Wert (hoch →
  niedrig)"). `width: 100%` hilft dagegen nicht, die Mindestgröße gewinnt;
  es braucht ausdrücklich `min-width: 0`. Safari hält sich strikt daran,
  Chromium schrumpft von selbst – deshalb war davon in der Nachbildung bei
  vier Bildschirmbreiten, allen Ansichten und 800 Einträgen nie etwas zu
  sehen.

  Gefunden hat es die Messung auf dem Gerät selbst. Dasselbe gilt jetzt für
  das Suchfeld, das denselben Bau hat.

## 2.88.8 – September 2026

### Behoben
- 📐 **Die Überstands-Messung nennt jetzt den richtigen Kasten.** Zwei
  Schwächen: Sie schlug den Scroll-Versatz auch fest positionierten
  Elementen auf – dadurch stand die Tab-Leiste als Übeltäter da, obwohl sie
  gar nicht mitwandert. Und die Liste „scrollt innen über" war nach innen
  sortiert: Ganz innen stehen harmlose Dinge (der Text in einem Auswahlfeld
  ist länger als das Feld – das klippt der Browser), während der
  interessante Kasten weiter außen liegt.

  Jetzt wird eigens ausgewiesen, welcher Kasten **genau den Überstand des
  Dokuments** weiterreicht, innerste Quelle zuerst. Das ist der Ort.

## 2.88.7 – September 2026

### Geändert
- 📐 **Der Überstands-Befund geht an den Server** und landet in der
  Fehlerliste – mit Zeit, Fassung und Gerät. Ihn in den Einstellungen zu
  suchen und abzufotografieren kostete jedes Mal eine Runde, und man sah
  ihm nicht an, ob er von heute oder von gestern war. Der Text in den
  Einstellungen trägt jetzt ebenfalls Zeitpunkt und Fassung.

- 📐 **Neu in der Messung: „Scrollt innen über".** Steht kein einziges
  Element über, ist das Dokument aber breiter, steckt die Ursache in etwas,
  das in keiner Elementliste auftaucht – ein `::before`/`::after`, ein Rand,
  eine Tabelle. Sichtbar wird sie trotzdem: Jeder Kasten, der sie enthält,
  meldet ein größeres `scrollWidth` als `clientWidth`. Die Messung nennt
  jetzt den **innersten** davon, und das ist der Ort.

## 2.88.6 – September 2026

### Behoben
- 📐 **Die Überstands-Messung fand bei 11 Pixeln kein einziges Element.**
  Zwei Gründe, beide behoben:

  `getBoundingClientRect` misst gegen das **Fenster**, nicht gegen das
  Dokument – ist die Seite schon seitlich geschoben, rutscht alles nach
  links und der Übeltäter versteckt sich hinter dem Rand. Und **Ränder
  zählen nicht mit**: Ein `margin-right` steht in keinem Rechteck, macht
  das Dokument aber trotzdem breiter. Genau so sehen elf Pixel aus, die
  nirgends zu sehen sind.

  Außerdem nennt die Messung jetzt immer etwas: Liegt nichts über der
  Schwelle, kommen die äußersten Elemente trotzdem in die Liste, dazu alles,
  was nach **links** hinausragt. Eine leere Liste hilft niemandem.

## 2.88.5 – September 2026

### Behoben
- 📐 **Die Überstands-Messung konnte gar nichts finden.** Sie maß die
  Ansicht, die gerade offen ist – und sobald man in die Einstellungen
  wechselt, ist die Sammlung ausgeblendet. Ausgeblendetes steht nicht über:
  Die Messung meldete pflichtschuldig „nichts" und hatte dabei recht. Nur
  eben nutzlos.

  Jetzt schaut eine Wache beim Blättern mit und schreibt den Befund einmal
  je Ansicht weg; die Einstellungen zeigen ihn später an. Man blättert also
  einfach durch die betroffene Ansicht und sieht danach nach. Der teure
  Durchlauf durch alle Elemente passiert nur, wenn wirklich etwas übersteht.

## 2.88.4 – September 2026

### Neu
- 📐 **„Was steht über den Rand?" in der Fehlersuche.** Lässt sich eine
  Ansicht seitlich schieben, ist irgendein Element breiter als das Fenster
  – welches, hängt an den eigenen Daten und am eigenen Browser. Der Knopf
  misst dort, wo es auftritt, und nennt das Element beim Namen, dazu seine
  Breite und den Weg nach oben: Ein überstehendes Kind sagt wenig, solange
  man nicht weiß, welcher Kasten es nicht halten konnte.

  Anlass war das seitliche Schieben in der Sammlung: In der Nachbildung
  stand es bei vier Bildschirmbreiten, allen drei Ansichten, allen
  Sortierungen und 800 Einträgen nie über – auf dem Gerät schon. Drei
  Anläufe gingen so ins Leere. Zu finden unter **Mehr → Einstellungen →
  📐 Fehlersuche**.

## 2.88.3 – September 2026

### Geändert
- 🔍 **Zu klein abgelegte Bilder holen sich selbst nach.** Mit 2.88.0 stieg
  die Ablagegröße von 400 auf 800 Pixel, damit das Bild im Popup über die
  volle Breite scharf bleibt – schon abgelegte Bilder blieben aber klein.

  Nachgeholt wird jetzt genau dann, wenn jemand die Figur oder das Set
  **aufruft**: beim vollen Bild, nicht beim Daumennagel im Raster. Wer durch
  800 Karten blättert, löst nichts aus – sonst stünden bei jedem Blick in
  die Sammlung Hunderte Abrufe an.

  *(Hier stand zunächst, ein Sammellauf ginge gegen dasselbe
  BrickLink-Tageskontingent wie die Preise. Das war falsch – siehe 2.88.15.)*

  Der Abruf läuft im Hintergrund; das Fenster wartet nicht darauf. Beim
  ersten Öffnen steht noch das alte Bild, ab dem zweiten das scharfe. Die
  daraus abgeleiteten Daumennägel werden mitgelöscht, sonst bliebe die
  Sammlung ausgefranst.

## 2.88.2 – September 2026

### Behoben
- ↔️ **Die Sammlung ließ sich seitlich schieben.** Die Karten standen in
  der rechten Spalte über den Bildschirmrand hinaus, und die ganze Seite
  wurde dadurch breiter als das Fenster.

  Ursache war eine Zeile, die harmlos aussieht:
  `contain-intrinsic-size: auto 236px`. Gemeint war die Höhe, die der
  Browser für noch nicht gezeichnete Karten annehmen soll – **ein
  einzelner Wert gilt aber für beide Achsen**. Karten außerhalb des
  Sichtfelds meldeten damit auch 236 Pixel *Breite*. Weil Rasterfelder von
  Haus aus `min-width: auto` haben, konnte `1fr` nicht darunter: Die zwei
  Spalten rechneten 260 statt 197 Pixel und standen 126 Pixel über.

  Sichtbar war das nur bei vielen Einträgen – wo der Browser nichts
  überspringt, gibt es auch keine Ersatzgröße. Mit sieben Karten in der
  Probe war nie etwas zu sehen, mit 780 sofort. Die Zeile steht seit
  2.73.0 (29.08.2026) im Stylesheet.

  Jetzt gilt die Ersatzgröße nur noch für die Höhe. Zusätzlich dürfen
  Karten ihre Spalte nicht mehr aufblähen (`min-width: 0`) – falls ein
  Browser die genauere Schreibweise nicht kennt.

## 2.88.1 – September 2026

### Neu
- 📷 **Die Kamera geht jetzt in der App auf.** Antippen zeigt das Livebild
  mit Auslöser, Sucher-Ecken und – das war der Punkt – einem Knopf zur
  **Fotomediathek gleich daneben**. Mit 2.88.0 kam an dieser Stelle noch
  die Auswahlliste des Systems: Sie bot die Mediathek zwar an, kostete aber
  jedes Foto einen Tipp mehr und sah nicht nach der App aus. Ein Licht
  erscheint oben rechts, wo das Gerät es kann.

  **Zweigleisig, und das ist wichtig:** Der Kamerazugriff im Browser
  (`getUserMedia`) gibt es nur über HTTPS. Über die Cloudflare-Adresse ist
  das gegeben. Wer eine Instanz im Heimnetz über `http://` aufruft, bekommt
  weiter den Dateidialog – genau wie vorher. Dasselbe gilt, wenn die
  Freigabe für die Kamera abgelehnt wird. Es wird also nirgends schlechter,
  nur an der einen Stelle besser.

  Ein `<input type="file" capture>` war dafür übrigens nie geeignet: Es
  reicht nur an das Betriebssystem weiter, und in dessen Kamera gibt es
  keinen Weg zur Mediathek.

## 2.88.0 – September 2026

### Geändert
- 🖼 **Das Detail-Popup macht mit dem Bild auf.** Es war eine Briefmarke von
  72 Pixeln neben dem Namen; jetzt steht das Bild über die volle Breite auf
  weißem Grund. Weiß ist bewusst fest und kommt nicht aus dem Design: Fast
  alle Katalogbilder bringen selbst einen weißen Grund mit, und auf Hellgrau
  bekam jedes von ihnen einen sichtbaren Kasten. Auch die Bilder in der
  Sammlung stehen jetzt auf Weiß.

- 💶 **Drei Kacheln statt fünf gleich lauter Zeilen.** Bezahlt, Wert und
  Gewinn stehen zuoberst, direkt unter dem Namen. Vorher standen sie als
  Zeilen zwischen „Anzahl" und „Zustand" – gleich laut wie die Bedienung,
  obwohl fast immer eine dieser drei Zahlen der Grund ist, das Fenster
  überhaupt zu öffnen. Kaufpreis ändern und „weiterer Kauf" sitzen als
  kleine Symbole in der Ecke ihrer Kachel.

- 🗂 **Der Rest liegt auf drei Blättern:** Exemplar, Preise, Mehr. Beim
  Umbau am 29.08.2026 war Zuklappen verworfen worden, weil es „bei jedem
  Öffnen einen Tipper kostet". Das gilt weiter – nur ist es erledigt: Die
  drei Zahlen stehen **über** den Reitern und kosten keinen. Ein Blatt ohne
  Inhalt bekommt keinen Reiter, und bleibt nur eines übrig, entfällt die
  Leiste ganz.

- 📓 **Die Notiz gehört jetzt zum Exemplar**, nicht mehr unter „Einordnung".
  Sie beschreibt *dieses* Stück – woher es kam, was ihm fehlt –, nicht seine
  Einsortierung. Und sie lag zuletzt so weit unten, dass sie beim Durchsehen
  übersehen wurde.

- 🎞 **Die Fenster fahren auf, statt zu erscheinen.** In der App bewegt sich
  sonst alles – der Startbildschirm baut sich auf, die Ladeanzeige hüpft –,
  nur die meistgeöffneten Fenster sprangen herein. Das war der größte Teil
  ihres alten Eindrucks. Der Schließen-Knopf hat dabei seinen schwarzen
  Kasten verloren: Umrandet war er das Kräftigste im ganzen Fenster,
  ausgerechnet für die Nebensache.

- 🧱 **Vier Noppen auf dem Aufnahme-Knopf.** Zwei einfarbige waren der
  letzte Rest der alten Handschrift; inzwischen sind es überall vier bunte
  Steine – im Logo, im Startbildschirm, in der Ladeanzeige. Sie sind unten
  geschlossen, damit jede als eigener Stein *auf* dem Knopf steht,
  unabhängig von dessen Farbe.

- ✍️ **Die Aufschrift des Aufnahme-Knopfes folgt dem Gerät.** Am Telefon
  „Figur oder Set fotografieren", am Rechner „Bild hierher ziehen oder
  auswählen". Entschieden wird über `hover` – ehrlicher als die
  Fensterbreite, denn ein schmales Browserfenster am Rechner bedient man
  weiter mit der Maus.

- 🏷 **Kein Stift mehr am Thema von Sets.** Er erschien nur, wo das Thema
  nicht feststand – bei Sets lieferte die Ableitung aber grundsätzlich
  nichts, weil sie nur Figurennummern kennt. Deshalb stand dort immer einer
  für etwas, das längst über BrickLink gefunden war. Bei selbst angelegten
  Einträgen und bei Teilen bleibt er: Ein Grundstein hat kein Thema, und
  was dort landet, kann danebenliegen.

### Neu
- 🖼 **Bilder aus der Fotomediathek.** Am Datei-Feld stand
  `capture="environment"` – das *erzwang* die Kamera, ein Foto, das man
  schon hatte, war schlicht nicht scanbar. Jetzt fragt das Telefon selbst:
  Mediathek, Foto aufnehmen, Datei. Der Preis ist ein Tipp mehr auf dem Weg
  zur Kamera.

- 📅 **Zeitspannen am Preisverlauf** – 1M, 3M, 1J, Alles. Das kostet keine
  einzige BrickLink-Abfrage: Die Punkte liegen längst vollständig mit
  Zeitstempel vor, gefiltert wird im Browser. Angeboten wird nur, was etwas
  zeigt – bei einem Stück von letzter Woche zeichnete „1J" dieselbe Kurve
  wie „1M".

- 🔎 **Ablesen im Preisverlauf.** Beim Berühren erscheint eine Linie in der
  Spalte, die Punkte werden hervorgehoben, und darunter stehen Datum und
  beide Preise. Getroffen werden muss die **Spalte**, nicht der Punkt: Auf
  dem Telefon liegen sie dicht beieinander, und der Finger verdeckt genau
  den, den man treffen will.

### Behoben
- 🔍 **Das große Bild war ausgefranst.** Zwei Ursachen: Das Popup holte die
  Daumennagel-Fassung, und abgelegt wurde ohnehin nur mit 400 Pixeln
  („reicht für Karte und Popup" – das stimmte, solange es eine Briefmarke
  war). Jetzt 800 Pixel und die volle Fassung. Bereits abgelegte Bilder
  bleiben bei 400, bis sie über „Bild erneuern" neu geholt werden; ein
  Sammellauf ginge gegen dasselbe Tageskontingent wie die Preise.

- 🪟 **Dialogfenster standen links statt mittig**, und ihr Schließen-Knopf
  schwebte rechts daneben in der Luft. Die Breitenbegrenzung saß am Inhalt
  statt am Fenster. Gleichzeitig haben die Dialoge die ruhigere Sprache
  bekommen: weiche Felder, gleich breite Knöpfe, Abstand zum Rand.

- 🏷 **Ein Klick auf den Themen-Stift ließ das Thema verschwinden.** Er
  blendet die Zeile aus und ein Feld ein – das lag seit den Blättern auf
  „Mehr" und war damit unsichtbar. Das Feld steht jetzt direkt neben der
  Zeile im Kopf.

- 📏 **Preiszeilen brachen mitten in der Klammer um.** „(717,74 € –" stand
  am Ende der einen, „959,66 €)" am Anfang der nächsten Zeile.

## 2.87.1 – September 2026

### Geändert
- 🧱 **Der drehende Klemmbaustein ist überall der hüpfenden Reihe
  gewichen.** Mit 2.87.0 kamen die vier Logo-Steine als Lade-Anzeige, aber
  zwei Stellen hatten den alten Stein behalten: das Feld, das beim
  Herunterziehen zum Aktualisieren oben erscheint, und der Bildschirm
  während eines Updates. Dort dreht sich jetzt nichts mehr.

  Aus dem runden Feld am oberen Rand ist dafür eine Pille geworden — vier
  Steine nebeneinander passten in 42 Pixel Durchmesser nicht hinein. Der
  Takt der Geste bleibt: Beim Ziehen stehen die Steine still, gehüpft wird
  erst, wenn das Neuladen losgeht.

- 🟢 **Die Schwelle beim Herunterziehen ist ein grüner Ring statt einer
  grünen Fläche.** Die Füllung stammte aus der Zeit des einfarbigen
  Steins; unter den vier bunten hätte sie ausgerechnet den grünen
  verschluckt.

### Behoben
- 📏 **Eine Regel im Stylesheet stand ohne schließende Klammer da** — ein
  zu großzügiger Schnitt beim Ausbau der alten Anzeige. Browser werfen so
  etwas stillschweigend weg; hier war die Sammlungsansicht betroffen, die
  im Raster über beide Spalten mittig stehen soll. Eine neue Probe
  (`test_css_wohlgeformt.py`) prüft künftig Klammern und Blöcke mit.

## 2.87.0 – September 2026

### Hinzugefügt
- 🧱 **Ein Startbildschirm, der sich aufbaut.** Beim Aufrufen der Seite
  fallen die vier Steine des Logos nacheinander ein und federn leicht,
  dann kommen Name, Wortmarke und Unterzeile versetzt hinterher. Nach drei
  Sekunden blendet das Bild aus – und **erst danach** fährt der Inhalt
  auf; sonst schiene er während des Ausblendens durch, und aus dem
  Auftritt würde eine Überblendung.

  **Der Name kommt vom Server**, nicht aus JavaScript. Sonst blitzte das
  Logo erst ohne Namen auf und spränge dann um. Ohne gesetzten
  Anzeigenamen fällt die Zeile weg und das Logo rückt zusammen.

  Die Haltedauer steht an **einer** Stelle (`--halt` am `#splash`), und
  der Ladebalken hängt an derselben – zwei Zahlen wären zwei
  Gelegenheiten, sie auseinanderlaufen zu lassen. Wer Bewegung reduziert
  hat, sieht dasselbe Bild ohne Animation.

  Ein Notausgang in `theme-boot.js` nimmt das Bild nach sechs Sekunden in
  jedem Fall weg. Bricht `app.js` je ab, läge es sonst für immer über
  einer App, die man nicht mehr bedienen kann – lieber ohne Startbild als
  ausgesperrt.

- 🌊 **Das Ladezeichen passt dazu.** Statt des drehenden Klemmsteins
  hüpfen in den Listen jetzt dieselben vier Steine nacheinander, im Takt
  des Startbildschirms. Beim **Herunterziehen zum Aktualisieren** bleibt
  es beim drehenden Stein: Dort sitzt das Zeichen in einem kleinen runden
  Knopf, und das Drehen gehört zur Geste.

### Behoben
- 🌙 **Das dunkle Design blitzte auf dem Anmeldebogen kurz hell auf.**
  `theme-boot.js` setzte vor dem ersten Zeichnen korrekt Galaxy – und
  `checkSetup()` überschrieb es eine Zehntelsekunde später mit dem
  Instanz-Standard. Genau das Aufblitzen, gegen das `theme-boot.js`
  überhaupt geschrieben wurde.

  Jetzt gilt auch dort, was nach dem Anmelden längst galt: **die eigene
  Wahl auf diesem Gerät vor dem Instanz-Standard.** Aufgefallen ist es
  erst beim Startbildschirm – mit einem ruhig stehenden Logo wird aus dem
  Zucken ein sichtbarer Farbwechsel.

- 🍎 **Die iOS-Kachel hieß „'s Brickfolio".** Derselbe Genitiv-Fehler wie
  in 2.85.0, nur an einer Stelle übersehen: Die Vorlage trug
  `__OWNER__'s Brickfolio`, und ohne gesetzten Namen klebte das s an einer
  leeren Zeichenkette. Wer die App aufs Handy legte, hatte das auf dem
  Startbildschirm stehen.

## 2.86.5 – September 2026

### Behoben
- 💶 **Ab dem sechsten Treffer fehlten Jahr und Preis.** Zwei Grenzen
  passten nicht zusammen: Die Oberfläche schickte **acht** Nummern zum
  teuren Abruf, der Server bediente davon **fünf** (`[:5]`). Die drei
  dazwischen bekamen den Hinweis „lade Jahr & Preise …", nie Daten – und
  am Ende räumte die Oberfläche den Hinweis wortlos wieder weg.

  Beide stehen jetzt auf **zehn**, so viele wie eine Seite zeigt. Und beim
  Blättern wandert das Fenster mit: Bisher wurden immer wieder dieselben
  ersten Treffer angereichert, seit 2.86.3 konnte man aber bis Treffer 200
  blättern.

  Gemessen am Beispiel „gelber Umhang": vorher fünf Karten mit
  Preis und fünf ohne, jetzt alle zehn – und nach einem Klick auf
  „Weitere Ergebnisse laden" auch die beiden nächsten.

### Hinzugefügt
- 🏷 **„keine Preisdaten bei BrickLink"** steht jetzt dort, wo bisher
  einfach nichts stand. Manche Einträge haben im Preisfenster **null
  Verkäufe** – `cas123`, eine Castle-Figur von 1987, ist so ein Fall;
  BrickLink führt sie dort sogar ohne Namen („Castle") und ohne Jahr.
  Neben ihren Nachbarn sah so eine Karte aus, als sei etwas kaputt.

  Gesagt wird es **nur, wo wirklich nachgefragt wurde**. Bei allem anderen
  hieße „kein Preis" bloß „noch nicht gefragt", und das als Auskunft
  hinzustellen wäre schlimmer als zu schweigen.

## 2.86.3 – September 2026

### Geändert
- 🔍 **Bei Figuren antwortet nur noch der eigene Katalogabzug.** Aufgefallen
  war, dass die Trefferliste zwei Quellen mit denselben Figuren mischt –
  und das stimmte: `dis080 · Donald Duck - Jester` und
  `fig-012635 · Donald Duck, Jester` sind dieselbe Figur.

  Die Entdoppelung konnte das nicht fangen. Sie vergleicht Nummer plus Typ,
  und die Nummern gehören zwei verschiedenen Katalogen. Über die Namen
  ginge es auch nicht, die sind nur gleichbedeutend („Qui-Gon Jinn (Yellow
  Head)" gegen „Qui-Gon Jinn, Yellow Skin"). Und eine Brücke gibt es nicht:
  **Rebrickable liefert für Figuren keine BrickLink-Nummer** – weder in der
  Suche noch im Einzelabruf, für Teile dagegen schon.

  Dazu kam, dass die zweite Hälfte die schlechtere war: ohne Preis, ohne
  Set-Zugehörigkeit, ohne BrickLink-Nummer – also ohne alles, woran hier
  die Bewertung hängt.

  Rebrickable springt bei Figuren jetzt nur noch ein, wenn der eigene Abzug
  **nichts** findet. Für **Sets und Teile** bleibt alles wie es war; dort
  ist es oft die einzige Quelle, und bei Teilen liefert es sogar die
  BrickLink-Nummer mit.

- 📜 **Mehr Treffer, und das Blättern geht ohne Nachfragen.** Der Abzug war
  auf 20 Treffer gedeckelt – das war der eigentliche Grund, warum
  Rebrickable überhaupt etwas beitragen konnte. Er gibt jetzt heraus, was
  er hat: „Stormtrooper" sind **69** statt 20, „Darth Vader" 35 statt 20.

  Angezeigt werden weiterhin zehn; **Weitere Ergebnisse laden** blättert
  durch das, was schon geholt wurde, und löst keine neue Anfrage aus.
  Nachgemessen: 10 von 45 → ein Klick → 20 von 45, ohne einen einzigen
  Netzzugriff.

  Die Schwelle für den Farb-Rückfall bleibt dabei bei 20. Wäre sie
  mitgewandert, liefe die Verbreiterung praktisch immer – und „gold" hieße
  wieder „yellow", was 9.231 Figuren hereinzöge.

## 2.86.2 – September 2026

### Behoben
- ⚡ **Die erste Suche nach einem Neustart dauerte fünf Sekunden.** Danach
  war alles schnell, und niemand konnte sich erklären, warum ausgerechnet
  die eine Anfrage hing.

  Die Suche rechnet aus den Daten selbst aus, welche Wörter in fast jeder
  Bildbeschreibung stehen (`torso`, `legs`, `yellow` …) – sonst fände
  „gelb" zwei Drittel des Katalogs. Dafür liest sie **alle** Beschreibungen
  und zerlegt sie: bei 19.267 Figuren gemessene **5,1 s** auf der NAS. Das
  Ergebnis lag bisher nur im Arbeitsspeicher, war also nach jedem
  Containerstart weg – und der nächste Suchende zahlte es.

  Jetzt steht es auch in den Einstellungen, mit der Zeilenzahl als
  Schlüssel: Ändert sich der Abzug, wird neu gezählt, sonst gelesen.
  Zusätzlich wärmt der Start es im Hintergrund vor, damit auch der erste
  Lauf nach einem neuen Abzug nicht vor dem Suchfeld stattfindet.

  Gemessen auf einer Instanz: erster Lauf **5,1 s → 0,2 s**, jeder weitere
  war schon vorher 0,2 s.

## 2.86.1 – September 2026

### Behoben
- 🔍 **„Figur mit blauem Hut" fand nichts.** Das Wörterbuch machte daraus
  `figure blue hat`, und weil die Suche **alle** Wörter verlangt, blieb sie
  leer: `figure` steht in 1.268 von 40.936 Katalogzeilen, fast nur bei
  Duplo. Dabei ist „Figur" in dieser Frage gar kein Merkmal, sondern ein
  Füllwort – gemeint ist „eine Figur, die einen blauen Hut hat", gesucht
  ist der Hut. Welche Gattung gemeint ist, sagt ohnehin schon die
  Typ-Auswahl über dem Feld.

  „Figur", „Figuren", „Minifigur" und „Minifiguren" zählen jetzt zu den
  Füllwörtern. Gemessen an **79 echten Anfragen** aus der Instanz plus neun
  Mustern: **sieben besser, keine schlechter, 82 unverändert.**

  | Anfrage | vorher | nachher |
  |---|---|---|
  | Figur mit blauem Hut | 0 | **20** |
  | Figur mit blauem Hut, roten Beinen und grünem Torso | 0 | **4** |
  | Figur mit gelbem Kopf | 2 | **20** |
  | Figur mit Kopf und Arm | 0 | **6** |
  | Figuren mit Umhang | 14 | **20** |

  Zwei der besseren Fälle standen so im echten Anfragen-Protokoll – das
  Muster wurde also wirklich getippt und lief wirklich ins Leere.

  **Eine Anfrage wird dabei nie zu nichts.** Wer nur „Figur" tippt, hat ein
  Füllwort getippt und sonst nichts; dann bleiben die Füllwörter stehen.
  Ohne diese Rückfallebene wäre genau diese eine Anfrage schlechter
  geworden – der einzige Rückschritt in der ersten Messung, und vermeidbar.

## 2.86.0 – September 2026

### Hinzugefügt
- 📈 **Pfeile im Preis-Protokoll.** Neben jedem Betrag steht jetzt ein
  grünes **↑** oder ein rotes **↓** – je nachdem, wohin der Preis seit dem
  vorherigen Punkt desselben Artikels gegangen ist. Eine Zahl allein sagt
  nämlich nicht, ob sie gut ist: „Ø 4,55 €" liest sich gleich, ob der Preis
  gestiegen oder gefallen ist. Der Hinweis unter der Maus nennt den alten
  Wert und die Veränderung („vorher 620,00 € · −14,50 €"). Neu und
  gebraucht haben je einen eigenen Pfeil; sie laufen nicht immer in
  dieselbe Richtung.

  **Kein Pfeil heißt: nichts zu zeigen** – erster Punkt eines Artikels,
  oder der Betrag ist derselbe geblieben. Verglichen wird **auf Cent**,
  also genau das, was in der Zeile steht: BrickLink liefert vier
  Nachkommastellen, und ein Pfeil für eine Bewegung, die im angezeigten
  Betrag nicht zu sehen ist, wäre nur verwirrend.

  Der Endpunkt liefert den Vorgänger über eine Fensterfunktion (`LAG`) mit.
  Der Fallstrick steckte im `LIMIT`: Das Protokoll zeigt die jüngsten 50
  Zeilen, aber der vorherige Punkt eines Artikels liegt fast immer weiter
  zurück. Das Fenster läuft deshalb über den **ganzen** Verlauf und wird
  erst danach begrenzt – dafür gibt es eine eigene Probe.

## 2.85.1 – September 2026

### Geändert
- ⏱ **Die Namen des Katalogabzugs kommen schneller – ohne das Kontingent zu
  reißen.** Der Stapel je Lauf war fest auf 1.500 gesetzt. Die Zahl stammte
  aus einer Zeit mit 9.700 Namen; bei inzwischen **19.267** wären das
  sechseinhalb Tage, in denen eine frische Instanz nur über die
  Bildbeschreibungen sucht.

  Einfach hochsetzen ging nicht: BrickLink lässt 5.000 Abrufe am Tag zu, und
  am Preis-Deckel ist das bereits ausgeschöpft. Nur trifft dieser Deckel
  genau die Instanzen, die den Namenslauf **längst hinter sich haben** – wer
  gerade erst installiert hat, hat eine leere Sammlung, und die Preise
  brauchen fast nichts. Deshalb wird der Stapel jetzt gerechnet statt
  gesetzt: Was nach den Preisen vom Tagesbudget übrig bleibt, gehört den
  Namen.

  | Sammlung | Namen je Tag | 19.267 Namen in |
  |---|---|---|
  | leer (Neuinstallation) | 3.620 | **5,3 Tagen** (vorher 6,4) |
  | 900 Artikel | 3.456 | 5,6 Tagen |
  | 3.000 Artikel | 2.708 | 7,1 Tagen |
  | 9.000 Artikel | 2.180 | 8,8 Tagen |

  Bei großen Sammlungen ist das **langsamer** als die festen 1.500 – und
  genau richtig so: Dort war die feste Zahl ein Überzug aufs Kontingent.
  Sieben Proben halten fest, dass die Summe aus Preisen und Namen das
  Tagesbudget in keinem Fall überschreitet.

## 2.85.0 – September 2026

### Behoben
- 🏷 **Ohne Anzeigenamen hieß die App „'s Brickfolio" – und das Logo
  trug einen fremden Vornamen.** Auf **jeder** frischen Installation,
  bevor jemand einen Namen setzt. Die Vorlage trug `__OWNER__'s Brickfolio`, und der Server setzte
  nur den nackten Namen ein: Das Genitiv-s klebte an einer leeren
  Zeichenkette. Das Logo blieb beim Platzhalter, weil `applyOwnerName` bei
  leerem Namen mit einem frühen `return` ausstieg.

  Jetzt setzt der Server denselben `_app_title()` ein, den das Manifest
  längst richtig benutzt („Dein Brickfolio"), der Name kommt ebenfalls von
  dort, und eine leere Namenszeile blendet sich aus. Auch der
  Einrichtungsassistent nennt nicht mehr einen festen Vornamen als Beispiel,
  sondern zeigt den fertigen Titel als Vorschau.

- 🔍 **„Nichts gefunden" stand über zehn sichtbaren Treffern.** Nicht die
  Suche war schuld, sondern der Übersetzungs-Zusatzversuch: Er läuft auch
  dann, wenn nur der *eigene* Abzug leer blieb – und auf einer neuen
  Instanz ist das der Normalfall, weil die Namen darin erst nach und nach
  bei BrickLink nachgeschlagen werden. Fand die Übersetzung nichts, schrieb
  sie ihr „Nichts gefunden" über die Treffer, die schon dastanden.

  Der Versuch weiß jetzt, ob schon etwas zu sehen ist: Dann heißt es
  währenddessen „Suche zusätzlich nach der Übersetzung …", und ein
  Misserfolg endet still, statt zu widersprechen.

### Geändert
- 🔒 **`Permissions-Policy` ergänzt.** Sie fehlte als einzige der üblichen
  Kopfzeilen. Gesperrt sind jetzt Mikrofon, Standort, Zahlung, USB, MIDI und
  Seriell; die Kamera bleibt für die eigene Seite erlaubt. Gescannt wird
  zwar über ein Dateifeld mit `capture`, das die Regel gar nicht betrifft –
  ein `camera=()` wäre aber eine Falle für den Tag, an dem jemand auf
  `getUserMedia` umstellt.
- 📘 **Das Handbuch sagt jetzt, dass die Sicherung die API-Schlüssel im
  Klartext trägt.** Genannt waren bisher nur die Passwort-Hashes. In der
  Oberfläche erscheinen die Schlüssel maskiert (`…41c7`), in der Sicherung
  vollständig – anders ließe sich eine Instanz nicht wiederherstellen. Die
  Datei ist damit so vertraulich wie die Datenbank selbst.
- 🧹 **Drei Dateien entfernt, die niemand mehr abrief:**
  `frontend/icons/icon-180.png` (das Apple-Touch-Symbol wird je Instanz
  erzeugt), `frontend/manifest.webmanifest` (wird erzeugt, seit der Name aus
  den Einstellungen kommt – die feste Fassung war obendrein veraltet) und
  `docs/screenshots/start.png` (seit Juli in keiner Doku eingebunden).

  Ebenfalls aufgeräumt, aber ohne Wirkung auf die App: Projektseite,
  Katalogdienst, Tausch-Hub und Hub-Konsole liegen jetzt in eigenen,
  nicht öffentlichen Repos. Hier bleibt das Programm.

## 2.84.1 – September 2026

### Behoben
- 📘 **Eine Dublette im Handbuch wieder entfernt.** 2.84.0 hat einen
  Abschnitt 9.1 „Wie der Gesamtwert gerechnet wird" angelegt, weil ein
  Suchlauf die vorhandene Erklärung nicht fand – gesucht wurde nach
  „bereinigt", im Handbuch steht „**B**ereinigt" am Satzanfang. Die Regel
  stand also längst in Kapitel 13, und das Handbuch erklärte sie danach
  zweimal mit verschiedenen Worten. 9.1 ist wieder raus, Kapitel 9 verweist
  nur noch auf 13, und die Hilfe verlinkt dorthin.

  *Diese Fassung sollte man 2.84.0 vorziehen.*

## 2.84.0 – September 2026

### Geändert
- 📖 **Die Hilfe ist auf die Hälfte geschrumpft.** Sie war über die Jahre
  zu acht Textwänden gewachsen: **934 Wörter**, davon 340 allein für „Wie
  der Wert berechnet wird", und in sechs von acht Abschnitten keine
  einzige Aufzählung. Wer auf dem Handy eine schnelle Antwort suchte, las
  einen Aufsatz.

  Jetzt hat jeder Abschnitt dieselbe Form: **ein Leitsatz, dann kurze
  Punkte**. Aus 934 Wörtern wurden **560** – und das mit einem Abschnitt
  *mehr*. Der längste Abschnitt hat jetzt 91 statt 340 Wörter.

- 🗣 **Eine Anrede statt zwei.** Die App duzte und ihrzte gleichzeitig: in
  der Oberfläche 32× „du" gegen 13× „ihr", in den Meldungen aus dem Code
  13× „ihr" gegen 12× „du", und innerhalb der Hilfe 9× „ihr" gegen 2× „du".
  Mal hieß es „in eurer Sammlung", zwei Zeilen weiter „deine Sammlung".

  Jetzt sagt alles **„du"**: Oberfläche, Meldungen, Hilfe und Handbuch.
  Betroffen waren 27 Stellen im Code und rund 100 im Handbuch; die
  englischen Schlüssel sind mitgewandert, sonst wäre die englische Fassung
  an 13 Stellen ins Deutsche zurückgefallen.

### Hinzugefügt
- 🔍 **Ein eigener Abschnitt „Suchen".** Dass die Suche seit 2.80.0 Deutsch
  versteht, stand in der Hilfe nirgends – ausgerechnet die Neuerung, nach
  der man dort suchen würde. Vier Zeilen: beide Sprachen, Merkmale
  kombinieren, reine Nummern, und dass ein *kürzerer* Begriff mehr bringt
  als ein längerer.
- 🔗 **Die Hilfe verlinkt das Handbuch abschnittsweise.** Was beim Kürzen
  wegfiel, ist nicht verloren – „Wie der Wert berechnet wird" zeigt jetzt
  auf [Kapitel 13](docs/HANDBUCH.md#13-die-preis-automatik-im-detail), wo
  die Rechnung seit jeher ausführlich steht.

## 2.83.0 – September 2026

### Geändert
- 🐢 **Das Modell ist jetzt das letzte Mittel, nicht der zweite Reflex.**
  Bisher genügte **ein** unbekanntes Wort in der Anfrage, um die lokale KI
  zu bemühen – und bei Star-Wars-Figuren ist ein unbekannter Eigenname der
  Normalfall, nicht die Ausnahme. „Jedi mit gelbem Kopf und braunem
  Umhang" ging deshalb ans Modell, obwohl das Wörterbuch `jedi yellow head
  brown cape` liefert und damit auf Anhieb die richtigen Figuren findet.

  Jetzt wird **erst gesucht und dann gefragt**: Die Oberfläche versucht es
  mit dem, was das Wörterbuch hergibt, und holt das Modell nur, wenn dabei
  nichts herauskommt. Gemessen an 103 echten Anfragen: 97 beantwortet das
  Wörterbuch vollständig, und von den übrigen sechs war eine („Jedi mit …")
  schon vorher richtig übersetzt.

  Für „Bademantel", „Dirndl" oder „Trachtenhut" bleibt das Modell die
  einzige Hilfe – `bathrobe` steht in keiner Liste, die aus Katalogwörtern
  gebaut ist.

## 2.82.0 – September 2026

### Neu
- 🔎 **Deutsch suchen, ohne lokale KI.** Die Katalognamen sind englisch;
  „Ritter" fand bisher nur etwas, wenn ein Sprachmodell eingerichtet war.
  Die App bringt jetzt ein Wörterbuch mit: rund 1.400 deutsche Stichwörter,
  dazu Endungen abstreifen und zusammengesetzte Wörter zerlegen
  („Protokolldroide" → `protocol droid`, „Sturmtruppler" → `storm trooper`).

  Gewonnen wurde es aus der Worthäufigkeit des Katalogs selbst: 19.267
  Figurennamen bestehen aus 7.016 verschiedenen Wörtern, aber die
  häufigsten 300 decken 77 % aller Vorkommen – Farben, Kleidung,
  Körperteile. Der Rest sind Eigennamen, die man ohnehin so tippt.

  Die KI bleibt nützlich: Sie springt ein, wenn das Wörterbuch eine Anfrage
  nicht **vollständig** kennt. Von Hand Gepflegtes schlägt weiterhin beides.

### Behoben
- 🔤 **Umlaute waren Trennzeichen.** „Mütze" zerfiel in „m" + „tze",
  „König" in „k" + „nig", „Fußball" in „fu" + „ball" – und weil einzelne
  Buchstaben wegfallen, blieb ein Wortfetzen übrig. Zwölf von zwölf
  gescheiterten Anfragen im ersten Trainingslauf hatten einen Umlaut.
- 👑 **„king" fand gar nichts.** Der gespeicherte Suchtext klebt alle Wörter
  aneinander, `LIKE '%king%'` traf deshalb auch „Markings" und „Parking":
  377 Zeilen, und die Vorauswahl bricht bei 400 ab. Kein einziger echter
  König kam durch. Neue Spalte mit Leerzeichen zwischen den Wörtern.
- 🥷 **Bei mehreren Wörtern zählte nur das längste.** „schwarzer ninja"
  suchte nach „black" – die 400 Zeilen waren voll, bevor der erste Ninja
  kam. Jetzt muss jedes Wort vorkommen.
- 🎨 **Deutsche Farben umgingen die Farbprüfung.** „helm weiss" fand
  Figuren, die gar nicht weiß sind, während „helmet white" sie richtig
  aussortierte: `weiss` stand nicht in der Farbliste. Die Suche war nicht
  besser, sondern lockerer.

### Geändert
- 🧩 **Allerweltswörter zählen in der Bildbeschreibung nur im Verbund.** Das
  Sehmodell beschreibt jede Figur Teil für Teil, deshalb steht `torso` in
  19.266 von 19.267 Beschreibungen und `yellow` in 13.209 – im Namen
  dagegen nur 833 bzw. 1.155 Mal. Wer „gelb" suchte, bekam zwei Drittel des
  Katalogs. Ein Wort über 30 % Häufigkeit zählt dort jetzt nur noch, wenn
  die Anfrage im selben Abschnitt etwas Eigenes trifft: „gelber Kopf"
  findet ihn, „gelb" allein nicht.

  **Teil und Farbe zusammen bleiben scharf** – darum ging es: „Figur mit
  blauem Hut, roten Beinen und grünem Torso" trifft genau eine Figur, und
  zwar die richtige.
- 🇩🇪 **Die Bildbeschreibungen werden beim Update eingedeutscht.** Neu
  beschriebene Figuren bekommen ihren deutschen Teil vom Sehmodell; die
  vorhandenen zieht eine Wanderung nach – Wort für Wort aus demselben
  Wörterbuch, ohne Modell und ohne Netz. 19.267 Zeilen in rund neun
  Sekunden. Sie läuft bewusst **hier** und nicht zentral: Danach steht
  „kopf" in praktisch jeder Beschreibung, und eine ältere App ohne die
  Verbund-Regel fände damit den ganzen Katalog.

## 2.81.0 – September 2026

### Geändert
- 🏷 **Kein fremder Vorname mehr in der eigenen Installation.** Wer Brickfolio
  aufsetzte und keinen Anzeigenamen eintrug, bekam einen fest eingebauten
  Vornamen – im Logo, im Fenstertitel, auf dem Startbildschirm des Handys und
  in den Kopfzeilen der Druckexporte. Das war der Name des Kindes, für das
  diese App ursprünglich entstand, und er hatte in fremden Sammlungen nichts
  zu suchen.

  Ohne gesetzten Namen heißt die Instanz jetzt schlicht **„Dein Brickfolio"**
  (englisch *Your Brickfolio*), und das Symbol bleibt namenlos – der
  Symbol-Erzeuger zeichnet einfach keine Zeile mehr über das Gesicht. Wer
  einen Namen einträgt, bekommt wie bisher „*Name*'s Brickfolio". Das
  Eingabefeld zeigt statt eines Beispielnamens den Hinweis „ohne Namen".

  Zusammengesetzt wird der Titel jetzt an **einer** Stelle (`_app_title()`)
  statt an vier – vorher hing das `'s` an jedem Verwendungsort einzeln, und
  aus „Dein" wäre dort „Dein's" geworden.

  Dieselbe Bereinigung in der Beschreibung: Die vier Handbuch- und
  README-Überschriften lauteten „*Name*'s Brickfolio" und heißen jetzt nur
  noch **Brickfolio** – so wie das Projekt überall sonst auftritt.

## 2.80.3 – September 2026

### Geändert
- 📏 **Berichtigt, woran die verrutschten Rahmen lagen.** Die Erklärung in
  2.80.1 und 2.80.2 war falsch: Nicht der Browser schickte zu große Bilder,
  sondern **Brickognize rechnet selbst auf 1024 Pixel herunter** und
  antwortet in diesem Maßstab. Belegt durch das Protokoll der Instanz:
  `Upload 900x1200, Dienst 768x1024`. Die Lösung aus 2.80.1 stimmt
  unverändert – sie nimmt die Maße aus der Antwort und nicht aus einer
  Annahme. Berichtigt sind die Einträge, die Kommentare im Quelltext und die
  Proben; dazu eine neue Probe mit genau diesen Zahlen.

  Die Zeile im Container-Protokoll meldet jetzt nur noch den wirklich
  auffälligen Fall – ein Bild, das ungekürzt ankommt. Umgerechnet wird bei
  jedem Scan, das ist der Normalfall und keine Meldung wert.

## 2.80.2 – September 2026

### Geändert
- 🔎 **Das Verkleinern eines Fotos sagt jetzt, wenn es nicht greift.** Vor dem
  Scannen rechnet der Browser jedes Foto auf 1200 Pixel herunter. An fünf
  Stellen konnte er dabei stillschweigend das Original durchreichen. Das war
  die **vermutete** Ursache der verrutschten Rahmen aus 2.80.1 – sie war es
  nicht (siehe dort). Die fünf stummen Ausgänge bleiben trotzdem ein blinder
  Fleck, und jeder schreibt jetzt seinen Grund in die Spur
  (*Mehr → Wartung*).

  Dazu eine Zeile im **Container-Protokoll**, wenn der Server einen Rahmen
  umrechnen musste. Die Spur im Browser liegt auf dem Gerät; diese Zeile ist
  von außen lesbar und kommt nur im Ausnahmefall.

## 2.80.1 – September 2026

### Behoben
- 🎯 **Die Rahmen um die erkannten Figuren saßen daneben.** Bei „Alle Figuren
  erkennen" lagen sie zu klein und zu weit links oben – je weiter rechts die
  Figur stand, desto deutlicher.

  Der Erkennungsdienst rahmt sauber ein; das wurde eigens geprüft, indem der
  zurückgegebene Rahmen in ein Foto gezeichnet wurde. Nur gilt er für das
  Bild, auf dem **er** gearbeitet hat – und Brickognize rechnet selbst auf
  höchstens 1024 Pixel herunter. Aus den 900×1200, die der Browser schickt,
  werden dort 768×1024; der Browser zeichnete den Rahmen aber in den Maßen
  seines eigenen Bildes, also um 1024/1200 = **0,853** zu klein und
  entsprechend zu weit links oben.

  **Nachtrag vom selben Tag:** In der ersten Fassung dieses Eintrags stand
  als Ursache, der Browser habe ein zu großes Bild geschickt (1200/1400).
  Das war falsch, belegt durch die Protokollzeile aus 2.80.2: `Upload
  900x1200, Dienst 768x1024`. Die Probe, die zu dem Fehlschluss führte,
  hatte zwei Bilder **unter** 1024 verglichen – dort verkleinert der Dienst
  nichts. Die Lösung bleibt dieselbe, denn sie rechnet mit den Zahlen aus
  der Antwort und nicht mit einer Annahme.

  Der Server rechnet den Rahmen jetzt in die Maße des Bildes zurück, das er
  bekommen hat – samt EXIF-Drehung. Beide Zahlen dafür liefert der Dienst
  ohnehin mit (`image_width`, `image_height`), sie wurden bisher nur nicht
  gelesen.

  **Das betraf mehr als die Anzeige:** Aus denselben Rahmen schneidet die App
  die Ausschnitte fürs eigene Foto am Artikel und fürs Weitersuchen. Die
  kamen bisher vom falschen Fleck.

## 2.80.0 – September 2026

### Behoben
- 🏷 **Im Browser-Reiter stand auf jeder Instanz derselbe feste Name.** Das App-Symbol
  trägt seit 2.2.0 den eigenen Anzeigenamen – das kleine Symbol im Reiter
  aber nicht: `/favicon.ico` reichte eine feste Datei aus dem Repo durch.

  Aufgefallen ist es erst, weil es auf der Instanz, auf der entwickelt
  wird, richtig aussah. Nachgemessen am 20.09.2026 an einer fremden
  Instanz: `/icon/192.png` lieferte dort ein Symbol mit **ihrem** Namen,
  `/favicon.ico` dieselbe Datei wie das Repo, Prüfsumme gleich.

  Jetzt kommt auch das Reiter-Symbol aus dem Erzeuger, als .ico mit den
  drei Größen, die Browser abholen. Und die **mitgelieferten** Symbole
  (`frontend/icons/`) sind namenlos: Sie sind der Rückfall, wenn Pillow
  fehlt, und liegen öffentlich im Repo.

## 2.79.2 – September 2026

### Behoben
- 🧩 **Der Sprung zu einem Set blitzte nur auf.** Ein Klick auf das Set in
  „Fehlende Set-Figuren" wechselt in die Sammlung und trägt die Setnummer
  ins Suchfeld — das Set erschien kurz und wich dann wieder der
  **vollständigen** Sammlung, obwohl die Nummer im Suchfeld stehenblieb.

  Zwei Ursachen, beide behoben:

  **Die Reihenfolge.** `showTab("collection")` stößt selbst einen
  Ladevorgang an. Das Suchfeld wurde erst *danach* gesetzt, also lief ein
  zweiter mit **leerer** Abfrage — und dessen Antwort kam zuletzt an. Jetzt
  stehen die Felder vorher, `showTab` gibt seinen Ladevorgang zurück, und
  es wird nur noch **einmal** geladen statt zweimal.

  **Das Netz darunter.** `loadCollection` hatte keine Sperre gegen überholte
  Antworten: Es gewann schlicht die, die zuletzt eintraf — auch die ältere.
  Jede Abfrage trägt jetzt eine Laufnummer; wer überholt wurde, schreibt
  nichts mehr. Das betrifft auch das schnelle Tippen im Suchfeld, wo
  dasselbe passieren konnte.

## 2.79.1 – September 2026

### Behoben
- 📚 **„40878 Figuren" — der Katalog zählte Sets als Figuren.** BrickLinks
  Figurenkatalog hat gut 19.000 Einträge; die Zahl war mehr als das
  Doppelte. Sie stimmte trotzdem: Wer die Katalogdatei auch für **Sets**
  einliest (der Text daneben rät ausdrücklich dazu), hat beides im Abzug —
  auf einer Instanz 19.209 Figuren und 21.669 Sets. Nur die Beschriftung zählte
  alles zusammen und nannte es „Figuren".

  Jetzt steht dort, was drin ist: *„19.209 Figuren (19.209 beschrieben) und
  21.669 Sets"*. Auch nach dem Einlesen: *„21.669 neu, 0 berichtigt ·
  19.209 Figuren und 21.669 Sets im Abzug"*.

  Dazu passend: **„beschrieben" und „ohne Namen" gelten nur für Figuren.**
  Die Bildbeschreibung gibt es nur für sie, und der Namens-Nachtrag greift
  ohnehin nur nach Zeilen mit Beschreibung — ein Set ohne Namen als „wird
  nachgeschlagen" zu zählen wäre ein Versprechen gewesen, das niemand
  einlöst.

## 2.79.0 – September 2026

### Behoben
- 📈 **Der Preis-Hintergrundjob kam bei größeren Sammlungen nie hinterher.**
  Im Preis-Protokoll stand „Bei 328 Artikeln ist der Preisabruf älter als
  7 Tage" — und die Zahl ging nicht weg. Das war kein Fehler, sondern
  Arithmetik: feste **40 Einträge je Lauf**, zwei Läufe am Tag, also
  **80 Preise täglich**. Bei 926 Artikeln bräuchte es 133.

  Nachgemessen an der Altersverteilung: exakt 80 je Tagesstufe, und die
  ältesten Einträge lagen bei 12,5 Tagen — genau der Kreislauf, den die
  Rechnung vorhersagt (926 ÷ 80 ≈ 11,6 Tage). Damit war dauerhaft rund ein
  Drittel überfällig, ohne dass irgendetwas hängen geblieben wäre.

  **Der Stapel richtet sich jetzt nach der Sammlung**: so viel, dass eine
  Runde in sieben Tagen durch ist, mindestens 40 und höchstens 400 je Lauf.
  Bei 926 Artikeln sind das 83 je Lauf — eine Runde in 5,6 Tagen. Der
  Deckel schützt das BrickLink-Kontingent: selbst ausgereizt sind es 1.600
  Abrufe am Tag gegen erlaubte 5.000.

  Das Handbuch versprach „nie älter als gut eine Woche" — das stimmte für
  Sammlungen über 560 Artikel nicht und ist nachgezogen.

- 📈 **Die ältesten kommen zuerst dran.** Die Auswahl hatte kein
  `ORDER BY`, also entschied die Zeilennummer. Ein Artikel, dessen Abruf
  dauernd scheitert, behält seinen alten Zeitstempel und hätte sich so in
  jedem Lauf wieder vorgedrängt, während die dahinter nie an die Reihe
  gekommen wären. Im Betrieb ist das (noch) nicht passiert — alle
  Rückstände hatten Preise —, aber die Reihenfolge war Zufall.

## 2.78.0 – September 2026

### Neu
- 📖 **Das ⓘ führt jetzt in den Artikel — auch dort, wo er anders heißt.**
  „Bespin Guard" steht in der Jedipedia unter **Bespin-Sicherheitskräfte**;
  das lässt sich aus dem Katalognamen nicht ableiten, nur nachschlagen. Für
  die geläufigen Figuren liegt die Zuordnung jetzt bei — 190 Einträge, jeder
  einzeln gegen die MediaWiki-Schnittstelle des Wikis geprüft. Im Betrieb
  ruft Brickfolio dort weiterhin nichts ab.

  **Was hinausgeht, sind Namen — nie BrickLinks Beschreibungen.** Die löst
  die Begriffsbildung vorher heraus, und ein Test hält die Grenze: Jeder
  Schlüssel muss schon sein eigenes Ergebnis sein, sonst steckt eine
  Beschreibung darin.

- 📖 **Die Einheit hinter dem Komma bleibt stehen und wird verlinkt.** Bei
  „Clone Trooper Commander, 187th Legion" ist die **187. Legion** der
  interessantere Verweis, nicht der allgemeine Klonkommandant. Erkannt wird
  eine Einheit an ihrer Form (Ordnungszahl oder Legion/Bataillon/Korps/…) —
  eine Verbotsliste müsste jede Bemalung kennen, die BrickLink sich je
  ausdenkt.

  **Steht dort ein Name, geht er vor:** „Commander Fox, Coruscant Guard"
  führt zu Fox, nicht zu seiner Garde.

- 📖 **Begriffsklärungsseiten werden aussortiert.** „Cody", „Fox", „Hammer",
  „Hunter" — lauter Klonkrieger, und jeder dieser Titel ist im Wiki eine
  Auswahlliste. Das Werkzeug erkennt sie an der Kategorie und nimmt
  stattdessen den nächsten Kandidaten (`Commander Cody` → `CC-2224`). Ohne
  das landete „Echo" sogar bei einem **imperialen Piloten** statt beim
  Klon.

  Nachgemessen an 563 Star-Wars-Figuren: **554 landen im Artikel** — vorher
  waren es 151.

### Behoben
- 📖 **Eine offene Klammer als Suchbegriff.** „AT-DP Pilot (Imperial Combat
  Driver - White Uniform)" wurde am Bindestrich *innerhalb* der Klammer
  zerschnitten; übrig blieb „AT-DP Pilot (Imperial Combat Driver". Jetzt
  fliegen die Klammern zuerst raus, dann wird getrennt.

## 2.77.2 – September 2026

### Behoben
- ⚠️ **Die Zuordnungstabelle aus 2.77.0 ist wieder raus — sie enthielt
  BrickLink-Namen.** `frontend/jedipedia-titel.js` trug 123 Katalognamen als
  Schlüssel („Imperial Stormtrooper", „Astromech Droid, R2-D2, Light Bluish
  Gray Head") und lag damit in einem **öffentlichen** Repo.

  Das verstößt gegen genau die Regel, die `katalogdienst/veroeffentlichen.py`
  seit Langem festhält und begründet: Veröffentlicht werden Nummer und
  eigene Bildbeschreibung, **nicht** der Name — der ist BrickLinks Inhalt,
  und dessen Weitergabe an Dritte untersagen deren Nutzungsbedingungen. Die
  Datei ist gelöscht, und das Werkzeug kann nichts mehr ausliefern; es misst
  nur noch. Eine Zuordnung müsste an der **Nummer** hängen.

### Geändert
- 📖 **Dafür löst die Begriffsbildung jetzt mehr heraus.** Die Suche des
  Wikis springt von allein in den Artikel, sobald der Begriff dort ein Titel
  ist — es kam nur selten dazu, weil BrickLinks Namen Beiwerk mitschleppen:

  - Eine **Kennung gewinnt, wo immer sie steht**. „Assassin Droid (IG-88)"
    wurde zu „Assassin Droid"; jetzt zu `IG-88`. Ebenso hinter dem Komma:
    „Astromech Droid, R2-D2, Light Bluish Gray Head" → `R2-D2`.
  - **Hinter dem ersten Komma steht Beiwerk** — Einheit, Farbe, Bedruckung.
    „Clone Scout Trooper, 41st Elite Corps" → „Clone Scout Trooper".

  Nachgemessen an 563 Star-Wars-Figuren: **220 landen im Artikel** statt 151
  — ohne dass eine Zeile Katalogtext mitgeliefert würde. Bei englischen
  Gattungsnamen („Battle Droid" → „B1-Kampfdroide") bleibt es bei der
  Trefferliste.

## 2.77.1 – September 2026

### Behoben
- 📖 **Die Beschreibung in der App stand noch auf »öffnet eine Suche«.** Mit
  2.77.0 führt das ⓘ in den Artikel — nachgezogen hatte ich das aber nur in
  README und Handbuch, nicht dort, wo es jemand liest: in der App selbst.
  Betrifft die Karte *Mehr → 📖 Jedipedia-Verweis* und den Abschnitt unter
  *Quellen & Rechtliches*. Beide sagen jetzt, was tatsächlich passiert —
  einschließlich des Hinweises, dass die Zuordnung **einmalig** erfragt wurde
  und im Betrieb nichts abgerufen wird.

## 2.77.0 – September 2026

### Behoben
- 📖 **Das ⓘ führt jetzt in den Artikel statt auf die Suchseite.** Gemeldet:
  „Bei vielen kommt nur die Suchseite raus." Nachgemessen an 563
  Star-Wars-Figuren: nur **151** landeten im Artikel, die übrigen 412 auf
  einer Trefferliste.

  Der Grund war die Sprache. Der Katalog ist englisch, die Jedipedia
  deutsch — „Imperial Stormtrooper" steht dort unter „Sturmtruppen",
  „Battle Droid" unter „B1-Kampfdroide". Das Wiki springt nur dann von
  selbst in den Artikel, wenn der Suchbegriff der Titel ist.

  Deshalb liegt jetzt eine feste Zuordnung bei (`frontend/jedipedia-titel.js`),
  die `tools/jedipedia_titel.py` **einmalig** über die MediaWiki-Schnittstelle
  des Wikis erfragt hat. Übernommen wurde nur, was es dort wirklich gibt.
  Im Betrieb holt Brickfolio nach wie vor nichts von dort — es verlinkt nur.
  Jetzt landen **398 der 563** Figuren im Artikel; wo nichts eingetragen ist,
  öffnet sich unverändert die Suche.

- 📖 **Die Klammer trug den Namen und wurde weggeworfen.** „Assassin Droid
  (IG-88)" wurde zum Suchbegriff „Assassin Droid" — Trefferliste, obwohl
  „IG-88" ein Artikel ist. Steht in der Klammer eine Kennung wie `IG-88`,
  `C1-10P` oder `U-3PO`, ist **sie** der Name; Beschreibungen wie
  „(Padawan)" fliegen weiter raus.

## 2.76.0 – August 2026

### Geändert
- 🧩 **`in_sets` nennt jetzt auch den Zustand des Sets.** Bisher kamen
  Nummer, Name und Anzahl – der Live-Scanner konnte damit nicht
  unterscheiden, ob ein Set **versiegelt** oder längst geöffnet ist.

  Der Unterschied ist beim Mitbieten entscheidend: In einem neuen Set
  stecken die Figuren noch. Bei einem gebrauchten stünden sie längst
  einzeln in der Sammlung – wer ein Set *mit* Figuren kauft, trägt die
  Figuren einzeln ein.

  Angehängt als **viertes** Feld (`nummer|name|anzahl|zustand`): Wer nur
  drei liest, bekommt weiterhin genau das, was er bisher bekam.

## 2.75.1 – August 2026

### Behoben
- 📱 **Kompakte Ansicht plus Sortierung nach Thema war auf dem Handy
  unbrauchbar.** Das Raster legte sich über die **Themenkarten** statt über
  die Figuren: vier Spalten à 85 Pixel, in denen „Minifigure, Headgear"
  und „Ohne Thema" samt Erklärtext zu Buchstabentürmen zerfielen.

  Für die Rasteransicht gab es die Lösung längst
  (`#collection-list.by-theme`), nur griff sie hier nicht: Sie hat dieselbe
  Spezifität wie `#collection-list.kompakt-mode`, und bei Gleichstand
  gewinnt die Regel, die weiter unten steht – meine neuere. Zwei Klassen
  schlagen eine.

  Jetzt trägt die Themenkarte das Layout, und das Raster sitzt eine Ebene
  tiefer: auf 375 Pixeln drei Kacheln je Zeile, der Themenkopf über die
  volle Breite.

## 2.75.0 – August 2026

### Behoben
- 💾 **Die tägliche Sicherung entstand erst mittags.** Sie hing an der
  Preisschleife, und die schläft **zwölf Stunden**. Wann der Tagesstand
  angelegt wurde, hing damit davon ab, wann der Container zuletzt neu
  startete – irgendwo zwischen Mitternacht und Mittag. Der halbe Tag davor
  war ungeschützt.

  Am 30.08.2026 trat genau das ein: letzter Neustart 29.08. um 23:33,
  Sicherung dort übersprungen (die des 29. lag schon), nächster Lauf wäre
  **11:35** gewesen. Zurückgespielt wurde um **10:55** – vierzig Minuten zu
  früh, und ein ganzer Tag Arbeit hing an der Sicherheitskopie, die das
  Zurückspielen selbst anlegt.

  Ein eigener Wächter sieht jetzt **viertelstündlich** nach. Der Aufruf ist
  billig: Liegt der heutige Stand schon, kehrt er sofort zurück.

- 🗑️ **Jede Sicherheitskopie kostete einen Tagesstand.** Die Aufräumlogik
  lief über ein einziges `brickfolio-*.db` – und alphabetisch steht
  `brickfolio-manuell-…` **hinter** `brickfolio-2026-…`. Die Kopie galt
  damit als neueste Datei und blieb immer liegen; gelöscht wurde der
  älteste Tag. Lautlos. Aus 14 Tagen Historie waren 12 geworden.

  Tagesstände und Sicherheitskopien werden jetzt getrennt gezählt, jeder
  Topf behält seine 14. Fremde Dateien im Ordner werden nicht angefasst.

- 🧱 **Zurückspielen zieht die Migrationen nach.** Ein alter Stand bringt
  den alten Datenbankaufbau mit. Nach dem Zurückspielen fehlte deshalb eine
  tags zuvor hinzugekommene Tabelle, und die Themenauswahl im Katalog
  antwortete mit **500** – bis der Container das nächste Mal startete.

## 2.74.2 – August 2026

### Geändert
- ⚖️ **Ein Abschnitt zur Haftung** – in der App unter *Mehr → Quellen &
  Rechtliches*, im README und im Handbuch. Die MIT-Lizenz sagt das zwar
  auch, aber auf Englisch und in einer Datei, die niemand öffnet.

  Im Klartext: Brickfolio wird „wie besehen" bereitgestellt. Drei Dinge
  stehen ausdrücklich dabei –

  - **Preise sind Anhaltspunkte, keine Bewertung.** Nicht als Grundlage für
    Versicherungssummen oder Angaben gegenüber Behörden.
  - **Die Erkennung kann sich irren** – was Kamera und Suche vorschlagen,
    ist ein Vorschlag.
  - **Eure Daten liegen bei euch.** Ein Backup, das nie zurückgespielt
    wurde, ist keines.

  Die zwingende Haftung (Vorsatz, grobe Fahrlässigkeit, Personenschäden,
  Produkthaftung) bleibt unberührt – ein Ausschluss davon wäre ohnehin
  unwirksam.

## 2.74.1 – August 2026

### Geändert
- ⚖️ **Die Jedipedia steht jetzt bei den Quellen** – in der App unter
  *Mehr → Quellen & Rechtliches*, im README und im Handbuch.

  Festgehalten ist, was tatsächlich passiert: Der Verweis **verlinkt nur**.
  Es werden keine Inhalte abgerufen, übernommen oder gespeichert, und
  solange niemand das ⓘ antippt, geht nichts dorthin. Die Artikel stehen
  unter der **GNU-FDL 1.3** und gehören ihren Autoren; das Wiki steht in
  keiner Verbindung zu diesem Projekt.

## 2.74.0 – August 2026

### Geändert
- 📖 **Handbuch und README auf den Stand gebracht.** Der Tag hat viel
  gebracht, und die Doku hinkte hinterher. Neu beschrieben:

  - **Katalog durchblättern** samt Sprungbalken, Filtern und der Bremse
    beim Aushaken (Handbuch 6.2)
  - **Sets im Katalog** und warum es dafür den Kategoriebaum braucht –
    Figuren tragen ihr Thema in der Nummer, Sets nicht
  - **Katalog-Themen** mit Favoriten und Sichtbarkeit
  - **Der Steckbrief in vier Abschnitten**, Beschriftung links, Thema oben
    im Kopf – und der ✏️ nur dort, wo die App das Thema nicht ableiten kann
  - **Jedipedia-Verweis**, ausgeschaltet voreingestellt
  - **Bausteine einzeln abschalten** in der Absturzdiagnose, samt der
    Begründung: Wenn alle Dumps nur diese Seite betreffen, hilft halbieren
    statt raten

## 2.73.0 – August 2026

### Neu
- 🔬 **Bausteine einzeln abschalten – halbieren statt raten.** Unter
  *Mehr → Absturzdiagnose* lassen sich vier Dinge abschalten, die diese
  App tut und die meisten anderen Seiten nicht:

  | Baustein | was aus ist |
  |---|---|
  | Sichtbarkeitsoptimierung | `content-visibility` auf den Sammlungskarten |
  | Klebende Leisten | `position: sticky` bei Kopfleiste, Blocküberschriften, Sprungbalken |
  | Milchglas | `backdrop-filter` im Design „Nova" |
  | Offline-Helfer | der Service Worker |

  **Warum:** Alle bisherigen Absturz-Dumps betreffen ausschließlich diese
  Seite. Der Abbruch selbst steckt in Chromium – ein absichtlicher
  `EXC_BREAKPOINT` im Renderer, in Edge 151 genauso wie in Chrome 152, bei
  2 bis 9 MB Speicher. Aber irgendetwas hier löst ihn aus, und welches
  Stück, sagt niemand: Der Aufrufstapel im Dump trägt keine Namen.

  Fünf Vermutungen, fünf Fehlschläge. Deshalb der systematische Weg: eines
  abschalten, ein paar Stunden laufen lassen. **Was aus war, steht in jedem
  Fehlerbericht mit** (`OHNE: cv,blur`) – ohne diese Zuordnung wäre die
  ganze Halbiererei wertlos.

  Die Wahl liegt im `localStorage`, nicht im Profil: Sie muss einen Absturz
  und das Neuladen danach überleben, ohne dass vorher ein Server antworten
  muss. Sonst liefe die Sitzung, die es zu messen gilt, kurz mit
  angeschaltetem Baustein an.

## 2.72.0 – August 2026

### Geändert
- 🏷️ **Das Thema steht jetzt oben im Steckbrief**, direkt unter Nummer und
  Zustand – es gehört zur Figur, nicht zu dem, was man mit ihr macht. Aus
  dem Abschnitt „Einordnung" ist es verschwunden.

- ✏️ **Kein Stift mehr, wo das Thema aus der Nummer folgt.** `sw1213` ist
  Star Wars; da gibt es nichts zu entscheiden. An 910 Einträgen
  nachgesehen hatte auch **nie jemand** etwas anderes gesetzt als das
  Ableitbare.

  Bei eigenen Figuren, Teilen und unbekannten Kürzeln – 159 der 910 –
  weiß die App es dagegen nicht. Dort bleibt der Stift, und statt einer
  leeren Zeile steht dort „Thema setzen" als Einladung.

  Das Eingabefeld startet damit immer geschlossen. Vorher stand bei jedem
  Eintrag ohne Thema ein offenes Feld im Weg.

## 2.71.1 – August 2026

### Behoben
- 🔇 **„Zu diesem Artikel gibt es kein Bild" bei jedem Schließen.** Die
  Meldung war erst in 2.71.0 dazugekommen – und ging sofort daneben:
  `closeGallery` leert die Bildquelle, und **eine geleerte Quelle löst
  selbst ein `error`-Ereignis aus**. Der neue Behandler hielt das für ein
  totes Bild.

  Er prüft jetzt zuerst, ob überhaupt etwas geladen werden sollte, und die
  Quelle wird entfernt statt auf leer gesetzt.

### Geändert
- 🔙 **`content-visibility: auto` steht wieder auf den Sammlungskarten.**
  Der Versuch aus 2.67.0 ist gelaufen, das Ergebnis war negativ: Der
  Bericht zu 2.70.0 führt **drei** weitere Abstürze, alle nach dem Ausbau.

  Die Zeile spart dem Browser echte Arbeit – gemessen: statt 815
  Hintergrundbildern beim Öffnen nur noch 16 – und der Fehler ist woanders.
  Im Quelltext steht jetzt dabei, dass der Versuch gelaufen ist, damit ihn
  niemand ein zweites Mal macht.

## 2.71.0 – August 2026

### Behoben
- 🧩 **Bei Teilen ging die Großansicht sofort wieder zu.** Antippen,
  kurz aufblitzen, weg – bei Figuren und Sets funktionierte alles.

  Der Server baute für Teile die Adresse `ItemImage/PN/0/<nr>.png`. Bei
  Figuren und Sets stimmt die Null: Die haben keine Farbe. Ein Teil schon –
  dort gehört die **Farbnummer** hin, und die kennt der Server an dieser
  Stelle nicht. An sieben Teilen geprüft war die Adresse **jedes Mal** ein
  404, und weil sie die einzige in der Galerie war, klappte die Ansicht
  beim Ladefehler sofort wieder zu.

  Teile bekommen jetzt `PL/<nr>.jpg` – farbunabhängig, und bei vier der
  sieben vorhanden.

- 🔁 **Und einen Rückfall für den Rest.** Trägt auch das Katalogbild nicht,
  nimmt die Galerie die Adresse, die an der Karte steht – die lag die ganze
  Zeit daneben. Ist auch die tot, klappt sie zu und sagt warum, statt
  wortlos zu verschwinden.

## 2.70.0 – August 2026

### Geändert
- 📐 **Beschriftung links, Inhalt rechts.** „Zustand", „Thema" und „Wert"
  standen jedes für sich allein auf einer Zeile, mit der ganzen Breite
  daneben frei. Sie stehen jetzt nebeneinander – das spart bei jedem
  Steckbrief vier bis fünf Zeilen Höhe.

  Nur die Notizen bleiben gestapelt: Ein Textfeld braucht die Breite.

  Die Beschriftungsspalte ist so breit wie das längste Wort, nicht breiter.
  Eine feste Breite säße bei „Anzahl" zu weit und bei „Bezahlt" zu eng.

- Eine Zeile ohne Inhalt verschwindet mitsamt Beschriftung: „Wert" steht
  nur da, wenn es einen Marktpreis gibt. Über CSS statt über Code, weil
  die Verdrahtung den Preis später nachträgt – so greift es von selbst.

- Aus dem Wertfeld ist das Wort „Wert" verschwunden; es steht jetzt als
  Beschriftung daneben und stand sonst doppelt da.

## 2.69.0 – August 2026

### Geändert
- 🗂️ **Der Steckbrief ist in Abschnitte geteilt.** Er war über Monate
  gewachsen und zuletzt eine flache Liste aus zehn Blöcken – Anzahl,
  Zustand, Bezahlt, Tauschbörse, Thema, Notizen, BrickLink-Nummer,
  Verweise, enthaltene Teile, Marktpreise – ohne erkennbaren Zusammenhang.

  Vier Überschriften: **Mein Exemplar**, **Einordnung**, **Nachschlagen**,
  **Marktpreise**. Die Reihenfolge innerhalb der Abschnitte ist
  unverändert; Anzahl und Zustand stehen weiter zuerst, das braucht man
  beim Erfassen als Erstes.

  **Zugeklappt wird nichts.** Das spart zwar Scrollweg, kostet aber bei
  jedem Öffnen einen Tipper – und die Preise sieht man beim Bewerten fast
  immer an.

  Ein Abschnitt, der leer bliebe, wird gar nicht gezeichnet: Ohne
  BrickLink-Zugang gibt es keine Überschrift „Marktpreise" über einer
  leeren Fläche. Die Felder darunter bleiben trotzdem im Dokument – sonst
  schriebe die Verdrahtung ins Leere.

- Das **ⓘ** des Jedipedia-Verweises steht jetzt neben dem Namen statt
  darunter.

## 2.68.0 – August 2026

### Neu
- 📖 **Jedipedia-Verweis bei Star-Wars-Figuren.** Ein kleines **ⓘ** neben
  dem Namen schlägt die Figur im deutschen Star-Wars-Wiki nach.
  Einzuschalten unter *Mehr → Jedipedia-Verweis*.

  **Ausgeschaltet voreingestellt.** Es ist ein Weg nach draußen aus einer
  App, die sonst vollständig im eigenen Netz läuft; solche gehören nicht
  ungefragt hinein. Übertragen wird nichts, solange niemand das Zeichen
  antippt.

  **Gesucht wird, nicht direkt verlinkt.** Der Katalog ist englisch, die
  Jedipedia deutsch: „Battle Droid" heißt dort „Kampfdroide", und
  `/wiki/Battle_Droid` wäre eine tote Adresse. Die Suche landet auf einer
  Trefferliste mit dem richtigen Artikel obenan.

  Und nur bei Star Wars – das Wiki kennt nichts anderes. Bei einer
  City-Figur wäre der Verweis eine leere Trefferliste. Die Variante fällt
  weg: „Boba Fett - Classic Grays" sucht nach der Figur, nicht nach ihrer
  Bemalung.

## 2.67.0 – August 2026

### Geändert
- 🧪 **`content-visibility: auto` ist ausgebaut – als Versuch.**

  Von 40 Absturz-Dumps auf dem betroffenen Rechner sind **alle 40 auf
  Brickfolio**; keine andere Seite. Der Abbruch selbst ist ein
  Chromium-Fehler – ein absichtlicher `EXC_BREAKPOINT` im Renderer, in
  Edge 151 genauso wie in Chrome 152, bei 2 bis 9 MB Speicherverbrauch.
  Aber irgendetwas an dieser Seite löst ihn aus, und nur an dieser.

  `content-visibility` war das Ungewöhnlichste, was die App tut – kaum
  eine andere Seite benutzt es. Es saß auf den Sammlungskarten, also genau
  dort, wo in den Berichten immer wieder der Schaden entstand, und es griff
  ineinander mit `position: sticky`, dem Bildbeobachter und dem Bildladen
  auf denselben Elementen.

  Gebraucht wird es ohnehin kaum noch: Seine Aufgabe – nicht alles auf
  einmal zeichnen – macht seit 2.54.1 der eigene Beobachter, nachweislich
  (110 von 245 und 158 von 915 geladenen Bildern in den Berichten).

  **Bleiben die Abstürze aus, war es das.** Kommen sie weiter, gehört die
  Zeile zurück; ihr Fehlen kostet dann nur etwas Rechenzeit beim Scrollen
  sehr langer Sammlungen.

## 2.66.0 – August 2026

### Neu
- 📦 **Sets im Katalog.** Der Dateiimport nimmt jetzt auch BrickLinks
  `Sets.xml` – bisher warf er alles weg, was keine Minifigur war, und
  meldete „Gebraucht wird der Download mit Item Type Minifigures".

  Das war 2.46.1 richtig: Damals hatte eine `Parts.xml` 118.000 Steine als
  Minifiguren in den Abzug gespült, und es gab keinen Ort, an den Sets
  gehört hätten. Seit der Katalogliste gibt es einen. Teile und Zubehör
  bleiben weiter draußen.

- 🗂️ **Themen für Sets über den Kategoriebaum.** Figuren tragen ihr Thema
  in der Nummer – `sw1213` ist Star Wars. Sets nicht: `75192-1` sagt
  nichts. Deren Thema steht allein in der BrickLink-Kategorie, und die
  kommt als Nummer (129 verschiedene allein bei den Figuren).

  Ein einziger Abruf der offiziellen API holt den Baum; danach steht er in
  der Datenbank. Unterkategorien landen unter ihrem Dach: „Star Wars ▸
  Episode I" gehört zu Star Wars, sonst stünden in der Auswahl hunderte
  Zweige mit je einer Handvoll Sets. Der Knopf sitzt unter
  *Mehr → Katalog*.

  Ohne den Baum bleibt das Thema **leer** statt geraten.

### Behoben
- 🏷️ Eine neue Hilfsfunktion hieß `_katalog_bild` – so wie eine ganz andere,
  die weiter unten schon stand. Python nimmt die spätere Definition, und
  der Import legte daraufhin lautlos `None` in eine NOT-NULL-Spalte. Ein
  Test wacht jetzt darüber, dass kein Name zweimal vergeben ist.

## 2.65.1 – August 2026

### Behoben
- 📦 **„Sets" im Katalog führte in einen leeren Raum.** Der veröffentlichte
  Abzug enthält bisher **nur Minifiguren** – null Sets. Der Schalter ließ
  sich trotzdem umlegen, und die Meldung dort sagte fälschlich, es sei gar
  kein Katalog geladen.

  Jetzt ist der Schalter ausgegraut, solange nichts dahintersteht, und die
  Meldung nennt den wahren Grund. Drei Gründe für dieselbe leere Seite –
  kein Katalog, alle Themen ausgeblendet, keine Sets im Abzug – führen an
  ganz verschiedene Enden.

## 2.65.0 – August 2026

### Behoben
- ⏸️ **Ein Serverneustart wirft keine laufende Arbeit mehr weg.** Startet
  die Instanz neu – nach einem Update etwa –, laden alle offenen Seiten
  neu. Das ist richtig: Sonst liefe alter Programmcode gegen einen neuen
  Server. Der Zeitpunkt war es nicht.

  Am 29.08.2026 im LEGO-Museum: Beim Scannen lud sich die App mehrmals von
  selbst neu. Foto, erkannte Figuren und gezogene Rahmen sind danach weg,
  und die Arbeit fängt von vorn an – vor einer Vitrine besonders ärgerlich.

  Das Neuladen wartet jetzt, solange etwas offen ist: eine laufende
  Reihum-Suche, ein Foto mit Treffern, ein Steckbrief oder die Großansicht.
  Eine Leiste sagt, dass eine neue Fassung bereitliegt; geladen wird, sobald
  der Weg frei ist. Ein Update kann warten.

## 2.64.1 – August 2026

### Geändert
- 👆 **Der Hinweis unter der Großansicht verspricht kein Wischen mehr,
  wenn es nichts zu blättern gibt.** Seit dem Aufräumen der Galerie ist
  meist nur ein Bild da – „Wischen zum Blättern" versprach dann eine
  Geste, die nichts tut. Mehrere Bilder gibt es in aller Regel erst, wenn
  jemand ein eigenes Foto dazugehängt hat. Der Hinweis hängt jetzt an
  derselben Bedingung wie die Pfeile.

## 2.64.0 – August 2026

### Behoben
- 🖼️ **Das überflüssige zweite Bild in der Galerie.** Beim Scannen speichert
  die App die Adresse, die der Erkenner liefert – bei Brickognize ein
  kleines Vorschaubild von einer ganz anderen Adresse. Die Galerie legte
  BrickLinks Katalogbild daneben und zeigte damit „1/2" mit demselben
  Motiv, das zweite Bild besser als das erste.

  Gemessen an einer echten Sammlung: **379 von 910 Einträgen betroffen,
  368 davon Vorschaubilder von Brickognize.** Zusammenfassen half nicht –
  es sind wirklich zwei verschiedene Quellen.

  Die Liste vom Server ist ohnehin vollständig: Sie prüft das Katalogbild
  auf Existenz und hängt eigene Fotos selbst an. Das Startbild der Karte
  kommt jetzt nur noch dazu, wenn diese Liste leer bleibt – bei eigenen
  Figuren, oder wenn BrickLink kein Bild hat.

- 🧹 **Die Reihum-Zeichenfläche blieb liegen.** Wird beim Scannen
  „Weitersuchen" angeboten, bleibt die abgesuchte Fläche absichtlich
  stehen. Sie wanderte damit aber durch alle Ansichten und in den
  Hintergrund mit. Jetzt wird sie beim Verlassen des Scan-Tabs freigegeben –
  an derselben Grenze wie das Arbeitsbild, und nicht während eine Suche
  läuft.

### Geändert
- 📏 **Der Fehlerbericht misst jetzt Fläche, nicht nur Anzahl.** „12 von 95
  Bildern geladen" sagt nichts darüber, ob das zwölf Daumennägel sind oder
  zwölf Plakate – entpackt kostet ein Bild Breite × Höhe × 4 Byte, und das
  stand in keiner Zahl. Neu daneben: **MPx entpackt**, einschließlich der
  Reihum-Zeichenfläche, die als Zeichenfläche in keiner der bisherigen
  Zahlen auftauchte.

  Anlass ist der Absturz vom 29.08.2026 um 17:31: Der Bericht meldete
  7 MB JavaScript-Speicher und 12 von 95 geladenen Bildern – nach allem,
  was gemessen wurde, harmlos. Genau deshalb fehlt hier eine Zahl.

## 2.63.0 – August 2026

### Neu
- ⭐ **Katalog-Themen auswählen und mit Sternen versehen.** Unter
  *Mehr → 📚 Katalog-Themen* bekommt jedes Thema zwei Schalter: **★** hebt
  es in der Auswahl ganz nach oben, **☑/☐** bestimmt, ob es dort überhaupt
  erscheint.

  Bei 199 Themen war die Auswahl im Katalog-Reiter sonst ein Fass ohne
  Boden. Der bequemste Weg: ein paar Sterne setzen, dann **★ Nur
  Favoriten** – das blendet alles andere aus.

  Die Wahl gehört dem Benutzer, nicht der Instanz: Jeder kann eine ganz
  andere haben. Und der Stern überlebt das Ausblenden – wer ein
  Thema wieder einschaltet, findet seine Markierung, wo er sie gelassen
  hat.

  Ist alles ausgeblendet, sagt der Katalog-Reiter das auch. Vorher wäre er
  aus demselben Grund leer gewesen wie ohne geladenen Katalog, und man
  hätte am falschen Ende gesucht.

### Behoben
- 🖱️ **Schnelle Tipper gingen verloren.** Die ganze Themenwahl steht als
  *eine* Zeile in den Benutzereinstellungen. Wer zügig fünf Themen
  antippte, schickte fünf Anfragen, die sich überholten: Jede las denselben
  alten Stand und schrieb ihr eigenes Thema zurück – vier Änderungen waren
  danach weg. Gemessen kam von fünf Tippern einer an.

  Lesen, Ändern und Schreiben laufen jetzt am Stück.

- Und ein zweiter Fall derselben Ungeduld: Nach jedem Umschalten wurde die
  ganze Liste neu gezeichnet, wodurch die eben angetippte Zeile aus dem
  Dokument fiel. Der nächste Tipper ging ins Leere. Jetzt wird nur die eine
  Zeile umgestellt.

## 2.62.0 – August 2026

### Behoben
- 🗂️ **Die Themenauswahl gruppiert nach Thema, nicht nach Kürzel.**

  Mit den vielen neuen Namen aus 2.61.0 tragen mehrere Kürzel denselben:
  Belville läuft bei BrickLink unter vier (`belvbaby`, `belvfairy`,
  `belvfemale`, `belvmale`), Scala unter dreien, Duplo unter vieren. Nach
  Kürzeln gruppiert stand „Belville" viermal in der Auswahl, und jeder
  Eintrag zeigte ein Viertel der 213 Figuren. Ein Fehler, den erst das
  Benennen erzeugt hat.

  Der Sprungbalken zeigt bei solchen Themen die Kürzel statt der Ziffern –
  gekürzt um den gemeinsamen Anfang, weil „BELVFEMALE" auf einem Handy zu
  breit ist und die ersten vier Buchstaben ohnehin bei allen gleich sind:
  BABY, FAIRY, FEMALE, MALE.

### Neu
- 🥤 **Ein Kürzel kann zwei Themen tragen.** `cc4058` bis `cc4066` sind
  Studios-Figuren (Kameramann, Schauspieler, Assistentin), `cc4443` bis
  `cc4472` die Coca-Cola-Fußballer der WM-Serie 2002 – dieselben zwei
  Buchstaben, weil BrickLink sie über die Artikelnummer der Packung führt
  und nicht über das Thema.

  Dafür gibt es jetzt Bereichsregeln neben der Kürzeltabelle. Eine eigene
  Tabelle statt einer Ausnahme in der Zuordnung: So sieht man beim Lesen
  sofort, dass es Bereiche gibt, und der nächste Fall ist eine Zeile.

- 🏷️ Drei weitere Kürzel benannt, alle am BrickLink-Katalog
  bestätigt: `game` → Games, `hrf` → Studios (Frankenstein, Vampir,
  Werwolf, Mumie) und `cc` → Studios beziehungsweise Coca-Cola.

## 2.61.0 – August 2026

### Behoben
- ↕️ **Der Sprungbalken sprang nur nach unten.** Wer bei Block 15 stand
  und auf 08 tippte, blieb stehen.

  Die Blocküberschriften kleben (`position: sticky`). Alle schon
  durchlaufenen stapeln sich unsichtbar unter der Kopfleiste, und der
  Browser meldet für jede von ihnen **diese** Position – über
  `getBoundingClientRect` genauso wie über `offsetTop`. Gemessen lagen
  Block 08 und Block 15 zwölf Pixel auseinander, obwohl 7.000 Zeilen
  dazwischenstehen; der Sprung rechnete daraufhin „bin schon da".

  Gemessen wird jetzt an der ersten Zeile hinter der Überschrift. Die
  klebt nicht.

  Dieselbe verfälschte Zahl hatte zuvor eine Prüfung bestanden: „Ziel bei
  57 px" sah nach einem gelungenen Sprung aus und war der Wert, den der
  Fehler erzeugt. Der Test prüft deshalb jetzt, **woran** gemessen wird.

- 🏷️ **Noch 100 Themenkürzel benannt** – darunter `fort` (Fortnite), das
  beim ersten Durchgang durchfiel, weil nur die 45 größten Gruppen
  angesehen worden waren. Jetzt sind alle 115 verbliebenen durchgegangen:
  aus „ST" wurde Stranger Things, aus „BLU" Bluey, aus „SCD" Scooby-Doo,
  aus „MOF" Monster Fighters. Von 212 Kürzeln im Index tragen 203 einen
  Namen.

  Nicht benannt bleibt, was die Katalognamen nicht hergeben – etwa `bdp`,
  wo Löwenstein-Ritter, ein Hot-Dog-Verkäufer und ein Belagerungstechniker
  nebeneinanderstehen.

## 2.60.0 – August 2026

### Behoben
- 🔓 **Die Sperre „Update wird installiert" blieb manchmal für immer
  stehen** – nur ein Neuladen von Hand brachte die App zurück.

  Die Wache erkennt einen Neustart daran, dass sich der Startzeitpunkt des
  Servers ändert. Sie fragte ihn über einen Endpunkt ab, der eine Anmeldung
  verlangt. Ging die Sitzung während des Updates verloren, schlug dieser
  Aufruf fortan **immer** fehl: Die Seite erfuhr nie, dass der Server zurück
  war. Nachgebaut am 29.08.2026 – Token weggenommen, Server getauscht, und
  die Sperre stand auch nach Minuten noch.

  Version und Startzeitpunkt liegen jetzt zusätzlich unter `/api/laufzeit`,
  **ohne Anmeldung**. Geheim ist daran nichts: Die Version steht ohnehin in
  jeder ausgelieferten Seite. Alles Weitere – Countdown, Helferzustand, wer
  das Update angefordert hat – bleibt geschützt.

  Dazu zwei Kleinigkeiten: Die Sperre zeigt nach 20 Sekunden mit, wie lange
  sie schon wartet (ein Kasten, in dem sich nichts rührt, sieht nach zwei
  Minuten aus wie abgestürzt), und der Knopf „Jetzt neu laden" erscheint
  nach drei statt nach acht Minuten.

- 🏷️ **`mar` ist Super Mario, nicht Marvel.** `mar001` ff. sind Boo, Bowser
  und Bowser Jr.; Marvel-Figuren laufen bei BrickLink unter `sh` (Super
  Heroes). Der falsche Name fiel nie auf, weil die Figur unter dem falschen
  Thema genauso aussieht wie überall sonst – erst die Themenauswahl der
  neuen Katalogliste stellte die Namen nebeneinander.

  Bei der Gelegenheit **44 weitere Kürzel benannt**: Der Index kennt 212,
  benannt waren 57. Aus „SOC" wurde Fußball, aus „CRS" Cars, aus „DRM"
  DREAMZzz. Aufgenommen wurde nur, was die Katalognamen selbst belegen; wo
  sie es nicht taten (etwa `bdp`), bleibt das Kürzel stehen. Ein falscher
  Name ist schlechter als gar keiner – er sieht aus, als wüsste man es.

- ↕️ **Der Sprungbalken schnitt den Sprung ab.** Der angesprungene Block
  stand ganz am Ende des Geladenen, und weiter als bis zum Dokumentende
  kann kein Browser scrollen: Man landete eine halbe Seite zu früh (Ziel
  414 px statt 57 px unter der Kopfleiste). Jetzt wird erst genug
  darunter nachgeschoben, dann gesprungen – und mit Abstand zur
  Kopfleiste, die sonst den Blockkopf verdeckte.

### Neu
- 🔢 **Der Sprungbalken trägt sein Thema im Kopf.** „SW" über „00, 01, 02 …"
  liest sich als `sw00xx`; ohne den Kopf waren es nur Zahlen, und danach
  wurde prompt gefragt. Der gerade sichtbare Block ist markiert und zieht
  beim Scrollen mit – vorher blieb markiert, was man zuletzt angetippt
  hatte, und das stimmte nach drei Wischern nicht mehr.
- ⬆️ **Zurück zum Anfang.** Ein runder Pfeil unten rechts, sobald man zwei
  Bildschirmhöhen weit unten ist – in jeder langen Liste, nicht nur im
  Katalog. In Popups und während der Update-Sperre bleibt er weg.

## 2.59.0 – August 2026

### Neu
- 📚 **Den Katalog durchblättern.** Vierter Reiter unter *Listen*: alle
  Figuren eines Themas in Nummernfolge, mit dem eigenen Besitzstand daneben.
  Bisher konnte die App nur „wo ist X?" beantworten; die andere Frage –
  *was gibt es überhaupt, und was davon fehlt mir?* – ging nur über die
  Suche, und die zeigt nur, wonach man gefragt hat.

  Sortiert wird nach **Nummer, nicht alphabetisch**. So stehen Varianten
  beieinander (sw0001a bis sw0001d) und das Jahr wächst von oben nach unten.
  Am rechten Rand liegt ein Sprungbalken mit den Hunderterblöcken – bei
  1.663 Star-Wars-Figuren der Unterschied zwischen Suchen und Finden.

  **✔** legt die Figur in die Sammlung, **♥** auf die Wunschliste, ein Tipp
  auf den Namen öffnet einen Steckbrief. Vier Filter grenzen ein: *Alle*,
  *Fehlt mir*, *Hab ich*, *Gemerkt*.

  **Ausgehakt wird nur, was nichts wert ist.** Hängt an der Figur eine
  Stückzahl über eins oder eine Notiz, sagt die App das und rührt den
  Eintrag nicht an. Ein Fehltipper auf einem daumengroßen Knopf darf keine
  Kaufpreise wegräumen; Löschen geht in der Sammlung.

  Die Liste hält **alle** Zeilen eines Themas im Dokument, lädt aber nur die
  Bilder in Sichtweite: bei 1.663 Zeilen sind das rund 26. Umgekehrt zur
  Sammlung, wo die Adresse im HTML steht und ein Beobachter hinterher
  aufräumt – hier lädt der Beobachter, statt freizugeben. Bei 80 Zeilen je
  Nachschub-Schritt wären es sonst 80 Bilder auf einen Schlag, von denen 60
  sofort wieder wegkämen. Entpackte Bilder liegen außerhalb des
  JavaScript-Speichers und haben in der Sammlung wiederholt den Tab
  umgebracht.

### Geändert
- Das Popup einer Katalogzeile nimmt **denselben Daumennagel** wie die Zeile
  darüber. Bei 180 px Anzeige sieht man keinen Unterschied, aber der Browser
  hat das Bild schon und lädt kein zweites.

## 2.39.0 – August 2026

### Neu
- 🔄 **Der Katalogabzug zieht Änderungen von BrickLink nach.** Er entsteht,
  indem Nummern der Reihe nach abgeklappert werden – sw0001, sw0002, … –, und
  danach steht der Zeiger hinter der höchsten gefundenen Nummer. Neue Figuren
  werden so gefunden, eine **Umbenennung nie**: Eine bekannte Nummer wurde
  kein zweites Mal abgefragt.

  Naheliegend wäre, den Abzug reihum neu abzufragen. Das wären 9.741 Abrufe,
  gut zweieinhalb Stunden, und das BrickLink-Kontingent teilt sich der Lauf
  mit den Preisen. Der Change Log leistet dasselbe für eine Handvoll
  HTML-Seiten und **ohne Kontingent** – im August 2026 waren es 12 umbenannte
  Minifiguren im ganzen Monat.

  Der Leser dafür war schon da, zeigte aber in die andere Richtung: Er wurde
  nur befragt, wenn ein Artikel aus der *Sammlung* verschwunden war. Jetzt
  liest er zusätzlich Namensänderungen (`viewAction=N`) und schreibt Name,
  Suchtext und Nummer im Katalogindex fort. Läuft alle zwölf Stunden mit.

  Die Sammlung bleibt bewusst unangetastet: Für Figuren, die jemand besitzt,
  gibt es weiterhin die Benachrichtigung mit „Nummer übernehmen" – dort
  bestätigt ein Mensch die Änderung, statt dass sie still geschieht.

  **Gelöschte Figuren sind kein Fall.** Die Log-Seite kennt zwar „Item Marked
  for Deletion", aber von Juni bis August 2026 stand dort kein einziger
  Eintrag. BrickLink löscht nicht, es legt zusammen oder nummeriert um –
  beides steht im Log und wird übernommen.

## 2.38.5 – August 2026

### Behoben
- 🔁 **Eine einzige Figur hielt 9.740 fertige auf.** Der Bilderlauf blieb bei
  9.740 von 9.741 stehen. Die letzte offene war `cty0131` – dort verfiel das
  Modell im Aufdruck-Feld in „TATATATATA…", die Längengrenze schnitt die
  Zeichenkette ab, es begann im nächsten Feld von vorn, und `num_predict`
  kappte schließlich mitten im JSON. Unlesbar.

  Weil ein Fehlschlag bewusst nichts wegschreibt, stand dieselbe Figur beim
  nächsten Griff wieder vorn – zwölf Anläufe, dann beendete die
  Ausfallschwelle den ganzen Lauf.

  Zwei Dinge, die gleich aussahen, werden jetzt getrennt: „gar nicht
  geantwortet" ist ein Ausfall des Dienstes und hakt weiterhin nichts ab –
  sonst gälte der halbe Katalog als angesehen, ohne dass je jemand
  hingesehen hat. „Geantwortet, aber unlesbar" ist figurenspezifisch: Nach
  drei Anläufen wird die Figur ohne Ergebnis abgehakt, und der Lauf kommt
  ans Ende.

### Geändert
- ⚡ **Wiederholungsbremse für die Bildanalyse.** Ollama fährt ohne
  (`repeat_penalty` 1.0), und bei `temperature: 0` gibt es aus einer
  Schleife dann keinen Ausweg. Mit 1.1 antwortet dieselbe Figur in 3,5 s
  statt 12,6 mit gültigem JSON.

  Der Nebeneffekt ist größer als die Behebung: An sechs Vergleichsfiguren
  blieben Art und Farben gleich, die Laufzeit **halbierte sich** (8–9,7 s
  auf 2,4–4,3 s). Das Modell polstert nicht mehr aus.

## 2.38.4 – August 2026

### Behoben
- 🔢 **„Alle Bilder angesehen", obwohl 8.328 offen waren.** Die Statusanzeige
  meldete null offene Figuren, während erst 1.413 von 9.741 eine Beschreibung
  hatten.

  `offen` stand im Laufzustand des Bilderlaufs – einem Wörterbuch im
  Arbeitsspeicher – und wurde nur *während* eines laufenden Durchgangs
  gefüllt. Nach jedem Neustart des Containers stand dort wieder 0, und an
  diesem Tag wurde dreimal ausgerollt.

  Eine Null, die „fertig" bedeutet, ist die unangenehmste Sorte Fehler: Sie
  sieht aus wie ein Erfolg, und niemand sucht nach ihr. Die Zahl beschreibt
  die Daten, nicht den Lauf – sie wird jetzt bei jeder Abfrage frisch
  gezählt.

## 2.38.3 – August 2026

### Behoben
- 🥇 **Der goldene Droide stand auf Platz 6.** „goldener Droide" ergibt vier
  übersetzte Begriffe – `Gold Droid`, `C-3PO`, `Droid`, `Gold` –, und die
  Suche arbeitete sie nacheinander ab. Der erste traf fünf Astromechs mit
  zufälligen Goldanteilen (ein goldener Helmstreifen bei R5-D4, ein goldener
  Torso beim ASP Droid), und C-3PO kam erst danach.

  Die Sortierung nach Wortzahl bleibt richtig – ohne sie liefe `Minifigure`
  vor `Knight`, und in einer echten Sammlung stand daraufhin Greedo unter den
  Rittern (2.28.1). Sie sagt aber nur, welcher Begriff **anfängt**, nicht,
  dass er alle Plätze bekommt: Wortreicher heißt eingegrenzter, nicht
  treffender.

  Die Treffer werden jetzt reihum genommen – je Runde höchstens zwei pro
  Begriff, dann ist der nächste dran. Kein Begriff verhungert mehr hinter
  einem anderen, die Reihenfolge bleibt erhalten, und die UND-Logik innerhalb
  eines Begriffs ist unangetastet. Gilt für Sammlung und Katalog.

## 2.38.2 – August 2026

### Behoben
- 🔍 **„Ritter" fand Luke Skywalker.** Die Katalogsuche lieferte auf „Ritter"
  drei Figuren, die keine sind: Luke Skywalker (Tatooine), einen Imperial
  Royal Guard und den siebenjährigen Boba Fett. Alle drei trugen
  `art='knight'` – die vom Bildmodell geratene Art der Figur, die
  gleichberechtigt neben dem Namen im Suchtext stand.

  Das ist derselbe Fehler wie „Greedo unter den Rittern" in 2.28.1, nur
  durch eine andere Tür: Dort war es die Sortierung, hier eine Vermutung mit
  dem Gewicht einer Tatsache. Ein einziges Wort für die ganze Figur, und die
  Kategorien sind breit genug („Knight", „Alien", „Soldier"), um ständig mit
  deutschen Suchbegriffen zu kollidieren.

  Naheliegend wäre, dem Bildmodell Name und Thema mitzugeben, damit es
  besser rät. Gemessen an denselben drei Figuren verschwand „Knight"
  daraufhin zwar, wurde aber durch „Pilot" bzw. „Soldier" ersetzt – zwei von
  drei blieben falsch, und nebenbei kippte Boba Fetts Haarfarbe von
  „schwarz" (richtig) auf „dunkelblau".

  Deshalb steht im Suchtext jetzt nur noch, was entweder Katalogwahrheit ist
  (der Name) oder beobachtet (Farben und Teilbeschreibung). Geraten wird
  dort nicht mehr. `art` bleibt in der Datenbank – für die Anzeige taugt es,
  als Suchbegriff nicht.

## 2.38.1 – August 2026

### Behoben
- 🔁 **Der Bilderlauf blieb an einer einzelnen Figur hängen – und gab dann
  ganz auf.** Bei `sw0326` brach die Analyse jedes Mal nach exakt 120 s ab.
  Nach fünf solchen Figuren beendete sich der komplette Lauf; 9.000 Figuren
  blieben unbearbeitet liegen.

  Die naheliegende Erklärung – zu wenig Speicher auf dem Mac mini – war
  falsch, und die exakte Wiederholung von „2m0s" hätte das verraten müssen:
  Eine Ladeverzögerung streut, eine harte Zeitgrenze auf einer nie endenden
  Antwort nicht. Das Modell lud in 3,8 s, verarbeitete das Bild in 2,8 s und
  schrieb dann 15.190 Token am Stück – 436 Sekunden lang eine Endlosschleife
  **innerhalb einer einzigen Zeichenkette**:

      "...and a dark blue stripe on the upper part of the legs, and a dark
       blue stripe on the lower part of the legs, and a dark blue stripe ..."

  Die Teileliste hielt ihre sechs Einträge ein – Arrays begrenzte das Schema
  also. Die Länge einer Zeichenkette begrenzte es nicht, und bei
  `temperature: 0` mit `repeat_penalty` 1.0 gibt es aus so einer Schleife
  keinen Ausweg. Die Grammatik muss sie verhindern.

  Jetzt hat jede Zeichenkette im Schema eine Höchstlänge. Dieselbe Figur:
  **4,1 s statt 436**, mit brauchbarem Ergebnis. Ein Ausreißer wird dabei
  mitten im Wort abgeschnitten – gewollt: Ein angeschnittenes Merkmal ist
  Suchtext, eine hängende Anfrage kostet den ganzen Lauf. Dazu kommt eine
  Notbremse (`num_predict`), die großzügig über einer vollständigen Antwort
  liegt; ein Test rechnet das gegen die Längen im Schema nach.

### Geändert
- ⏱️ **Der Bilderlauf hält mehr aus.** Er gab nach fünf Fehlschlägen in Folge
  auf – passend für einen Lauf über Minuten, zu wenig für den ersten
  vollständigen über Stunden. Ein Moment, in dem Home Assistant sich das
  Textmodell in den Speicher holt, genügte. Jetzt sind es zwölf, und
  entscheidend: mit 20 s Pause dazwischen statt 0,3 s. Vorher brannten fünf
  Versuche in anderthalb Sekunden durch, während Ollama noch lud. Ein echter
  Ausfall wird weiterhin erkannt – er dauert nun vier Minuten.

## 2.36.0 – August 2026

### Behoben
- 🔢 **Der Katalog-Abzug fand halbe Themen gar nicht.** Er fragte fest nach
  vier Ziffern (`cas0001`) – die Burgfigur heißt aber `cas001`. Damit gingen
  `cas`, `pi`, `hp`, `jw`, `sp`, `ww`, `lor` und `iaj` **komplett leer** aus,
  und das Tückische: Der Lauf meldete nach fünfundzwanzig Fehlgriffen brav
  „fertig". Von außen sah es aus, als gäbe es diese Themen nicht.

  Die Breite wird jetzt zu Beginn jedes Themas mit ein paar Abrufen
  ermittelt. Ein `429` beendet dabei auch die Erkennung – sie als „gibt es
  nicht" zu lesen hieße, bei erschöpftem Kontingent munter weiterzufragen.

### Neu
- 📚 **Die Themenliste ist jetzt vollständiger.** Statt sieben geratener
  Präfixe stehen vierzehn gemessene darin: `sw`, `cty`, `njo`, `sh`, `frnd`,
  `gen`, `iaj`, `cas`, `pi`, `hp`, `jw`, `sp`, `ww`, `lor`.

  Ermittelt über die Bestandteile bekannter Sets – eine Liste der Präfixe
  gibt BrickLink nicht heraus, und die Katalogseite darf man nicht
  auslesen. Dabei kam auch heraus: Präfix ist **nicht** Kategorie. `cty`
  deckt „Town" und „Train" ab.

  Vollständig ist auch das nicht; weitere trägt man einfach dazu.

## 2.35.2 – August 2026

### Behoben
- 🔘 **„Cannot set properties of null (setting 'disabled')".** Aus dem
  Betrieb gemeldet, aus dem Abbrechen-Knopf der Update-Leiste: Der Handler
  schaltet den Knopf ab, wartet auf die Antwort und schaltet ihn wieder
  ein – nur ist `ev.currentTarget` dann **null**. Der Browser räumt es auf,
  sobald der Handler das erste Mal zurückkehrt, und das ist beim ersten
  `await`.

  Der Knopf wird jetzt vor dem `await` festgehalten. Dieselbe Stelle gab es
  ein zweites Mal beim anteiligen Verteilen eines Gesamtpreises auf eine
  Einkaufsliste – dort ausgerechnet im Fehlerzweig, wo der Knopf hängen
  blieb und die Fehlermeldung verschluckt wurde.

  Ein Test sucht das Muster im ganzen Frontend, damit es nicht wieder
  hineinwächst.

## 2.35.1 – August 2026

### Behoben
- 🌍 **Die Merkmale aus dem Bild waren deutsch – und trafen deshalb nie.**
  2.35.0 legte „rot" und „droide" ab. Gesucht wird aber mit den Begriffen
  aus der Übersetzung, und die sind **englisch** („Red Protocol Droid").
  Die beiden konnten sich nicht begegnen.

  Selbst die rohe deutsche Frage half nicht: „roter Protokolldroide" trifft
  „rot" nicht, weil die Beugung dazwischensteht. Deutsche Wortformen sauber
  aufeinander abzubilden wäre ein eigenes Projekt.

  Jetzt fragt die App auf Englisch und legt englisch ab – der Index ist
  einsprachig, und die Übersetzung greift wie überall sonst. Nebenbei
  antwortet `qwen3-vl` auf Englisch besser: beim Wookiee „Wookiee" statt
  nur „Alien".

  Damit greift auch die Genauigkeit wie erwartet: „roter Protokolldroide"
  findet den roten und **nicht** den grauen, weil alle Wörter des Begriffs
  vorkommen müssen.

## 2.35.0 – August 2026

### Neu
- 🎨 **Auch die Art der Figur kommt jetzt aus dem Bild**, nicht nur die
  Farbe. „Soldat", „Droide", „Alien" – vieles davon steht in keinem Namen:
  `R-3PO Protocol Droid` nennt keine Farbe, `Wicket (Ewok)` keine Art. Erst
  mit beidem findet „roter Droide", was gemeint ist.

  **Das ist eine Rücknahme.** 2.34.0 fragte bewusst nur nach Farben, weil
  `minicpm-v` die Art in zwei von drei Proben verfehlte und Darth Vader für
  einen Droiden hielt. Diese Messung stammte aus einer Zeit, in der es das
  beste verfügbare Modell war. Mit `qwen3-vl` sieht es anders aus: an zehn
  echten Figuren aus dem Abzug **zehn Treffer** – Stormtrooper → Soldat,
  Wookiee → Alien, R2-D2 → Droide, Luke im Fluganzug → Pilot, Yoda → Alien,
  Leia → Mensch.

  Die Einschränkung hing also am Modell, nicht an der Aufgabe. Wer ein
  schwächeres einstellt, bekommt entsprechend schwächere Antworten – die
  landen dann als Rauschen im Suchtext. Das ist der Preis der freien Wahl
  und steht so im Handbuch.

  Art und Farbe stehen in getrennten Spalten, damit sich eines verwerfen
  lässt, ohne das andere zu verlieren.

## 2.34.1 – August 2026

### Behoben
- 🧠 **Denkmodelle antworten woanders hin.** `qwen3-vl` legt seine Antwort
  in `thinking` ab; `content` bleibt leer, und `think: false` ändert daran
  nichts. Für die App sah das aus, als liefere das Modell gar nichts –
  ausgerechnet das beste Bildmodell im Haus wirkte kaputt, obwohl die
  richtige Antwort dastand, nur im falschen Feld.

  Ist `content` leer, wird jetzt `thinking` gelesen. Wo beides steht, zählt
  weiter `content`: Das Denkfeld ist der Notnagel, nicht die Quelle.

  Gemessen am 21.08.2026 gegen dieselben drei Figuren – `qwen3-vl` erkennt
  R-3PO als Droiden, den AT-AT-Fahrer als Soldaten und Darth Vader
  **namentlich**, bei richtigen Farben in allen drei Fällen. `gemma3:12b`
  liegt knapp dahinter, `qwen2.5vl:7b` und `minicpm-v` deutlicher.

## 2.34.0 – August 2026

### Neu
- 🎨 **Farben aus den Katalogbildern.** Zweiter Durchgang nach dem Abzug:
  Die lokale KI sieht sich die Bilder an und schreibt die Farben dazu. Viele
  BrickLink-Namen nennen keine – „R-3PO Protocol Droid" sagt nirgends „rot".
  Danach findet „roter Protokolldroide" beides: die Art aus dem Namen, die
  Farbe aus dem Bild.

  **Nur Farben, mit Absicht.** Nach der Art der Figur gefragt, lag
  `minicpm-v` in keiner von drei Proben richtig, `gemma3:12b` in zwei –
  und die Art steht ohnehin schon im Namen. Sie hier noch einmal raten zu
  lassen brächte nur Fehler hinein.

  Auch ein leeres Ergebnis wird festgehalten, sonst versuchte der nächste
  Lauf dieselbe Figur wieder und käme nie ans Ende.

- 🖼 **Das Modell fürs Bilderansehen ist getrennt einstellbar.** Übersetzen
  und Bilder ansehen sind verschiedene Aufgaben, und die besten Modelle
  dafür sind verschiedene.

  In beiden Listen stehen nur noch **sinnvolle** Modelle: Code-Modelle
  fallen raus. Für Bilder stehen die bildfähigen oben und tragen ein 👁.
  **Sortiert, nicht gefiltert** – `gemma3:12b` meldet Ollama gegenüber gar
  keine Bildfähigkeit und ist trotzdem das beste im Haus. Wer hart nach dem
  Merkmal filtert, versteckt den Sieger.

### Behoben
- 📚 **Der Abzug speicherte keine Bildadresse.** Treffer aus dem eigenen
  Abzug wären ohne Bild geblieben, obwohl BrickLink sie in derselben
  Antwort mitliefert. Bestehende Zeilen werden beim Start nachgetragen –
  ohne einen einzigen zusätzlichen Abruf, denn die Adresse folgt der Nummer
  (und der Bildserver unterscheidet nicht zwischen Groß- und
  Kleinschreibung). Fehlt sie in der Antwort, wird sie ebenso gebildet.

## 2.33.1 – August 2026

### Behoben
- 📚 **Die Karte des Katalog-Abzugs sprach noch von Star Wars.** Sie hieß
  „Katalog-Abzug (Star Wars)" und versprach „rund 25 Minuten" – beides war
  seit 2.33.0 falsch: Sie kann alle Themen, und die 25 Minuten stammten aus
  einer Schätzung mit 0,5 s je Abruf.

  Gemessen sind es **0,38 Abrufe je Sekunde** – BrickLink antwortet unter
  Dauerlast langsamer als bei Einzelabfragen. Das heißt rund **eine Stunde
  je 1.500 Nummern**, für alle sieben Themen zusammen etwa fünf. Handbuch
  und Oberfläche nennen jetzt diese Zahl.

## 2.33.0 – August 2026

### Neu
- 📚 **Der Katalog-Abzug kann mehrere Themen.** Bisher stand `sw` fest im
  Knopf. Jetzt trägt man sie mit Komma ein – `sw, cty, njo` – und sie laufen
  **nacheinander** ab, mit Fortschritt und Warteschlange in der Anzeige.

  Nacheinander, nicht nebeneinander: Alle Läufe teilen sich denselben
  BrickLink-Zugang. Zwei gleichzeitig hieße doppelter Takt – die Drosselung
  wäre ausgehebelt, für die es hier gute Gründe gibt.

  Bricht ein Lauf mit einem Kontingentfehler ab (`429`), bleiben auch die
  folgenden Themen stehen. Der Zugang ist derselbe; weiterzumachen würde das
  Problem nur verlängern.

  Als Präfix sind nur Buchstaben zugelassen – es wandert in eine Adresse,
  und `../` hätte dort nichts zu suchen.

  Gemessene Größenordnungen: `cty` über 2.000 Nummern, `njo` und `sh` je
  1.000–2.000, `cas`, `hp` und `col` je unter 500. Beim gemessenen Takt von
  0,38 Abrufen je Sekunde sind das für alle zusammen rund fünf Stunden –
  abbrechbar und fortsetzbar, also gut über mehrere Abende zu verteilen.

## 2.32.0 – August 2026

### Neu
- 📚 **Ein eigener Abzug des BrickLink-Katalogs (Star Wars).** Damit findet
  die Suche endlich, was man nur beschreiben kann: „Protokolldroide" führt
  zu `R-3PO Protocol Droid`. Über den gewöhnlichen Katalog ging das nicht –
  Rebrickable nennt dieselbe Figur schlicht `R-3PO`, ohne ein einziges Wort
  zum Suchen. Kein Modell muss dafür etwas wissen; gesucht wird in eigenem
  Text.

  Der Abzug läuft die Nummern der Reihe nach ab (`sw0002`, `sw0003`, …).
  Eine Auflistung einer Kategorie bietet BrickLink nicht an – geprüft: dort
  gibt es nur das Nachschlagen einer einzelnen Nummer. Gemessen liegen die
  Nummern dicht: Von `sw0002` bis etwa `sw1500` fehlt praktisch keine.

  **Gedrosselt auf einen Abruf je Sekunde**, rund 25 Minuten. Das ist keine
  Höflichkeit gegenüber BrickLink, sondern Selbstschutz: Es ist derselbe
  Zugang, über den die Preise laufen. Ein Durchlauf mit Vollgas könnte das
  Tageskontingent aufbrauchen – und dann stünde der Scanner ohne Preise da.

  Jederzeit anhaltbar, der Fortschritt bleibt: Zwanzig Minuten Arbeit dürfen
  nicht verfallen, nur weil jemand gestoppt hat. Lücken in der Nummerierung
  beenden den Lauf nicht (25 am Stück gelten als Ende), ein anderer Fehler
  als „gibt es nicht" dagegen sofort – `429` heißt Kontingent erschöpft, und
  stur weiterzulaufen machte das schlimmer.

  Findet der eigene Abzug etwas, wird Rebrickable gar nicht mehr gefragt.

### Behoben
- Der Vorfilter der Abzugssuche benutzte den rohen Namen, der Vergleich
  danach die satzzeichenfreie Form – „c3 po" fand `C-3PO` deshalb nicht,
  weil `LIKE '%c3%'` am Bindestrich scheitert. Beide benutzen jetzt dieselbe
  Elle.

## 2.31.1 – August 2026

### Geändert
- 📖 **Die gelernten Begriffe haben ein eigenes Fenster.** In den
  Einstellungen stand die vollständige Liste – bei ein paar Zeilen ging das,
  aber sie wächst mit jedem Suchlauf, und ein geplanter Durchlauf über die
  BrickLink-Nummern brächte Tausende auf einen Schlag. Die Einstellungen
  wären damit unbrauchbar geworden.

  Dort steht jetzt nur die Bilanz („38 Begriffe gelernt, davon 12 eigene").
  **Ansehen und pflegen** öffnet die Liste mit Suchfeld, seitenweise zu 25.
  Gesucht wird in beiden Richtungen: „ritter" über den deutschen Begriff,
  „Knight" über das, was dabei herauskommt – wer eine Zeile korrigieren
  will, weiß mal das eine und mal das andere.

  Die Bilanz gilt dabei immer für alles, nie für die gefilterte Sicht: Sonst
  sagte „12 eigene" plötzlich etwas anderes, nur weil jemand etwas ins
  Suchfeld getippt hat.

  Die Liste trägt jetzt dieselbe Laufnummer gegen überholte Antworten wie
  die Katalogsuche. Wer sofort nach dem Öffnen tippt, löst eine zweite
  Abfrage aus, während der Erstaufbau noch läuft – käme der später zurück,
  überschriebe er das gefilterte Ergebnis.

## 2.31.0 – August 2026

### Neu
- 📖 **Die Suche lernt – und du kannst ihr etwas beibringen.** Die Zuordnung
  „deutscher Begriff → englische Katalogbegriffe" lag bisher nur im
  Arbeitsspeicher: nach jedem Neustart weg, nur vom Modell beschrieben, für
  niemanden einsehbar. Wer „roter c3po" tippte, bekam für immer
  C-3PO-Varianten – obwohl die gesuchte Figur „R-3PO Protocol Droid" heißt.

  Unter **Mehr → 🤖 Lokale KI** steht die Liste jetzt offen da. Jede
  erfolgreiche Übersetzung wandert automatisch hinein, eigene Zeilen trägst
  du selbst ein:

      Gesucht wird nach: roter c3po
      Finden soll er:    R-3PO

  Drei Entscheidungen stecken darin:

  - **Das Gelernte hängt an der App, nicht am Modell.** Ein Wechsel des
    Modells oder des Rechners nimmt den Wissensstand mit; ein
    nachtrainiertes Modell täte das nicht. Deshalb gelten eigene Zeilen auch
    dann, wenn gar keine KI eingerichtet ist.
  - **Die KI überschreibt eine eigene Zeile nicht.** Sonst wäre das
    Beigebrachte beim nächsten Suchlauf wieder weg.
  - **Fehlschläge werden nicht gelernt.** Ein leeres Ergebnis ist kein
    Wissen; dauerhaft gespeichert stellte es den Begriff für immer tot.

  Nebenbei wird die Suche deutlich schneller: Ein bekannter Begriff kostet
  **4 Millisekunden statt 1,6 Sekunden**, weil das Modell gar nicht erst
  gefragt wird.

### Geändert
- Ein Wechsel der KI-Adresse leert weiterhin den Zwischenspeicher, fragt das
  Modell aber nicht erneut nach bereits Gelerntem – das steht ja in der
  Liste. Taugt eine Zeile nichts, löscht man sie sichtbar, statt sie stumm
  neu raten zu lassen.

## 2.30.1 – August 2026

### Behoben
- 🔇 **Die Katalogsuche endete stumm.** Wer beim manuellen Erfassen einen
  Begriff eintippte, der nichts fand, bekam **gar keine Meldung** – nicht
  einmal „Nichts gefunden". Man wusste nicht, ob noch gesucht wird, ob die
  KI dran ist oder ob etwas kaputt ist.

  Die Ursache stand schon länger im Code: `renderSuggestions` setzt bei
  leerer Liste selbst „Nichts gefunden …", und eine Zeile später löschte ein
  pauschales `hint.hidden = true` die Meldung wieder – ohne Ansehen des
  Ergebnisses. Jetzt wird der Hinweis nur weggenommen, wenn es Treffer gibt.

  Zwei weitere stumme Ausgänge kamen mit 2.29.0 dazu: Fand die KI nichts
  oder fiel sie aus, blendete der Zweig den Hinweis ebenfalls aus. Beide
  hinterlassen jetzt wieder die „Nichts gefunden"-Meldung.

  Und ohne eingerichtete Katalogsuche steht endlich da, warum nichts
  passiert, statt dass man tippt und ins Leere schaut.

  Geprüft am laufenden Programm, alle vier Wege: kein Katalog, KI ohne
  Treffer, KI ausgefallen, KI erfolgreich.

## 2.30.0 – August 2026

### Neu
- 📋 **Das KI-Modell wird ausgesucht, nicht abgetippt.** Der Name musste
  exakt so eingetragen werden, wie Ollama ihn führt – `qwen2.5:14b`, nicht
  `qwen2.5-14b` und nicht `qwen 2.5`. Ein Tippfehler sah dabei aus wie ein
  kaputter Dienst: Die Verbindung stand, nur das Modell gab es nicht. Auf
  dem Server im Haushalt liegen 14 Stück, darunter `qwen2.5:14b` **und**
  `qwen2.5:14b-instruct` – die Verwechslung ist keine Theorie.

  Steht die Adresse, holt die App jetzt die Liste der installierten Modelle
  und stellt sie zur Wahl. **Modelle laden** holt sie erneut, etwa nach
  einem `ollama pull`.

  **Kein `datalist`.** Der wäre der kürzere Weg gewesen, aber iOS zeigt ihn
  bis heute nicht an – und dort wird die App am meisten benutzt. Also eine
  echte Auswahlliste.

  **Das Textfeld bleibt.** Schweigt der Dienst oder ist die Adresse noch
  nicht gespeichert, übernimmt es wie bisher; die Auswahl ist eine
  Bequemlichkeit, kein Zugangsweg. Auch abfragen lässt sich eine noch nicht
  gespeicherte Adresse – sonst müsste man erst eine ungeprüfte Einstellung
  sichern, um zu sehen, was dort zur Wahl steht.

  Ein bereits gespeichertes Modell bleibt wählbar, auch wenn es nicht mehr
  auf dem Server liegt – sonst überschriebe ein Speichern still eine noch
  gültige Einstellung.

## 2.29.0 – August 2026

### Neu
- 🤖 **Die KI-Suche gilt jetzt auch für den Katalog.** 2.28.0 hat die
  Übersetzung an die Sammlungssuche gehängt. Ausprobiert wird sie aber
  zuerst dort, wo man beim Erfassen tippt: im Feld **Name** unter
  „✏️ Manuell erfassen". Das sucht im Katalog, und dort gab es die
  Übersetzung nicht – „Roter c3po" blieb leer, und von außen sah das aus,
  als funktioniere die KI nicht.

  Dabei ist der Katalog der Ort, an dem sie am meisten hilft: In der eigenen
  Sammlung kann man notfalls blättern, im Katalog sucht man etwas
  Unbekanntes. Ohne Treffer hat man gar nichts.

  Findet der Katalog nichts, übersetzt die App und fragt noch einmal nach –
  wie in der Sammlung mit dem genauesten Begriff zuerst, sortiert nach
  Wortzahl und ausdrücklich nicht nach Länge (daran hing 2.28.1). Über den
  Treffern steht, wonach zusätzlich gesucht wurde.

  **Höchstens zwei Versuche.** In der Sammlung kostet ein Begriff mehr fast
  nichts, die Einträge liegen im Speicher. Hier ist jeder Versuch eine
  eigene Anfrage an Rebrickable – mehr Wartezeit beim Tippen und mehr Last
  auf einem fremden Kontingent. Zwei decken den Anlassfall ab („roter c3 po"
  → `C-3PO`, dann `C-3PO red`), ohne aus einer Suche fünf zu machen.

  Unverändert gilt: Das Modell liefert **Suchbegriffe, niemals Ergebnisse**.
  Jede Zeile kommt weiter von Rebrickable, ein erfundener Begriff findet
  dort nichts. Antwortet der Katalog beim Zusatzversuch nicht, bleibt es bei
  der leeren Liste – ein Fehlschlag der Zugabe ist kein Fehler der Suche.

## 2.28.1 – August 2026

### Behoben
- 🎭 **Greedo stand unter den Rittern.** Beim ersten Einsatz an einer echten
  Sammlung (888 Figuren) zeigte die neue KI-Suche für „Ritter" neun Treffer –
  darunter Greedo und Obi-Wan. Für „Zauberer" kam ein kampfbeschädigter
  Anakin Skywalker. Zwei Ursachen, beide in der Testsammlung unsichtbar, weil
  dort schlicht nichts so hieß:

  **Die Länge war das falsche Maß für Genauigkeit.** Das Modell liefert für
  „Ritter" die Begriffe `Knight, Minifigure, Hero, Character`. Sortiert wurde
  nach Wortzahl *und Länge* – damit lief `Minifigure` (10 Zeichen) vor
  `Knight` (6) und griff sich als Erstes alles, was „Minifigure" im Namen
  trägt. Innerhalb gleicher Wortzahl bleibt jetzt die Reihenfolge des Modells
  stehen; es nennt den Eigennamen zuerst.

  **„Mage" steckt in „Damaged".** Damit „c3 po" den Artikel „C-3PO" findet,
  wirft der Vergleich Satzzeichen weg – und verlor dabei die Wortgrenze. Ein
  Begriff muss jetzt dort stehen, wo auch ein Wort anfängt. Bindestrichnamen
  bleiben trotzdem auffindbar.

## 2.28.0 – August 2026

### Neu
- 🤖 **„Ritter" fand nichts, obwohl die Figuren im Regal lagen.** Die
  Oberfläche ist deutsch, die Namen in der Sammlung kommen von BrickLink und
  sind **englisch**. Die Suche war ein reines `LIKE '%…%'` auf Name und
  Nummer – wer „Ritter" eintippte, bekam eine leere Liste, obwohl die Figur
  als „Castle Knight" in der eigenen Datenbank steht. Das war kein Randfall,
  sondern die naheliegendste Suche eines deutschen Nutzers. Dasselbe galt für
  „Kopf" (Head), „Schwert" (Sword) und „Piraten" (Pirate).

  Findet die Suche nichts, fragt die App jetzt eine **optionale** lokale KI
  nach englischen Begriffen und sucht damit erneut. Über den Treffern steht,
  wonach zusätzlich gesucht wurde – gemeldet werden nur Begriffe, die
  wirklich etwas gefunden haben.

  **Die KI liefert Suchbegriffe, niemals Ergebnisse.** Jede angezeigte Zeile
  kommt weiter aus der eigenen Datenbank; ein erfundener Begriff findet
  schlicht nichts. Deshalb genügt hier ein kleines Modell auf dem eigenen
  Rechner, und deshalb kann die Funktion nichts erfinden, was es nicht gibt.

  Einzurichten unter **Einstellungen → Lokale KI für die Suche** mit der
  Adresse eines [Ollama](https://ollama.com) und einem Modellnamen
  (Vorgabe `qwen2.5:14b`), wahlweise über `OLLAMA_URL` und `OLLAMA_MODEL` aus
  der `docker-compose.yml`. **Ohne Adresse ist alles wie vorher** – nicht
  jeder betreibt eine lokale KI. Antwortet der Dienst nicht innerhalb von
  acht Sekunden, bleibt es beim gewohnten Hinweis „Nichts gefunden".

  Die Adresse wird wie ein API-Schlüssel aus Fehlerberichten entfernt: Sie
  verrät den Aufbau des Heimnetzes und kann Zugangsdaten enthalten, und ein
  Fehlerbericht kann als öffentliches Issue enden.

  **Satzzeichen zählen nicht mit.** BrickLink schreibt die bekanntesten
  Figuren mit Bindestrich – `C-3PO`, `R2-D2` –, getippt wird „c3 po" oder
  „r2d2". Der Vergleich lässt deshalb alles außer Buchstaben und Ziffern weg.
  Aus mehreren Wörtern müssen **alle** vorkommen, sonst zöge ein erfundener
  Begriff wie „Knight Hunter" jeden Ritter herein.

  **Der genaueste Begriff zuerst.** „roter c3 po" ergibt `C-3PO (red)` und
  `C-3PO`. In der Reihenfolge des Modells sammelte der breite Begriff alle
  C-3POs ein, und die Farbvariante kam auf null neue Treffer – die Eingrenzung
  verpuffte. Jetzt steht der rote oben, die übrigen darunter als Rückfall.

  Gleiche Frage, gleiche Antwort: Ein Zwischenspeicher verhindert, dass beim
  Tippen alle 300 ms ein Modellaufruf losläuft. **Ein Fehlschlag verfällt nach
  einer Minute** – die erste Fassung merkte ihn sich dauerhaft, sodass ein
  einziger Aussetzer (etwa während Ollama das Modell lud) genau diesen
  Suchbegriff bis zum Neustart tot bleiben ließ. Damit das seltener vorkommt,
  bittet die App Ollama, das Modell 30 Minuten geladen zu lassen.

## 2.27.0 – August 2026

### Behoben
- 💤 **Die Absturzerkennung zählte das Betriebssystem mit.** Wirft iOS eine
  App im Hintergrund aus dem Speicher, läuft `pagehide` nicht – für die
  Erkennung sah das aus wie ein Abbruch. Das war nicht bloß unsauber, es hat
  zwei Wochen Suche in die falsche Richtung geschickt.

  Von 23 Abbrüchen im Archiv lagen **15** nach einer Pause von einer bis
  achtunddreißig Stunden. Aus einem davon – 15.351 Elemente am 15.08., danach
  8,7 Stunden Lücke – entstand die These, die Sammlung sei zu groß. Sie war
  es nicht: Am 19.08. hat ein iPhone die Sammlung mit 664 Bildern
  durchgescrollt und lief weiter, ein Mac mit 886 Bildern ebenso. Von den
  acht verbleibenden echten Abbrüchen kamen sieben in Sitzungen vor, die nie
  über 2.000 Elemente hinauskamen.

  Die App merkt sich jetzt beim Wechsel in den Hintergrund einen Vermerk und
  löscht ihn beim Zurückkommen. Fehlt der Abschied und liegt der Vermerk noch
  da, heißt es „im Hintergrund weggeräumt" und zählt in einer eigenen Zeile –
  mitsamt der Liegezeit. Die Fälle verschwinden also nicht, sie stehen nur
  nicht mehr in derselben Spalte wie die echten Abstürze.

  **Ohne Zeitvergleich**, anders als beim Abschiedszettel: Auf dem
  Schreibtisch misst ein verborgener Tab gedrosselt weiter, sein letzter
  Messwert ist dann jünger als der Vermerk. Auch die Auswertung „wie lange
  lief eine Sitzung vor dem Abbruch" lässt diese Fälle jetzt aus – 38 Stunden
  im Hintergrund verzerren dort jede Aussage.

## 2.26.3 – August 2026

### Behoben
- 🔍 **Ein Hub-Ausfall hinterließ keine Spur.** Am 13.08.2026 um 10:03 meldete
  eine Instanz einen 502 bei `POST /api/hub/trades/sync`. Im Fehlerbericht
  stand davon nur „Fehler 502" und der Anfang einer Cloudflare-Fehlerseite.

  Die App hatte ihre Erklärung durchaus dabei – „Hub: …" oder „Hub nicht
  erreichbar" –, aber der Rumpf ihrer Antwort wurde zwischen Instanz und
  Browser durch jene Fehlerseite ersetzt. Der Hub wiederum antwortet nach
  außen grundsätzlich nur mit „interner Fehler", damit kein Innenleben nach
  draußen geht, und seine eigenen Protokolle wurden nicht aufbewahrt.

  Beide Seiten kannten den Grund, keine behielt ihn. Nicht einmal die Frage,
  ob der Worker überhaupt zu Wort gekommen war oder etwas davor geantwortet
  hatte, ließ sich nachträglich klären – und genau daran hängt, wo man
  weitersucht.

  Die Instanz schreibt eine Störung des Hubs jetzt selbst ins Protokoll:
  Status, Grund und – wenn keine JSON-Antwort kam – den Anfang dessen, was
  stattdessen kam. Bei einer Zeitüberschreitung steht dort die Art
  (`ConnectTimeout` heißt „nie erreicht", `ReadTimeout` heißt „angenommen und
  dann nichts mehr") samt Zeitgrenze. Abgelehnte Anfragen bleiben still: Ein
  401 bei falschem Token ist eine Antwort, kein Ausfall. Der Instanz-Token
  steht nie in der Zeile.

  Im Hub ist zusätzlich die Aufbewahrung der Worker-Protokolle eingeschaltet
  (`[observability]`). Ohne sie sah `console.error` nur, wer zufällig gerade
  `wrangler tail` laufen ließ.

## 2.26.2 – August 2026

### Behoben
- 🔐 **CSP-Meldungen schleppten ein Access-JWT mit.** Aus einer Instanz kam
  zweimal „Vom Browser blockiert: img-src →
  flat-leaf-5175.cloudflareaccess.com". Kein Defekt: Die Instanz steht hinter
  Cloudflare Access, und ist dessen Sitzung abgelaufen, antwortet Access auf
  jede Anfrage – hier das Symbol der Web-App – mit einer Umleitung auf seine
  Anmeldeseite. Die liegt auf einem anderen Host, und den erlaubt `img-src`
  nicht.

  In der Meldung stand bisher die vollständige Adresse samt einem JWT von
  rund 1,5 kB. Das ist kein Zugangsschlüssel (ein `meta`-Token mit
  `auth_status: NONE`, fünf Minuten gültig), es gehört aber weder ins
  Fehlerprotokoll noch in einen Bericht an den Hub. Gespeichert wird jetzt
  nur noch Herkunft und Pfad, ein `?…` zeigt an, dass gekürzt wurde.

  Außerdem steht bei dieser einen Umleitung dabei, was sie bedeutet:
  „(Access-Anmeldung abgelaufen)". Ohne den Hinweis sucht man den Fehler in
  der App, obwohl niemand etwas zu reparieren hat.

## 2.26.1 – August 2026

### Behoben
- 🔍 **Die Fremdsuche meldete die eigene Zieh-Anzeige.** In den Berichten einer Instanz
  vom 10.08.2026 stand in **jeder** Zeile `FREMD: <div.ptr>` – und das war
  die App selbst: die Anzeige für „nach unten ziehen = neu laden", die es
  nur beim Start vom Startbildschirm gibt.

  Der Grund ist eine Reihenfolge. Beim Laden merkt sich die App, was unter
  `<body>` steht; alles, was später dazukommt, gilt als fremd. Die
  Zieh-Anzeige entsteht danach und bleibt stehen.

  Der Fehler ist nicht die falsche Zeile, sondern was sie verdeckt: Das Feld
  soll die seit Wochen offene Frage beantworten, welcher fremde Code im
  Renderer sitzt, wenn der Tab stirbt. Solange es in jeder Zeile dasselbe
  meldet, liefert es null Information – und sieht dabei aus wie eine
  Bestätigung.

  Betroffen war nicht nur `div.ptr`: Dialoge, der Kopier-Notausgang und die
  Download-Verweise hängen ebenfalls nachträglich an `<body>` und hätten
  während einer Messung genauso im Bericht gestanden. Die bisherige Ausnahme
  galt nur für das Artikel-Popup und hätte mit jedem neuen Overlay wachsen
  müssen. Stattdessen kennzeichnet die App jetzt am Element selbst, was von
  ihr stammt – ein Test hält fest, dass keine Stelle das vergisst.

## 2.26.0 – August 2026

### Neu
- 🐞 **Fehlerbericht an den Hub senden.** Der Speicher-Verlauf liegt im
  Browser und nirgends sonst – für die Absturzsuche fehlte damit genau das
  Stück, das die Frage entscheidet: Stürzt es nur bei **einem** ab (dann
  liegt es an dessen Gerät) oder bei **allen** (dann an der App)?

  Der Knopf erscheint **nur nach einem erkannten Absturz**. Vor dem Senden
  bekommt man wortwörtlich zu sehen, was rausgeht – derselbe Text wie bei
  „Verlauf kopieren", aus derselben Funktion. Darin stehen Zeitpunkte,
  Speicher, Elemente, Bilder, Version, Design, Ansicht, Gerät und die Namen
  fremder Erweiterungen im Fenster; **keine** Artikel, Namen oder Preise.
  Nach dem Senden wird der Verlauf auf dem Gerät geleert, damit derselbe
  Absturz nicht dreimal ankommt.

  **Eigener Token, nicht der des Tausch-Netzwerks.** Das ist keine
  Ordnungsliebe: Von vier Instanzen im Haushalt sind zwei Mitglied im
  Netzwerk. Hinge der Kanal am Mitgliedskonto, bliebe die Hälfte stumm – und
  zwar ausgerechnet die, deren Berichte am meisten erklären würden.
  Umgekehrt gibt niemand mit einem Bericht etwas über sein Tauschen preis,
  und der Kanal lässt sich einzeln zurückziehen.

  **Ohne hinterlegten Token** bietet derselbe Knopf den Bericht zum
  Kopieren an, statt stumm zu bleiben.

### Hub (1.5.0)
- Neue Tabellen `report_tokens` und `crash_reports`, der Endpunkt
  `POST /v1/crash` **vor** der Mitglieder-Anmeldung, und in der
  Admin-Konsole eine Übersicht, die mehrere Berichte nebeneinanderlegt –
  samt Auszählung, auf welchen Ansichten sich Abstürze häufen.

## 2.25.0 – August 2026

### Neu
- 🔎 **Der Speicher-Verlauf notiert die geöffnete Ansicht** an jedem
  Messwert (`▸ scan`), und die Zusammenfassung sagt, wo die App bei einem
  Absturz zuletzt stand: „↳ zuletzt offen war dabei: scan (2×)". Gezählt
  wird die Ansicht des **letzten Messwerts davor** – der Starteintrag nennt
  die nach dem Neustart und damit die falsche.

  Anlass sind zwei bestätigte Abstürze (08. und 09.08.), die beide auf der
  Scan-Ansicht passierten, bei identischem Zustand: 7 MB, 1007 Elemente,
  6 Bilder. Ob das ein Muster ist oder Zufall, war nicht zu beantworten –
  die Ansicht stand nur in der **Spur**, und die behält zwanzig Einträge und
  ist nach einem Neustart weg. Jetzt zeigt der dritte und vierte Absturz es
  von selbst.

## 2.24.0 – August 2026

### Neu
- 📉 **Größte Wertverluste** in der Statistik, als Gegenstück zu den besten
  Wertsteigerungen: die fünf Stücke, bei denen der Kaufpreis am weitesten
  über dem heutigen Wert liegt. Ein Tipp auf eine Zeile öffnet den
  Steckbrief.

### Geändert
- 📈 **Verluste stehen nicht mehr unter „Beste Wertsteigerungen".** Dort
  landeten sie bisher nur dann, wenn es **weniger als fünf Gewinner** gab –
  ausgerechnet in einer gewachsenen Sammlung sah man sie also nie, und wenn
  doch, dann unter einer Überschrift, die das Gegenteil versprach. Die
  Steigerungen zeigen jetzt nur noch Gewinne, die Verluste stehen daneben

## 2.23.0 – August 2026

Vier Funde aus dem vollständigen Funktionstest, die lange liegen geblieben
sind. Keiner davon hat je jemanden umgebracht – gemeinsam ist ihnen, dass
sie **still** danebengehen.

### Behoben
- 👤 **„  " war ein gültiger Benutzername.** Die Längenprüfung zählte die
  rohe Eingabe, abgeschnitten wurde erst danach – zwei Leerzeichen kamen
  damit durch und landeten als **leerer** Name in der Datenbank. Anmelden
  konnte sich damit niemand mehr, und in der Benutzerverwaltung stand eine
  namenlose Zeile. Auch Steuerzeichen sind jetzt draußen: Ein Name mit
  Zeilenumbruch zerlegt jede Liste, in der er auftaucht. Anlegen, Umbenennen
  und Einrichten prüfen ab sofort **gleich** – vorher hatte jede Stelle ihre
  eigene, halbe Fassung
- 🖼️ **Gelöschte Artikel ließen ihre Fotos liegen** – die Einträge *und* die
  Dateien. Sichtbar war das nirgends, erreichbar auch nicht: Ohne Artikel
  gibt es keine Galerie, in der sie auftauchen könnten. Nur der Platz auf
  der Platte wuchs. Aufgeräumt wird jetzt, sobald der Artikel **überall**
  weg ist – Sammlung, Wunschliste, Einkaufslisten. Eine Aufnahme, die an
  mehreren Artikeln hängt, bleibt liegen, solange einer sie noch braucht
- 🔗 **Die Galerie zeigte Bilder, die es nicht gibt.** Findet die
  BrickLink-API kein Bild, baut die App eine Adresse aus Typ und Nummer
  zusammen – das ist eine Vermutung. Stimmte sie nicht, stand ein leerer
  Rahmen zum Durchblättern in der Galerie. Jetzt wird nachgefragt, aber die
  Beweislast liegt beim Weglassen: Nur ein klares „gibt es nicht" (404)
  wirft die Adresse raus. Zeitüberschreitung oder gar kein Netz heißen
  *unbekannt* – dann bleibt die Vermutung stehen, denn eine leere Galerie
  wäre schlimmer als ein Bild, das vielleicht lädt

### Geändert
- 💼 **Wer die Instanz einrichtet, ist jetzt auch Sammlerprofi.** Vorher
  bekam das erste Konto nur Admin-Rechte und sah damit weder Kaufpreise noch
  Einkaufslisten oder Verkaufsliste – freischalten musste man sich in der
  Benutzerverwaltung selbst. Ein Einrichtungsassistent, nach dem man sich
  erst selbst freischaltet, ist keiner. Alle weiteren Benutzer starten
  unverändert als Standard-Konto

## 2.22.0 – August 2026

### Behoben
- 🧮 **Der Speicher-Verlauf erfand Abstürze.** Ein zweiter Tab wurde als
  „OHNE ABSCHIED" eingetragen – also als Absturz. Der Abschiedszettel liegt
  im localStorage, und der gehört **allen** Tabs derselben Adresse
  gemeinsam: Ein frisch geöffneter Tab fand darin keinen frischen Abschied,
  während der erste munter weiterlief, und trug sich selbst als Absturz ein.
  Im Verlauf vom 06.08. um 23:31:40 stand genau das, und drei Sekunden
  später maßen **zwei** Reihen im Abstand von 30 Sekunden weiter. Der alte
  Notbehelf (ein Aufruf mehr als 90 Sekunden nach dem letzten Messwert zählt
  nicht) griff dort nicht – es waren 27 Sekunden.

  Das ist der schlimmste Fehler, den eine Messung haben kann: Sie erfand die
  Ereignisse, die sie erklären sollte. Jeder Tab hat jetzt eine eigene
  Kennung und meldet ein Lebenszeichen; beim Start wird nachgesehen, ob ein
  *anderer* gerade läuft. Dann steht dort **„weiterer Tab"** statt eines
  Absturzes. Echte Abstürze werden unverändert erkannt.

### Neu
- 🪟 **Der Verlauf sagt, wenn mehrere Tabs offen sind** („2 Tabs offen").
  Alle schreiben in dieselbe Liste, ihre Messwerte wechseln sich also ab –
  ohne diese Angabe sah das nach wilden Sprüngen bei Speicher und Elementen
  aus. Genau danach hatten wir gesucht.

### Geändert
- 🔍 Der **allererste Eintrag** eines Verlaufs wird nicht mehr bewertet. Er
  hat keinen Vorgänger, über dessen Ende sich etwas sagen ließe – stand aber
  trotzdem als „OHNE ABSCHIED" da. Die Zählung überspringt ihn längst, die
  Anzeige tat es nicht

## 2.21.3 – August 2026

### Behoben
- 🐳 **`sudo bash update.sh` scheiterte auf Synology – nach getaner Arbeit.**
  `sudo` bringt einen eigenen, kurzen Suchpfad mit, und dort fehlt
  `/usr/local/bin`, wo auf der Synology `docker` liegt. Das Skript lief
  deshalb bis zum letzten Schritt durch, legte den Datenbank-Schnappschuss
  an, **tauschte den Quellstand auf der Platte aus** – und brach erst dann
  mit `docker: command not found` ab. Zurück blieb der schlechteste
  Zustand: auf der Platte der neue Stand, im Betrieb der alte Container,
  und eine Ausgabe, die bis zur vorletzten Zeile nach Erfolg aussah. Das
  Skript ergänzt den Suchpfad jetzt selbst und prüft **vor** dem ersten
  Schreiben, ob es `docker` überhaupt gibt – fehlt es, bleibt die Instanz
  unangetastet. Über den Aufgabenplaner fiel das nie auf, weil der einen
  längeren Suchpfad mitbringt; betroffen war nur der Weg von Hand, den die
  App selbst anzeigt

## 2.21.2 – August 2026

### Behoben
- 🪟 **Der Steckbrief ging hinter der Karte auf, aus der er kam.** Die
  Figurenliste eines Sets steht im Detail-Fenster einer Sammlungs-Karte
  (Ebene 70) – der Steckbrief lag auf der Grundebene der Popups (60) und
  damit dahinter. Man sah nur, dass irgendwo etwas aufging. Er liegt jetzt
  auf 80: über der Karte, unter der Großansicht, damit ein Tipp auf sein
  Bild die Galerie weiterhin davor öffnet
- ⌨️ **Escape schloss beides auf einmal.** Die Detail-Karte bringt einen
  eigenen Escape-Empfänger mit. Jetzt schließt jeder Druck nur das oberste
  Fenster
- 🔤 **Die Schrift im Steckbrief passte nicht zum Rest.** Die Artikelnummer
  stand mit 16 px in voller Textfarbe da statt mit 12,5 px gedämpft wie
  überall sonst – fast so laut wie der Name darüber. Grund: `.sub` hat keine
  Grundregel, sondern wird immer im Zusammenhang gesetzt, und der Steckbrief
  stand außerhalb. Auch die Abschnitte („Marktpreis", „Steckt in diesen
  Sets") hatten eigene Größen; sie benutzen jetzt dieselben Klassen wie der
  Detailblock einer Karte. Der Name selbst hatte die Browser-Vorgabe für
  Überschriften (18,7 px) – bei „Snowtrooper – Male, Printed Legs, White
  Hands" eine Wand, jetzt 16 px

## 2.21.1 – August 2026

### Behoben
- 👓 **Das Update-Banner war in Galaxie und Nova nicht zu lesen.** Seine
  Fläche ist die Akzentfarbe – in Galaxie ein helles Gelb, in Nova ein
  helles Blau –, die Schrift blieb aber die helle des dunklen Designs.
  Gemessen waren das **1,22 : 1** (Galaxie) und **1,66 : 1** (Nova); lesbar
  wären 4,5 : 1. Ausgerechnet die Meldung, die auffallen soll, war damit
  unsichtbar. Jetzt steht dunkle Schrift darauf: 13,2 : 1 und 8,8 : 1
- 🔗 **„Release-Notes ansehen" nahm die Browser-Vorgabe für Verweise.** Auf
  der hellen Fläche kaum zu sehen, und einmal besucht vollends weg – im
  Bildschirmfoto ein dunkles Rot auf Hellblau. Der Verweis erbt jetzt die
  Schriftfarbe des Banners und bleibt über die Unterstreichung als Verweis
  erkennbar

## 2.21.0 – August 2026

### Neu
- 👤 **Figuren-Steckbrief: ein Tipp auf die Zeile, und alles steht da.**
  Überall, wo eine Figur bisher nur als Zeile auftauchte – unter einem Set in
  eurer Sammlung, in der Teileliste, bei den fehlenden Set-Figuren, auf den
  Einkaufslisten, auf der Wunschliste, in der Statistik und bei den Doppelten
  –, öffnet ein Tipp jetzt den **Steckbrief**: Bild, Nummer, Jahr,
  Marktpreise, ob ihr sie habt (Sammlung / Einkaufsliste / Wunschliste), in
  welchen eurer Sets sie steckt, dazu + Sammlung, ☆ Merken und BrickLink.
  Schließt beim Tippen daneben, mit ✕ oder Escape. Das Bild behält seine
  Aufgabe: ein Tipp darauf öffnet weiterhin die Bildergalerie – jetzt auch
  aus dem Steckbrief heraus, und Escape schließt erst das Bild, dann den
  Steckbrief

### Geändert
- 🛒 **„Auf einer Einkaufsliste" ist jetzt blau statt gelb.** Bisher sah die
  Marke genauso aus wie „auf der Wunschliste" – dabei bedeuten die beiden das
  Gegenteil voneinander: im Korb gegen fehlt euch. Gleiche Farbe hieß damit
  gar nichts. Grün heißt *habt ihr*, blau *ist unterwegs*, gelb *wollt ihr*

### Behoben
- 📷 **„Nur Foto dazu" stand auch da, wenn es den Artikel gar nicht gab.**
  Der Knopf hängt ein Foto an einen vorhandenen Artikel – ohne Artikel gibt
  es nichts, woran es hängen könnte. Er erscheint jetzt nur noch, wenn das
  Stück in eurer Sammlung oder auf einer Einkaufsliste steht. Die
  Wunschliste zählt bewusst nicht: Was man sich wünscht, hat man gerade nicht

## 2.20.1 – August 2026

### Behoben
- 🌍 **„30 Artikel haben noch Preise aus einem anderen Gebiet" – obwohl nie
  ein Gebiet umgestellt wurde.** Der Zähler füllte sich selbst nach. Kaufte
  man einen Wunsch („✔ Gekauft!") oder verbuchte einen angekommenen Posten
  von einer Einkaufsliste, wanderten Preis, Zeitstempel und Rohdaten mit in
  die Sammlung – **Gebiet und Währung aber nicht**. Der Artikel galt damit
  sofort als „fremdes Gebiet", obwohl sein Preis aus genau dem eingestellten
  stammte. Nachrechnen half bis zum nächsten Kauf und kostete dabei zwei
  BrickLink-Abrufe je Artikel für nichts. Beide Wege reichen Gebiet und
  Währung jetzt mit durch; ein Preis, der wirklich aus den USA stammt, wird
  weiterhin gemeldet

## 2.20.0 – August 2026

### Neu
- 🛒 **Die Wunschliste sagt jetzt, was schon unterwegs ist.** Steht ein Wunsch
  bereits auf einer offenen Einkaufsliste, trägt seine Karte einen blauen
  Vermerk „🛒 auf Einkaufsliste: Flohmarkt". Bei mehreren Listen stehen alle
  da, mit der zusammengezählten Stückzahl. Abgehakte Posten und archivierte
  Listen zählen nicht mit – abgehakt heißt gekauft, archiviert heißt vorbei.
  Zusammen mit dem grünen „✔ in eurer Sammlung" beantwortet die Wunschliste
  damit auf einen Blick die Frage, die man vor dem Kauf hat: *haben wir das
  schon, oder holt es gerade jemand anders?*

## 2.19.2 – August 2026

### Behoben
- 🐞 **„Ein Fehler wurde aufgezeichnet" – und der Bericht war leer.** Wer den
  Fehlerbericht leerte, ließ den Zettel dazu stehen. Er zeigte danach auf
  einen Fehler, den es nicht mehr gab. Das Leeren räumt die Zettel jetzt mit
  weg
- 🔕 **Ein verwaister Zettel machte die App stumm.** Gemeldet wird nur, wenn
  kein Zettel offen ist – damit ein Problem nicht zehn Karten übereinander
  stapelt. Zeigte der offene aber ins Leere, kam **nie wieder** eine
  Meldung. Jetzt blockiert nur noch ein Zettel, dessen Fehler wirklich
  existiert; verwaiste werden dabei abgeräumt

> Gefunden auf einer laufenden Instanz: drei Benachrichtigungen vom Typ
> `error`, null Zeilen im Fehlerbericht. Der jüngste Zettel war offen – und
> hätte jede weitere Fehlermeldung verschluckt.

## 2.19.1 – August 2026

### Behoben
- 🔎 **Die Suche nach fremdem Code lief zum falschen Zeitpunkt.** Sie stand
  nur in der Startzeile – und die entsteht beim **Laden** der Seite, also
  bevor eine Erweiterung ihre Sachen einhängt. Das leere Ergebnis war
  deshalb kein Ergebnis, sondern ein Messfehler. Jetzt wird bei jeder
  Messung nachgesehen; geschrieben wird nur, wenn etwas da ist

## 2.19.0 – August 2026

### Neu
- 🔎 **Der Bericht nennt jetzt, wer sonst noch in der Seite sitzt.** Bisher
  stand dort „Script error." – der Satz, auf den der Browser jeden Fehler
  aus **fremden Skripten** zusammenkürzt. Er sagt, *dass* fremder Code lief,
  nicht *welcher*. Jetzt stehen die Erweiterungs-Adressen und die
  nachträglich eingehängten Elemente daneben, im Fehlereintrag **und** in
  jeder Startzeile des Speicher-Verlaufs

> **Warum das jetzt zählt.** Vier ausgewertete Abstürze, vier verschiedene
> Situationen: Listen offen mit 5094 Elementen, zweimal Leerlauf im
> Hintergrund, zuletzt die **leere Scan-Ansicht mit 970 Elementen und 4
> Bildern**. Derselbe Tab hat vorher 14.585 Elemente mit 822 Bildern
> getragen. Kein Maß der App erklärt das – aber fremder Code läuft im
> **selben Renderer-Prozess**, und stürzt der ab, nimmt er die Seite mit,
> ganz gleich wie klein sie ist.
>
> Gemeldet wird nur, nie geblockt: Es ist euer Browser, und eine
> Passwort-Ausfüllhilfe hat dort gute Gründe zu sein.

## 2.18.0 – August 2026

Gefunden beim vollständigen Durchlauf einer frisch aufgesetzten Instanz –
von der Installation bis zur Wiederherstellung.

### Behoben
- 💾 **Das Kaufbuch fehlte in der Sicherung.** `purchases` stand nicht in
  `BACKUP_TABLES`. Nach einer Wiederherstellung war es leer, während der
  aufsummierte Kaufpreis an der Zeile stehen blieb: Man sah, **dass** etwas
  bezahlt wurde, aber nicht mehr wann, wo und wie oft
- 🖼 **Artikel ohne Bildadresse bekamen nie eins.** „🖼 Bilder jetzt holen"
  spiegelte nur schon bekannte Adressen auf die Instanz – wer per CSV
  importiert, legt aber Zeilen ganz ohne an. Der Lauf meldete „nichts zu
  tun", während jede Karte den Platzhalter zeigte. Jetzt schlägt er die
  fehlende Adresse erst im Katalog nach
- 💶 **„Preislose erneut abrufen" übersprang die nie versuchten.** In der
  Bedingung stand `price_updated_at IS NOT NULL` – gedacht als „schon
  versucht, nichts gefunden". Damit blieben ausgerechnet die Artikel außen
  vor, die noch nie an der Reihe waren
- 🗂 **CSV: `item_type` galt nicht als Typspalte.** `item_id` zählte als
  Nummer, das Gegenstück aber nicht – ein Set landete still als Minifigur,
  und Preise, Themen und Filter stimmten danach nie wieder
- 🐞 **Gleichartige Fehler wurden nicht zusammengefasst.** Die Kennung nahm
  den **Detailtext** und ließ den **Ort** weg – genau verkehrt herum. Bei
  „Script error." steht im Detail die Spur der letzten Schritte, die jedes
  Mal anders aussieht: Jedes Auftreten erzeugte einen neuen Eintrag

> **Warum das lange nicht auffiel.** Der übliche Weg führt über Scannen und
> Suchen, und dort kommt schon eine Bildadresse mit, wird schon ein Preis
> geholt, steht schon ein Typ fest. Hineingelaufen ist nur, wer importiert
> oder wiederhergestellt hat.

## 2.17.0 – August 2026

### Behoben
- 🧹 **Die Listen-Ansicht blieb für immer im Dokument stehen.** Ein Blick in
  die Einkaufslisten legte bei 310 Artikeln rund **4600 Elemente und 310
  Bilder** ab – und die blieben dort, auch wenn längst Sammlung, Statistik
  oder Einstellungen offen waren. Für die Sammlung wird seit 2.9 beim
  Verlassen geräumt; für die Listen fehlte es
- 📦 **Eine eingeklappte Liste baute ihre Zeilen trotzdem auf.** Sie standen
  nur auf `display: none` – unsichtbar, aber vollständig im Dokument. Jetzt
  entstehen sie erst beim Aufklappen und verschwinden beim Zuklappen

> Gemessen an 310 Listenposten:
>
> | | vorher | nachher |
> |---|---|---|
> | Listen-Tab, eingeklappt | 4631 Elemente · 310 Bilder | **973 · 4** |
> | nach dem Weiterklicken | 4631 Elemente · 310 Bilder | **973 · 4** |
>
> Aufgeklappt sind es weiterhin rund 5900 Elemente – das ist die Liste, die
> man gerade ansieht.

## 2.16.0 – August 2026

### Behoben
- 🖼 **Neun Stellen holten weiterhin Bilder in voller Größe.** 2.11.0 hat den
  Daumennagel eingeführt, aber nur die Sammlungskarten umgestellt. Listen,
  Statistik, Doppelte, fehlende Set-Figuren, die Set-Figuren-Dialoge und die
  Hub-Angebote luden weiter 400 px – und die zugehörige Prüfung sah es nicht,
  weil sie `class="card-img"` **wörtlich** verlangte und diese Stellen
  `class="card-img fig-img"` heißen

> **Aus einem eingeschickten Verlauf.** Der Tab stand drei Stunden ruhig bei
> 1784 Elementen und 32 Bildern. Dann ging die Listen-Ansicht auf: **5094
> Elemente, 336 Bilder** – 90 Sekunden später war der Renderer tot, bei 7 MB
> JS-Speicher.
>
> | | vorher | nachher |
> |---|---|---|
> | 336 Bilder, entpackt | 215 MB | 34 MB |
>
> Entpackte Bilder liegen **außerhalb** des JS-Speichers. Deshalb blieb die
> Kurve flach, während der Tab starb – und deshalb war die Ursache so lange
> nicht zu sehen.

- 🧪 **Die Prüfung dazu prüft jetzt den Anfang der Klassenliste.** Sonst
  rutscht dieselbe Sorte Stelle beim nächsten Mal wieder durch

## 2.15.0 – August 2026

Gefunden beim Durchtesten an einer laufenden Instanz.

### Behoben
- ⬆️ **Auch nach einer eigenen Änderung sprang die Liste nach oben.**
  2.12.0 hat das fürs automatische Auffrischen erledigt – löschen, Nummer
  richtigstellen, Thema setzen, Benachrichtigung übernehmen und die
  Sammelaktionen unter „Mehr" luden aber weiter schlicht neu. Elf Stellen,
  jetzt alle über denselben Weg
- 🪟 **Ein Thema zu setzen räumte das Popup weg.** Bei Sortierung nach Thema
  wechselt der Eintrag die Gruppe, die Liste muss also neu – aber nicht in
  dem Moment, in dem man gerade „Setzen" gedrückt hat. Jetzt wartet es, bis
  das Popup zu ist
- ✍️ **Der Text beim Bildabruf sprach von Preisen.** „BrickLink führt zu
  dieser Nummer keine verkauften Artikel" klang, als wäre nur gerade nichts
  verkauft worden – beim Bild fehlt aber der **Eintrag**, nicht der Verkauf

> **Sortierung, Suche und Filter landen weiter am Anfang.** Dort steht
> danach etwas anderes in der Liste; die alte Stelle zu halten wäre kein
> Dienst, sondern ein neuer Fehler.

## 2.14.0 – August 2026

### Geändert
- 🏷 **Das Themenfeld steht nur noch da, wenn keins gefunden wurde.** Als es
  kam (1.90.0), standen Teile reihenweise unter „Ohne Thema" – BrickLink
  sortiert sie nach **Form** („Brick, Modified"), nicht nach Thema. Seit das
  Thema über die Zweitnummer gefunden wird, ist der Normalfall erledigt, und
  Eingabefeld samt Knopf standen für etwas da, das längst richtig ausgefüllt
  war. Jetzt steht bei einem gefundenen Thema nur noch das Thema

> Ganz weg ist es nicht: Der Stift daneben holt das Feld zurück. Falsch
> zugeordnet wird auch mal etwas, und ohne einen Weg dahin bliebe es falsch.
> Wer das Thema leert, bekommt das Feld wieder offen – dann steht der
> Eintrag ja wirklich ohne.

## 2.13.0 – August 2026

### Behoben
- 🖼 **Das ↻ neben dem Bild holte bei bedruckten Teilen nichts.** Dieselbe
  Verwechslung wie beim Preis: Die Rebrickable-Nummer ging unverändert an
  BrickLink. Jetzt nimmt auch der Bildabruf die BrickLink-Nummer, wenn die
  eigene nichts ergibt
- 🚦 **Ein 404 wurde als „BrickLink nicht erreichbar" gemeldet.**
  `requests.HTTPError` ist eine Unterklasse von `RequestException` – stand
  kein eigener Zweig davor, fiel „kennt die Nummer nicht" in den Ast für
  Ausfälle. Betroffen waren der Bildabruf und die Teileliste einer Figur
- 📋 **Fehlgeschlagene Aufrufe standen in keinem Bericht.** Aufgezeichnet
  wurde nur, was niemand auffing. Fast jeder Knopf fängt seinen Fehler aber
  ab und schreibt ihn in eine Kurzmeldung – auf dem Bildschirm stand „Fehler
  502", und der Bericht meldete „keine Fehler"

> Jetzt landet jede Antwort ab Status 500 im Protokoll, mit Weg und dem
> **Anfang der Antwort**. Genau daran hängt die Frage, die zählt: Kommt der
> Fehler aus der App, steht dort ihr JSON mit `detail`; kommt er von etwas
> davor – Zwischenserver, Tunnel, Zugangsschutz –, steht dort dessen
> HTML-Seite. Ohne diesen Unterschied sucht man an der falschen Stelle.
>
> Ein 404 („kennt BrickLink nicht") und ein 400 („Eingabe nicht gültig")
> bleiben draußen: gewöhnlicher Betrieb, der das Protokoll nur zumüllt.

## 2.12.0 – August 2026

### Behoben
- 💶 **Bedruckte Teile bekamen keine Preise.** Rebrickable nennt den
  Gungan-Schild `2586pr0028`, BrickLink nennt ihn `2586ps1`; beim
  Karbonitblock stehen `87561pr0001` und `87561pb01` nebeneinander. Fürs
  Thema wurde diese Übersetzung längst gemacht, beim Preis nicht – dort ging
  die Rebrickable-Nummer unverändert an BrickLink und kam als „kennt die
  Nummer nicht" zurück. Jetzt wird bei einem Teil die BrickLink-Nummer
  nachgeschlagen und der Preis noch einmal darunter geholt

> Gefragt wird erst, wenn die eigene Nummer nichts ergeben hat, und die
> Antwort bleibt gespeichert – auch eine leere, sonst ginge dieselbe
> vergebliche Frage bei jedem Aufklappen erneut nach draußen. Stammt der
> Preis von der Zweitnummer, steht sie im Popup dabei: Sonst sucht man ihn
> auf BrickLink unter der eigenen Nummer vergebens.

- ✍️ **Der Hinweis dazu stimmte nicht.** Er schob es pauschal auf eine
  Rebrickable-Figurennummer und riet zu „BrickLink-Nr. setzen" – ein Feld,
  das die Oberfläche bei einem Teil gar nicht anbietet. Bei einem Teil steht
  dort jetzt, was wirklich los ist
- ⬆️ **Die Liste sprang beim Auffrischen an den Anfang.** Sie baut sich
  blockweise auf, und ein Neuaufbau fängt wieder bei den ersten 60 Karten an
  – die Seite wird kurz sehr kurz, und der Browser setzt das Fenster nach
  oben. Wer bei Nummer 300 stand, sah danach den Anfang. Jetzt werden Platz
  und Kartenzahl gemerkt und danach wieder eingenommen

> Ausgelöst wurde das nicht nur, wenn jemand etwas anlegt: auch beim bloßen
> Zurückkommen aus einem anderen Fenster und nach jedem Preisabruf, der
> einen Kaufpreis nachträgt – dessen Summe steckt im Fingerabdruck, an dem
> die App Änderungen erkennt.

- 🪟 **Ein offenes Popup wurde vom Auffrischen weggeräumt.** Wer darin gerade
  etwas eintrug, verlor es mitten im Satz. Jetzt wartet das Auffrischen, bis
  das Popup zu ist, und holt es dann nach

## 2.11.0 – August 2026

### Behoben
- 🖼 **Karten holten Bilder in sechsfacher Größe.** Katalogbilder liegen mit
  400 px auf der Instanz, angezeigt werden sie in den Karten mit **72**. Der
  Browser entpackt aber immer die volle Größe – 0,6 MB je Bild, und zwar
  **außerhalb** des JS-Speichers, wo keine Messung hinschaut. Jetzt gibt es
  eine Daumennagel-Fassung mit 160 px; die Großansicht bekommt weiter das
  volle Bild

> **Warum das kein Schönheitsfehler ist.** In einem eingeschickten Verlauf
> standen **839 Bilder** in einer Ansicht, bei 8 MB JS-Speicher. Entpackt
> sind das rund **500 MB**, die in keiner Kurve auftauchen – und wenige
> Sekunden später brach der Tab ab. Mit 160 px bleiben davon 85 MB.
>
> | Ansicht | vorher | nachher |
> |---|---|---|
> | 130 Bilder | 79 MB | 13 MB |
> | 839 Bilder | 512 MB | 85 MB |
>
> Erzeugt wird die kleine Fassung einmal und liegt dann neben dem Original.
> Freie Größen bedient der Server nicht – sonst könnte man ihn mit 500
> Anfragen 500 Dateien schreiben lassen.

## 2.10.1 – August 2026

### Behoben
- 🔁 **Jeder Ansichtswechsel lud die Ansicht ein zweites Mal.** Der neue
  Änderungs-Fühler verglich mit `letzterStand && letzterStand[name]` – das
  ergibt **`null`**, wenn noch nichts gemerkt ist, und `null !== undefined`
  ist wahr. Damit galt der erste Blick nach jedem Wechsel als Änderung, und
  die gerade frisch geladene Ansicht lud sofort erneut. Bei einer Sammlung
  mit hundert Bildern ist das kein Schönheitsfehler

> Im eingeschickten Verlauf war es gut zu sehen: `10:45:35 Ansicht: lists`,
> zwei Sekunden später „lade neu"; `10:45:48 Ansicht: collection`, fünf
> Sekunden später wieder. Jetzt: drei Wechsel, kein einziger Ladevorgang –
> und eine echte Änderung von außen kommt weiterhin an.

## 2.10.0 – August 2026

### Neu
- 📡 **Die Ansicht hält sich von selbst aktuell – ohne Fensterwechsel.**
  2.9.0 frischte beim Zurückkommen auf; wer die App aber **neben** einem
  anderen Fenster liegen hat, will gar nicht erst wechseln müssen. Jetzt
  fragt Brickfolio alle fünf Sekunden nach einem **Fingerabdruck** der Daten
  – eine Handvoll Zahlen, kein Datenbestand – und lädt die offene Ansicht
  nur dann neu, wenn er sich geändert hat

> **Gemessen:** Einkaufsliste offen und aufgeklappt, von außen eine vierte
> Figur dazugelegt, den Browser **nicht angefasst** – acht Sekunden später
> stand sie da. Die Liste blieb dabei offen, und es wurde genau **einmal**
> geladen.
>
> Der Fingerabdruck zählt nicht nur Zeilen: Menge, Haken und Preis gehen
> mit ein, sonst fiele das Ändern einer bestehenden Zeile nicht auf. Ein Tab
> im Hintergrund fragt gar nicht, und der Scannen-Tab wird nie aufgefrischt.

## 2.9.0 – August 2026

### Neu
- 🔄 **Die Ansicht frischt sich auf, wenn ihr zum Tab zurückkommt.** Bisher
  wurde beim Zurückkehren nur das Tausch-Netzwerk abgefragt – Sammlung,
  Listen und Statistik blieben auf dem Stand von vorhin. Das fällt auf,
  sobald **mehr als ein Weg** in die Daten führt: ein Familienmitglied am
  Handy, ein zweiter Tab, oder ein Werkzeug an der Schnittstelle. Man sah
  dann eine Liste, die es so nicht mehr gab

> **Zwei Einschränkungen mit Absicht:** Der **Scannen-Tab** bleibt
> unberührt – dort steht womöglich ein Foto samt Treffern, und das darf ein
> Fensterwechsel nicht wegräumen. Und wer nur kurz hin- und herklickt, löst
> nichts aus; erst ab vier Sekunden Abwesenheit wird geladen.
>
> Gemessen: Liste mit 1 Artikel offen, von außen ein zweiter dazu, Fenster
> gewechselt – danach **2 Artikel, Einkauf 13,00 €**. Und bei 0,3 Sekunden
> Wegklicken: kein einziger Ladevorgang.

## 2.8.4 – August 2026

### Behoben
- 🖼 **Zwei Bilder im README wurden gar nicht angezeigt.** Die
  Alternativtexte enthielten typografische Anführungszeichen („…"), womit
  GitHub die `<img>`-Auszeichnung nicht mehr las – statt der Bilder stand
  dort der nackte Quelltext. Die Alternativtexte sind jetzt schlicht

### Geändert
- 📸 **Kein fremdes Bildmaterial mehr in den Abzügen.** Die neuen
  Bildschirmabzüge zeigten Katalogbilder von BrickLink. Die vorhandenen
  Abzüge kommen seit jeher ohne aus – sie zeigen den Platzhalter der App.
  Neu erzeugt, jetzt genauso; die Fotos in der Galerie sind selbst erzeugte
  Beispielbilder

## 2.8.3 – August 2026

### Neu
- 🐢 **Der Speicher-Verlauf sagt jetzt, ob der schonende Bildmodus lief.**
  Jede Messzeile trägt bei eingeschaltetem Modus ein `🐢 schonend`. Ohne
  diese Angabe ließe sich hinterher nicht sagen, welcher der beiden Wege in
  einer Sitzung aktiv war – und der Vergleich, wofür der Modus gebaut wurde,
  wäre wertlos

## 2.8.2 – August 2026

### Behoben
- 🔢 **„1 Bilder, 24 KB".** In der Sicherungskarte stand die Mehrzahl auch bei
  einem einzigen Bild. Beim Erstellen der neuen README-Bilder aufgefallen –
  wer Abzüge macht, liest die Oberfläche eben zum ersten Mal wieder genau

### Dokumentation
- 📸 **Neue Bildschirmabzüge im README**: Scan-Treffer mit dem Kästchen fürs
  eigene Foto und dem Knopf „Nur Foto dazu", die Galerie mit Katalogbild und
  eigenem Foto nebeneinander, sowie die Sicherung mit „Eigene Bilder
  mitsichern". Der alte Scan-Abzug zeigte den Stand von Mitte Juli
- 📖 Die Funktionsliste nennt die eigenen Fotos und die Bilder in der Sicherung

## 2.8.1 – August 2026

### Aufgeräumt
- 🧹 **Totes Feld `letzteBoxen`** entfernt – wurde nie gelesen und stand
  verwirrend neben `scanBoxen`, das dasselbe hält und tatsächlich benutzt wird
- 🧹 **Vier CSS-Regeln** für den Anzahl-Block, den es seit 2.1.0 nicht mehr
  gibt
- 🏷 **Klasse `eigenbild-wahl` → `wahl-kasten`.** Sie gilt längst für drei
  Kästchen – Scan-Foto, Sicherung, schonender Modus – und der alte Name
  behauptete etwas anderes

### Dokumentation
- 📖 **„Browser aktualisieren" allein reicht nicht.** Das Handbuch legte das
  nahe; tatsächlich war nach dem Edge-Update die alte Bucket-ID verschwunden
  und sofort eine **neue** da – gleiche Art Fehler, andere Stelle. Steht
  jetzt so drin, samt einer Reihenfolge, was zu tun bleibt

## 2.8.0 – August 2026

### Neu
- 🐢 **Schonender Bildmodus** (*Mehr → Fehlerbericht*, standardmäßig aus).
  Diese App entpackt Fotos, malt sie auf Zeichenflächen, liest Bildpunkte
  aus und kodiert wieder – Arbeit, die der Browser gern auf die
  **Grafikeinheit** schiebt und die kaum eine andere Seite ihm gibt. Der
  Modus geht denselben Weg zu Fuß, im Hauptspeicher: Entpacken über ein
  gewöhnliches Bildelement statt `createImageBitmap`, Zeichenflächen mit
  `willReadFrequently`. Etwas langsamer, sonst gleich

> **Wofür das gut ist:** Bricht der Tab beim Scannen ab, während die
> Speicherkurve flach bleibt, lässt sich damit prüfen, ob es an diesem Weg
> liegt. Gemessen liefern beide Modi dasselbe Ergebnis (3000×2000 → Vorschau
> 1200×800, gleicher Treffer, gleiche Dauer).
>
> Ehrlicherweise: Ein Absturz **ohne jeden Scan** zeigt, dass es nicht nur
> daran liegen kann. Der Modus ist ein Werkzeug zum Eingrenzen, kein Heilmittel.

### Behoben
- ⏳ **`img.decode()` blieb an einem losen Bild hängen.** Beim Bauen des
  schonenden Modus aufgefallen: Ein Bild, das nicht im Dokument hängt, gibt
  das Versprechen unter Umständen nie zurück – der ganze Scan blieb stehen.
  `onload` genügt für das Weiterzeichnen

## 2.7.1 – August 2026

### Behoben
- 🧹 **Das entpackte Foto blieb nach „Foto dazu" liegen.** Um den Ausschnitt
  zu schneiden, entpackt die App das Original in Arbeitsgröße – bis zu
  2400 px, gemessen **16 MB**. Alle anderen Wege gaben es danach wieder frei,
  der neue Foto-Weg aus 2.5.0 als einziger nicht: Es lag bis zum nächsten
  Foto herum. Jetzt geht es acht Sekunden nach dem letzten Gebrauch weg, und
  beim Verlassen des Scan-Tabs sofort

> **Warum das in keiner Kurve zu sehen war:** Eine entpackte Bitmap liegt
> **außerhalb** des JS-Speichers. Der Verlauf unter *Mehr → Fehlerbericht*
> zeigte weiter flache 6 MB – im Browser lagen die 16 MB trotzdem. Genau
> solche unsichtbaren Brocken sind es, die einen Tab umbringen, während die
> Kurve nichts anzeigt.
>
> Ein Test wacht darüber, dass **jede** Stelle, die einen Ausschnitt
> schneidet, das Arbeitsbild auch wieder loslässt.

## 2.7.0 – August 2026

### Neu
- 📷 **„Nur Foto dazu" auf der Trefferkarte.** Steht die Figur längst in der
  Sammlung und man will bloß ein Bild davon hinterlegen, genügt jetzt ein
  Tipp. Der Knopf hängt das Foto an den Artikel und rührt sonst nichts an –
  keine zweite Zeile, keine erhöhte Menge, kein Listeneintrag

> Er wirkt **unabhängig vom Kästchen** oben: Das gilt fürs Anlegen, hier ist
> das Foto der ganze Zweck. Bei mehreren erkannten Figuren nimmt auch dieser
> Weg den Ausschnitt, in dem die jeweilige gefunden wurde.

## 2.6.1 – August 2026

### Behoben
- 🪟 **„Mein Foto entfernen?" ging hinter der Großansicht auf.** Die Rückfrage
  lag auf Ebene 80, die Großansicht auf 100 – man sah die Frage nur
  abgedunkelt durchschimmern und die Aktion schien zu hängen. Rückfragen
  liegen jetzt über allem außer dem Toast

> Ein Test hält die Reihenfolge fest: Rückfrage über Großansicht, Toast über
> allem. Sonst rutscht das beim nächsten Umbau wieder durcheinander.

## 2.6.0 – August 2026

### Geändert
- 📷 **Das eigene Foto kommt jetzt *neben* das Katalogbild, nicht an seine
  Stelle.** In 2.5.0 hat es das Katalogbild ersetzt – das war nicht gemeint.
  Gedacht ist es wie die Bilder, die Käufer bei BrickLink beisteuern: Das
  Katalogbild bleibt das erste, was man sieht, das eigene Foto kommt daneben

### Neu
- 🖼 **Galerie mit den eigenen Fotos.** Tippt auf das Bild eines Artikels und
  blättert: Erst das Katalogbild, dann eure Fotos. Bei einem eigenen steht
  oben **„mein Foto"**, und unten erscheint **🗑 Mein Foto entfernen**
- 💾 **Eigene Bilder gehen in die Sicherung mit.** Sie sind Dateien, keine
  Datenbankzeilen – bisher trug die Sicherung nur den Verweis, und nach einem
  Umzug zeigten die Artikel ins Leere. Jetzt steht in der Sicherungs-Karte
  ein Kästchen mit Anzahl und Größe; die Bilder wandern als Teil derselben
  JSON-Datei mit und werden beim Einspielen unter ihren alten Namen wieder
  angelegt. Gilt auch für die Sicherung beim allerersten Start

> **Die Fotos hängen am Artikel, nicht an der Sammlungszeile.** Wer dieselbe
> Figur zweimal hat – einmal neu, einmal gebraucht –, sieht bei beiden
> dieselben Fotos. Es ist ja dieselbe Figur.
>
> Ab etwa 150 MB Bildern verweigert die App das Mitsichern und sagt es auch;
> dann gehört `data/uploads/` ins normale Backup.

## 2.5.0 – August 2026

### Neu
- 📷 **Das eigene Scan-Foto als Bild des Artikels.** Über den Treffern steht
  ein Kästchen: **„Mein Foto statt des Katalogbilds"**. Ist es angehakt,
  bekommt alles, was aus diesem Scan angelegt wird – Sammlung, Wunschliste
  **und** Einkaufsliste – das eigene Bild
- 🧩 **Bei mehreren Figuren jeweils der eigene Ausschnitt.** Nicht einmal das
  ganze Regalfoto für alle, sondern genau der Rahmen, in dem die Figur
  gefunden wurde – gleich, ob er aus der Reihum-Suche stammt, von einem
  gemerkten Rahmen oder von einem selbst gezogenen

> **Standardmäßig aus**, denn ein Katalogbild ist meist das sauberere; die
> Entscheidung merkt sich die App auf dem Gerät. Hochgeladen wird erst beim
> Anlegen – wer nur schaut oder abbricht, lädt nichts hoch.

### Dokumentation
- ⚠️ **Was die Sicherung nicht enthält.** Eigene Bilder sind Dateien in
  `data/uploads/`, keine Datenbankeinträge. Die JSON-Sicherung trägt den
  **Verweis** darauf, nicht die Datei. Beim Umzug gehört `data/uploads/`
  also mit kopiert – das galt immer schon für eigene Figuren, stand aber
  nirgends. Jetzt steht es in beiden Handbüchern

## 2.4.4 – August 2026

### Behoben
- 📋 **Kopieren scheiterte trotz Rückfallweg.** Die Reihenfolge war falsch
  herum. `navigator.clipboard.writeText` liefert ein Versprechen – wer darauf
  wartet, gibt die **Benutzergeste** des Klicks aus der Hand, und genau die
  verlangt der Rückfallweg `execCommand`. Schlug die moderne Schnittstelle
  fehl, kam der Rückfall zu spät: Er half nur, wenn er gar nicht nötig war.
  Jetzt läuft erst der **synchrone** Weg, das Versprechen danach

### Neu
- 🆘 **Und wenn beides nichts wird, ist der Text trotzdem da.** Statt einer
  Absage legt die App ihn in einem Fenster **fertig markiert** hin –
  Strg/Cmd+C genügt
- 🔍 **Die Absage nennt jetzt den Grund.** In Klammern hinter der Meldung, und
  zusätzlich im Verlauf unter *Speicher-Verlauf*. „Geht nicht" allein war als
  Auskunft wertlos

## 2.4.3 – August 2026

### Geändert
- 🧩 **„Script error." sieht nicht mehr nach einem Defekt aus.** Der Eintrag
  stand ohne Datei und Zeile zwischen echten Fehlern. Er kommt aber gar nicht
  aus der App: Fehler aus **fremden Skripten** kürzt der Browser aus
  Sicherheitsgründen auf genau diesen Satz zusammen – in Frage kommen
  Erweiterungen, Inhaltsblocker und was der Browser selbst einspritzt. Solche
  Einträge sind jetzt als **🧩 Kein Fehler der App** beschriftet, auch die
  schon gespeicherten
- 🔎 **Und sie tragen jetzt etwas bei.** Wo der Browser Datei und Zeile
  verschweigt, hängt die App die **letzten Schritte vor dem Fehler** an. Damit
  lässt sich wenigstens sehen, wobei es passiert

> Die Aussage steht auf einem prüfbaren Fundament: Die Seite lädt zwei eigene
> Skripte und bindet keine Rahmen ein. Ein Test wacht darüber – käme je ein
> fremdes Skript dazu, wäre die Beschriftung eine Lüge und der Test rot.

## 2.4.2 – August 2026

### Behoben
- 🙈 **Benutzernamen auf dem Anmeldebogen.** Nach dem Einspielen einer
  Sicherung (2.4.0) stand dort „Jetzt anmelden als: anna, bruno" – gedacht
  als Hilfe, tatsächlich aber eine Liste aller Admin-Namen auf einer Seite,
  an der noch niemand angemeldet ist. Der Hinweis nennt jetzt keine Namen
  mehr, und auch das Namensfeld bleibt leer

> Der Endpunkt gibt die Namen gar nicht erst heraus – nicht nur die Anzeige
> ist weg, sondern die Quelle. Wer die Sicherung eingespielt hat, kennt seine
> Zugangsdaten ohnehin.

## 2.4.1 – August 2026

### Neu
- 🔢 **Version steht auf dem Startbildschirm.** Klein und grau unter der
  Anmeldekarte („Brickfolio 2.4.1"). Wer mehrere Instanzen betreibt, sieht
  jetzt ohne Anmeldung, welche er gerade vor sich hat – und wer einen Fehler
  meldet, muss die Version nicht erst suchen

> Verraten wird damit nichts Neues: Die Version stand auf dieser Seite
> ohnehin schon, nur unsichtbar – an den Versionsmarken der Dateien
> (`style.css?v=…`), die jeder Seitenquelltext zeigt.

## 2.4.0 – August 2026

### Neu
- 📥 **Sicherung gleich beim ersten Start einspielen.** Wer umzieht, hatte
  bisher einen unnötigen Umweg: erst ein Admin-Konto anlegen, das die
  Sicherung gleich darauf wieder überschreibt. Jetzt steht im Willkommens-
  Bogen unter dem Anlegen-Knopf **„📥 Sicherung einspielen"** – der ganze
  alte Stand kommt herüber, samt Konten. Danach meldet man sich mit den
  **bisherigen Zugangsdaten** an

> **Ohne Anmeldung – ist das in Ordnung?** Ja, denn es geht nur, solange die
> Instanz **leer** ist. Wer sie in diesem Zustand erreicht, könnte ohnehin
> das erste Admin-Konto anlegen und wäre damit Herr über alles; der Weg gibt
> also nichts preis, was nicht schon offenstünde. Sobald ein Benutzer
> existiert, antwortet er nur noch mit einer Absage.

## 2.3.1 – August 2026

### Behoben
- 👥 **Fehler 500 beim Entfernen eines Benutzers.** Freigeräumt wurde nur die
  Sammlung. Auf den Benutzer zeigen aber noch vier weitere Stellen – Wünsche,
  angelegte Listen, abgehakte Listeneinträge und die Push-Anmeldung –, und die
  Datenbank ließ das Löschen deshalb nicht zu. Wer also irgendetwas davon
  hinterlassen hatte, war nicht zu entfernen

> **Was jetzt mit seinen Sachen passiert:** Sammlung, Wünsche, Listen und
> Haken bleiben – sie gehören der Instanz, nicht der Person; nur der Name
> dahinter verschwindet. Mit gelöscht wird allein die Push-Anmeldung, damit
> sein Gerät keine Meldungen dieser Instanz mehr bekommt.

## 2.3.0 – August 2026

### Behoben
- 📋 **„Kopieren nicht möglich" im Heimnetz.** Die Knöpfe zum Kopieren –
  Fehlerbericht, Wiederherstellungscode, Cloudflare-Befehl, Diagnose – gingen
  nur über `https://` oder `localhost`. Ruft man die App über die IP-Adresse
  im Heimnetz auf, ist das kein *sicherer Kontext*, und der Browser rückt die
  Zwischenablage nicht heraus. Jetzt gibt es einen Rückfallweg über ein
  unsichtbares Textfeld, der auch dort kopiert

> Der Rückfallweg braucht einen echten Klick – das ist der Grund, warum er
> nicht überall greifen kann, sondern nur an den Kopier-Knöpfen selbst.
> Geprüft mit ausgeblendeter Zwischenablage: echter Klick, echter Text.

### Geändert
- 🔤 **Gleicher Name überall.** Fenstertitel und der Name der installierten
  App schrieben `Annas Brickfolio`, die Überschrift in der App dagegen
  `Anna's Brickfolio`. Jetzt steht überall dasselbe

## 2.2.0 – August 2026

### Behoben
- 📱 **Derselbe feste Name auf jedem Handy.** Legte man die App auf den
  Startbildschirm, stand dort der fest eingebaute Name – auch auf einer
  Instanz, die längst anders heißt. Manifest, Fenstertitel und der Name für
  iOS kommen jetzt aus dem **Anzeigenamen** unter *Mehr → Anzeigename*
- 🖼 **Und der feste Name stand im Symbol.** Das App-Symbol wird jetzt erzeugt: die
  bekannte Zeichnung, darüber der Anzeigename der Instanz. Die Schriftgröße
  richtet sich nach der Länge, damit auch längere Namen hineinpassen

> Gebraucht wird dafür keine mitgelieferte Schriftdatei – Pillow bringt eine
> skalierbare Standardschrift mit, die auch im schlanken Docker-Abbild
> vorhanden ist. Erzeugt wird je Name und Größe einmal, danach kommt das
> Symbol aus dem Zwischenspeicher.

## 2.1.1 – August 2026

### Behoben
- 🧭 **„Reihum-Suche fertig (–)" statt der Zahl.** Endete die Suche endgültig,
  war der Suchstand beim Schreiben der Protokollzeile schon freigegeben – im
  Verlauf stand dann ein Strich statt der Zahl der gefundenen Figuren. Jetzt
  steht dort, was wirklich gefunden wurde

> **Was der Verlauf vom 2.8. sonst zeigt:** Die Wiederherstellung aus 2.0.0
> hat gegriffen – nach dem Absturz um 00:16:19 setzte die App bei „Listen"
> wieder auf, also genau dort, wo die Sitzung aufgehört hatte. Und das
> Weitersuchen aus 2.1.0 lief: 10 Figuren, dann eine elfte.

## 2.1.0 – August 2026

### Neu
- 🔎 **Weitersuchen statt Wand.** Die Reihum-Suche hört nach 10 Figuren auf –
  das ist keine technische Grenze, sondern Rücksicht auf einen kostenlos
  bereitgestellten Dienst. Sind noch Figuren da, erscheint jetzt
  **🔎 Weitersuchen**: Die App macht dort weiter, wo sie aufgehört hat, und
  die neuen Funde kommen zu den bisherigen dazu
- 🧠 **Der Suchstand bleibt liegen**, solange weitergesucht werden kann – und
  wird freigegeben, sobald die Suche zu Ende ist oder ein neues Foto kommt.
  So kostet das Weitersuchen keine zweite Runde durch das ganze Bild

> **Gemessen an einem Bild mit 14 Figuren:** erster Durchgang 10, dann
> „Weitersuchen" → insgesamt 13 (die vierzehnte Anfrage ging an den
> Einzelscan beim Fotografieren). Rahmen und Karten stimmen nach beiden
> Durchgängen überein, der Knopf verschwindet, sobald nichts mehr kommt.

## 2.0.0 – August 2026

### Neu
- 💾 **Ein Abbruch kostet nichts mehr.** Verhindern lässt sich der
  Edge-Absturz nicht (siehe 1.99.0) – aber die App kommt jetzt zurück: Sie
  merkt sich die **offene Ansicht** und die **angefangene Eingabe** im
  Formular „Manuell erfassen". Nach einem Abbruch steht beides wieder da
- 🎯 **Nur nach einem Abbruch.** Bei einem normalen Start öffnet die App wie
  immer den Scan-Tab – niemand will nach dem Öffnen in den Einstellungen
  landen, nur weil er dort zuletzt etwas nachgesehen hat. Unterschieden wird
  am Abschiedszettel, der beim gewollten Ende geschrieben wird und beim
  Abwürgen eben nicht

> **Was nicht gerettet wird:** ein ausgewähltes Foto. Das ließe sich nur mit
> erheblichem Aufwand ablegen, und der Schaden ist gering – neu fotografieren
> dauert Sekunden. Ein halb ausgefülltes Formular mit Preis und Notiz ist das,
> was wirklich wehtut.

## 1.99.0 – August 2026

### Neu
- 🔎 **Der Absturz ist gefunden – und er liegt nicht in der App.** Die
  Absturzliste von Edge zeigt 17 Abstürze über vier Tage, **alle unter
  derselben Bucket-ID** und an derselben Stelle im Programm: `P6 = renderer`
  (der Tab selbst), `P3 = Microsoft_Edge_Framework` (Edges eigener Code),
  `P7 = 0x6` (auf macOS SIGABRT). Drei davon treffen sekundengenau die
  „OHNE ABSCHIED"-Einträge unseres Speicher-Verlaufs – die übrigen vierzehn
  hat die App nie gesehen, weil sie gar nicht offen war
- 💡 **Der Weg dorthin steht jetzt in der App.** Beim Speicher-Verlauf hängt
  ein Hinweis: Bleibt die Kurve flach und der Tab stirbt trotzdem, steht der
  echte Grund in `edge://crashes` – und gleiche Bucket-ID heißt gleicher
  Fehler des Browsers

> **Was das für die Diagnose bedeutet.** Sieben Versionen lang habe ich in der
> App gesucht: Hintergrundbilder, Glasflächen im Nova-Design, entpackte Fotos,
> die Sammlungsansicht. Jede These war messbar falsch, weil der Tab immer bei
> 6 bis 8 Megabyte starb – zuletzt im **Vordergrund**, auf einem Mac mit
> 16 GB. Die Zahlen haben die App früh entlastet; was fehlte, war der Blick in
> die Absturzliste des Browsers. Der steht jetzt dort, wo man ihn sucht.

## 1.98.0 – August 2026

### Behoben
- 🧭 **Die Reihum-Suche stand nicht in der Spur.** Sie kam in 1.97.0 dazu,
  schrieb aber nichts mit – und ausgerechnet in die 46 Sekunden davor fiel ein
  Absturz. Jetzt steht jede Runde einzeln drin: Start, jede gefundene Figur
  mit Nummer und Sicherheit, Ende
- 🧹 **Halber Speicherbedarf beim Suchen.** Bitmap und Zeichenfläche hielten
  dieselbe Bildfläche doppelt, bis die Schleife fertig war. Die Bitmap wird
  jetzt sofort nach dem ersten Zeichnen freigegeben; die Zeichenfläche wird
  auch bei einem Fehler zuverlässig geleert
- 🔁 **Abbruch bei doppeltem Fund.** Liefert der Dienst zweimal denselben
  Bereich, hört die Suche auf, statt bis zum Anschlag weiterzufragen

> **Gemessen:** fünf vollständige Durchläufe hintereinander, JS-Speicher
> 2,4 → 2,9 MB. Ein halbes Megabyte auf fünf Läufe ist kein Leck, das einen
> Tab umbringt – der Verdacht gegen den neuen Ablauf ist damit **nicht**
> bestätigt, aber auch nicht widerlegt. Dafür sagt es beim nächsten Mal die
> Spur.

## 1.97.0 – August 2026

### Neu
- 🔎 **Die App sucht die Figuren nicht mehr selbst – der Erkennungsdienst
  sucht.** Jede Antwort von Brickognize bringt einen Rahmen mit; er sagt also
  immer mit, *wo* er hingeschaut hat. „Alle Figuren erkennen" nutzt das jetzt
  reihum: erkennen, den gefundenen Bereich in **Hintergrundfarbe** ausblenden,
  erneut fragen – bis nichts mehr kommt
- 🎯 **Kommt mit Anordnungen zurecht, an denen alles bisherige scheiterte:**
  Figuren, die sich **berühren**, **mehrere Reihen**, kreuz und quer Liegendes.
  Gemessen an vier Klonkriegern dicht nebeneinander: **4 von 4 Figuren, 72–91 %
  sicher, in 1,2 Sekunden** – das alte Verfahren fand an derselben Aufnahme
  **gar nichts**
- 🧹 **206 Zeilen weniger.** Spaltenanalyse, Kantenberechnung, Talsuche, der
  Regler für die Streifenzahl und die Reihen-Warnung aus 1.93.0 sind
  ersatzlos entfallen – es gibt nichts mehr einzustellen und nichts mehr zu
  warnen

> **Warum es vorher nicht ging.** Das alte Verfahren maß die Struktur je
> Bildspalte und schnitt in den Lücken. Bei Figuren, die sich berühren, gibt es
> keine Lücke – deshalb kam bei einem Testfoto in **keinem** Streifen etwas an.
> Der Dienst kann dagegen lokalisieren; das war die ganze Zeit da und wurde nur
> einmal statt mehrfach genutzt.

> **Gemessen, nicht vermutet.** Die Maskenfarbe entscheidet: Mit einer fest
> gewählten Farbe blieben nach drei Figuren harte Rechteckkanten stehen, die
> der Dienst für ein Objekt hielt – die vierte fand er nicht mehr. Mit der aus
> den Bildecken gemittelten Hintergrundfarbe: alle vier.

## 1.96.0 – August 2026

### Neu
- 🛡 **Bremse vor dem Erkennungsdienst.** Brickognize stellt seine Erkennung
  kostenlos bereit; jeder Ausschnitt ist eine eigene Anfrage. Der Server lässt
  jetzt **40 Erkennungen je Minute** für die ganze Instanz durch und weist
  darüber hinaus mit einer verständlichen Meldung ab. Die Grenze sitzt
  bewusst im Server – sie gilt damit für alle Benutzer und auch dann, wenn
  jemand an der Oberfläche vorbei anfragt
- 🔢 **Auch von Hand gemerkte Rahmen sind gedeckelt.** Die automatische
  Trennung hörte seit jeher bei 10 auf, die gemerkten Rahmen waren
  unbegrenzt. Jetzt gilt dieselbe Zahl für beide Wege

> **Geprüft und wieder verworfen:** Brickognize hat einen eigenen Endpunkt für
> Minifiguren (`/predict/figs/`). Zweimal gegen `/predict/` gemessen – einmal
> mit einem sauberen Figurenbild, einmal mit einem Ausschnitt samt
> Tischplatte und angeschnittenen Nachbarfiguren: **beide Male dasselbe
> Ergebnis, 89 % bzw. 90 %.** Kein Gewinn, dafür der Nachteil, dass man dann
> kein Set mehr einrahmen könnte. Bleibt also bei `/predict/`.

## 1.95.0 – August 2026

### Behoben
- 🟩 **Fünf Rahmen, unter denen „nichts erkannt" stand.** Die nummerierten
  Rahmen blieben stehen, egal was die Abfrage ergab – das Bild behauptete
  fünf gefundene Figuren, während darunter „Keine Übereinstimmung gefunden"
  zu lesen war. Jetzt bleiben **nur die Streifen stehen, in denen wirklich
  etwas erkannt wurde**; ergab keiner etwas, verschwinden alle und es steht
  dran, dass sich dieses Bild so nicht zerlegen lässt
- 🏷 **„Geteilt in: 5 Streifen" statt „Gefunden: 5 Figuren".** Vor der
  Abfrage weiß die App nur, wo sie geschnitten hat – nicht, was dort steht.
  Die Beschriftung sagt das jetzt

> **Warum die Warnung aus 1.93.0 hier nicht kam:** Sie misst die Figur, die
> der Erkennungsdienst beim ersten Scan gefunden hat, an der Bildhöhe. Findet
> er **gar nichts**, gibt es nichts zu messen. Für diesen Fall greift jetzt
> das Ergebnis selbst: Keine Treffer, keine Rahmen.

## 1.94.0 – August 2026

### Behoben
- 🔢 **Die geklärte BrickLink-Nummer galt nur halb.** Seit 1.92.0 fragt die
  App bei Rebrickable nach der BrickLink-Entsprechung (`2586pr0028` →
  `2586ps1`) – benutzt hat sie sie aber nur für die Zweitnummer. Die
  **Kategorie** wurde weiter mit der Nummer abgefragt, die BrickLink gar nicht
  kennt, und lief deshalb ins Leere. Jetzt wird die Nummer **einmal** geklärt
  und für beide Wege verwendet
- 🗂️ **Damit greift auch der Katalogpfad.** Teile ohne Zweitnummer bekommen
  ihre Kategorie als Thema: Aus *Catalog: Parts: Minifigure, Shield* wird
  **„Minifigure, Shield"** statt „Ohne Thema"
- ⚡ Die Kategorie-ID kommt jetzt mit dem Katalogeintrag mit – eine Abfrage
  weniger je Teil

> **Was das für die beiden Teile heißt.** Der Karbonitblock hat eine
> Zweitnummer (`sw0978`) und landet unter **Star Wars**. Der Gungan-Schild
> steht bei BrickLink ohne Zweitnummer, dort bleibt nur der Pfad: **Minifigure,
> Shield**. Das ist eine Form und kein Thema – wem das nicht passt, setzt auf
> der Karte von Hand „Star Wars".

## 1.93.0 – August 2026

### Behoben
- 🚫 **Vier Rahmen, die nichts bedeuteten.** Bei einem Regalfoto mit mehreren
  Reihen schnitt „🔎 Alle Figuren erkennen" das Bild in senkrechte Streifen –
  in jedem standen dann fünf Figuren übereinander. Angezeigt wurden vier
  nummerierte Rahmen, als wären es vier Figuren. Das ist schlimmer als kein
  Ergebnis
- ❓ **Jetzt fragt die App vorher.** Füllt die Figur, die der Erkennungsdienst
  beim ersten Scan gefunden hat, **weniger als ein Drittel der Bildhöhe**,
  steckt mehr als eine Reihe im Bild. Dann kommt ein Hinweis samt dem Weg
  über gemerkte Rahmen – „Trotzdem versuchen" bleibt möglich

> **Woher die App das weiß, ohne zu raten:** Der Erkennungsdienst liefert
> beim ersten Scan seinen eigenen Rahmen mit („hier geschaut"). Wie groß der
> im Verhältnis zum Bild ist, ist eine gemessene Zahl – keine Schätzung. Bei
> einem einreihigen Foto füllt die Figur 60 bis 90 % der Höhe, beim Regalfoto
> 15 %.

## 1.92.0 – August 2026

### Neu
- 🗂️ **Teile bekommen ihr Thema doch – über die Zweitnummer.** BrickLink
  führt Teile nach Form („Minifigure, Utensil, Decorated"), aber bedruckte
  Teile tragen im Katalog die Nummer der Figur, zu der sie gehören: Beim
  Karbonitblock mit Han Solo steht **`sw0978`** daneben – und `sw…` heißt
  Star Wars. „🔄 Themen nachladen" liest das jetzt aus
- 🔁 **Zwei Kataloge, zwei Nummern.** Rebrickable nennt dasselbe Teil
  `87561pr0001`, BrickLink `87561pb01`. Führt die eigene Nummer zu nichts,
  wird die Entsprechung bei Rebrickable erfragt und der Abruf wiederholt
- ✅ Ein echtes Thema hat Vorrang vor der Formkategorie

> **Korrektur zu 1.90.0.** Dort stand, für Teile ließe sich grundsätzlich
> nichts abrufen. Das stimmte nicht: Die *Kategorie* eines Teils sagt nichts
> über das Thema – die *Zweitnummer* sehr wohl. Der Hinweis bei „Ohne Thema"
> ist entsprechend richtiggestellt.

## 1.91.0 – August 2026

### Behoben
- 🔍 **Ausschnitte kamen aus der Vorschau statt aus dem Foto.** Zugeschnitten
  wurde bisher aus der auf 1200 Pixel verkleinerten Fassung – bei vielen
  Figuren im Bild blieb einer einzelnen damit kaum mehr als ein Daumennagel,
  und genau der ging zur Erkennung. Jetzt wird aus einer **Arbeitskopie mit
  2400 Pixeln** geschnitten: gemessen an einem 12-MP-Foto **238×334 statt
  120×168 Pixel – die vierfache Fläche**
- 💬 **Ein Hinweis statt Rätselraten.** Bleibt ein einzelner Treffer unter
  60 %, steht jetzt darüber, woran es liegt: Die Erkennung sucht **ein**
  Objekt je Anfrage – bei vielen Figuren im Bild hilft ein Rahmen oder ein
  Foto aus der Nähe

> **Warum nicht direkt aus dem Original geschnitten wird.** Gemessen: Ein
> Ausschnitt per Quellrechteck aus der 12-MP-Datei kostet rund 50 ms – **je
> Ausschnitt**, weil dabei jedes Mal das ganze Bild entpackt wird. Bei vierzig
> Figuren wären das vierzig volle Entpackvorgänge; daran ist der Tab schon
> gestorben. Einmal auf 2400 entpacken kostet dieselben ~300 ms **insgesamt**
> und hält rund 17 MB, deren Lebensdauer bekannt ist.

## 1.90.0 – August 2026

### Neu
- 🗂️ **Thema von Hand setzen.** Auf jeder Karte steht jetzt ein Feld
  **Thema** – mit Vorschlagsliste aus den Themen, die in der Sammlung schon
  vorkommen, damit nicht „Star wars" neben „Star Wars" entsteht. Leeren setzt
  den Eintrag zurück auf „Ohne Thema"
- 🔒 Ein von Hand gesetztes Thema **bleibt stehen**: Die Automatik rührt ein
  vorhandenes nie an

> **Warum das nötig ist.** Für **Teile** kann die Automatik grundsätzlich
> nichts liefern: BrickLink führt sie nach **Form** („Brick, Modified"), nicht
> nach Thema – da ist nichts abzurufen, was hier stehen könnte. Bei Minifiguren
> steckt das Thema in der Nummer (`sw…`), bei Sets in der Kategorie; bei Teilen
> gibt es diesen Weg nicht. „🔄 Themen nachladen" hilft dort also nie, und
> genau das steht jetzt auch bei der Gruppe „Ohne Thema".

## 1.89.0 – August 2026

### Neu
- 📱 **Welches Gerät?** Der Verlauf hält beim Sitzungsbeginn fest, worauf die
  App läuft: System, Browser, **als App oder im Browser**, Arbeitsspeicher des
  Geräts und Bildschirmgröße. Nach vier Abstürzen stand das in den Daten
  bisher nirgends
- ⏱ **„Abgestürzt nach … Minuten Laufzeit."** Die Zusammenfassung rechnet aus,
  wie lange eine Sitzung lief, bevor sie abbrach. Zweimal dieselbe Dauer wäre
  ein Muster und kein Zufall
- 🔄 **Der Update-Vorgang steht jetzt in der Spur**: nach Update gesucht,
  Update angefordert, Update-Sperre sichtbar, Server nicht erreichbar, Server
  wieder da, Server neu gestartet

> **Warum genau das.** Die beiden Abstürze vom 1.8. um 16:41 und 16:51 fielen
> beide in den Update-Vorgang – und die Sitzungen liefen **8:27** bzw. **9:14**
> Minuten, bevor der Tab starb. Der zweite lag außerdem **nicht** in der
> Scan-Ansicht, womit meine Vermutung von vorhin („beide beim Fotografieren")
> widerlegt ist. Beide Male: 7 MB von 4096 MB Grenze.

## 1.88.0 – August 2026

### Neu
- 🧭 **Eine Spur neben dem Speicher-Verlauf.** Zwischen zwei Messwerten
  liegen 30 Sekunden – ein Absturz wartet darauf nicht. Deshalb wird jetzt
  **sofort** festgehalten, was passiert: Foto aufgenommen (mit
  **Megapixeln und Dateigröße**), verkleinert auf …, Erkennung läuft/fertig,
  Ansicht gewechselt, **in den Hintergrund / wieder da**
- 📋 Die Spur steht unter der Kurve und geht beim Kopieren mit

> **Warum das nötig war.** Der Verlauf vom 1.8. zeigt zwei Stunden zwischen
> 5 und 9 MB, ohne jedes Wachstum – und trotzdem starb der Tab um 16:41 bei
> **7 MB und 981 Elementen**. Damit ist der JavaScript-Speicher als Ursache
> erledigt. Beide bisher auswertbaren Abstürze fielen in dieselbe Lage: die
> Scan-Ansicht bei rund 980 Elementen. Was dort groß ist, steht außerhalb
> jeder Messung – das Foto selbst und die Kamera-App daneben. Ob die Seite in
> dem Moment im Hintergrund war, sagt ab jetzt die Spur.

## 1.87.0 – August 2026

### Behoben
- 🗂️ **„LEGO Ideas &#40;CUUSOO&#41;" statt „LEGO Ideas (CUUSOO)".** BrickLink
  liefert Kategorienamen HTML-maskiert; bei Artikelnamen wurde das längst
  umgewandelt, bei den Themen nicht. Da die Oberfläche beim Anzeigen ein
  zweites Mal maskiert, stand die Maskierung selbst auf dem Bildschirm.
  Betrifft alle Themen mit Klammern oder Sonderzeichen im Namen
- 🔧 **Bestehende Einträge werden beim Start geradegezogen** – auch die schon
  gespeicherte Kategorieliste, ohne neuen Abruf. Nichts nachzuladen, das
  Update genügt

## 1.86.0 – August 2026

### Neu
- 📤 **Gegenstück zum Übernehmen: austragen.** Fragt jemand nach einem
  deiner Artikel und du nimmst an, geht das Stück ja weg. Dafür steht im
  Gespräch jetzt **📤 Aus der Sammlung austragen** – in Rot, damit es nicht
  mit dem grünen Übernehmen zu verwechseln ist
- ❓ **Neu oder gebraucht? Wird gefragt, nicht geraten.** Steht dieselbe
  Nummer zweimal in der Sammlung, fragt das Fenster **„Welches Stück?"**.
  Ohne Antwort passiert nichts – ein geratener Zustand wäre ein verlorenes
  Exemplar
- ⏳ **„noch nicht ausgetragen"** an angenommenen eingehenden Vorgängen,
  passend zum „noch nicht verbucht" der anderen Richtung

Ausgetragen wird ausschließlich nach Bestätigung im App-Fenster: Artikel,
Gegenüber und der Bestand stehen darin, dazu die Anzahl. Bleibt nichts übrig,
verschwindet die Zeile samt Kaufbuch – wie beim Austragen über die Karte.

## 1.85.0 – August 2026

### Behoben
- 🤝 **„Annehmen" tat sichtbar nichts.** Der Vorgang wurde zwar auf
  *angenommen* gesetzt, aber bei einem schon angenommenen Tausch änderte sich
  nichts auf dem Bildschirm – und vor allem: Der Artikel selbst blieb außen
  vor und musste von Hand nachgetragen werden. Jetzt bestätigt eine Meldung
  die Zusage, und es geht direkt das Fenster **Tausch übernehmen** auf

### Neu
- 📥 **Angenommene Tausche verbuchen.** Wohin (Sammlung oder eine
  Einkaufsliste), Anzahl, Zustand, bezahlter Preis – der Eintrag entsteht wie
  ein normaler: gleiche Nummer erhöht die Anzahl, der Preis landet im
  Kaufbuch, in den Notizen steht „Tausch mit …". Der Knopf steht im Gespräch
  unter dem Verlauf, solange der Tausch angenommen ist und der Artikel zu mir
  kommt
- ⏳ **„noch nicht verbucht"** an angenommenen Vorgängen in der Liste – bis
  der Artikel wirklich eingetragen ist. Gebucht wird nur auf Knopfdruck:
  Zwischen Zusage und Karton in der Hand liegen beim Tauschen gern ein paar
  Tage, und der Preis steht oft erst dann fest
- 🏷 **Art, Bild und Zustand reisen mit der Anfrage mit.** Gespeichert waren
  bisher nur Nummer und Name; damit ließ sich ein Tausch nicht sauber
  übernehmen. Ältere Vorgänge raten die Art aus der Nummer (reine Ziffern =
  Set)

## 1.84.0 – Juli 2026

### Behoben
- 📷 **Ein Handyfoto wurde vollständig entpackt, bevor es verkleinert
  wurde.** Bei 12 Megapixeln sind das **46 MB in einem Stück**, bei einem
  50-MP-Handy rund 200 MB – außerhalb des JS-Speichers, wo keine Messung
  etwas sieht. Jetzt wird schon **beim Entpacken** verkleinert: gemessen
  **46 MB → 4 MB, 91 % weniger**
- 🔁 **Jeder Ausschnitt entpackte das Foto neu.** Bei fünf Figuren fünfmal
  gut 20 MB, zeitweise nebeneinander. Jetzt wird einmal entpackt und für
  alle Ausschnitte wiederverwendet – gemessen **1 statt 5**

> **Warum das jetzt kommt.** Der Absturz vom 31.7. um 21:58 trug „OHNE
> ABSCHIED", geschah im **klassischen** Design – die Glasflächen aus 1.77.0
> waren es also nicht – und zwar bei **980 Elementen und 6 Bildern**, während
> fotografiert wurde. Die Seite war winzig, der JS-Speicher bei 6 MB. Was in
> diesem Moment groß ist, ist das entpackte Foto.

## 1.83.0 – Juli 2026

### Neu
- 🖐 **Mehrere Rahmen sammeln.** Die automatische Trennung sucht senkrechte
  Lücken – sie ist für Figuren gemacht, die **nebeneinander** stehen. Liegen
  sie kreuz und quer oder versetzt hintereinander, gibt es keine Lücke, an
  der sich schneiden ließe. Deshalb jetzt: Rahmen ziehen, **➕ Rahmen
  merken**, für jede weitere Figur wiederholen, **🔎 Alle erkennen**. Das
  funktioniert bei jeder Anordnung, weil die Grenzen von Hand kommen

### Behoben
- 🟩 **Zwei grüne Rahmen mit zwei Bedeutungen.** Der Rahmen des
  Erkennungsdienstes stand neben den nummerierten und sah aus wie eine
  weitere Figur. Er trägt jetzt die Beschriftung **„hier geschaut"** und
  verschwindet, sobald nummerierte Rahmen da sind

> **Was ich versucht und wieder verworfen habe.** Eine Trennung in Flächen
> statt Streifen, damit auch kreuz und quer liegende Figuren automatisch
> gefunden werden. In vier Anläufen kippte das Ergebnis jedes Mal: mal fehlten
> Figuren, mal wurde ein Lichtreflex mitgezählt. Jede Stellschraube half
> einem Fall und schadete einem anderen. Statt weiter an Schwellwerten zu
> drehen, bleibt die Automatik bei dem, was sie nachweislich kann – Figuren
> nebeneinander – und für alles andere gibt es den Weg von Hand, der immer
> stimmt.

## 1.82.0 – Juli 2026

### Neu
- ➕ **Die BrickLink-Endung kommt beim Erfassen von selbst dazu.** Wer bei
  einem Set `21306` eintippt – die Zahl von der Packung –, bekommt `21306-1`
  und landet damit sofort in derselben Zeile wie ein gescanntes Exemplar.
  Vorbeugen statt hinterher zusammenführen. Gilt auch für Wunschliste und
  CSV-Import
- 🏷 **Der Katalogname hat Vorrang.** Sind die BrickLink-Schlüssel hinterlegt,
  wird beim Ergänzen der Nummer gleich der offizielle Name übernommen –
  „Yellow Submarine" statt „gelbes U-Boot vom Flohmarkt". Ohne Schlüssel
  bleibt der eingetippte stehen, und eine Erfassung scheitert nie daran,
  dass der Katalog gerade nicht antwortet
- Beim Zusammenführen zweier Zeilen gilt derselbe Grundsatz: Es bleibt die
  BrickLink-Zeile **samt ihres Namens**

> **Angefasst wird nur, was eindeutig ist:** eine reine Zahl bei einem
> **Set**. Figurennummern, Teilenummern, eigene Nummern und alles mit
> vorhandener Endung bleiben unverändert.

## 1.81.0 – Juli 2026

### Neu
- 🔗 **Dieselbe Nummer, zweimal erfasst.** Auf der Packung steht `21306`,
  BrickLink führt dasselbe Set als `21306-1`. Wer eines von Hand einträgt und
  das andere scannt, hatte zwei Zeilen für ein Set – und die Sammlung zählte
  es doppelt. Die App erkennt solche Paare jetzt und fragt auf der Scan-Seite
  nach, mit **zwei** Antworten statt einer:
  - **Ein Exemplar** – derselbe Kasten, zweimal erfasst. Eine Zeile bleibt,
    das Kaufbuch der aufgegebenen fällt weg (sonst stünde der Betrag doppelt
    drin)
  - **Zwei Exemplare** – ihr besitzt wirklich zwei. Stückzahlen werden
    addiert, beide Käufe bleiben im Kaufbuch
- Bleiben darf die Zeile mit der **BrickLink-Nummer** – sie hat Preise,
  Set-Inhalte und passt zum Katalog

> **Wo die App sich heraushält:** Bei zwei echten Varianten wie `21306-1` und
> `21306-2` kommt kein Hinweis. Das sind zwei verschiedene Ausgaben, und
> welche gemeint ist, weiß nur der Mensch davor. Aus demselben Grund führt
> die App auch nichts von allein zusammen.

## 1.80.0 – Juli 2026

### Behoben
- 📷 **Figurentrennung, die auch in der Vitrine funktioniert.** Der erste
  Anlauf (1.79.0) verglich jeden Bildpunkt mit einer aus dem Bildrand
  geschätzten Hintergrundfarbe. Auf weißem Papier geht das – in einer
  Vitrine nicht: Das Glas spiegelt, der Regalboden ist hell, die Rückwand
  blaugrau und die Figuren sind genau so blaugrau. Es gibt keine Farbe, von
  der sie sich abheben
- Jetzt zählt **Struktur statt Farbe**: Wo eine Figur steht, wechseln
  Helligkeiten dicht an dicht – Helm, Arme, Gürtel; die Lücke daneben ist
  ruhig. Geschnitten wird in den Tälern dieser Kantendichte, und zwar dort,
  wo sie **ausgeprägt** sind: Gemessen lagen echte Lücken bei einer
  Ausprägung von 58, Rauschen bei 17 bis 22
- 🔢 **Die Zahl lässt sich nachbessern.** Unter dem Bild steht, wie viele
  Figuren gefunden wurden, mit **−** und **+**. Wer die Zahl ändert, bekommt
  das Bild gleichmäßig geteilt und alles erneut abgefragt – das hilft bei
  Figuren, die sich berühren, wo es keine Lücke zum Schneiden gibt
- ✂️ **Der Ausschnitt geht über die volle Bildhöhe.** Vorher endete er dort,
  wo die Kantendichte nachließ – und das ist bei einer Figur der Helm:
  rund, ruhig, kaum Kanten. Gemessen fehlte er im Ausschnitt

## 1.79.0 – Juli 2026

### Neu
- 🔎 **Alle Figuren auf einem Bild erkennen.** Der Dienst kann nur **ein**
  Objekt je Anfrage – also trennt die App die Figuren jetzt selbst: Sie
  schätzt aus dem Bildrand die Hintergrundfarbe, sucht die abweichenden
  Flecken, fasst Kopf, Körper und Beine einer Figur zusammen und schickt
  jeden Bereich einzeln zur Erkennung. Die Figuren werden nummeriert
  eingerahmt, darunter steht für jede eine eigene Karte
- Ein Foto von vier Figuren statt vier Fotos

> **Bedingung:** einfarbiger Hintergrund und etwas Abstand zwischen den
> Figuren – dieselben Bedingungen, die der Erkennung ohnehin guttun. Findet
> die Trennung nur eine Figur, sagt die App das; dann hilft der Rahmen von
> Hand aus 1.78.0.

## 1.78.0 – Juli 2026

### Neu
- 🔍 **Mehrere Figuren auf einem Bild.** Die Erkennung sucht **ein** Objekt je
  Anfrage – so ist der Dienst gebaut, seine Antwort enthält genau einen
  Rahmen. Bisher hieß das: Bei fünf Figuren auf dem Tisch riet sie über eine
  davon, und niemand sah, über welche.
- Jetzt umrahmt die Vorschau die erkannte Figur **grün**, und für die
  übrigen zieht man einfach einen **eigenen Rahmen** und tippt auf
  **🔍 Diesen Ausschnitt erkennen**. Zugeschnitten wird im Browser, zum
  Server geht nur der Ausschnitt – bei fünf Figuren fünf Rahmen statt fünf
  Fotos

## 1.77.0 – Juli 2026

### Neu
- 🪟 **Eigene Fenster statt Browser-Abfragen.** Sechs Stellen benutzten das
  graue `prompt()` des Browsers – eigene Schrift, eigene Farben, und für
  zwei Angaben zwei Fenster hintereinander. Jetzt fragt ein Fenster im Stil
  der App alles auf einmal: weiterer Kauf, neue Liste, mehr Einladungen,
  Passwort setzen. Mit Enter bestätigen, mit Esc abbrechen

### Verbessert
- 🧊 **Nova: weniger Glasflächen.** „Glas" heißt, dass der Browser den
  Hintergrund in Echtzeit weichzeichnet – jede solche Fläche kostet ihn eine
  eigene Zeichenfläche im Grafikspeicher, und **den sieht keine Messung**.
  Auf den Einstellungen lagen so **19 davon gleichzeitig**, und die Karte im
  Popup zeichnete weich, was die Überlagerung darunter schon weichgezeichnet
  hatte. Mehrfach vorkommende Flächen tragen jetzt eine durchscheinende
  Farbe – kaum zu sehen, aber statt rund zwanzig Zeichenflächen sind es drei
- 🔍 **Das Design steht jetzt im Speicher-Verlauf.** Nur so lässt sich
  überhaupt feststellen, ob Abstürze an Nova hängen

> **Warum das jetzt kommt.** Der Absturz vom 31.7. um 20:36 trug „OHNE
> ABSCHIED" – ein echter also – und passierte bei **2.005 Elementen und 64
> Bildern**. Die Seite war winzig. Damit ist klar, dass die Bilder nicht die
> Ursache waren; die Kosten liegen woanders, und Echtzeit-Weichzeichner sind
> der nächste Ort, an dem sie außerhalb jeder Messung anfallen.

## 1.76.1 – Juli 2026

### Verbessert
- 🧹 **Die Kaufpreis-Ecke der Karte aufgeräumt.** „Bezahlt" stand zweimal
  untereinander – einmal als Feld, einmal am Anfang der Gewinnzeile. Jetzt
  steht der Betrag einmal, das **+ für einen weiteren Kauf** sitzt am Ende
  derselben Zeile statt als eigener Knopf in der Fläche, und die Gewinnzeile
  beginnt mit dem Wert. Ohne Marktpreis fällt sie ganz weg, statt nur den
  Betrag von oben zu wiederholen

## 1.76.0 – Juli 2026

### Neu
- 🧾 **Kaufbuch: mehrere Käufe zum selben Artikel.** Dasselbe Set einmal bei
  LEGO für 39,99 € und einmal im Markt für 34,99 € – in der Sammlung war das
  **eine** Zeile mit Stückzahl 2, und danach ließ sich nicht mehr sagen,
  welcher Kauf welcher war. Jetzt steht unter der Gewinnzeile die
  Aufstellung: Stückzahl, Preis, Quelle, Datum. **+ Weiterer Kauf** trägt
  einen Posten ein (die Stückzahl wächst mit), **✕** nimmt ihn zurück
- Gilt für **Sets und Figuren** gleichermaßen – der Kauf hängt am Eintrag,
  nicht am Typ
- Der bisherige Bestand wird **übernommen**: Was heute als Kaufpreis
  dasteht, wird beim ersten Start ein Posten im Buch

> **Was sich nicht ändert.** Oben steht weiterhin die Summe, und mit ihr
> rechnen Statistik, Gewinn und die Einkaufslisten. Damit Summe und
> Aufstellung nicht auseinanderlaufen können, gehen alle sechs Stellen, die
> bisher einen Kaufpreis geschrieben haben – Anlegen, Zusammenführen,
> CSV-Import, Zustandswechsel, Bearbeiten, Verbuchen aus der Liste – jetzt
> durch denselben Weg.

## 1.75.0 – Juli 2026

### Neu
- 💬 **Ungelesene Nachrichten sieht man sofort.** Bisher stand der Zähler nur
  am Unter-Reiter im Tausch-Bereich – wer woanders war oder die App gerade
  erst geöffnet hatte, merkte von einer neuen Nachricht nichts. Jetzt sitzt
  ein Zeichen mit der Zahl **oben in der Kopfzeile**, von jedem Tab aus
  sichtbar. Ein Tipp führt direkt zu *Tausch → Meine Vorgänge*
- Ist nichts offen, ist auch **kein Zeichen** da – die Kopfzeile bleibt so
  ruhig wie vorher
- Beim Öffnen der App wird **einmal beim Hub nachgefragt**, statt nur den
  zuletzt bekannten Stand zu zeigen. Sonst stünde die Zahl bis zum nächsten
  Takt auf dem Wert von gestern

## 1.74.1 – Juli 2026

### Behoben
- 💬 **„Anfrage senden" ging gar nicht.** Der Wegweiser für
  `POST /api/hub/trades` stand seit dem 29. Juli über der falschen Funktion:
  Beim Einbau der Schlüsselprüfung landete eine interne Hilfsfunktion
  zwischen dem Wegweiser und dem Vorgang, der dort hingehört. Seitdem
  beantwortete diese Hilfsfunktion die Anfrage – und verlangte eine Angabe,
  die die App gar nicht schickt. Ein Test prüft jetzt, dass **keine** Route
  auf eine Hilfsfunktion zeigt
- 🇩🇪 **Halb deutsch, halb englisch.** Die Eingabeprüfung im Server schreibt
  englisch („Field required"), und das stand ungefiltert mitten im deutschen
  Satz. Jetzt wird daraus ein ganzer Satz in der eingestellten Sprache:
  „Eingabe nicht gültig: Da fehlt eine Angabe" bzw. „Invalid input:
  Something is missing here"

## 1.74.0 – Juli 2026

### Verbessert
- 🧱 **Die Sammlung kommt blockweise.** Bisher entstanden beim Öffnen alle
  Karten auf einen Schlag – bei 815 Einträgen **14.697 Elemente und 837
  Bilder** in einem Rutsch. Jetzt sind es die ersten 60; der Rest kommt beim
  Scrollen nach. Gemessen mit denselben 815 Einträgen: **1.952 Elemente,
  64 Bilder, 28 Bilder vom Server** beim Öffnen
- 👁 **Was weit außerhalb des Fensters liegt, wird nicht mehr gezeichnet.**
  Selbst wenn man sich durch die ganze Sammlung scrollt und am Ende alle
  815 Karten im Dokument stehen, hat der Browser nur **82 Bilder** geholt
  und 60 entpackt – der Rest wird übersprungen und darf wieder weg
- 🗂 **Zugeklappte Themen kosten nichts mehr.** Nach Thema gruppiert wurden
  bisher auch die zugeklappten Gruppen mit allen Karten aufgebaut. Jetzt
  füllt sich eine Gruppe erst, wenn man sie sieht: **163 statt 815 Karten**
  beim Öffnen

> **Warum das der Punkt war.** Der JS-Speicher blieb bei allen Abstürzen
> flach – entpackte Bilder liegen außerhalb und tauchen dort nicht auf.
> 837 Bilder auf einmal sind entpackt ein halbes Gigabyte, und das war die
> letzte Stelle, an der die App das noch tat.

## 1.73.1 – Juli 2026

### Behoben
- 🪧 **Der Abschiedszettel lag am falschen Ort und wurde falsch gelesen.**
  Zwei Fehler, beide beim ersten Einsatz aufgefallen: Er lag im
  `sessionStorage`, und der verschwindet ausgerechnet dann, wenn die App
  geschlossen wird – also im häufigsten *sauberen* Fall. Und verglichen
  wurde mit der Uhr (10 Sekunden), nicht mit dem letzten Messwert. Wer die
  App zumachte und später wieder aufmachte, wäre als Absturz gezählt worden.
  Jetzt liegt der Zettel im `localStorage` und gilt, wenn er **nach** dem
  letzten Messwert geschrieben wurde – egal wie lange das her ist
- ⏱ **Die 90-Sekunden-Frist ist weg.** Sie war der Notbehelf, solange es den
  Zettel nicht gab. Ein Absturz um 21:08, bemerkt beim Wiederöffnen um 21:16,
  fiel damit durchs Raster – der Eintrag trug „OHNE ABSCHIED", die
  Zusammenfassung meldete trotzdem nichts
- 🔐 **Antwort ohne JSON wird nicht mehr verschluckt.** Sitzt zwischen App und
  Instanz ein Zugangsschutz (Cloudflare Access) oder ein Zwischenserver, kommt
  dessen Anmeldeseite zurück – als HTML, mit Status 200. Daraus wurde
  stillschweigend ein leeres Objekt, die Oberfläche baute darauf weiter und
  fiel erst viel später über ein fehlendes Element. Jetzt sagt sie sofort,
  was los ist

## 1.73.0 – Juli 2026

### Verbessert
- 🪧 **Der Abschiedszettel.** Bisher blieb ein Rest Rätselraten: Ein Neuladen
  von Hand sah im Verlauf genauso aus wie ein Absturz. Jetzt hinterlässt die
  Seite beim Verlassen eine Notiz – das passiert bei jedem gewollten Ende
  (neu laden, weiterklicken, schließen) und ausgerechnet **nicht**, wenn der
  Browser sie abwürgt. Fehlt die Notiz, war es wirklich ein Absturz.
  Der Verlauf sagt das jetzt im Klartext: „ohne sich zu verabschieden – das
  ist ein echter Absturz" gegen „von Hand neu geladen – kein Absturz"
- 🗂 **Ein zweiter Tab zählt nicht mehr als Absturz.** Wer die App noch einmal
  öffnet, während die erste Sitzung läuft, hat weder Notiz noch Vorgeschichte
  – das sah aus wie ein Abbruch und war keiner

## 1.72.0 – Juli 2026

Aus einem Belastungstest: 132 Endpunkte, bis zu 5.041 Einträge, alle Tabs.
Angemeldet, Rechte, Einschleusung, XSS, Pfad-Ausbruch – alles dicht. Was
nicht gehalten hat, steht hier.

### Behoben
- 🇬🇧 **Der Export war deutsch, auch auf Englisch.** Druckausgabe und CSV
  hatten ihre Überschriften fest im Code: „Nummer, Name, Jahr, Anz., Zustand".
  Jetzt laufen Titel, Spalten, Dateinamen und Zahlenformat über die
  Übersetzung – und die Geldspalten tragen die **eingestellte Währung** statt
  eines festen „(EUR)"
- 💥 **CSV-Import stürzte ab statt zu meckern.** Ein einzelnes
  Anführungszeichen ohne Gegenstück macht aus dem Rest der Datei ein Feld; ab
  128 KB gab Python auf und der Server antwortete mit einem nackten
  „Internal Server Error". Jetzt kommt der Satz, der weiterhilft
- 🔀 **Zwei Leute, derselbe Artikel, im selben Moment.** Beide Anfragen sahen
  „gibt es noch nicht", eine legte an, die andere lief in die eindeutige
  Bedingung – Serverfehler, und ihr Stück war weg. Jetzt wird daraus
  nachträglich das Zusammenführen
- 🧾 **„… in 3 von 12 Setsvon 12 Sets"** – in der Druckausgabe der fehlenden
  Set-Figuren stand die Zahl doppelt
- 🔎 **Suche ohne Treffer zeigte eine leere Fläche.** Kein Hinweis, kein
  Ladezeichen – man wusste nicht, ob nichts passt oder noch geladen wird.
  Jetzt steht „Nichts gefunden" da, mit einem Knopf, der die Filter räumt
- 🔌 **„Failed to fetch".** Ist die Instanz nicht erreichbar (NAS schläft,
  VPN weg, Update läuft), stand diese englische Browser-Meldung als ganzer
  Inhalt in der Statistik. Jetzt: „Keine Verbindung zur Instanz. Läuft der
  Server, und ist das Gerät im richtigen Netz?"

### Verbessert
- 🧹 **Die Sammlung gibt den Platz frei, wenn man sie verlässt.** Bisher
  blieben alle Karten im Dokument stehen, auch in der Statistik – gemessen
  bei 400 Einträgen: **5.731 → 988 Elemente**, bei 815 sind es rund 13.800
  weniger. Die Daten bleiben im Speicher, beim Zurückkommen ist die Liste
  sofort wieder da
- 🔒 **`item_type` wird geprüft** – bisher landete „raumschiff" klaglos in
  der Datenbank und tauchte danach in Adressen und Auswertungen wieder auf.
  Und **Bildadressen** nehmen nur noch die eigene Instanz oder http(s);
  `javascript:` und `data:` sind raus (ausgeführt wurde davon nie etwas, die
  CSP hat es abgefangen – in der Datenbank hatte es trotzdem nichts verloren)

## 1.71.0 – Juli 2026

### Neu
- ↓ **Nach unten ziehen lädt neu.** Vom Startbildschirm gestartet fehlt die
  Adressleiste – und damit der Knopf zum Neuladen; auf iOS gibt es dort auch
  keine Geste dafür. Jetzt kommt ein Stein von oben mit dem Finger herunter,
  färbt sich grün, sobald es reicht, und beim Loslassen lädt die Seite neu.
  Nur in der App: Im Browser bringt die Adressleiste das schon mit, zwei
  Anzeigen übereinander wären keine Verbesserung

> Der Zug greift nur ganz oben und nur, wenn kein Popup offen ist – und er
> fängt weder das Scrollen noch das Wischen zur Seite ab. Das Neuladen trägt
> sich als **„Nach unten gezogen"** in den Speicher-Verlauf ein, damit es
> dort nicht als Absturz erscheint.

## 1.70.1 – Juli 2026

### Verbessert
- 🔍 **Der Verlauf sagt jetzt, *warum* eine Sitzung neu begann.** Bisher galt
  jeder Start kurz nach dem letzten Messwert als Absturz – auch dann, wenn die
  App sich selbst neu geladen hatte. Genau das passiert nach jedem
  Server-Neustart, damit niemand mit veraltetem Code weiterarbeitet. Im
  Verlauf vom 30.7. steht der Beweis: Der „Absturz" um 09:19:44 war das Update
  auf 1.70.0, eine halbe Minute später lief die neue Version. Jetzt trägt
  jedes gewollte Neuladen seinen Grund, und die Zusammenfassung zählt getrennt:
  „ohne erkennbaren Grund", „vom Browser weggeräumt", „App selbst neu geladen"
- 🖥 **Die Startzeit des Servers steht in jedem Messwert.** Springt sie, ist der
  Container neu gestartet – das ist im Verlauf jetzt direkt zu sehen, statt es
  aus einem Neustart der Seite erraten zu müssen
- 🧹 **Der Browser verrät, wenn er den Tab weggeräumt hat** (`wasDiscarded`).
  Das tut er bei Speichermangel – es ist der einzige Hinweis auf Speicher, den
  er einer Seite gibt, und damit der erste belastbare statt eines vermuteten

## 1.70.0 – Juli 2026

### Behoben
- 💥 **Der abstürzende Tab.** Der Speicher-Verlauf aus 1.69.0 hat die Stelle
  gezeigt: 6 MB JS-Speicher, flach über elf Minuten, 14.680 Elemente,
  815 Bilder – und dann weg. Die Kurve blieb flach, also lag es woanders.
  Es lag am **weichen Hintergrundbild der Sammlungskarten**: Jede Karte trug
  ein zweites Bild, und für CSS-Hintergründe gibt es kein `loading="lazy"`.
  Mit 815 Einträgen nachgestellt – identisch bis auf 100 Elemente genau –
  holte das Öffnen der Sammlung **815 Bilder auf einmal**, ohne eine Zeile zu
  scrollen. Entpackt ist das ein halbes Gigabyte, und das steht nirgends im
  JS-Speicher. Jetzt bekommt eine Karte ihr Hintergrundbild erst, wenn sie in
  die Nähe des Fensters kommt, und gibt es wieder her, wenn sie weit weg ist:
  gemessen **54 statt 815** Bilder beim Öffnen, und beim Weiterscrollen
  wandert ein Fenster von rund 40 Karten mit

### Verbessert
- 🔒 **Auch die Hintergrundbilder laufen jetzt über die eigene Instanz.**
  Sie hingen als einzige noch am Original bei BrickLink – damit verriet jede
  angezeigte Karte, was hier steht, und geladen wurde die unverkleinerte
  Fassung. Jetzt gilt für sie derselbe Weg wie für die Kartenbilder

## 1.69.0 – Juli 2026

### Neu
- 🩺 **Speicher-Verlauf im Fehlerbericht.** Ein abgestürzter Tab hinterlässt
  normalerweise nichts – keine Konsole, kein Protokoll. Deshalb misst die App
  jetzt alle 30 Sekunden JS-Speicher, Zahl der Elemente und Zahl der Bilder
  und legt das **im Browser** ab, wo es einen Abbruch übersteht. Nach dem
  nächsten Start steht da, was in den zwei Stunden davor passiert ist, samt
  Kurve
- ⚠️ **Abstürze werden erkannt und gezählt.** Folgt der Beginn einer Sitzung
  unmittelbar auf einen Messwert, ohne dass jemand neu geladen hat, war es
  ein Abbruch. Senkrechte Linien in der Kurve zeigen, wo
- 📋 Der Verlauf lässt sich als Text kopieren; er bleibt auf dem Gerät

> **Was die Zahl aussagt – und was nicht.** Gemessen wird der
> JavaScript-Speicher. Entpackte Bilder und der Seitenaufbau stecken da nicht
> drin. Wächst die Kurve, liegt es an der App. Bleibt sie flach, während der
> Tab trotzdem stirbt, liegt es sehr wahrscheinlich woanders. Auch das ist
> ein Ergebnis.

## 1.68.5 – Juli 2026

### Verbessert
- 🖼 **Bilder werden vor Anzeige und Versand verkleinert.** Ein
  Bildschirmfoto in 4K belegt entpackt **32 MB** im Browser – obwohl die
  Vorschau es auf 300 Pixel Höhe zeigt und der Server es ohnehin auf 1200
  Pixel bringt, bevor er es zur Erkennung weiterreicht. Jetzt passiert das
  gleich im Browser: aus 32 MB werden 3 MB, und statt 10 MB gehen 250 KB
  durch die Leitung. Für die Erkennung ändert sich nichts – der Server hat
  auch vorher nur die verkleinerte Fassung gesehen
- 🧹 **Der Zwischenspeicher der Übersetzung mistet aus.** Er hält Verweise auf
  Elemente, um beim Sprachwechsel zurücksetzen zu können. Neu gezeichnete
  Listen ließen die alten darin zurück – bei tausend Karten summiert sich
  das. Betraf nur die englische Fassung

## 1.68.4 – Juli 2026

### Behoben
- 🧠 **Jedes hineingezogene Bild blieb für immer im Speicher.** Die
  Scan-Vorschau erzeugt für das gewählte Foto eine Objekt-Adresse – und die
  hält die Datei bis zum Neuladen der Seite fest, auch wenn längst ein
  anderes Bild angezeigt wird. Drei andere Stellen in der App geben ihre
  Adressen ordentlich frei, ausgerechnet diese nicht. Wer nacheinander
  Bildschirmfotos in die Erkennung zieht, sammelte sie also alle an: ein
  2560×1440-Foto belegt entpackt rund **14 MB**. Nach ein paar Dutzend
  beendet der Browser den Tab – bei Edge mit „Auf dieser Seite gibt es ein
  Problem". Jetzt wird die vorherige Vorschau freigegeben, sobald die
  nächste kommt
- 🧪 Ein Test zählt `createObjectURL` gegen `revokeObjectURL` in `app.js` –
  wer künftig eine Adresse erzeugt, ohne sie freizugeben, fällt auf

## 1.68.3 – Juli 2026

### Behoben
- 📷 **Das eigene Foto war in der Vorschau nie zu sehen.** Sie zeigt das
  gerade aufgenommene oder hereingezogene Bild als `blob:` aus dem
  Arbeitsspeicher, noch bevor es hochgeladen ist – und genau dieses Schema
  fehlte in den Sicherheits-Regeln. Der Browser blockierte also ausgerechnet
  das Bild, das man selbst ausgewählt hatte, und es blieb beim Platzhalter.
  Aufgefallen ist es, weil der Fehlerbericht seit 1.60.2 blockierte Inhalte
  meldet: „Vom Browser blockiert: img-src → blob"

### Vorbeugend
- 🧪 **Ein Test leitet aus dem Quelltext ab, welche Schemata die Oberfläche
  benutzt**, und prüft, ob die Regeln dazu passen – statt eine feste Liste
  abzuhaken. Das ist der vierte Fall dieser Art (Katalogbilder, Bild-Ersatz,
  Design-Setzen, jetzt die Vorschau); eine Liste, die jemand pflegen muss,
  hätte ihn wieder nicht gefunden

## 1.68.2 – Juli 2026

### Behoben
- 🎨 **Der Scan-Knopf war in Nova die Warnfarbe.** Er nutzt `--red` – im
  hellen Design das LEGO-Rot, und dort sieht er auch genau richtig aus. In
  Nova ist Rot aber die Farbe für Löschen und Verlust. Der wichtigste Knopf
  der App stand damit als große pinke Fläche da und las sich wie eine
  Fehlermeldung. Jetzt in der Akzentfarbe des Designs, mit dunkler Schrift
  wie auf allen anderen hellen Flächen dort, einem leichten Verlauf und
  passenden Noppen. Klassisch und Galaxie bleiben unverändert rot

## 1.68.1 – Juli 2026

### Verbessert
- 🏷 **Der Hub sagt jetzt, welcher Stand läuft.** Bisher hatte der Worker
  keine Versionsnummer – nach einem Deploy war nirgends abzulesen, ob der
  neue Code tatsächlich oben ist. Die Zahl in der Admin-Konsole ist deren
  **eigene** und steht nur zufällig neben „Hub-Admin", was leicht zu
  verwechseln ist. `/v1/health` und `/v1/me` nennen den Hub-Stand jetzt
  ausdrücklich (`version` bzw. `hub_version`), beginnend bei **1.4.0**

## 1.68.0 – Juli 2026

Zweiter Teil der Durchsicht: der Hub und der Weg dorthin. Ein struktureller
Fund, zwei kleinere.

### Sicherheit
- 🔐 **Der Hub verteilt die Verschlüsselungs-Schlüssel – und konnte damit
  dazwischengehen.** Die Nachrichten sind Ende-zu-Ende verschlüsselt, aber
  verschlüsselt wird mit dem Schlüssel, den der Hub liefert. Wer ihn
  kontrolliert, hätte statt des echten einen eigenen ausliefern und
  mitlesen können, ohne dass es auffällt. Keine Hintertür im Programm, aber
  die Stelle, an der man dem Hub vertrauen musste. Dagegen jetzt:
  - **Die Instanz merkt sich jeden Schlüssel beim ersten Mal.** Taucht später
    ein anderer auf, wird **nichts verschickt**, sondern abgebrochen. Ein
    Wechsel kann harmlos sein – unterscheiden lässt es sich nur durch
    Nachfragen; danach bestätigt ein Admin den neuen Schlüssel
  - **Sicherheitsnummer zum Vergleichen** im Gespräch: zwei kurze Zahlenreihen,
    einmal am Telefon vorgelesen. Stimmen sie, ist niemand dazwischen
- 🎟 **Ein Einladungscode konnte doppelt eingelöst werden.** Prüfen und
  Einlösen waren zwei Schritte – zwei gleichzeitige Anmeldungen mit demselben
  Code kamen beide durch. Jetzt ein einziger Schritt, und wer verliert, wird
  gar nicht erst angelegt
- 🤐 **Der Hub verriet bei einem internen Fehler dessen Wortlaut.** Solche
  Texte können Tabellennamen oder Abfragen enthalten. Sie stehen jetzt nur
  noch im Worker-Protokoll, das der Hub-Admin sieht

### Geprüft und in Ordnung
- **Zugriff auf fremde Vorgänge**: Jeder Nachrichten- und Löschzugriff prüft,
  ob man überhaupt beteiligt ist
- **Token** sind 192 Bit Zufall und liegen nur als SHA-256 im Hub
- **SQL im Worker** läuft durchgehend über gebundene Parameter
- **Keine Rechte-Erhöhung**: Der Endpunkt zum Ändern des eigenen Profils fasst
  nur den Anzeigenamen an – „Admin" lässt sich nicht mitschicken
- **Was der Hub überhaupt sieht**: veröffentlichte Angebote (Nummer, Name,
  Zustand, Menge, Vorschaubild) und Vorgangsdaten. Sammlung, Preise, Notizen
  und Einkaufslisten bleiben zu Hause

### Offen
- **Keine Ratenbremse im Hub.** Für ein Netzwerk unter Bekannten mit
  Einladungspflicht vertretbar; wächst es, gehört das nachgezogen

## 1.67.0 – Juli 2026

Ergebnis einer systematischen Durchsicht: alle 129 Endpunkte und ihre Rechte,
SQL, Dateipfade, XSS (mit vergifteten Daten in jedem Feld), der Update-Weg,
die Sitzungslogik. Zwei echte Lücken, beide behoben.

### Sicherheit
- 🔐 **Ein Passwortwechsel beendet jetzt alle bisherigen Sitzungen.** Bisher
  blieb ein einmal ausgestelltes Token **90 Tage** gültig – auch nach einem
  Passwortwechsel. Wer sein Passwort änderte, weil ein Gerät abhandengekommen
  war, sperrte es damit *nicht* aus. Jetzt zählt jeder Wechsel einen Stand
  hoch, den jedes Token mitführt; das eigene Gerät bekommt eine frische
  Sitzung und bleibt drin. Dasselbe beim Zurücksetzen durch einen Admin und
  beim Abnehmen des zweiten Faktors – gerade dort ist es der Sinn der Sache
- 🤐 **Fehlermeldungen kannten nur die Hälfte der Geheimnisse.** Entfernt
  wurden bisher nur die API-Schlüssel und der GitHub-Token. **Hub-Zugang,
  privater Hub-Schlüssel und Push-Schlüssel wären stehen geblieben** – und
  eine Fehlermeldung kann per Knopfdruck ein **öffentliches** GitHub-Issue
  werden. Jetzt gibt es eine Liste, und ein Test schlägt an, sobald eine neue
  Einstellung dazukommt, die niemand eingeordnet hat
- 🧪 12 neue Tests dafür, unter anderem: alte Token ohne Zählerstand bleiben
  gültig (niemand wird durch das Update ausgeloggt)

### Geprüft und in Ordnung
- **Rechte** kommen bei jeder Anfrage frisch aus der Datenbank – Entzug und
  Löschen wirken sofort, nicht erst mit Ablauf der Sitzung
- **SQL**: Werte laufen ausnahmslos über Platzhalter; wo Tabellennamen
  eingesetzt werden, stammen sie aus festen Listen im Code
- **Dateipfade**: Uploads über eine strenge Namensprüfung, Sicherungen gegen
  eine Positivliste, Katalogbilder über einen Hash – kein Weg nach oben
- **XSS**: mit Schadcode in Artikelnamen, Notizen, Listennamen, Benutzernamen,
  Fehlermeldungen und Hinweisen durchgespielt und in allen Ansichten
  nachgemessen – nichts wurde ausgeführt, nichts als Markup eingeschleust
- **Der Update-Helfer** liest aus der Markierungsdatei nur eine Zahl und führt
  ein festes Skript aus. Selbst wer die Datei schreiben könnte, bekäme keinen
  eigenen Befehl ausgeführt
- **Keine CORS-Freigabe**, Sitzung im Header statt im Cookie – damit ist die
  klassische Cross-Site-Anfrage kein Thema

## 1.66.2 – Juli 2026

### Behoben
- 🎨 **Die Themenkarten hatten in Galaxy und Nova einen dicken hellen Rahmen.**
  Sie fehlten in der Liste der Flächen, die in den dunklen Designs anders
  aussehen – und griffen deshalb auf die 2px-Kante des hellen Designs zurück,
  die dort aus der Textfarbe gebildet wird und damit fast weiß ist. Jetzt
  gleichen sie den Kacheln darüber
- 📕 **Die zugeklappte Karte „Fehlerbericht" zeigte die Benachrichtigung
  trotzdem.** Der Kasten trug `display:block` als Inline-Stil, und der schlägt
  jede Regel aus dem Stylesheet – auch die fürs Zuklappen. Als Klasse verliert
  er diesen Wettstreit und verschwindet mit

## 1.66.1 – Juli 2026

### Behoben
- 🏷 **Neue Sets und Teile bekommen ihr Thema jetzt von selbst** ([#13]).
  Bisher blieb es leer, bis jemand *Themen nachladen* drückte – wer das nicht
  wusste, sammelte nach und nach Einträge unter „Ohne Thema". Der Abruf läuft
  im Hintergrund, hält also das Erfassen nicht auf. Bei Sets zusätzlich noch
  einmal, sobald die Set-Inhalte da sind: Erst dann kann der Rückfall über
  die Figuren greifen. Ein von Hand gesetztes Thema wird nie überschrieben
- 🖼 **Ein Aussetzer beim CDN wird einmal nachgefasst** ([#12]). Ein einzelner
  Netzhänger ließ das Vorschaubild sonst als Platzhalter stehen, bis jemand
  die Seite neu lud
- 🔕 **Ein Bild, das nicht lädt, ist kein Fehler mehr.** Als die Bilder noch
  direkt vom CDN kamen, war die Meldung berechtigt. Seit sie über die eigene
  Instanz laufen, heißt ein Fehlschlag nur: Das CDN hat gerade nicht
  geantwortet. Gemeldet wurde es trotzdem – bis hin zu einem GitHub-Issue und
  einer Meldung aufs Handy, für ein einziges hakeliges Vorschaubild. Vom
  Browser **blockierte** Inhalte werden weiterhin gemeldet

[#12]: https://github.com/Melle79/brickfolio/issues/12
[#13]: https://github.com/Melle79/brickfolio/issues/13

## 1.66.0 – Juli 2026

### Neu
- 🔔 **Benachrichtigung aufs Gerät bei neuen Fehlern.** Web-Push **von der
  eigenen Instanz** – einzuschalten je Gerät unter *Mehr → Wartung →
  Fehlerbericht*. Damit erfährt man von einem Fehler auch, wenn Brickfolio
  gerade zu ist
- 🧪 **Probemeldung senden**, damit sich eine klemmende Zustellung nicht erst
  beim echten Fehler zeigt

### Bewusst so gebaut
- 🔑 **Die Schlüssel entstehen auf eurem Server** und bleiben dort; der
  private Teil verlässt ihn nie. Ein Test wacht darüber, dass er in keiner
  Antwort auftaucht
- 🤐 **Die Meldung sagt nur, *dass* etwas war** – kein Fehlertext, keine
  Nummer, nichts aus der Sammlung. Zustellen muss der Push-Dienst des
  Browser-Herstellers, anders geht Web-Push nicht; der Inhalt ist dabei
  verschlüsselt, aber was gar nicht drinsteht, kann auch nicht auffallen
- 🚫 **Der Tausch-Hub ist nicht beteiligt.** Fehler sind Sache dieser
  Instanz. Sie an einen Dienst zu schicken, den jemand anderes betreibt,
  wäre genau die Telemetrie, die es hier nicht geben soll
- 🧹 Abonnements, die ins Leere zeigen (App neu installiert), räumt der
  Server beim nächsten Versand selbst weg – ein Aussetzer beim Push-Dienst
  trägt dagegen **kein** Gerät aus

### Voraussetzungen
- **https** (Cloudflare-Tunnel oder eigenes Zertifikat) – über `http` im
  Heimnetz erlauben Browser keine Benachrichtigungen
- Auf dem iPhone die **auf dem Startbildschirm installierte** App
- Neue Abhängigkeit `pywebpush`; fehlt sie, bleibt die Karte einfach aus

## 1.65.0 – Juli 2026

### Neu
- 🔔 **Ein neuer Fehler hinterlässt einen Zettel auf der Startseite.** Bisher
  füllte sich das Protokoll still – man musste von sich aus nachsehen. Jetzt
  steht dort, dass etwas aufgezeichnet wurde, mitsamt der Meldung und einem
  Knopf **Fehlerbericht öffnen**, der direkt zur passenden Karte springt und
  sie aufklappt
- 🙈 **Höchstens ein Zettel gleichzeitig.** Ein Problem löst oft mehrere
  verschiedene Fehler aus; zehn Karten übereinander helfen niemandem. Ist der
  eine weggeklickt, meldet sich der nächste **neue** Fehler wieder –
  derselbe zum zweiten Mal nicht
- 👑 **Nur Admins sehen ihn.** Der Fehlerbericht liegt in einer Admin-Karte,
  ein Zettel dorthin wäre für alle anderen eine Sackgasse

## 1.64.2 – Juli 2026

### Verbessert
- 🔑 **Liegt ein Token, verschwindet das Eingabefeld.** Es stand sonst leer da
  und lud dazu ein, aus Versehen zu überschreiben. Stattdessen stehen dort
  jetzt drei Knöpfe: **Token prüfen**, **Ersetzen** (holt das Feld zurück,
  ohne den alten zu löschen) und **Token entfernen**
- ⚠️ Das Entfernen fragt nach – GitHub zeigt einen Token **kein zweites Mal**,
  wer ihn hier löscht, braucht sonst einen neuen

## 1.64.1 – Juli 2026

### Verbessert
- 🔑 **Beim GitHub-Token sieht man jetzt, ob einer liegt.** Bisher war das nur
  daran zu erkennen, dass der Melden-Knopf an einem Fehler auftauchte – und
  der taucht erst auf, wenn es überhaupt einen Fehler gibt. Jetzt steht über
  dem Feld „Gespeichert: …9999" oder „Kein Token hinterlegt"
- ✅ **Neuer Knopf „Token prüfen".** Er fragt GitHub, ob der Token gültig ist
  und das Repository sehen darf, und sagt beim Scheitern, *woran* es liegt:
  abgelaufen, oder gültig aber Repository nicht freigegeben. Ob er auch
  schreiben darf, prüft GitHub erst beim Schreiben – das sagt die Antwort
  ausdrücklich, statt eine Sicherheit vorzugeben, die sie nicht hat

## 1.64.0 – Juli 2026

### Verbessert
- ⚙️ **Der Mehr-Tab ist sortiert.** 17 Karten lagen in einer flachen Liste,
  und die Sortierung der Sammlung saß mitten zwischen Admin-Sachen. Jetzt
  stehen sie in vier Gruppen, geordnet danach, **wen es angeht**:
  🙋 Für dich · 🏠 Diese Instanz · 🌐 Nach außen · 🛠 Wartung. Quellen &
  Rechtliches bleibt ohne Gruppe ganz unten
- 🙈 **Leere Gruppen verschwinden mitsamt ihrer Überschrift.** Ein normaler
  Benutzer sieht damit nur „Für dich" und die Quellen – statt dreier
  Zwischenzeilen ohne Inhalt darunter

## 1.63.2 – Juli 2026

### Behoben
- 🔎 **Ein klemmendes Katalogbild meldete die falsche Adresse.** Seit die
  Bilder über die eigene Instanz laufen, stand im Fehlerbericht deren Name –
  als wäre der eigene Server kaputt. Gemeldet wird jetzt der Host dahinter,
  also der, der wirklich nicht antwortet

## 1.63.1 – Juli 2026

### Behoben
- 🏷 **Der Rückfall über die Figuren lief nur mit BrickLink-Schlüsseln.** Er
  stand innerhalb der Schl