Scarriffle eaacfd03e5 Gruppen: Obergruppen + Mindestbestaende nur noch je Lagerort (Backend)
Zwei zusammenhaengende Umbauten, weil sie dieselben Stellen betreffen.

Obergruppen: Gruppen bilden jetzt einen gerichteten azyklischen Graphen statt
einer flachen Liste. Eine Gruppe darf unter MEHREREN Obergruppen haengen -
"Grillwurst" unter "Wurst" UND unter "Grillgut"; mit einem einzelnen parent_id
waere genau das nicht abbildbar. Bestand und Mindestbestand einer Gruppe zaehlen
den gesamten Untergraphen, wobei eine ueber zwei Wege erreichbare Untergruppe
nur einmal zaehlt (services/gruppen.py arbeitet durchgaengig mit Mengen).
Product.group_id bleibt unveraendert - ein Artikel haengt weiter an genau einer
Gruppe.

Mindestbestaende: der separate Gesamt-Mindestbestand entfaellt. Er wird zur
Zeile mit location_id NULL ("Ueberall") und ist damit die Wurzel ueber allen
Lagerorten - dieselbe Verrechnung wie bei verschachtelten Orten greift jetzt
auch zwischen Ueberall und Kueche, wodurch derselbe Artikel nicht mehr doppelt
in der Einkaufsliste steht. Alle Werte liegen einheitlich in Basiseinheiten
statt in drei verschiedenen Einheiten nebeneinander; das Umrechnen beim
Umschalten der Erfassungseinheit entfaellt dadurch ersatzlos.

_netted_topups nimmt die Hierarchie jetzt als Parameter und faltet damit
Lagerort-Baum und Gruppen-Graph. Verrechnet wird zwischen zwei Gruppen nur,
wenn die zaehlenden Artikel der Untergruppe eine Teilmenge der Obergruppe sind -
zaehlt die Obergruppe in Kilogramm und die Untergruppe in Stueck, kommt ein Kauf
dort oben nicht an.

Die vierfach kopierte Bestandssumme wandert in Sammelabfragen
(summe_bestand_base), sonst vervielfacht der transitive Teilgraph die Abfragen.

Einmalige Datenwanderung beim Start (Merker in den Einstellungen), 18 neue
Tests - darunter Doppelzaehlung ueber zwei Wege, Ringschutz und die bewusst
offene Grenze bei zwei Obergruppen mit gemeinsamer Untergruppe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 21:48:14 +02:00
2026-07-23 17:35:45 +02:00
2026-07-23 17:35:45 +02:00

Vorrania Selfhostbare Vorrats- und Gegenstandsverwaltung

Ein selbst gehosteter Dienst, um sowohl deinen Lebensmittelvorrat als auch allgemeine Gegenstände (Haushalt, Elektronik, Kleidung, Verbrauchsmaterial …) zu verwalten: Ein-/Auslagern per Barcode, Chargen mit MHD, Einzelstücke mit eigener UID/QR, Mindestbestände, automatische Einkaufsliste, verschachtelte Lagerorte, Gruppen, Kategorien und Dashboards mit Web-UI und nativer iOS-App, die beide dieselbe REST-API nutzen.

Was Vorrania verwaltet

Lebensmittel laufen als Chargen mit Mindesthaltbarkeitsdatum. Beim Auslagern wird automatisch die zuerst ablaufende Charge entnommen (FEFO).

Gegenstände kennen drei Arten:

  • Menge je Lagerort reines Zählen (z. B. Unterhosen, Batterien).
  • Einzelstücke jedes Exemplar mit eigener UID/QR, Kaufdatum, Garantie, Bezugsquelle und Beleg (z. B. Powerbank, Kamera).
  • Verbrauchsgegenstand wie ein Lebensmittel als Charge mit Menge und Einheit geführt (z. B. Sonnencreme in ml), nur ohne eindeutigen Code.

