1. shopping_name compound-phrase map (computeShoppingName)
Add phraseMap checked against the full product name BEFORE the single-token
keyword loop. Prevents 'pane grattugiato' → 'Pane', 'panna da cucina' → 'Panna', etc.
Key new phrases:
- pane/pan grattugiato → Pangrattato
- panna da cucina / panna cucina / panna chef → Panna da cucina
- fette biscottate → Fette biscottate
- aceto balsamico / glassa balsamico → Aceto balsamico
- latte condensato/evaporato/vegetale/di soia/mandorla/avena/riso/cocco → specific
- prosciutto cotto → Prosciutto cotto
- farina di riso/mais/integrale → specific
- pasta fresca, zucchero di canna, acqua minerale/frizzante/gassata, brodo, …
Also added single-token safety-net entries: 'grattugiato'/'grattato'/'pangrattato'
→ 'Pangrattato', 'biscottate' → 'Fette biscottate'.
2. DB migration (sqlite3 UPDATE)
Re-classified 10 products that had wrong shopping_name:
Pane grattugiato → Pangrattato
Panna da cucina (×4) → Panna da cucina
Fette biscottate (×2) → Fette biscottate
Aceto balsamico (×3) → Aceto balsamico
Cleared 2 stale Gemini cache entries.
3. showLowStockBringPrompt (app.js)
When totalRemaining <= 0 (product fully depleted), skip the modal entirely.
The backend already auto-adds to Bring! on depletion; the JS only asks as a
fallback if that failed (fire-and-forget async, never blocks the UI).
The afterCallback (e.g. move-remainder modal, navigate to dashboard) is called
immediately without user interaction.
- Extended keyword map: 100+ entries covering bread (bauletto->Pane),
cheese (bel->Formaggio, casatella->Formaggio), wine (vesoletto/trebbiano->Vino),
foreign brand names (kaffee->Caffe, risofrolle->Cracker, zuppalatte->Biscotti,
inchusa->Birra, apfelsaft->Succo, kartoffelpüree->Purè, ciobar->Cioccolata calda,
ovomaltine->Bevande), desserts (gelato->Gelato), herbs (camomilla->Camomilla),
liquors (sambuca->Liquore), sugar variants (zuccheri->Zucchero), foreign words
(jus/zumo/arome->Italian equivalents)
- Add _geminiClassifyProduct(): calls Gemini 2.0 Flash for ambiguous product names,
with persistent cache in data/shopping_name_cache.json (never re-queries same product)
- computeShoppingName() now calls Gemini when keyword map and Bring! catalog both fail
and the product name is multi-token or has a brand/category hint
- saveProduct() auto-computes shopping_name on every create/update (already in prev commit)
- DB migration: all 210 products re-classified with new rules
- shopping list: 38->33 groups (Formaggio +4v, Affettato +5v, Biscotti +1v, Pane +1v...)
- Final SQL fixes for edge cases: Gelato, Camomilla, brand name single tokens