Jinja2 mit HTMX, Tailwind über die Standalone-Binärdatei im Docker-Build -
kein Node.js, kein npm. Mobile-First, Tippflächen mindestens 44 px hoch.
Seiten: Galerie mit Filterleiste, Detailseite, Erfassungsformular,
Stapel-Import mit Entwurfsliste, Anmeldung. HTMX tauscht beim Filtern nur
die Liste aus statt die ganze Seite neu zu laden.
Aus den Entscheidungen im Plan folgt konkret:
- Der Stapel-Import steht ZUERST im Formular: wer zwanzig Teile hat, will
nicht zwanzigmal ein Formular ausfüllen. Bewusst ohne capture-Attribut,
damit sich wahlweise fotografieren oder aus der Mediathek wählen lässt -
mit capture ginge nur je ein Foto pro Vorgang.
- Grösse, Kategorie, Geschlecht, Saison und Zustand werden vom zuletzt
gespeicherten Teil übernommen. Beim Abarbeiten einer Kiste sind das fünf
Felder weniger pro Stück.
- Nach dem Nachtragen eines Entwurfs geht es direkt zum nächsten, nicht auf
die Detailseite - das ist der eigentliche Arbeitsablauf.
- Titel bleibt leer erlaubt; angezeigt wird dann Kategorie und Grösse.
- reserved_by erscheint öffentlich nur als "reserviert". Den Namen sieht
ausschliesslich der angemeldete Betreiber.
- Nach dem Reservieren wird der Freigabe-Link angezeigt, als vollständige
Adresse zum Aufbewahren.
- Post/Redirect/Get überall, damit ein Neuladen nicht erneut abschickt.
- CSRF-Token in jedem Formular, zusätzlich zu SameSite=Lax.
HTMX liegt lokal im Repository, nicht vom CDN: die CSP erlaubt nur
script-src 'self', und ein CDN-Aufruf gäbe die IP jedes Besuchers weiter -
dieselbe Überlegung wie bei Swagger und bei den Schriften der Kantone-App.
Ein Test prüft für alle Seiten, dass nichts von aussen geladen wird.
Nebenbei TemplateResponse auf die aktuelle Signatur umgestellt (64
Deprecation-Warnungen weniger).
77 Tests, alle grün. Zusätzlich der ganze Weg gegen den Container:
anmelden, drei Fotos als Stapel, Entwurf nachtragen, Werte werden für das
nächste Teil übernommen, als Gast reservieren, Name bleibt verborgen,
Selbst-Freigabe über den Link.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
Zwei Fehler, beide erst im Browser sichtbar:
1. /docs blieb weiss. FastAPI holt Swagger von cdn.jsdelivr.net, und die
in Phase 3 eingeführte CSP (script-src 'self') blockiert das zu Recht.
Die Dateien liegen jetzt unter app/static/swagger/ im Repository - das
funktioniert auch ohne Internet und ruft keinen fremden Server auf, aus
demselben Grund, aus dem die Kantone-App ihre Schriften lokal ausliefert.
Das Favicon holte FastAPI ebenfalls von aussen; auch das ist jetzt lokal.
2. Die Wurzel / lieferte ein nacktes 404-JSON - im Browser sieht das aus
wie eine kaputte Anwendung. Jetzt eine schlichte Platzhalter-Seite, bis
die Galerie in Phase 4 steht.
Ausserdem beim Testen aufgefallen: eine lokale .env-Datei reicht
ADMIN_PASSWORD auch dann herein, wenn die Umgebungsvariable gelöscht wird -
bei pydantic-settings haben Umgebungsvariablen Vorrang, ein leerer Wert
überstimmt die Datei, ein Löschen nicht. Der Test setzt jetzt leer statt zu
löschen; im Betrieb ist das dieselbe Falle.
Der neue Test prüft, dass /docs keinen einzigen Verweis auf einen fremden
Host enthält - genau das würde sonst unbemerkt wieder hereinrutschen.
61 Tests, alle grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o