Features

  • Barcode-Lookup über Open Food Facts und Open Products Facts mit lokalem Fallback; unbekannte Produkte selbst anlegen, Bild wird automatisch geholt.
  • Chargen mit MHD & FEFO, Mengen in Packungen oder Teilmengen (Basiseinheit Stück / Gramm / Milliliter plus Packungsgröße/Gebinde).
  • Lagerorte beliebig verschachtelt (Keller → Regal 2 → Fach A), mit QR-Etiketten, Inhaltsansicht („was liegt hier?“), Umlagern und Entfernen mit Grund. Chargen und Einzelstücke sind einem Lagerort zugeordnet.
  • Kategorien verschachtelt und pro Typ (Lebensmittel/Gegenstand); für Gegenstände mit eigenen Feldern (z. B. Kapazität, Größe, Farbe).
  • Gruppen rechnen Bestände mehrerer Marken/Artikel zusammen (z. B. „5 kg Mehl“) mit eigenem Mindestbestand und Einheit.
  • Mindestbestände je Produkt und Gruppe gesamt und je Lagerort mit zentraler Übersichtsseite, daraus die automatische Einkaufsliste und Ablaufwarnung für bald ablaufende Chargen.
  • Übergreifende Listen für Produkte (getrennt Lebensmittel/Gegenstände), Einzelstücke und Chargen filter-, sortier- und spaltenkonfigurierbar; bei Chargen lässt sich der Lagerort mehrerer auf einmal setzen.
  • Dashboards mit konfigurierbaren Karten und Diagrammen, Verlauf (wer hat wann was ein-/ausgelagert), Stammdaten (Einheiten, Gebinde, Shops) und Import/Export.
  • Mehrbenutzer mit Rollen: Admin verwaltet Stammdaten und Benutzer, Nutzer lagert nur ein/aus und sieht Bestände; alle Bewegungen werden protokolliert.

In der iOS-App zusätzlich

  • Scannen von Barcode, MHD/Datum per Texterkennung (auch nur Tag+Monat ohne Jahr bei Frischware), Lagerort-QR und Name/Marke per Text-Scan.
  • Foto direkt beim Anlegen (Kamera/Galerie), Push-Benachrichtigungen bei ablaufenden Produkten, lokale Dashboards und Home-Screen-Schnellaktionen.

Details zur App: ios/README.md.

Architektur

Teil Technik
Backend Python · FastAPI · SQLAlchemy
DB PostgreSQL (SQLite für Tests/lokal)
Web-UI React · Vite (via nginx ausgeliefert)
iOS Native SwiftUI-App (VisionKit-Scanner)
Deploy Docker Compose · install.sh
backend/   FastAPI-App + Tests
web/        React/Vite SPA
ios/        Native SwiftUI-App (XcodeGen-Projekt)
deploy/     docker-compose.yml, install.sh, update.sh, .env.example
docs/       Roadmap

Das Schema wird beim Start per idempotenter ALTER TABLE-Migration in backend/app/main.py nachgezogen (kein Alembic).

Installation (selfhosted, Linux)

Voraussetzung: eine Linux-Maschine (Server, NAS, Raspberry Pi …). Docker wird bei Bedarf automatisch installiert.

git clone https://git.scarriffle.com/Scarriffle/vorrania.git
cd vorrania/deploy
chmod +x install.sh
./install.sh            # interaktiv  fragt Port & Admin-Passwort
# oder vollautomatisch mit generiertem Admin-Passwort:
# ./install.sh --yes

Ist das Gitea-Repo privat, fragt git clone nach Benutzername + Access-Token. Falls git fehlt: apt update && apt install -y git.

Nach dem Start:

  • Web-UI: http://<server-ip>:8080 (Port konfigurierbar)
  • Anmeldung mit dem im Installer angezeigten Admin-Benutzer/Passwort.

Die iOS-App wird mit derselben Adresse verbunden (http://<server-ip>:8080).

Aktualisieren

cd vorrania/deploy
./update.sh                # holt den neuesten Stand aus Git und baut neu
./update.sh --prune        # zusätzlich alte Images aufräumen
./update.sh --no-pull      # nur neu bauen, ohne git pull

Das Skript ist von überall aufrufbar, nutzt die vorhandene deploy/.env und prüft am Ende, ob das Backend wieder erreichbar ist.

Verwaltung:

cd deploy
docker compose logs -f     # Logs ansehen
docker compose down        # stoppen
docker compose up -d       # starten

Die Konfiguration liegt in deploy/.env (Passwörter, Port, JWT-Secret). Für den Produktivbetrieb bitte hinter einen HTTPS-Reverse-Proxy (z. B. Caddy/Traefik) stellen.

Entwicklung (ohne Docker)

Backend:

cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# lokale SQLite-DB nutzen:
export DATABASE_URL="sqlite:///./vorrania.db"
uvicorn app.main:app --reload

API-Doku dann unter http://localhost:8000/docs.

Web:

cd web
npm install
npm run dev     # http://localhost:5173, proxyt /api → localhost:8000

iOS: siehe ios/README.md (XcodeGen-Projekt, xcodegen generate).

Tests:

cd backend
pip install -r requirements.txt
DATABASE_URL="sqlite://" pytest

Weiteres

Fahrplan und Ideen: docs/ROADMAP.md.

Description
No description provided
Readme 5.7 MiB
Languages
Swift 32.7%
JavaScript 31.7%
Python 31.4%
CSS 3.4%
Shell 0.7%