Commit Graph
6 Commits
Author SHA1 Message Date
StefanandClaude Opus 5 3d7b7c706a Phase 1: Datenmodell, CRUD-API und Stammdaten
FastAPI mit SQLAlchemy und SQLite, Migrationen über Alembic. Die
Endpunkte aus projekt.md für items, categories und sizes stehen samt
Reservierung; Bilder und Anmeldung folgen in Phase 2 und 3.

Umgesetzt wie in Plan.md festgelegt:

- Feste Wertelisten als Enum UND als CHECK in der Datenbank. Die
  CHECK-Bedingung ist der eigentliche Schutz: an SQLAlchemy vorbei (Import,
  sqlite3 von Hand) käme sonst "Gril" durch, und die Filter griffen still
  nicht mehr.
- Status "draft" für den Stapel-Import. Entwürfe erscheinen weder in der
  Galerie noch in GET /items, solange nicht ausdrücklich status=draft
  angefragt wird, und lassen sich nicht reservieren.
- Titel ist freiwillig und wird sonst beim ANZEIGEN aus Kategorie und
  Grösse gebildet ("Jacken 98/104") - nicht beim Speichern, damit er einer
  späteren Korrektur der Grösse folgt.
- reservation_token: nur wer es hat, kann die eigene Reservierung aufheben.
  Verglichen mit compare_digest, gelöscht beim Freigeben und beim
  Erledigen, damit ein alter Link nicht später eine fremde Reservierung
  aufhebt.
- Eigene sizes-Tabelle mit sort_order statt SELECT DISTINCT: sonst stünde
  "104" vor "56" und jeder Tippfehler würde zur Filteroption.
- Pagination auf GET /items, in projekt.md nicht vorgesehen.

Zwei SQLite-Eigenheiten, die leicht untergehen: foreign_keys ist
standardmässig AUS (ohne PRAGMA greift ON DELETE CASCADE nicht), und
check_same_thread muss für FastAPI abgeschaltet werden. Beides in
database.py, dazu WAL fürs gleichzeitige Lesen.

24 Tests, alle grün. Zusätzlich von Hand geprüft: Migration anwenden,
Eintrag anlegen, reservieren, ohne Token freigeben (403), mit Token
freigeben (200), Swagger UI erreichbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
2026-08-29 22:00:58 +02:00
StefanandClaude Opus 5 3cf6903df5 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
2026-08-29 21:50:34 +02:00
StefanandClaude Opus 5 da4267c369 Stapel-Import und automatischer Titel
Beim Erstbestand sind viele Teile auf einmal zu erfassen. Der Aufwand
steckt nicht im Fotografieren, sondern im Rundlauf pro Stück. Darum:

- Stapel-Import: erst alles mit der Kamera-App fotografieren, dann alle
  Fotos auf einmal hochladen. Pro Foto entsteht ein Entwurf, die Details
  kommen später. Bewusst ohne capture="environment" - das erzwingt ein
  Foto pro Vorgang und schliesst multiple aus.
- Titel wird optional und sonst aus Kategorie und Grösse gebildet
  ("Hose 98/104"). Erzeugt beim Anzeigen, nicht beim Speichern, damit er
  einer späteren Korrektur der Grösse folgt.

Daraus folgt ein neuer Status "draft" im Datenmodell; title und size
müssen NULL erlauben. Entwürfe erscheinen nicht in der Galerie.

Ausserdem HEIC in Phase 2 aufgenommen: iPhones nehmen so auf, und beim
Stapel-Import fiele ein nicht lesbares Bild sonst still hinten runter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
2026-08-29 21:45:29 +02:00
StefanandClaude Opus 5 c8f11e0642 Bauen über Gitea Actions in die Roadmap aufnehmen
Fehlte in Phase 4: das Image soll wie bei der Kantone-App über einen
Versions-Tag gebaut, vor dem Veröffentlichen getestet und in die Gitea-
Registry gestellt werden.

Der Plan hält dazu die Punkte fest, die dort nachträglich korrigiert werden
mussten - vor allem, Werte aus ${{ ... }} nicht direkt in die Shell zu
schreiben, weil Tag-Namen Sonderzeichen enthalten dürfen und der Job ein
Registry-Token hält.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
2026-08-29 21:29:21 +02:00
StefanandClaude Opus 5 198108ff5f Zeilenenden auf LF festlegen
Gilt unabhängig vom lokalen core.autocrlf und damit auch für Klone auf
anderen Rechnern. Wichtig, sobald Shell-Skripte im Container laufen: mit
CRLF scheitern die dort an "bad interpreter: /bin/sh^M".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
2026-08-29 21:15:44 +02:00
StefanandClaude Opus 5 d5bb83a94f Projektbeschrieb und Umsetzungsplan
projekt.md beschreibt die Kinderkleider-Börse (FastAPI, SQLite, Bild-Upload
mit WebP-Konvertierung). Plan.md ergänzt die dort offenen Entscheidungen:
Frontend-Variante A (Jinja2 + HTMX, kein Node.js), Erfassen hinter Passwort,
Reservieren ohne Anmeldung, erreichbar aus dem Internet.

Aus dieser Kombination folgt der Schwerpunkt des Plans - ein offener,
zustandsändernder Endpunkt im Internet und ein Bild-Upload sind die beiden
Angriffsflächen, die den Ausschlag geben.

Noch kein Code.

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