Neue wiederverwendbare DataTable: feste Filterzeile je Spalte (Freitext + Dropdown der vorhandenen Werte, ueber Spalten kombinierbar), Spalten per Drag verschieben und in der Breite ziehen, Klick-Sortierung; Reihenfolge/Breiten merkt der Browser (localStorage). Produkte-Seite darauf umgestellt. Tabellenseiten (Produkte/Kategorien/Gruppen/Einheiten/Gebinde) nutzen jetzt die volle Fensterbreite (content--wide); Kategorien-Seitenspalte etwas breiter und die Feldliste bricht um, statt ueber den Container zu laufen. Farbschema unveraendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Klick aufs Artikelbild oeffnet es bildschirmfuellend; Schliessen per Knopf, Klick auf den Hintergrund oder Escape. Neue Lightbox-Komponente (Portal an <body>), im bestehenden Farbschema.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die .content-Spalte war global auf max-width 1400px gedeckelt - gut fuer Tabellen/Formulare, aber das Dashboard-Raster klebte dadurch auf breiten Bildschirmen links mit viel Leerraum. Die Dashboard-Routen bekommen jetzt .content--wide (max-width: none), sodass das Raster (react-grid-layout, WidthProvider) die ganze Breite ausmisst und fuellt. Andere Seiten bleiben auf Lesebreite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der 'Preis-Vorschlag aus Beleg' stand mit Kaufpreis, Waehrung und Datei-Auswahl in einer Zeile und wirkte gequetscht. Jetzt bleibt die Preiszeile zweispaltig (Kaufpreis | Beleg) und der Vorschlag bekommt eine eigene Zeile darunter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1) Beleganalyse erkennt Datumsangaben mit Monatsnamen (DE+EN, z.B. Amazon 'Bestelldatum 29 April 2026'), nicht nur 29.04.2026 - so wird das Kaufdatum solcher Rechnungen gefunden. 2) Beim direkten Anlegen eines Einzelstuecks mit Beleg werden jetzt alle erkannten Preise als Vorschlag angeboten (Dropdown), statt stillschweigend nur den wahrscheinlichsten zu nehmen. 3) Alle Lagerort-Dropdowns zeigen den vollen Pfad (Hedingen -> Keller -> Schublade 1) statt nur den Namen, damit gleichnamige Orte unterscheidbar sind.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CategorySelect wandelte den Wert per Number() um - bei den neuen Lagerort-Codes (Zeichenkette) ergab das NaN, sodass die Anzeige auf 'keiner' zuruecksprang, obwohl korrekt gespeichert wurde. Wert jetzt unveraendert nehmen und typunabhaengig (String-Vergleich) markieren, damit Zahl-IDs (Kategorien) wie Code-IDs (Lagerorte) passen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lagerort-IDs sind jetzt ein zufaelliger 10-Zeichen-Code (wie die Einzelstueck-UIDs) statt einer fortlaufenden Zahl - so kollidiert die Stammdaten-Sicherung zwischen zwei Instanzen praktisch nie mehr, und der Code ist zugleich der Inhalt des QR /l/<code>. Alle Fremdschluessel (lots, movements, items, Mindestbestaende, parent_id) ziehen mit; die Umstellung laeuft einmalig und transaktional beim Serverstart (_migrate_locations_to_code) und rollt bei Fehlern komplett zurueck. Vor dem Deploy ein DB-Backup machen.
iOS-Einlagern oeffnet nicht mehr sofort die Kamera, sondern ein Formular mit Artikelsuche; die Kamera kommt erst per Button. Im Formular laesst sich der Lagerort zusaetzlich per /l/-QR scannen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Backend: services/master_data.py exportiert/importiert Kategorien (inkl.
eigener Felder), Lagerorte, Einheiten und Gebinde als JSON – MIT IDs, damit
gedruckte QR-Codes und Verweise nach dem Wiederherstellen passen. Import-Modus
skip (Vorhandenes lassen) oder overwrite (per ID aktualisieren); Namens-
Konflikte werden uebersprungen, nicht abgebrochen. Postgres-Sequenzen werden
danach angehoben. Endpunkte GET /export/master-data, POST /import/master-data.
5 neue Tests, Suite 162 gruen.
- Web: neue Karte "Stammdaten sichern & wiederherstellen (JSON)" in Import/Export.
- Web: beim Lagerort-Anlegen bleibt der uebergeordnete Ort in der Auswahl.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Abschnitt in Import/Export: exportiert je Lagerort eine Zeile
(QR-Inhalt = Link auf den Ort, ID, Name, Pfad "Hedingen → Keller") als CSV mit
demselben wählbaren Trennzeichen wie der Einzelstück-Export und derselben
Formel-Injektion-Härtung. Client-seitig aus den Lagerorten gebaut.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Web: der übergeordnete Lagerort wird beim Anlegen jetzt über den
aufklappbaren Baum (CategorySelect) gewählt statt über das flache Dropdown.
- Backend: Mindestbestand je Lagerort wird jetzt gegen den Bestand INKL. aller
Unter-Lagerorte geprueft. Ein Bedarf auf „Hedingen" gilt also als gedeckt,
wenn der Vorrat in „Hedingen -> Keller" liegt. Helfer
location_subtree_stock_base; 2 neue Tests, Suite 157 gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Anlege-Maske: Kaufpreis (+Währung) und Beleg-Upload. Beim Datei-Auswählen wird
der Beleg analysiert (ohne Speichern) und Kaufdatum/Garantie/Preis/Shop
vorbefuellt; ein erkannter, noch nicht hinterlegter Shop wird beim Anlegen
erstellt. Der Beleg haengt an das erste angelegte Stueck.
- Beleg-Vorschlag (bestehende Stuecke) zeigt/uebernimmt jetzt auch Kaufdatum und
Shop (bekannter Shop zuweisen, sonst anlegen).
- API analyzeItemDocument.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Neuer LocationMinStock-Editor (Zeilen: Lagerort + Menge, separat speichern).
- Produktformular: Abschnitt „Mindestbestand je Lagerort" (Menge in Artikel-
einheit), zusaetzlich zum Gesamt-Mindestbestand.
- Gruppen: je Gruppe ein Editor „Mindestbestand je Lagerort".
- Einkaufsliste: Abschnitt „Bedarf: <Lagerort>" mit Produkten und Gruppen, die
am Ort unter dem dort hinterlegten Mindestbestand liegen.
- API-Methoden set*LocationMinStock und shoppingByLocation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Findet die Beleg-Analyse mehrere Beträge, liefert der Upload jetzt eine
Kandidatenliste (bester Tipp zuerst). Web und iOS bieten dann ein Dropdown zur
Auswahl des richtigen Kaufpreises, statt nur den automatischen Tipp. 1 neuer
Test; Backend-Suite gruen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Haken zum Ein-/Ausblenden von "Ohne MHD" ist eine Karten-Einstellung und
erscheint jetzt nur, wenn das Dashboard bearbeitet wird (.dash-grid.editing).
In der normalen Ansicht bleibt er verborgen, die gewaehlte Einstellung wirkt
aber weiterhin.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Ablauf-Ring-Karte bekommt einen Umschalter, ob der Anteil "Ohne MHD"
(Gegenstaende/undatierte Chargen) mitgezaehlt wird. Aus zeigt der Ring nur
In Ordnung/Bald/Abgelaufen mit entsprechend neu berechneten Prozenten. Die Wahl
wird in localStorage gemerkt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Waehlt man beim P-touch-Export eine Kategorie, schliesst der Server ihre
Unterkategorien mit ein – das war im UI nicht sichtbar. Jetzt erscheinen die
Unterkategorien einer gewaehlten Kategorie als „enthalten" (angehakt,
deaktiviert, gedimmt); gewaehlte Oberkategorien mit Unterkategorien tragen
„inkl. Unterkategorien", nicht gewaehlte einen „+ Unterkategorien"-Hinweis. Der
Einleitungstext erklaert es zusaetzlich.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"Foto machen"/"Galerie" sind <label> und erbten das margin-bottom des globalen
label-Stils, wodurch sie hoeher sassen als der "Entfernen"-<button>. margin:0
an den Foto-Knoepfen stellt alle drei auf eine Hoehe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Barcode-Zeile: Eingabefeld fuellt die Breite, die beiden Knoepfe (Nachschlagen
+ Vergleichen) stehen nebeneinander statt gestapelt – keine Luecke mehr rechts.
- Foto: "Entfernen" ist jetzt ein normaler Button wie "Foto machen"/"Galerie"
(gleiche Hoehe/Ausrichtung) statt reiner Text.
- Umschalter "Typ"/"Verwaltung": Abstand zwischen Beschriftung und Segmenten.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die blaue Hinterlegung der Detailzeile (Preis/Belege) entfernt; Stück-Zeile und
Detailzeile bilden jetzt eine zusammenhaengende Ansicht ohne Trennlinie
dazwischen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Anlege-Maske war ein grosses, dauerhaft sichtbares Formular. Jetzt klappt
sie hinter einen "Einzelstück anlegen"-Knopf. Dafuer werden Kaufpreis und Belege
je Stueck nicht mehr ueber einen Aufklapp-Knopf versteckt, sondern direkt unter
jeder Zeile angezeigt (leicht abgesetzte Detailzeile).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Je Einzelstück eine ausklappbare Detailzeile: Kaufpreis (Betrag + CHF/EUR) und
Belege (Rechnung/Garantieschein) hochladen, ansehen, löschen. Nach dem Upload
eines PDFs schlägt der Server „Garantie bis" und Kaufpreis vor – per Knopf
übernehmbar. Belege werden mit Anmeldung geladen (kein offener Zugriff).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zellen, die mit = + - @ (oder Tab/CR) beginnen, werden mit einem vorangestellten
Apostroph zu Text entschaerft. So fuehrt ein Produktname wie "=HYPERLINK(...)"
beim Oeffnen der Etiketten-CSV in Excel/P-touch nicht mehr als Formel aus.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bestehende Lagerorte lassen sich jetzt nachträglich einem anderen Elternort
zuordnen oder auf die oberste Ebene holen.
- Backend: LocationUpdate um parent_id (Name jetzt optional); update_location
haengt um, mit Schutz gegen Ringe (weder auf sich selbst noch auf einen
eigenen Unterort) und Existenzpruefung des Ziels. 6 Tests.
- Web: Lagerorte-Seite bekommt je Ort Bearbeiten (Name + Elternort ueber den
CategorySelect-Baum, eigene Unterorte ausgeschlossen); api.updateLocation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Backend und API-Client konnten Felddefinitionen laengst aendern (PATCH), nur die
Oberflaeche bot bisher nur Anlegen und Loeschen. In der Felder-Verwaltung einer
Kategorie gibt es jetzt je Feld einen Bearbeiten-Knopf: er laedt Name, Typ,
Einheit, Auswahlmoeglichkeiten und Pflicht ins Formular; Speichern aktualisiert
das Feld (oder Abbrechen). Geerbte und eingebaute Felder bleiben unveraendert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Statt der nativen "— —"-Dropdowns nutzen jetzt auch Produktformular
(Kategorie + Inline-"Neue Kategorie"-Elternwahl), Einlagern-Maske und
Produkte-Filter den CategorySelect-Baum. CategorySelect um optionale
Zusatz-Eintraege (extraOptions) erweitert, damit der Produkte-Filter
"Alle Kategorien"/"Ohne Kategorie" weiter anbietet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Der Entfernen-Knopf stand auch ohne Bild da. ProduktBild meldet jetzt via
onLoaded, ob ein Bild geladen wurde; das Produktformular blendet "Entfernen"
entsprechend ein oder aus. "Foto machen" und "Galerie" bleiben immer sichtbar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Kategorien und Gruppen standen in der Alltags-Navigation, obwohl sie – wie
Lagerorte, Shops, Einheiten und Gebinde – nur von Admins gepflegte Katalog-
Stammdaten sind. Jetzt sind alle Stammdaten zusammen im Admin-Bereich, der in
zwei Abschnitte gegliedert ist:
- Stammdaten: Kategorien, Gruppen, Lagerorte, Shops, Einheiten, Gebinde
- System: Benutzer, Import/Export, Einstellungen
Normale Nutzer sehen nur noch den Alltag (Uebersicht, Ein-/Auslagern, Produkte,
Einkaufsliste, Verlauf). /categories und /groups sind jetzt Admin-Routen. Das
entspricht der Gliederung der iOS-App.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auswertungen (by_category, expiry_split, stats) iterierten nur Lots. Gegenstaende
mit Menge-je-Lagerort liegen als Lots und tauchten auf – Einzelstuecke liegen
aber als Items und fehlten dadurch komplett (Dashboard zeigte z.B. nur die
Powerbank, nicht Kamera/Kabel). Neuer Helfer _bestand_beitraege deckt beide
Speicherformen ab: jedes Item zaehlt als ein Stueck ohne MHD. Regressionstest
ergaenzt; volle Suite gruen (120).
CategorySelect: Scrollen IM aufklappbaren Menue schloss es, weil jeder Scroll als
Seiten-Scroll gewertet wurde. Jetzt schliesst nur ein Scroll ausserhalb des
Menues; die lange Liste laesst sich scrollen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die uebergeordnete Kategorie wird nicht mehr ueber ein <select> mit
"— —"-Einrueckung gewaehlt, sondern ueber einen aufklappbaren Baum-Picker
(CategorySelect): echte Einrueckung, Aeste per Pfeil auf-/zuklappbar wie in der
Liste. Das Menue haengt per Portal am <body>, damit der horizontal scrollende
Tabellenrahmen es nicht abschneidet. Ersetzt beide Stellen (Zeilen-Elternwahl
und Anlege-Formular); die kompakten Knoepfe machen die Zeile schmaler, sodass
die Tabelle nicht mehr seitwaerts ueber den Block hinauslaeuft.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
P-touch will Komma, wir hatten fest Semikolon - jetzt einstellbar und in
localStorage gemerkt, sodass man es nur einmal setzt. Standard ist Komma.
Anfuehrungszeichen werden passend zum gewaehlten Trennzeichen gesetzt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auf "Import / Export" neue Karte: Kategorien auswaehlen (inkl. Unterkategorien)
und je Einzelstueck eine CSV-Zeile herunterladen - Spalten QR-Inhalt (…/i/<UID>),
UID, Produkt, Marke, Kategorie, Lagerort. In der Etiketten-Software als Datenbank
verknuepfen, dann entsteht QR + Text automatisch - kein einzelnes Bild-Download
und Zuordnen mehr.
Backend: GET /export/labels?category_ids=... liefert die Zeilen (JSON); den
QR-Inhalt setzt das Web mit window.location.origin dazu.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Server liefert /.well-known/apple-app-site-association (nur /i/* beansprucht;
/l/* bleibt im Browser). iOS: Associated-Domains-Entitlement, Universal Link
(https://…/i/<UID>) wird abgefangen (onContinueUserActivity) und öffnet das
Einzelstück direkt.
Hinweis: Damit das Signieren durchläuft, muss die Capability "Associated
Domains" einmalig im Apple-Developer-Portal für die App-ID aktiv sein.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Web: druckbare QR-Etiketten fuer Lagerorte (Locations-Seite) und Route /l/<id>
(zeigt den Ort im Browser). Geteilter QR-Helfer (web/src/qr.jsx).
iOS: neuer Ablauf "Ort zuordnen" - erst Einzelstueck-QR (…/i/<UID>) scannen, dann
Lagerort-QR (…/l/<ID>); das Stueck wird dem Ort zugewiesen, danach gleich das
naechste. Plus die zuvor gebaute "Nachschlagen"-Kachel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gegenstands-Produkte haben jetzt den Umschalter "Menge je Lagerort / Einzelstücke".
Bei Einzelstücken erscheint (volle Breite) eine Liste je Stueck mit eigener UID,
QR-Code, Lagerort, Kaufdatum, Garantie, Bezugsquelle und Notiz - direkt inline
aenderbar, mit Entfernen (Grund) und druckbaren QR-Etiketten. Ein Scan oeffnet
ueber die Route /i/<uid> das passende Stueck. QR via qrcode (gebundelt, offline).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Durch die neue Spalte "Uebergeordnet" wurde die Kategorie-Tabelle im halben Grid
zu breit und scrollte seitwaerts. Die Kategorien-Seite nutzt jetzt das
wide-aside-Layout; dessen Block daneben ist zudem schmal gedeckelt (clamp), damit
die Tabelle den restlichen Platz bekommt. Gilt auch fuer die Gruppen-Seite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In der Kategorien-Verwaltung gibt es je Zeile eine Spalte "Uebergeordnet" mit
Auswahl - so laesst sich eine (Unter-)Kategorie unter eine andere haengen oder
auf die oberste Ebene holen. Zielauswahl auf denselben Typ beschraenkt und um die
eigenen Unterkategorien bereinigt; das Backend verhindert Ringe zusaetzlich.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zum leichteren Unterscheiden gibt es in der Produkte-Liste und in der
Kategorien-Verwaltung einen Umschalter Alle/Lebensmittel/Gegenstaende. Er filtert
die jeweilige Liste und in der Produktsuche auch die Kategorieauswahl auf den Typ.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Statt die Verwaltungsart nur implizit ueber die Kategorie zu waehlen (und dabei
Werkzeug & Co. zwischen 50 Lebensmittel-Kategorien zu suchen), gibt es jetzt oben
einen klaren Umschalter. Die Kategorieauswahl zeigt nur Kategorien des gewaehlten
Typs; neu angelegte Kategorien erben den Typ automatisch. Neuanlage startet als
Gegenstand, beim Bearbeiten kommt der Modus aus dem Artikel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- nginx client_max_body_size auf 12m (Standard 1 MB loeste beim Bild-Upload
einen 413 aus, bevor das Backend den Upload sah).
- Backend-Bildlimit auf 8 MB angehoben, bleibt unter dem nginx-Limit, damit
Uebergroesse eine klare 400-Meldung statt eines nackten 413 ergibt.
- Web: Foto vor dem Upload clientseitig verkleinern (max 1600px, JPEG) -
schneller, kleiner in der DB, zuverlaessig unter dem Limit.
- iOS: Kamera ueber fullScreenCover statt sheet und Schliessen deterministisch
ueber ein Binding - behebt das "Kamera geht direkt wieder zu"-Flackern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bei Gegenstaenden fragt das Backend Open Products Facts ab, bei Lebensmitteln
Open Food Facts. Die sichtbaren Texte (Vergleichs-Button, Toasts, das
Gegenueberstellungs-Panel) nannten aber immer "Open Food Facts". Jetzt richtet
sich die Beschriftung nach der Verwaltungsart der Kategorie.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Web: Kategorien/Unterkategorien und eigene Felder direkt im Artikelformular
anlegen (ohne Umweg über die Kategorien-Seite).
- Artikelfoto per Kamera oder Galerie hochladen – Backend-Endpunkt
(PUT/DELETE /products/{id}/image), Web (Foto machen / Galerie) und iOS
(Kamera + PhotosPicker, inline in der Produktansicht angezeigt).
- CSV-Import: neue Spalte "art" (Gegenstand/Lebensmittel) steuert den Modus
automatisch angelegter Kategorien; Export schreibt sie mit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Kategorie bestimmt die Verwaltungsart (food/object). Gegenstaende:
Menge je Lagerort statt Chargen/MHD, Umlagern (ohne Grund) und Entfernen
mit Pflicht-Grund samt Entnahme-Statistik. Beliebig viele eigene Felder
je Kategorie (vererbt an Unterkategorien), "gekauft bei" ueber eine
verwaltbare Shop-Liste und ein Produktlink. Barcode-Lookup zusaetzlich
ueber Open Products Facts.
Der Lebensmittel-Teil (Chargen/MHD/FEFO) bleibt unveraendert. Umgesetzt in
Backend (FastAPI, +Tests gruen), Web (React) und iOS (SwiftUI).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Die Ein-/Auslagern-Karten schickten unit: "article" - eine Einheit, die der
Server nicht kennt (services/units.py akzeptiert nur package/packung bzw. die
Basiseinheiten g/ml/stück). Jede Buchung ueber die Karte scheiterte damit an
"Unbekannte Einheit: article", in der Web-Oberflaeche wie in der App.
Jetzt wird die Menge in Artikeleinheiten gebucht: gibt es ein Gebinde, ist das
eine Packung, sonst die Basiseinheit des Produkts. Gegen ein laufendes Backend
geprueft (package und Basiseinheit je 200).
Aufgefallen beim Testen der Ablauf-Benachrichtigungen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drei Dinge in einem, weil sie dieselbe Umstellung brauchen.
Karten sind jetzt Instanzen: Die Anordnung merkt sich neben der Kennung auch
die Art und ein "props" je Karte. Dadurch laesst sich dieselbe Art mehrfach
auflegen, und "Verlauf eines Artikels" merkt sich endlich, welcher Artikel
gemeint ist - vorher lag diese Wahl nur in useState und war nach jedem
Neuladen wieder weg, was die Karte zum Beobachten unbrauchbar machte. Wer
mehrere Artikel im Blick haben will, legt jetzt einfach mehrere Karten an.
Mehrere Dashboards stehen als eingerueckte Eintraege unter "Übersicht" in der
Seitenleiste, anlegen und umbenennen laeuft ueber die Kopfzeile. Ab dem
zweiten werden sie aufgezaehlt; bei einem einzigen waere die Liste nur eine
Verdopplung.
Neu sind die Karten "Einlagern" und "Auslagern": Artikel suchen, Menge
eintragen, gebucht. MHD und Lagerort bleiben bewusst weg - wer die braucht,
ist auf der vollen Seite besser aufgehoben. Die alte Karte "Schnellzugriff"
bleibt als reine Verlinkung bestehen.
Der Bestaetigungsdialog kann jetzt auch nach Text fragen (prompt: true). Das
war noetig, weil Dashboards benannt werden - und window.prompt sieht aus wie
der Browser, nicht wie diese Anwendung; derselbe Grund, aus dem es hier schon
kein window.confirm gibt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bisher war die Auswahl eine fest im Frontend verdrahtete Liste und es gab nur
eine Form: ueberall stand "3 Glas".
Neu unter Verwaltung > Gebinde: anlegen, umbenennen, loeschen, jeweils mit
Einzahl und Mehrzahl. Die eingebauten Gebinde lassen sich in der Schreibweise
aendern, aber nicht loeschen; ein Gebinde, das ein Artikel verwendet, ebenfalls
nicht.
Der Artikel speichert weiterhin nur die Einzahl als Text - so bleiben
vorhandene Artikel, Sicherungen und CSV-Dateien gueltig, und eine unbekannte
Bezeichnung faellt schlicht auf die Einzahl zurueck. Deshalb zieht ein
Umbenennen die Artikel mit; sonst zeigten sie auf eine Bezeichnung, die es
nicht mehr gibt.
Die Mehrzahl greift jetzt in Artikelliste, Artikelseite (Chargen und Gebinde-
Auswahl), Auslagern und in allen Ablauf- und Einkaufslisten samt Startseite.
Einheiten wie Gramm oder Liter bleiben unveraendert - die haben im Deutschen
keine Mehrzahl.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Zwei Ursachen dafuer, dass der Knopf folgenlos wirkte.
Sichtbar: Uebernehmen schreibt nur ins Formular, das Artikelbild wechselt erst
beim Speichern - es gab aber nichts, woran man das erkannt haette. Die Spalte
"Bisher" zeigt jetzt sofort das uebernommene Bild mit Kennzeichnung, der Knopf
heisst danach "Uebernommen", und eine Meldung erklaert den naechsten Schritt.
Tatsaechlich folgenlos war der haeufigste Fall: Stimmte die Bildadresse
laengst und nur der Abruf war damals fehlgeschlagen, aenderte sich beim
Speichern nichts - und die Bedingung fragte genau nach einer Aenderung. Sie
richtet sich jetzt danach, woher die vorhandene Kopie stammt. Fehlt sie, wird
geholt.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Neuer Knopf unter "Nachschlagen" auf der Artikelseite. Er fragt OFF erneut und
stellt die Antwort den eigenen Daten gegenueber: Name, Marke, Packungsgroesse,
Kategorie und Bild, jeweils mit eigenem Uebernehmen-Knopf und einem
"Alle uebernehmen". Uebernommen wird nur ins Formular - gespeichert erst mit
"Speichern", damit man bis zuletzt bei den eigenen Daten bleiben kann.
Dafuer noetig: GET /products/{id}/off. /lookup taugt hier nicht, weil es bei
einem bekannten Barcode den eigenen Artikel meldet und OFF gar nicht erst
fragt. Der neue Endpunkt probiert auch die zusaetzlichen EAN-Codes durch - oft
ist nur einer davon bei OFF hinterlegt.
Damit ist das Bild unabhaengig davon nachholbar, ob ein Backup eine
Bildadresse enthielt.
Nebenbei: Der Nachschlagen-Knopf uebergab die Gruppenliste, wo die
Einheitenliste erwartet wird - die Einheit eines Vorschlags wurde deshalb nie
richtig zugeordnet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Das alte Bild in der Chargen-Karte entfaellt - seit dem neuen Bild neben den
Kennfeldern stand es doppelt auf der Seite.
Der Rahmen ist jetzt hochkant (3:4) statt quadratisch. Lebensmittelverpackungen
sind fast immer hoeher als breit; im Quadrat blieben links und rechts leere
Streifen.
Beim Import wurde image_url komplett verworfen, obwohl das JSON-Backup sie
enthaelt - eingelesene Artikel blieben deshalb dauerhaft ohne Bild. Die Adresse
wird jetzt uebernommen (bei bestehenden Artikeln nur ergaenzend, nie
ueberschreibend); die lokale Kopie holt der Bildabruf beim ersten Ansehen.
Bewusst nicht waehrend des Imports: Ein Backup mit 200 Artikeln wuerde sonst
200 Downloads in einer Anfrage abarbeiten.
Ausserdem holen jetzt auch Artikelliste, Ein- und Auslagern ihr Vorschaubild
aus der eigenen Datenbank statt direkt von Open Food Facts. Einzige Ausnahme
bleibt der OFF-Vorschlag beim Scannen: Dort existiert der Artikel noch nicht.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Open Food Facts liefert nur eine Bildadresse. Direkt dorthin zu verlinken hiesse:
Das Bild verschwindet, wenn OFF es austauscht, die Installation braucht Internet,
und jeder Seitenaufruf verraet OFF, welche Artikel jemand ansieht.
Das Bild wird daher einmal geholt und in einer eigenen Tabelle product_images
abgelegt - eigene Tabelle, damit Artikellisten die Blobs nicht mitziehen.
Geholt wird beim Anlegen, bei geaenderter Bildadresse und beim ersten Abruf
(so bekommen auch bestehende Artikel ihre Kopie, ohne Wanderung ueber alle
Datensaetze).
GET /products/{id}/image verlangt eine Anmeldung - aus den Bildern liesse sich
sonst ohne Konto ablesen, was im Vorrat liegt. Da ein <img src> keinen
Authorization-Header schickt, laedt die Oberflaeche das Bild ueber fetch und
zeigt es als Objekt-URL.
Angezeigt wird es rechts neben Barcode, Name und Marke. Fehlt ein Bild, rendert
die Komponente nichts und die Felder nehmen die volle Breite ein.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auf ausdruecklichen Wunsch jetzt auch die internen Bezeichner, weil die
Installation noch keine echten Daten enthaelt: POSTGRES_USER/PASSWORD/DB, der
Volume-Name, die Standard-DATABASE_URL, der localStorage-Schluessel und die
iOS-Zeichenketten inklusive Keychain-Konto.
Das setzt eine leere Datenbank voraus: Der neue Volume-Name legt eine neue,
leere Datenbank an. Die alte bleibt als verwaistes Volume liegen und muss von
Hand entfernt werden.
Die Warnung in docker-compose.yml bleibt stehen, damit eine spaetere
Umbenennung nicht versehentlich mit Daten im Volume passiert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>