Files
kleiderboerse/Plan-Verbesserungen.md
T
StefanandClaude Opus 5 c9861613cc GZip, Cache-Dauer fuer statische Dateien, Sicherungsskript
GZip: Die Startseite ging unkomprimiert raus - 9725 Byte, jetzt 1900.
Zuletzt angemeldet heisst zuerst ausgefuehrt, die Komprimierung liegt damit
aussen.

Statische Dateien: StaticFiles kennt keine Cache-Dauer, per Unterklasse
nachgeruestet. Bewusst nur eine Stunde - die Dateien tragen keinen
Versionsanhaenger, eine lange Dauer wuerde nach einem Update die alte
Fassung festhalten. (Die hochgeladenen Bilder hatten ihre Header laengst;
der Plan behauptete faelschlich das Gegenteil, korrigiert.)

Sicherung: sicherung.sh sichert Datenbank UND Bilder - eine Datenbank ohne
die Fotos ist wertlos. Pfade werden aus der Anwendung gelesen statt geraten.
Die Pruefung oeffnet die Kopie, nicht das Original. Erprobt: 4 Eintraege,
4 Bilder, vollstaendig; ein entferntes Bild wird erkannt.

81 Tests weiterhin gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
2026-09-13 21:08:44 +02:00

4.1 KiB
Raw Blame History

Plan: Verbesserungen

Erstellt am 13.09.2026 nach einer Durchsicht des gesamten Repos, parallel zur Kantone-App. Ergänzt Plan.md, der den ursprünglichen Aufbau beschreibt.

Noch nichts davon ist umgesetzt.

Vorabprüfung (13.09.2026, erledigt)

Arbeitsverzeichnis sauber
Offene Branches keine
Tests 81 grün in 12 Sekunden
Letzter Tag v1.0.0

Der CI-Lauf zu v1.0.0 wurde nie bestätigt. Der Tag wurde einmal auf dem Server gelöscht und danach auf e0212cf neu gesetzt. Vor dem nächsten Release prüfen, ob in der Registry tatsächlich ein Image liegt.

Zum Zustand des Codes

Die Durchsicht hat wenig ergeben, und das ist das Ergebnis: Escaping, CSRF, Token-Vergleich in konstanter Zeit, Bild-Upload mit Inhaltsprüfung statt Endung, bewusst vermiedenes N+1, CHECK-Constraints in der Datenbank statt nur in Python — das ist alles vorhanden und richtig gemacht.

Die Punkte unten sind Ergänzungen, keine Korrekturen.


P1 — Keine Sicherung der Datenbank ERLEDIGT 13.09.2026

Der wichtigste offene Punkt, und hier wiegt er schwerer als bei der Kantone-App: In kleiderboerse.sqlite stecken Einträge und in uploads/ die dazugehörigen Fotos. Beides ist nicht wiederherstellbar — anders als die Kantonsdaten, die sich neu importieren liessen.

docker-compose.betrieb.yml sieht keinen Sicherungsschritt vor.

Ein cp der laufenden Datei genügt nicht; sie kann mitten in einer Schreiboperation erwischt werden. Richtig ist sqlite3 ... ".backup ..." oder VACUUM INTO, beide konsistent auch bei laufendem Zugriff.

Vorgehen

  1. Täglicher Lauf, sieben Stände, danach rollierend überschreiben.
  2. Die Bilder gehören dazu — eine Datenbank ohne uploads/ ist wertlos.
  3. Einmal einen Stand tatsächlich zurückspielen und prüfen, dass die Galerie danach vollständig ist. Eine ungetestete Sicherung ist keine.

Punkt 3 ist kein Formalismus: Am 13.09.2026 ist Jellyfin auf demselben Netzwerk an einer Datenbank-Migration hängengeblieben. Dass es dort Sicherungen gab, war der einzige Grund, warum die Lage beherrschbar blieb.

P2 — Antworten werden nicht komprimiert ERLEDIGT 13.09.2026

app/main.py bindet keine GZipMiddleware ein. Jede HTML- und HTMX-Antwort geht unkomprimiert über die Leitung — bei einer Galerie mit vielen Kacheln merkbar, besonders über Mobilfunk.

from fastapi.middleware.gzip import GZipMiddleware
app.add_middleware(GZipMiddleware, minimum_size=1000)

P2 — Statische Dateien ohne Cache-Dauer ERLEDIGT 13.09.2026

app.mount("/static", StaticFiles(directory=...), name="static")

Ohne max_age werden htmx.min.js, theme.js und die beiden Swagger-Dateien bei jedem Aufruf neu verhandelt. Eine lange Cache-Dauer setzen und bei Änderungen einen Versionsanhänger an die URL hängen.

Korrektur: Für die hochgeladenen Bilder galt das nicht — die haben ihre Cache-Header längst (app/routers/images.py setzt max-age=31536000, immutable). Das war eine Fehlannahme beim Erstellen dieses Plans.

P4 — Zwei Filterspalten ohne Index

crud.items_suchen() filtert unter anderem nach gender und season. Beide Spalten haben keinen Index; status, size und category_id haben einen.

Bei den zu erwartenden Stückzahlen ist das ohne praktische Bedeutung — der Vollständigkeit halber notiert, nicht als Handlungsbedarf.


Reihenfolge

  1. Sicherungen einrichten, inklusive Bilder, mit einer echten Rückspielprobe
  2. GZip und Cache-Dauer — zusammen wenige Zeilen
  3. Rest nach Bedarf

Umsetzung am 13.09.2026 (Branch verbesserungen)

Punkt Ergebnis
Sicherung sicherung.sh, Datenbank und Bilder, geprüft
GZip Startseite 9725 → 1900 Byte (80 %)
Statische Dateien Cache-Control: public, max-age=3600
Tests 81 grün, unverändert

Die Sicherung wurde gegen den laufenden Container erprobt: 4 Einträge, 4 Bilder, alle in der Datenbank verzeichneten Bilder auch wirklich im Sicherungsordner. Gegenprobe mit entferntem Bild wird erkannt.

Offen bleibt P4 (Indizes auf gender/season) — ohne praktische Bedeutung.