Files
Vorrania/docs/ROADMAP.md
T
ScarriffleandClaude Opus 5 aa72d8342a App: Einzelstuecke verleihen - alle Scan-Wege enden schon dort
Verleih-Abschnitt im Einzelstueck: an wen, seit wann, bis wann, dazu
Herausgeben bzw. Zuruecknehmen und der Verleih-Verlauf. Pflicht ist nur der
Name; Grund und Rueckgabedatum sind abschaltbar, weil "kurz mal
mitgenommen" nicht an einem Datum scheitern soll.

Der Abschnitt sitzt bewusst oben in ItemEditView, und zwar nicht nur der
Wichtigkeit wegen: QR ueber Nachschlagen, eingenaehtes NFC-Tag und ein
angetipptes Tag (vorrania://i/<UID>) landen alle in genau dieser Ansicht.
Damit ist "scannen und verleihen" ueberall moeglich, ohne einen eigenen
Weg dafuer zu bauen.

In der Einzelstueck-Liste steht der Verleih unter dem Stueck - ueberfaellig
in Rot - und das Filter-Menue kann auf Verliehen, Ueberfaellig oder Im Haus
eingrenzen. Wo etwas ist, war bisher immer der Lagerort; ist es verliehen,
ist der Entleiher die Antwort, und der Lagerort steht daneben.

days_overdue rechnet der Server (GET /loans, ItemOut.loan), damit App und
Web nicht getrennt rechnen und nicht auseinanderlaufen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 09:36:05 +02:00

9.4 KiB
Raw Blame History

Vorrania – Roadmap

Selfhostbare Lebensmittel-Lagerverwaltung. Aufbau in mehreren Schritten.

Schritt 1 – Fundament ✅

  • Backend (FastAPI + PostgreSQL): Datenmodell, Auth mit Rollen (Admin/Benutzer), Chargen mit MHD, FEFO-Auslagern, Open-Food-Facts-Lookup (v0-API) mit lokalem Fallback.
  • Web-UI (React/Vite): Login, Dashboard, Ein-/Auslagern, Produkte, Lagerorte, Benutzerverwaltung, Einkaufsliste.
  • Deployment: Docker Compose + install.sh (Docker-/curl-Autoinstall, Secrets, erster Admin, Health-Check), README.
  • Tests: pytest für FEFO, Einheiten-Umrechnung und OFF-Mengenerkennung.

Schritt 1b – Ausbau Web-UI ✅

  • Design: professionelles Layout mit Seitenleiste, eigenes SVG-Icon-Set (bewusst keine Emojis), Light-/Dark-Mode, konsistente Farbcodierung (gelb = Warnfrist, rot = abgelaufen).
  • Gruppen: Verwaltung, Zuordnung im Produkt, Gruppen-Mindestbestand mit Einheit, Auto-Zuordnungsvorschlag aus der OFF-Kategorie.
  • Einheiten (verwaltbar): eigene Tabelle mit Art (Anzahl/Gewicht/Volumen) und Umrechnungsfaktor. Eingebaut: Stück, Gramm, Kilogramm, Milliliter, Liter. Admins können weitere anlegen (z.B. Pfund = 500 g). Gilt für Produkte und Gruppen-Mindestbestände; Bestände werden intern in der kanonischen Basiseinheit (Stück/Gramm/Milliliter) gespeichert.
  • Einlagern: Drei-Wege-Barcode-Erkennung (bekannt / bei OFF gefunden → inline anlegen / unbekannt), mehrere Chargen je Vorgang mit eigenem MHD, Warnung bei bereits abgelaufenem MHD.
  • Auslagern: automatisch per FEFO oder gezielte Auswahl einer Charge/MHD, auch Teilmengen.
  • Chargen bearbeiten: Menge/MHD korrigieren und Chargen löschen (mit Protokollierung als Korrektur-Bewegung).
  • Lagerorte: beliebig tief verschachtelbar (Schrank → Fach → Kiste → …).
  • Mindestbestände: je Produkt wahlweise in der Produkteinheit oder in Packungen.
  • Verlauf: Bewegungsprotokoll (wer/was/wann), Einstellungen: Ablauf-Warnfrist.
  • Import / Export: CSV (eine Zeile je Charge, in Excel bearbeitbar) und JSON (vollständiges Backup inkl. Einheiten, Gruppen, Lagerorte). Der Import ist rein additiv – unbekannte Produkte/Gruppen/Lagerorte werden angelegt, Chargen ergänzt, nichts gelöscht oder überschrieben.
  • Migration: schonendes Nachziehen neuer Spalten beim Start (ADD COLUMN IF NOT EXISTS), damit bestehende Installationen ihre Daten behalten.

Schritt 2 – Native iOS-App (SwiftUI) ✅

  • Login (Server-URL + Passwort, Token im Keychain), „angemeldet bleiben“ abwählbar.
  • Barcode-Scan (AVFoundation) mit Nahbereich-Autofokus, Licht und Tippen zum Scharfstellen.
  • Einlagern-Flow: scannen → Lookup/Vorbefüllung → Menge + Einheit + MHD (mehrere Chargen).
  • MHD per Texterkennung ablesbar (VisionKit); erkannte Daten werden vorgeschlagen, nie ungefragt übernommen.
  • Auslagern-Flow: scannen → Menge/Einheit, FEFO oder Chargenauswahl.
  • Einkaufsliste, „bald ablaufend“ und Produktliste mit Bearbeiten.
  • Home-Screen-Shortcuts und URL-Schema vorrania://checkin / checkout.
  • Anzeige folgt dem Datumsformat aus den Servereinstellungen.

Schritt 2b – MHD-Genauigkeit und Benennung ✅

  • MHD wahlweise nur mit Monat und Jahr. Gespeichert wird weiterhin ein echtes Datum (Monatsletzter), damit FEFO unverändert arbeitet; die Genauigkeit steht getrennt an Charge und Produkt. Export/Import bleiben verlustfrei.
  • Kategorien als eigene Ebene neben den Gruppen. Zuvor wurden beide Begriffe vermischt – aus der Open-Food-Facts-Kategorie wurde sogar eine Gruppe geraten. Jetzt getrennt: Die Gruppe zählt Bestände mehrerer Marken zusammen (Mindestbestand, EAN-Codes), die Kategorie ordnet nur die Artikelliste und ist verschachtelbar (Süßwaren → Schokolade). Mitgelieferte Startliste, Vorschlag aus der OFF-Einordnung, Filter in App und Web.
  • EAN-Codes an der Gruppe werden automatisch gepflegt: Beim Zuordnen eines Artikels landet sein Code dort, beim Gruppenwechsel wandert er mit, beim Löschen verschwindet er. Vorher blieb die Codeliste einer Gruppe leer, obwohl Artikel darin lagen.
  • Eigenes Logo und Favicon je Installation (Einstellungen → Darstellung).

Schritt 2c – Modulare Startseite mit Auswertungen ✅

  • Raster statt fester Seite: Die Übersicht besteht aus Karten, die sich ziehen, in der Größe ändern und einrasten lassen (react-grid-layout, 12 Spalten). „Anordnen" schaltet das frei, gespeichert wird ausdrücklich.
  • Pro Benutzer eigene Anordnung (dashboard_layouts, user_id = NULL ist die Admin-Vorgabe). Admins speichern eine Vorgabe für alle und können sie über dashboard_enforced auch verbindlich setzen; Benutzer setzen jederzeit auf die Vorgabe zurück.
  • 15 Karten im Verzeichnis web/src/dashboard/cards.jsx: Schnellzugriff, Status, zwei Kennzahlen, Bald ablaufend, Abgelaufen, Einkaufsliste, letzte Bewegungen sowie sechs Auswertungen. Eine neue Karte ist ein Eintrag mehr.
  • Diagramme als eigene SVG-Komponenten (kein Diagramm-Paket): Ring, gestapelte Balken, Linie mit Fadenkreuz. Zustandsfarben (ok/bald/abgelaufen) sind Statusangaben aus den Tokens und stehen nie ohne Beschriftung; Kategorien nutzen eine geprüfte Farbreihe in fester Ordnung, ab sieben Kategorien wird zu „Andere" gebündelt. Hell und Dunkel haben eigene Stufen.
  • Alle Mengen in Artikeleinheiten (Gläser, Packungen, Stück). Gramm und Stück lassen sich nicht addieren – Gebinde schon. Der Helfer dafür liegt jetzt einmal zentral in backend/app/services/conversion.py::article_unit.
  • Verlauf wird aus den Bewegungen rückwärts vom heutigen Bestand rekonstruiert. Bekannte Ungenauigkeit: Die Umrechnung nutzt die heutige Packungsgröße; wird sie später geändert, verschiebt sich auch die Historie.

Schritt 2e – Verleih von Einzelstücken (Backend ✅, Oberfläche offen)

  • Eigene Tabelle item_loans statt eines Lagerort-Werts „verliehen". Der Lagerort am Stück bleibt stehen und sagt weiter, wohin es nach der Rückgabe zurückgehört; ein Lagerort-Wert hätte diese Information vernichtet. Je Vorgang: Entleiher (Freitext), Grund (Freitext, optional), Verleihdatum, erwartetes Rückgabedatum (optional – „kurz mal mitgenommen" soll nicht an einem Datumszwang scheitern) und das Konto, das herausgegeben hat.
  • Zurückgegebene Verleihe bleiben stehen (returned_on gesetzt) – damit ist die Tabelle gleichzeitig die Verleih-Historie je Stück. Ein Teilindex auf die offenen Vorgänge sichert ab, dass ein Stück nicht zweimal gleichzeitig verliehen ist.
  • Verliehen heißt nicht im Bestand. Ein verliehenes Stück zählt nirgends mehr mit – weder am Lagerort noch im Gesamtbestand. Entschieden wird das an einer Stelle (services/loans.py::nicht_verliehen), die alle fünf Zählungen benutzen. „Was liegt hier?" behauptet damit nicht länger, das Stück liege im Regal. Folge: Fällt es unter den Mindestbestand, erscheint der Artikel auf der Einkaufsliste – gewollt, aber gut zu wissen.
  • Verleihen darf jeder angemeldete Benutzer (es ist eine Buchung wie Ein- und Auslagern, keine Stammdatenänderung) und wird mit dem Konto protokolliert. Nur das Löschen eines Vorgangs bleibt Admins vorbehalten, weil es Historie vernichtet.
  • Bewusst keine Movement-Bewegung je Verleih: Der Verlauf rechnet den Bestand rückwärts aus vorzeichenbehafteten Bewegungen – ein Abgang ohne Gegenbuchung würde diese Kurve verfälschen.
  • Web-Oberfläche: Verleihen und Zurücknehmen in der Einzelstück-Tabelle eines Artikels und in der Liste aller Einzelstücke (Spalten „Verliehen an" und „Zurück bis", filter- und sortierbar), zwei Dashboard-Karten („Verliehen", „Überfällige Verleihe") und der Verleih-Verlauf je Stück. Überfällig ist rot, demnächst fällig gelb – dieselben Zustandsfarben wie beim MHD.
  • Nach dem Scannen direkt verleihen: Das Ziel eines Einzelstück-QR bzw. NFC-Tags (/i/<uid>) leitete vorher nur zum Artikel weiter. Jetzt zeigt es, was man in der Hand hält, und bietet Verleihen bzw. Zurücknehmen an der Stelle an – Gegenstück zur Lagerort-Seite (/l/<code>).
  • iOS-App: Verleih-Abschnitt im Einzelstück mit Herausgeben und Zurücknehmen, Verleih-Verlauf, Zustand in der Einzelstück-Liste und ein Filter Verliehen / Überfällig / Im Haus. Weil alle Scan-Wege (QR über Nachschlagen, NFC-Tag, vorrania://i/<UID>) in derselben Ansicht enden, ist „scannen und verleihen" damit überall möglich, ohne einen eigenen Weg dafür.
  • Noch offen: die Rückgabe-Erinnerung. Sie kann nur den Weg der Ablauf-Meldungen gehen (lokale Benachrichtigung der App aus einem Server-Snapshot, GET /loans?due_in=… ist dafür schon die Datenquelle) – echtes Push fehlt weiterhin, siehe Schritt 3. Beachten: iOS erlaubt 60 geplante Meldungen je App, die sich Verleih und MHD dann teilen müssen.

Schritt 3 – Weitere Ideen – offen

  • Ablauf-Push-Benachrichtigungen via APNs (setzt die App voraus).
  • Einkaufsliste verfeinern: Abhaken dauerhaft speichern, manuelle Einträge, Mengenvorschläge in Packungen.
  • Statistik/Auswertung über den Bewegungsverlauf (Verbrauch pro Zeitraum).
  • Lagerort beim Auslagern berücksichtigen bzw. pro Charge wählbar beim Einlagern.
  • Produktbilder lokal cachen (aktuell direkt von Open Food Facts geladen).
  • Alembic-Migrationen statt create_all + Startup-ALTER, sobald das Schema stabil ist.