feat(api): Fuzzy-Match in parseItems gegen Geschäfts-Sortiment-DB #415

Closed
opened 2026-05-28 06:39:38 +02:00 by pm-bot · 1 comment
Collaborator

Ziel

OCR-Output (egal ob Server- oder On-device-Pfad) gegen Geschäfts-Sortiment matchen, damit "MILCH IL" → "Milch 1L (Edeka)" wird statt als Roh-String in die Liste zu landen.

Insertionspunkt

apps/api/src/modules/lists/ocr.service.ts:131parseItems(text: string): { name: string }[]

Aktuell: Splits Text bei Newlines, filtert ≥2 chars, returnt {name: rawString}[].

Neu: Optional {name, matchedProductId?, matchedStoreId?, confidence?}.

Scope

  • Lookup-Quelle: Bestehende produkte / geschaefte Tabellen (Drizzle)
  • Algorithmus: Levenshtein-basiert mit Threshold (≤30% normalized edit-distance), Tie-break über Store-Affinität wenn storeId aus Context bekannt
  • Fallback: Bei No-Match → unverändertes Verhalten (rawString als name)
  • Performance: Ziel <50 ms für 20-Item-Liste auf API-Server
  • UI: Web + Mobile Korrektur-Routen zeigen Match-Vorschlag mit "akzeptieren/ablehnen"-Button

Definition-of-Done

  • Unit-Tests: parseItems mit Sortiment-Mock — Match-Hits, Misses, Edge-Cases (Umlaute, Zahlen-Suffix)
  • Drizzle-Migration falls Match-Audit-Tabelle nötig (forward-only)
  • Web + Mobile UI-Integration in bestehenden List-Image-Routen
  • Telemetry: Match-Hit-Rate via existing analytics

Referenzen

  • Parent-Spike: #77 (TrOCR-on-device)
  • Architecture-Reconciliation: #413, #77#issuecomment-2688
  • Related: #82 (On-device-Pipeline + Server-Fallback)
## Ziel OCR-Output (egal ob Server- oder On-device-Pfad) gegen Geschäfts-Sortiment matchen, damit "MILCH IL" → "Milch 1L (Edeka)" wird statt als Roh-String in die Liste zu landen. ## Insertionspunkt `apps/api/src/modules/lists/ocr.service.ts:131` — `parseItems(text: string): { name: string }[]` Aktuell: Splits Text bei Newlines, filtert ≥2 chars, returnt `{name: rawString}[]`. Neu: Optional `{name, matchedProductId?, matchedStoreId?, confidence?}`. ## Scope - Lookup-Quelle: Bestehende `produkte` / `geschaefte` Tabellen (Drizzle) - Algorithmus: Levenshtein-basiert mit Threshold (≤30% normalized edit-distance), Tie-break über Store-Affinität wenn `storeId` aus Context bekannt - Fallback: Bei No-Match → unverändertes Verhalten (rawString als name) - Performance: Ziel <50 ms für 20-Item-Liste auf API-Server - UI: Web + Mobile Korrektur-Routen zeigen Match-Vorschlag mit "akzeptieren/ablehnen"-Button ## Definition-of-Done - [ ] Unit-Tests: parseItems mit Sortiment-Mock — Match-Hits, Misses, Edge-Cases (Umlaute, Zahlen-Suffix) - [ ] Drizzle-Migration falls Match-Audit-Tabelle nötig (forward-only) - [ ] Web + Mobile UI-Integration in bestehenden List-Image-Routen - [ ] Telemetry: Match-Hit-Rate via existing analytics ## Referenzen - Parent-Spike: #77 (TrOCR-on-device) - Architecture-Reconciliation: #413, #77#issuecomment-2688 - Related: #82 (On-device-Pipeline + Server-Fallback)
Author
Collaborator

Status: Neuer v0.5-OCR-Hauptdeliverable

Nach Spike-Exit #77 (Real-Data-Eval #416 zeigte CER 0.51 vs. synthetic 0.04 + Privacy-Modell macht On-Device unnötig) ist dieses Issue der Hauptpfad für v0.5-OCR.

Begründung:

  • Server-OCR liefert CER 0.67 — Roh-Output ist unbrauchbar
  • Aber: User-Pain ist nicht "schlechte CER", sondern "viele Korrektur-Taps"
  • Fuzzy-Match gegen Sortiments-DB löst die User-Pain unabhängig von Roh-OCR-Qualität: "REHOL" → "Hund" via Levenshtein-Match

Insertion bleibt wie beschrieben: apps/api/src/modules/lists/ocr.service.ts:131 parseItems. Funktioniert für jeden OCR-Backend (aktuell EasyOCR, evtl. später TrOCR-handwritten server-side).

Geschlossene Spike-Cluster: #77, #81, #82, #414, #416 — siehe jeweils close-comments für Pivot-Details.

## Status: Neuer v0.5-OCR-Hauptdeliverable Nach Spike-Exit #77 (Real-Data-Eval #416 zeigte CER 0.51 vs. synthetic 0.04 + Privacy-Modell macht On-Device unnötig) ist dieses Issue der Hauptpfad für v0.5-OCR. **Begründung:** - Server-OCR liefert CER 0.67 — Roh-Output ist unbrauchbar - Aber: User-Pain ist nicht "schlechte CER", sondern "viele Korrektur-Taps" - Fuzzy-Match gegen Sortiments-DB löst die User-Pain unabhängig von Roh-OCR-Qualität: "REHOL" → "Hund" via Levenshtein-Match **Insertion bleibt wie beschrieben:** `apps/api/src/modules/lists/ocr.service.ts:131 parseItems`. Funktioniert für jeden OCR-Backend (aktuell EasyOCR, evtl. später TrOCR-handwritten server-side). **Geschlossene Spike-Cluster:** #77, #81, #82, #414, #416 — siehe jeweils close-comments für Pivot-Details.
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
admin-mrrm/mrrmlabapp#415
No description provided.