Vorratsschrank - Kategorie per Steuer-Barcode in der Scan-Station vorgeben + druckbarer Bogen mit allen Steuer-Codes #222

Closed
opened 2026-09-29 09:56:14 +02:00 by lena · 2 comments
Collaborator

Story: Kategorie per Steuer-Barcode beim Scannen setzen (Scan-Station)

As a Nutzer, der den Wocheneinkauf mit dem Hardware-Scanner in den Vorratsschrank eincheckt,
I want to vor den Produkten optional einen Kategorie-Barcode (z. B. "Kühlregal") scannen, der für alle folgenden Scans gilt,
so that ich die Kategorien direkt beim Einräumen setze und nicht hinterher am Laptop nachpflegen muss.

Kontext (verifiziert im Code):

  • Die Scan-Station (#171/#172, PantryScanStationPage.tsx) kennt bereits zwei Steuer-Barcodes: 999000001 = ab jetzt einchecken, 999000002 = ab jetzt auschecken. Sie sind neunstellig und bestehen nur aus Ziffern, damit sie nicht mit EAN-8/UPC-A/EAN-13 kollidieren und auf jedem Tastaturlayout funktionieren.
  • Diese Codes existieren nur im Code; einen druckbaren Bogen gibt es in der App nicht.
  • Der Barcode-Scan-Command im Vorratsschrank nimmt bereits eine optionale Kategorie für neue Produkte an (FallbackCategoryId, #190).

Acceptance criteria:

  • Neue Steuer-Barcodes im gleichen Schema (neunstellig, nur Ziffern, eigener Nummernbereich getrennt von 999000001/999000002) für:
    • "Keine Kategorie" (beendet den Kategorie-Modus: ab jetzt wird keine Kategorie mehr vorgegeben)
    • Obst & Gemüse
    • Glas und Dosen
    • Essig, Öl & Co
    • Trockenwaren
    • Müsli & Nüsse
    • Gewürze
    • Backwaren
    • Glutenfreie Lebensmittel
    • Snacks / Süßigkeiten
    • Kühlregal
    • Tiefkühl
    • Getränke
    • Drogerie & Haushalt
    • Bioladen
    • ("Aufstriche" bewusst nicht - siehe unten)
  • Nach dem Scan eines Kategorie-Codes werden alle folgenden Produkt-Scans mit dieser Kategorie eingecheckt, bis ein anderer Kategorie-Code oder "Keine Kategorie" gescannt wird. Die Codes sind optional: ohne sie verhält sich die Station wie bisher.
  • Der Kategorie-Modus gilt nur für die aktuelle Sitzung der Scan-Station. Nach Schließen/Neuladen ist er zurückgesetzt, und es greift wieder der normale Vorschlags-Mechanismus (eigene Liste, dann app-weite Wissensbasis aus #212).
  • "Keine Kategorie" heißt: über diesen Weg wird keine Kategorie mitgegeben, der normale Vorschlags-Mechanismus greift unverändert.
  • Der Kategorie-Modus wirkt nur beim Einchecken; beim Auschecken wird er ignoriert.
  • Der Kategorie-Modus gilt für alle eingecheckten Produkte: neue Produkte werden in der Kategorie angelegt, bereits bekannte Produkte werden in die gescannte Kategorie verschoben. Ein Produkt existiert immer nur unter einer Kategorie (verschieben, nie duplizieren).
  • Die Kategorie wird über den Namen auf die gleichnamige Kategorie der Liste gemappt (nicht über eine feste ID, da jede Liste eigene Kategorie-IDs hat). Existiert sie auf der Liste nicht, wird sie neu angelegt.
  • Die aktive Kategorie ist in der Scan-Station gut sichtbar (analog zur Anzeige des Ein-/Auscheck-Modus), inklusive Symbol der Kategorie.
  • Ein Wechsel von Kategorie oder Modus erscheint in der Aktivitätsanzeige der Station, damit man bei einem Fehlscan sieht, was aktiv war.
  • Druckbarer Bogen in der App: je Steuer-Code (auch die bestehenden zwei für Einchecken/Auschecken) ein scannbarer Barcode mit Klartext-Beschriftung und daneben einem aussagekräftigen Bild bzw. dem Kategorie-Symbol, damit man den richtigen Code beim Einräumen schnell findet. Druckoptimiert (A4, ausreichend groß für Handscanner).
  • "Aufstriche" aus den Standard-Kategorien neuer Listen entfernen (ShoppingListDefaultSections). Bestehende Listen behalten eine vorhandene "Aufstriche"-Kategorie unverändert - nichts wird bei Nutzern gelöscht.
  • Prio B (darf nachgezogen werden, wenn der Rest steht): zusätzlich je selbst angelegter Kategorie der Liste ein Code auf dem Bogen.

Entscheidungen (vom Menschen, 2026-09-29):

  • Gültigkeit: nur für die aktuelle Sitzung der Scan-Station; danach normaler Vorschlags-Mechanismus.
  • "Keine Kategorie": gibt über diesen Weg keine Kategorie weiter, der bestehende Mechanismus greift.
  • Auschecken: Kategorie-Modus nicht nötig.
  • Aufstriche: aus den Standards entfernen.
  • Eigene Kategorien auf dem Bogen: ja, Prio B.
  • Kategorie fehlt auf der Liste: neu anlegen.
  • Zurücksetzen beim Verlassen/Neuladen: ja.
  • Bekannte Produkte: ja, werden ebenfalls in die gescannte Kategorie verschoben - ein Produkt existiert immer nur unter einer Kategorie.
## Story: Kategorie per Steuer-Barcode beim Scannen setzen (Scan-Station) **As a** Nutzer, der den Wocheneinkauf mit dem Hardware-Scanner in den Vorratsschrank eincheckt, **I want to** vor den Produkten optional einen Kategorie-Barcode (z. B. "Kühlregal") scannen, der für alle folgenden Scans gilt, **so that** ich die Kategorien direkt beim Einräumen setze und nicht hinterher am Laptop nachpflegen muss. **Kontext (verifiziert im Code):** - Die Scan-Station (#171/#172, `PantryScanStationPage.tsx`) kennt bereits zwei Steuer-Barcodes: `999000001` = ab jetzt einchecken, `999000002` = ab jetzt auschecken. Sie sind neunstellig und bestehen nur aus Ziffern, damit sie nicht mit EAN-8/UPC-A/EAN-13 kollidieren und auf jedem Tastaturlayout funktionieren. - Diese Codes existieren nur im Code; einen druckbaren Bogen gibt es in der App nicht. - Der Barcode-Scan-Command im Vorratsschrank nimmt bereits eine optionale Kategorie für neue Produkte an (`FallbackCategoryId`, #190). **Acceptance criteria:** - [ ] Neue Steuer-Barcodes im gleichen Schema (neunstellig, nur Ziffern, eigener Nummernbereich getrennt von `999000001`/`999000002`) für: - "Keine Kategorie" (beendet den Kategorie-Modus: ab jetzt wird keine Kategorie mehr vorgegeben) - Obst & Gemüse - Glas und Dosen - Essig, Öl & Co - Trockenwaren - Müsli & Nüsse - Gewürze - Backwaren - Glutenfreie Lebensmittel - Snacks / Süßigkeiten - Kühlregal - Tiefkühl - Getränke - Drogerie & Haushalt - Bioladen - ("Aufstriche" bewusst nicht - siehe unten) - [ ] Nach dem Scan eines Kategorie-Codes werden alle folgenden Produkt-Scans mit dieser Kategorie eingecheckt, bis ein anderer Kategorie-Code oder "Keine Kategorie" gescannt wird. Die Codes sind optional: ohne sie verhält sich die Station wie bisher. - [ ] Der Kategorie-Modus gilt nur für die aktuelle Sitzung der Scan-Station. Nach Schließen/Neuladen ist er zurückgesetzt, und es greift wieder der normale Vorschlags-Mechanismus (eigene Liste, dann app-weite Wissensbasis aus #212). - [ ] "Keine Kategorie" heißt: über diesen Weg wird keine Kategorie mitgegeben, der normale Vorschlags-Mechanismus greift unverändert. - [ ] Der Kategorie-Modus wirkt nur beim Einchecken; beim Auschecken wird er ignoriert. - [ ] Der Kategorie-Modus gilt für alle eingecheckten Produkte: neue Produkte werden in der Kategorie angelegt, bereits bekannte Produkte werden in die gescannte Kategorie verschoben. Ein Produkt existiert immer nur unter einer Kategorie (verschieben, nie duplizieren). - [ ] Die Kategorie wird über den Namen auf die gleichnamige Kategorie der Liste gemappt (nicht über eine feste ID, da jede Liste eigene Kategorie-IDs hat). Existiert sie auf der Liste nicht, wird sie neu angelegt. - [ ] Die aktive Kategorie ist in der Scan-Station gut sichtbar (analog zur Anzeige des Ein-/Auscheck-Modus), inklusive Symbol der Kategorie. - [ ] Ein Wechsel von Kategorie oder Modus erscheint in der Aktivitätsanzeige der Station, damit man bei einem Fehlscan sieht, was aktiv war. - [ ] Druckbarer Bogen in der App: je Steuer-Code (auch die bestehenden zwei für Einchecken/Auschecken) ein scannbarer Barcode mit Klartext-Beschriftung und daneben einem aussagekräftigen Bild bzw. dem Kategorie-Symbol, damit man den richtigen Code beim Einräumen schnell findet. Druckoptimiert (A4, ausreichend groß für Handscanner). - [ ] "Aufstriche" aus den Standard-Kategorien neuer Listen entfernen (`ShoppingListDefaultSections`). Bestehende Listen behalten eine vorhandene "Aufstriche"-Kategorie unverändert - nichts wird bei Nutzern gelöscht. - [ ] Prio B (darf nachgezogen werden, wenn der Rest steht): zusätzlich je selbst angelegter Kategorie der Liste ein Code auf dem Bogen. **Entscheidungen (vom Menschen, 2026-09-29):** - Gültigkeit: nur für die aktuelle Sitzung der Scan-Station; danach normaler Vorschlags-Mechanismus. - "Keine Kategorie": gibt über diesen Weg keine Kategorie weiter, der bestehende Mechanismus greift. - Auschecken: Kategorie-Modus nicht nötig. - Aufstriche: aus den Standards entfernen. - Eigene Kategorien auf dem Bogen: ja, Prio B. - Kategorie fehlt auf der Liste: neu anlegen. - Zurücksetzen beim Verlassen/Neuladen: ja. - Bekannte Produkte: ja, werden ebenfalls in die gescannte Kategorie verschoben - ein Produkt existiert immer nur unter einer Kategorie.
Author
Collaborator

Claimed by the autonomous loop (2026-09-29). Starting: Architect design -> backend (category-by-name on pantry barcode scan, move known products, drop Aufstriche from defaults) -> frontend (category control codes in the scan station, activity entries, printable code sheet) -> tests.

Claimed by the autonomous loop (2026-09-29). Starting: Architect design -> backend (category-by-name on pantry barcode scan, move known products, drop Aufstriche from defaults) -> frontend (category control codes in the scan station, activity entries, printable code sheet) -> tests.
Author
Collaborator

Done - landed on master, see commits feat(#222): scan check-in can force a category by name, drop Aufstriche from defaults and feat(#222): category control codes in the scan station + printable code sheet (tip bed4ae69, CI green incl. e2e and docker).

Scope delivered

  • New control codes (9 digits, digits only): 999100000 = Keine Kategorie, 999100001-999100014 = the 14 default categories (Obst & Gemuese ... Bioladen, no Aufstriche). Existing 999000001/999000002 unchanged. Prio B: a list's own categories get 9992 + 5-digit category id (ids above 99999 are left off the sheet).
  • Scan station: a category code sets the category mode (banner with the category's icon, greyed with a hint while checking out). Every check-in sends the category name; the backend maps it case-insensitively onto the pantry list's category, creates it if missing (with the default icon when it is a default name), puts new products there and moves known products there (never duplicates). Check-out ignores it. Mode is plain component state, so leaving/reloading resets it.
  • While a category mode is active, the confirm-name step for an unknown barcode hides the category picker (the category is already decided).
  • Mode and category switches show up in the station's activity feed as session-only rows, interleaved by time with the persisted events. An unknown code from the reserved range is rejected with an error instead of being scanned as a product.
  • Printable sheet at /pantry/<id>/scan-codes (printer button in the station header): every code as Code 128 with label, digits and a large symbol, A4 print rules that print only the sheet (2 pages).
  • "Aufstriche" removed from the default sections of new lists; existing lists keep theirs (the backfill never deletes, no version bump needed).

Tests

  • Backend: 6 new handler tests (case-insensitive mapping, creation with icon, no creation on the unconfirmed first call, move of known products, no move when already there, ignored on check-out) plus updated default-section tests.
  • Frontend: Code 128 encoder round-tripped through zxing's own reader; control-code parsing; 5 new scan-station tests; sheet page test. Full suite 1544+ tests green.
  • Manually verified against the local review container: known product moved from Obst & Gemuese to Kuehlregal and checked in, feed interleaving, printed PDF.

Key decisions

  • Category by name, not id: the printed codes are the same for every list.
  • Session entries are not persisted: the mode itself is session-only by design.
  • Own Code 128 encoder instead of a new dependency (@zxing only reads 1D codes).

Note: the assignee could not be set from this session (permission), the claim was marked via the status/claimed label and the start comment.

Done - landed on master, see commits `feat(#222): scan check-in can force a category by name, drop Aufstriche from defaults` and `feat(#222): category control codes in the scan station + printable code sheet` (tip bed4ae69, CI green incl. e2e and docker). **Scope delivered** - New control codes (9 digits, digits only): `999100000` = Keine Kategorie, `999100001`-`999100014` = the 14 default categories (Obst & Gemuese ... Bioladen, no Aufstriche). Existing `999000001`/`999000002` unchanged. Prio B: a list's own categories get `9992` + 5-digit category id (ids above 99999 are left off the sheet). - Scan station: a category code sets the category mode (banner with the category's icon, greyed with a hint while checking out). Every check-in sends the category *name*; the backend maps it case-insensitively onto the pantry list's category, creates it if missing (with the default icon when it is a default name), puts new products there and moves known products there (never duplicates). Check-out ignores it. Mode is plain component state, so leaving/reloading resets it. - While a category mode is active, the confirm-name step for an unknown barcode hides the category picker (the category is already decided). - Mode and category switches show up in the station's activity feed as session-only rows, interleaved by time with the persisted events. An unknown code from the reserved range is rejected with an error instead of being scanned as a product. - Printable sheet at `/pantry/<id>/scan-codes` (printer button in the station header): every code as Code 128 with label, digits and a large symbol, A4 print rules that print only the sheet (2 pages). - "Aufstriche" removed from the default sections of new lists; existing lists keep theirs (the backfill never deletes, no version bump needed). **Tests** - Backend: 6 new handler tests (case-insensitive mapping, creation with icon, no creation on the unconfirmed first call, move of known products, no move when already there, ignored on check-out) plus updated default-section tests. - Frontend: Code 128 encoder round-tripped through zxing's own reader; control-code parsing; 5 new scan-station tests; sheet page test. Full suite 1544+ tests green. - Manually verified against the local review container: known product moved from Obst & Gemuese to Kuehlregal and checked in, feed interleaving, printed PDF. **Key decisions** - Category by name, not id: the printed codes are the same for every list. - Session entries are not persisted: the mode itself is session-only by design. - Own Code 128 encoder instead of a new dependency (@zxing only reads 1D codes). Note: the assignee could not be set from this session (permission), the claim was marked via the status/claimed label and the start comment.
lena closed this issue 2026-09-30 09:32:45 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
robert/todo#222
No description provided.