feat: separate AI and product suggestion chips, normalize product names, and validate AI categories

This commit is contained in:
Nils-Johan Gynther
2026-05-01 23:59:16 +02:00
parent 2c71970fb5
commit d3dac61765
4 changed files with 151 additions and 41 deletions
+42 -1
View File
@@ -2,6 +2,47 @@
Viktigt att komma ihåg vid implementering av nya funktioner och kodning är att inte använda Windows-sökvägar. Använd inte `c:/dev/recipe-app/...` eftersom bygg- och testmiljön är på en remote Ubuntu-server. Utveckling sker lokalt och test samt drift sker på remote server. Säkerställ att inga absoluta Windows-sökvägar används i koden, för att stödja bygg och drift på Linux/Ubuntu.
## Senaste ändringar (2026-05-01, session 3)
### Separering av AI-chip och produktsuggestions-chip
**Problem:** AI-chipet visade felaktigt produktnamnsförslag som om de vore kategoriförslag, vilket skapade förvirring när användaren såg "AI-förslag: Dryck Multivitamin" (ett produktnamn) istället för en kategori.
**Lösning:**
- **Blå chip** "Förslag: [produktnamn]" — när systemet hittat en trolig produkt via ordmatchning (inga AI-anrop inblandade). Klick väljer produkten.
- **Grön chip** "AI-kategori: [kategoriväg]" — när AI:n föreslagit en kategori från databasen. Klick öppnar produktpickern filtrerad på den kategorin.
**Kodändringar:**
- `aiLabel` beräknas enbart från `categorySuggestionName`/`categorySuggestionPath` (kategoriförslag).
- Nytt fält `suggestedProductLabel` för produktsuggestions-chip.
- Separata villkor och UI-block för de två chipen i `_EditDialogState.build()`.
### Produktnamns-normalisering
**Problem:** Kvittonamn i VERSALER (t.ex. "APRIKOSMARMELAD 284G") såg oprofessionella ut i UI:n.
**Lösning:** Ny funktion `_normalizeProductName()` som tillämpar smarta regler:
- Token med `/` (förkortningar) lämnas i versaler: `KY/KAL/LE/TO`
- Token som börjar med siffra (mängd/storlek) görs till gemener: `284G``284g`, `12X85G``12x85g`
- Övriga token: första bokstav versal, resten gemen: `APRIKOSMARMELAD``Aprikosmarmelad`, `JUICE TROPISK``Juice Tropisk`
**Implementering:**
- Top-level-funktion i `receipt_import_tab.dart`
- Tillämpas när "Ny produkt"-fältet prefylls: `_newProductNameCtrl.text = _normalizeProductName(widget.current.productName ?? widget.item.rawName)`
### AI-kategorisering — validering i backend
**Problem:** Användaren rapporterade att AI föreslog kategorin "Dryck Multivitamin", som inte fanns i databasen.
**Undersökning:**
- Backend-AI:n (`ai.service.ts`) validerar redan att `categoryId` finns i `categories`-listan och faller tillbaka på "Övrigt" om inte.
- Problemet var att frontend visade produktnamnsförslag som om de vore kategoriförslag.
**Lösning:**
- Separering av chipen (se ovan) gör det tydligt att AI-kategoriförslag alltid kommer från databasen.
---
## Senaste ändringar (2026-05-01, session 2)
### Tvåstegs-picker: Kategori → Produkt
@@ -58,7 +99,7 @@ Importfliken laddar globala och privata produkter parallellt via `Future.wait` o
User-scope-principen dokumenterades formellt i båda tekniska beskrivningarna (2026-05-01). Privata produkter är det första exemplet på mönstret för resurser som är varken globala (alla ser dem) eller fullt user-owned (bara ägaren ser dem):
- `Product.isPrivate = true` + `Product.ownerId = userId`
- `normalizedName`-prefix undviker databaskollision med globala produkter
- Migration: `20260501000000_add_product_is_private`
- Migration: `20260501000000_add_product_is_private
## Senaste ändringar (2026-05-01, session 1)