Reservierung aufheben und offene Galerie entschieden

- Aufheben darf der Reservierende selbst (per Token-Link) und der
  Betreiber. Ein offener release-Endpunkt wäre die naheliegende, aber
  falsche Variante: dann löscht jeder Besucher fremde Reservierungen, und
  weil reserved_by mitgeht, bleibt nicht mal nachvollziehbar, dass jemand
  reserviert hatte. Token wird beim Aufheben und beim Erledigen gelöscht,
  Vergleich mit compare_digest.
- Die Galerie bleibt frei zugänglich, ohne Zugangscode. Damit wird das
  Rate-Limit zur einzigen Bremse vor dem Reservieren-Endpunkt, und zwei
  Dinge gehören zwingend dazu: reserved_by erscheint öffentlich nur als
  "reserviert", und noindex/robots.txt verhindern, dass Fotos und Texte
  dauerhaft im Suchindex landen.

projekt.md bei /release entsprechend präzisiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
This commit is contained in:
2026-08-29 21:50:34 +02:00
co-authored by Claude Opus 5
parent da4267c369
commit 3cf6903df5
2 changed files with 53 additions and 24 deletions
+48 -24
View File
@@ -10,11 +10,15 @@ offen waren, und um die Punkte, die durch den Internet-Zugang dazukommen.
| Frontend | **Variante A** Jinja2 + HTMX + Tailwind, ein einziger Dienst, kein Node.js |
| Erfassen/Bearbeiten/Löschen | Hinter **einem Passwort** |
| Reservieren | **Ohne Anmeldung** |
| Reservierung aufheben | **Der Reservierende selbst** (per Token-Link) **und der Betreiber** |
| Galerie | **Frei zugänglich**, ohne Zugangscode |
| Erreichbarkeit | **Aus dem Internet**, per Reverse-Proxy mit HTTPS |
Die letzten beiden zusammen sind der eigentliche Knackpunkt dieses Projekts:
ein Endpunkt, den jeder im Internet ohne Anmeldung auslösen kann, der den
Zustand ändert. Alles unter „Absicherung" ergibt sich daraus.
Die Kombination aus „frei zugänglich" und „Reservieren ohne Anmeldung" ist der
eigentliche Knackpunkt: ein Endpunkt, den jeder im Internet ohne jede Hürde
auslösen kann und der den Zustand ändert. Alles unter „Absicherung" ergibt
sich daraus bei einer offenen Galerie ist das Rate-Limit keine Kür, sondern
das Einzige, was zwischen einem Skript und dem kompletten Bestand steht.
---
@@ -86,7 +90,8 @@ Das Schema wird grundsätzlich übernommen. Fünf Ergänzungen:
2. **`reservation_token` (neu) in `items`.** Zufälliger Wert, der beim
Reservieren erzeugt wird. Nur wer ihn hat, kann die eigene Reservierung
wieder aufheben. Begründung unten unter „Offene Punkte".
wieder aufheben; der Betreiber kann es ohnehin. Wird beim Aufheben und
beim Erledigen wieder gelöscht. Einzelheiten unter „Absicherung", Punkt 2.
3. **`sizes` als eigene Tabelle.** `projekt.md` sieht `GET /api/v1/sizes` vor,
aber keine Tabelle dazu. Grössen aus den vorhandenen Einträgen zu
@@ -176,16 +181,48 @@ bei einem Heimnetz-Dienst. Punkte 1 und 2 sind die wichtigsten.
### 2. Reservieren ohne Anmeldung
Ein offener, zustandsändernder Endpunkt im Internet. Ohne Bremse kann ein
Skript in Sekunden alles reservieren oder `reserved_by` als Werbefläche
missbrauchen.
Ein offener, zustandsändernder Endpunkt im Internet bei frei zugänglicher
Galerie ohne jede vorgelagerte Hürde. Ohne Bremse kann ein Skript in Sekunden
alles reservieren oder `reserved_by` als Werbefläche missbrauchen.
- **Rate-Limit pro IP** (`slowapi`), z.B. 5 Reservierungen pro Stunde.
- `reserved_by` begrenzen (Länge, keine URLs) und beim Anzeigen maskieren.
Jinja2 maskiert von sich aus entscheidend ist, `|safe` dort nirgends zu
verwenden.
- Reservierungen sind **jederzeit vom Betreiber aufhebbar** (Admin-Ansicht),
damit eine Missbrauchswelle in einem Rutsch aufgeräumt werden kann.
- Reservierungen sind **jederzeit vom Betreiber aufhebbar**, auch mehrere auf
einmal, damit eine Missbrauchswelle in einem Rutsch aufgeräumt werden kann.
**Wer darf aufheben und wie das ohne Konten funktioniert**
Zwei Wege, entsprechend der Entscheidung oben:
1. **Der Reservierende selbst.** Beim Reservieren erzeugt die Anwendung ein
`reservation_token` (Zufallswert) und zeigt danach einen Link
`/items/{id}/release?token=…` zum Merken oder Weiterschicken. Nur wer
ihn hat, kann *diese* Reservierung zurücknehmen.
2. **Der Betreiber**, aus der Admin-Ansicht heraus, ohne Token.
Ein offener `release`-Endpunkt ohne Token wäre die naheliegende, aber falsche
Variante: dann könnte jeder Besucher die Reservierung eines anderen löschen
und weil `reserved_by` mitgelöscht wird, bliebe nicht einmal nachvollziehbar,
dass überhaupt jemand reserviert hatte.
Das Token wird beim Aufheben und beim Erledigen (`mark-given`) gelöscht, damit
ein alter Link nicht später eine neue Reservierung eines anderen aufhebt.
Verglichen wird es mit `secrets.compare_digest`.
### 2b. Folgen der offenen Galerie
Die Galerie ist ohne Zugangscode erreichbar. Das ist eine bewusste
Entscheidung; zwei Dinge gehören dann aber dazu:
- **`reserved_by` nicht öffentlich anzeigen** (siehe Abschnitt 5). In der
Galerie steht nur „reserviert", der Name erscheint ausschliesslich in der
Admin-Ansicht. Ohne Zugangscode wäre der Name sonst für jeden lesbar.
- **`noindex` und eine `robots.txt`.** Frei erreichbar heisst nicht, dass die
Seite in Suchergebnissen auftauchen muss. Ohne das landen Fotos und Texte
im Index von Google und sind auch dann noch auffindbar, wenn die Börse
längst abgeräumt ist.
### 3. Anmeldung fürs Erfassen
@@ -302,24 +339,11 @@ Gleiches Vorgehen wie bei der Kantone-App
## Offene Punkte
1. **Wer darf eine Reservierung wieder aufheben?** `projekt.md` sieht
`POST /items/{id}/release` vor, sagt aber nicht, wer ihn aufrufen darf. Ist
er offen, kann jeder die Reservierung eines anderen löschen. Vorschlag: beim
Reservieren wird ein Token vergeben und als Link angezeigt („Reservierung
aufheben") wer ihn hat, kann die eigene zurücknehmen; der Betreiber kann
es ohnehin. Bitte bestätigen, dann kommt `reservation_token` ins Modell.
2. **Soll die Galerie überhaupt öffentlich sein?** Auch ohne Schreibzugriff
zeigt sie Kinderkleidung, Namen und indirekt den Wohnort. Ein einfacher
Zugangscode für die ganze Seite (einmal eingeben, bleibt im Cookie) würde
Suchmaschinen und Zufallsbesucher aussperren, ohne dass jemand ein Konto
braucht. Empfehlung: ja, zusätzlich zu `noindex`. Deine Entscheidung.
3. **Benachrichtigung bei Reservierung?** Nicht in `projekt.md`. Ohne sie musst
1. **Benachrichtigung bei Reservierung?** Nicht in `projekt.md`. Ohne sie musst
du selbst nachschauen. Ein einfacher Weg wäre eine Nachricht per E-Mail oder
Telegram. Kann auch später kommen dann aber besser gleich als eigener
Meilenstein statt nachträglich eingeschoben.
4. **Mehrere Kinder / Grössenverläufe?** Aktuell ist alles ein flacher Bestand.
2. **Mehrere Kinder / Grössenverläufe?** Aktuell ist alles ein flacher Bestand.
Falls du später nach „von wem" oder „Jahrgang" filtern willst, wäre jetzt
der günstige Zeitpunkt für ein zusätzliches Feld.