# 📦 Kinderkleider-Börse (Web-App) Eine schlanke, mobile-optimierte Web-App zum Katalogisieren, Präsentieren und Reservieren von zu klein gewordener Kinderkleidung für Familie, Freunde und Nachbarn. --- ## 🚀 Zielsetzungs & Kern-Features - **Schnelles Erfassen (Mobile First):** Foto direkt mit dem Smartphone aufnehmen, Grösse & Kategorie wählen, fertig. - **Übersichtliche Galerie & Filter:** Schnelle Filterung nach Konfektionsgrösse, Kategorie, Geschlecht und Saison. - **Einfaches Reservierungssystem:** Interessierte können Kleidungsstücke mit einem Klick reservieren. - **Bildoptimierung:** Automatische Skalierung und WebP-Komprimierung beim Upload, um Speicherplatz und Bandbreite zu sparen. --- ## 🛠 Technologiestack (Python-basiert) - **Backend:** Python 3.11+ mit [FastAPI](https://fastapi.tiangolo.com/) (hohe Performance, automatische OpenAPI/Swagger-Dokumentation) - **Datenbank & ORM:** SQLite mit [SQLAlchemy](https://www.sqlalchemy.org/) & [Alembic](https://alembic.sqlalchemy.org/) (Migrations) - **Bildverarbeitung:** Pillow (PIL) für WebP-Konvertierung und Resizing - **Frontend (Optionen):** - *Variante A (Single File / Monolith):* Jinja2 Templates + HTMX + Tailwind CSS (sehr schnell zu entwickeln, kein Node.js Build-Step nötig) - *Variante B (Decoupled):* Vue.js / React SPA (greift auf die REST-API zu) - **Deployment:** Docker & Docker Compose (leicht auf Unraid / Server auszuführen) --- ## 🗄 Datenbank-Schema ### 1. `categories` | Feld | Typ | Beschreibung | |---|---|---| | `id` | INTEGER (PK) | Eindeutige ID | | `name` | VARCHAR(50) | Name (z. B. Hosen, Jacken, Schuhe, Pullover) | | `slug` | VARCHAR(50) | URL-freundlicher Name | ### 2. `items` (Haupttabelle) | Feld | Typ | Beschreibung | |---|---|---| | `id` | INTEGER / UUID (PK) | Eindeutige ID | | `title` | VARCHAR(100) | Kurzer Titel (z. B. "Warme Winterjacke rot") | | `description` | TEXT | Optionale Details oder Mängel | | `size` | VARCHAR(20) | Konfektionsgrösse (z. B. `98/104`, `24`, `80`) | | `gender` | VARCHAR(10) | `boy`, `girl`, `unisex` | | `season` | VARCHAR(15) | `spring_summer`, `autumn_winter`, `all_year` | | `condition` | VARCHAR(20) | `new`, `very_good`, `good`, `worn` | | `status` | VARCHAR(20) | `available`, `reserved`, `given_away` | | `category_id` | FK -> `categories.id` | Zuordnung zur Kategorie | | `reserved_by` | VARCHAR(100) | Name/Kontakt der Person, die es reserviert hat | | `created_at` | TIMESTAMP | Erstellungsdatum | | `updated_at` | TIMESTAMP | Letztes Update | ### 3. `item_images` | Feld | Typ | Beschreibung | |---|---|---| | `id` | INTEGER / UUID (PK) | Eindeutige ID | | `item_id` | FK -> `items.id` | Referenz zum Kleidungsstück | | `image_url` | VARCHAR(255) | Pfad zur Bilddatei (z. B. `/static/uploads/img_1234.webp`) | | `is_primary` | BOOLEAN | Hauptbild für Galerie-Vorschau | --- ## 🔌 API-Endpunkte (FastAPI REST) ### Kleidung verwalten & durchsuchen - `GET /api/v1/items` - **Query-Params:** `?size=98/104&category_id=2&status=available&gender=unisex` - **Response:** Liste gefilterter Kleidungsstücke mit Primärbild. - `GET /api/v1/items/{id}` - **Response:** Einzelnes Kleidungsstück inklusive aller Bilder und Details. - `POST /api/v1/items` - **Content-Type:** `multipart/form-data` - **Body:** JSON-Daten + Bild-Uploads. - `PATCH /api/v1/items/{id}` - **Body:** Partial Update für Status, Titel, Beschreibung etc. - `DELETE /api/v1/items/{id}` - **Description:** Kleidungsstück und zugehörige Bilder löschen. ### Reservierung & Status - `POST /api/v1/items/{id}/reserve` - **Body:** `{"reserved_by": "Familie Meier"}` - **Response:** enthält das `reservation_token` – daraus wird der Link zum Aufheben gebildet. - `POST /api/v1/items/{id}/release` - Setzt Status zurück auf `available` und löscht `reserved_by`. - **Erlaubt für:** den Reservierenden (mit gültigem `token`) oder den angemeldeten Betreiber. Ohne beides: `403`. Sonst könnte jeder Besucher fremde Reservierungen löschen. - `POST /api/v1/items/{id}/mark-given` - Setzt Status auf `given_away`. ### Stammdaten - `GET /api/v1/categories` - `GET /api/v1/sizes` --- ## 📂 Empfohlene Projekt-Struktur ```text kinderkleider-app/ ├── app/ ├── database.py # DB-Engine & Session Setup ├── models.py # SQLAlchemy Modelle ├── schemas.py # Pydantic Schemas (Request/Response validation) ├── crud.py # Datenbank-Zugriffslogik ├── main.py # FastAPI App Entrypoint & Routen ├── utils.py # Bild-Komprimierung & Helper │ ├── static/ # Uploaded Images & CSS │ └── templates/ # Jinja2 Templates (falls HTML direkt gerendert wird) ├── Dockerfile ├── docker-compose.yml ├── requirements.txt └── README.md ``` --- ## 📋 Meilensteine / Roadmap - [ ] **Phase 1: Backend Basic MVP** - [ ] FastAPI Setup mit SQLite & SQLAlchemy - [ ] Datenmodelle & Migrationen anlegen - [ ] CRUD Endpunkte für `items` und `categories` testen (Swagger UI) - [ ] **Phase 2: Bild-Handling & Speicher** - [ ] `multipart/form-data` Upload via FastAPI - [ ] Pillow-Integration zur Konvertierung aller Uploads nach WebP (max. 1200px Breite) - [ ] **Phase 3: Frontend Setup** - [ ] Mobile-First Layout mit Tailwind CSS - [ ] Filterleiste für Grösse, Kategorie & Status - [ ] Reservierungs-Modal / Button - [ ] **Phase 4: Containerisierung & Deployment** - [ ] `Dockerfile` & `docker-compose.yml` schreiben - [ ] Persistence per Volume-Mount für Datenbank & Bild-Uploads - [ ] Gitea Actions: Image bei einem Versions-Tag (`v*`) bauen, testen und in die Registry stellen — gleiches Vorgehen wie bei der Kantone-App (`.gitea/workflows/docker-image.yml` dort als Vorlage) - [ ] Zweite Compose-Datei zum Starten des fertigen Images (ohne Quellcode)