Commit Graph

637 Commits

Author SHA1 Message Date
dadaloop82 8da627f8a6 Merge branches 'main' and 'main' of github-evershelf:dadaloop82/EverShelf 2026-05-12 15:31:40 +00:00
dadaloop82 d3492a38f7 release: v1.7.11 — scan redesign, AI OCR, anomaly fixes 2026-05-12 15:31:23 +00:00
dadaloop82 34e13075ea chore: release v1.7.11 — scan redesign, AI OCR, anomaly fixes 2026-05-12 15:31:07 +00:00
dadaloop82 bba0f4715a fix: remove datalist suggestions from quick-name input (scan page) 2026-05-12 15:29:40 +00:00
github-actions[bot] e3ae2d10b2 chore: auto-merge develop → main
Triggered by: 696a9c6 feat: scan page redesign — fixed 2x zoom, torch, camera flip, tabs, recents, AI number OCR
2026-05-12 14:57:53 +00:00
dadaloop82 696a9c6d11 feat: scan page redesign — fixed 2x zoom, torch, camera flip, tabs, recents, AI number OCR
- Always-on 2x hardware zoom (CSS scale fallback)
- Torch button with toggle + visual feedback
- Camera flip (front/back) with settings persistence
- 3-tab input panel: Barcode / Name / AI
- Recent products chips (last 6 scanned, from localStorage)
- Live barcode code overlay during partial detection
- Confirm overlay (checkmark + name) on successful scan
- AI number OCR (Gemini reads barcode digits from image, shown after 4s)
- Guide corners frame in viewport
- PHP: gemini_number_ocr action + rate-limited
- Translations: new scan.* keys in it/en/de
2026-05-12 14:55:14 +00:00
github-actions[bot] 35de42657a chore: auto-merge develop → main
Triggered by: 27ba417 fix: consumption predictions require >=5 txns, 7-day spread, and >=15% predicted consumption ratio
2026-05-12 14:33:12 +00:00
dadaloop82 27ba41700f fix: consumption predictions require >=5 txns, 7-day spread, and >=15% predicted consumption ratio 2026-05-12 14:31:24 +00:00
github-actions[bot] 2f040ee041 chore: auto-merge develop → main
Triggered by: 2c34387 fix: remove 'untracked' anomaly direction — incomplete purchase history is normal, not an anomaly
2026-05-12 05:53:53 +00:00
dadaloop82 2c34387592 fix: remove 'untracked' anomaly direction — incomplete purchase history is normal, not an anomaly 2026-05-12 05:52:09 +00:00
dadaloop82 3e65c7ee43 Merge branch 'main' of github-evershelf:dadaloop82/EverShelf 2026-05-11 17:40:22 +00:00
dadaloop82 49ac0b4ce8 release: v1.7.10 — banner fixes, opened tracking, anomaly detection improvements 2026-05-11 17:40:13 +00:00
dadaloop82 9e2722f7a4 chore: update CHANGELOG and README for v1.7.10 2026-05-11 17:40:01 +00:00
github-actions[bot] c47eba3ddb chore: auto-merge develop → main
Triggered by: d056a6a fix: expired section hides items with quantity=0
2026-05-11 17:37:45 +00:00
dadaloop82 d056a6a116 fix: expired section hides items with quantity=0
Query was missing AND i.quantity > 0, so thrown-away items (qty=0)
with a past expiry_date kept appearing in the expired list.
Also cleaned up the orphan row for Aglio in the DB.
2026-05-11 17:35:53 +00:00
github-actions[bot] cdc776d7c7 chore: auto-merge develop → main
Triggered by: cb39b63 fix: drastically reduce false-positive consumption anomaly banners
2026-05-11 17:33:31 +00:00
dadaloop82 cb39b63997 fix: drastically reduce false-positive consumption anomaly banners
Two changes:
1. Skip prediction when expected_qty=0 — model says 'should be finished'
   but user simply restocked or consumed less. Not actionable.
2. Raise 'more than expected' threshold to 400% (was 30%).
   Having more than expected almost always means a restock the model
   doesn't know about yet — only truly extreme cases (>4x) are flagged.
   'Less than expected' stays at 30% (still actionable: unregistered use).
2026-05-11 17:31:41 +00:00
github-actions[bot] 1eb7a6733c chore: auto-merge develop → main
Triggered by: 5b401f8 fix: consumption predictions false positives after restocking
2026-05-11 17:26:31 +00:00
dadaloop82 5b401f8d5f fix: consumption predictions false positives after restocking
Root cause: baseline was 'restockQty' (only the new items added) but
actualQty = pre-existing stock + new items → always looked like 'more than expected'.

New approach: baseline = current_qty + consumed_since_restock.
This correctly reflects the true starting point regardless of pre-existing stock,
eliminating all false positives after shopping trips.
2026-05-11 17:24:44 +00:00
github-actions[bot] 448a8237f6 chore: auto-merge develop → main
Triggered by: 20c1640 fix: inventory_update now records compensating transactions
2026-05-11 17:23:38 +00:00
dadaloop82 20c16401d2 fix: inventory_update now records compensating transactions
When a user manually edits quantity (e.g. after restocking), the diff
is recorded as 'in' or 'out' transaction with note '[Correzione manuale]'.
This prevents the anomaly detector from flagging manual edits as phantom
or missing consumption.
2026-05-11 17:21:57 +00:00
github-actions[bot] 5ffc4581f4 chore: auto-merge develop → main
Triggered by: a9a512e fix: clear opened_at on sealed packages row during split
2026-05-11 17:20:37 +00:00
dadaloop82 a9a512e014 fix: clear opened_at on sealed packages row during split
When usage splits a row into 'whole sealed packages' + 'opened fraction',
the sealed row was updated without clearing opened_at — if it had been
opened previously, the stale flag would persist and wrongly show
'aperto da N giorni' on intact packages.

Now all 3 split paths (conf early-split, conf post-split, g/ml/l split)
explicitly set opened_at = NULL on the sealed row.
2026-05-11 17:19:00 +00:00
github-actions[bot] 7cc4ce91a9 chore: auto-merge develop → main
Triggered by: 3391106 feat: banner opened items show 'aperto da X giorni in frigo' instead of 'scaduto'
2026-05-11 17:12:53 +00:00
dadaloop82 3391106010 feat: banner opened items show 'aperto da X giorni in frigo' instead of 'scaduto'
When inventory item has opened_at set, the expired banner now shows:
- Title: '[Nome] — Aperto da troppo tempo!' (instead of '— Scaduto!')
- Detail: 'Aperto da N giorni in [icon] [location] · hai ancora X'
Also removed hardcoded Italian 'scade il' string from non-opened expired detail.
2026-05-11 17:11:07 +00:00
github-actions[bot] 184042a0ae chore: auto-merge develop → main
Triggered by: 85090ec fix: generic 'latte' opened shelf life 4→7 days (UHT default)
2026-05-11 17:09:26 +00:00
dadaloop82 85090ecc9f fix: generic 'latte' opened shelf life 4→7 days (UHT default)
Fresh milk is explicitly matched by 'latte fresco/intero/parzial/scremato' (3 days).
Generic 'Latte' without qualifier is almost always UHT in Italian households — 7 days.
2026-05-11 17:07:59 +00:00
github-actions[bot] 27238a39cb chore: auto-merge develop → main
Triggered by: 8407dea fix: editBannerNoExpiry load inventory before opening edit modal
2026-05-11 16:58:48 +00:00
github-actions[bot] 6cb7aeaf5b chore: auto-merge develop → main
Triggered by: e3975b7 fix: editBannerNoExpiry called undefined openEditInventoryModal
2026-05-11 16:57:11 +00:00
dadaloop82 8407dea781 fix: editBannerNoExpiry load inventory before opening edit modal
currentInventory is empty on dashboard. Fetch inventory_list first
(same pattern as editReviewItem and weighBannerItem).
2026-05-11 16:57:00 +00:00
dadaloop82 e3975b7d2e fix: editBannerNoExpiry called undefined openEditInventoryModal
Replace with correct editInventoryItem() call — same function used
by all other banner edit handlers.
2026-05-11 16:55:26 +00:00
github-actions[bot] b5789bbc8b chore: auto-merge develop → main
Triggered by: 38c6c5a fix: auto-create data dir on first Docker run (HY000[14])
2026-05-11 15:56:26 +00:00
dadaloop82 38c6c5aac3 fix: auto-create data dir on first Docker run (HY000[14])
When a Docker named volume is first mounted at /var/www/html/data,
the directory may be owned by root (the volume is created empty before
the image's chown step applies). This caused PDO::__construct to throw:
  SQLSTATE[HY000][14] unable to open database file

Fix: _ensureDataDir() checks/creates the directory and attempts chmod
before every getDB() call. On subsequent calls the is_dir+is_writable
checks are O(1) stat calls with no overhead.

Fixes #34 (also closes #28 #29 #30 #31 #32 #33)
2026-05-11 15:54:40 +00:00
github-actions[bot] fc2849be19 chore: auto-merge develop → main
Triggered by: a21b54d feat: i18n — translate all hardcoded Italian strings (nutrition, facts, kiosk, gemini, scanner, shopping)
2026-05-11 15:51:53 +00:00
dadaloop82 a21b54deaa feat: i18n — translate all hardcoded Italian strings (nutrition, facts, kiosk, gemini, scanner, shopping)
- Added 106 new translation keys across all 3 languages (it/en/de):
  - nutrition.* (11 keys): card title, score labels, health/variety/fresh bars, source
  - facts.* (70 keys): screensaver facts — greetings, expiry, shopping, categories, tips
  - kiosk.* (12 keys): update check, install flow, exit/refresh button titles
  - update.* (2 keys): badge label and button
  - gemini.* (2 keys): chat button title, not-configured tooltip
  - dashboard.banner_explain_title/btn/analyzing (3 keys): anomaly explain button
  - add.history_badge_tip (1 key): history badge tooltip
  - shopping.smart_last_update, names_already_updated (2 keys)
  - appliances.empty (1 key)
  - scanner.save_new_btn (1 key)
- app.js: replaced all remaining hardcoded Italian strings with t() calls
- api/index.php: fixed Frutta/Früchte Bring! loop (Pass 2 genericQualifiers)
- index.html: asset version bumped to v=20260511b
2026-05-11 15:49:55 +00:00
github-actions[bot] 0fd39db5d3 chore: auto-merge develop → main
Triggered by: da62647 feat: v1.7.9 — category badges, category search, AI guards
2026-05-11 05:55:10 +00:00
dadaloop82 da62647089 feat: v1.7.9 — category badges, category search, AI guards
- Category badge on every inventory item (icon + label); 'altro' items
  refined asynchronously via new guess_category Gemini endpoint
  (data/category_ai_cache.json) — no AI call when key not configured
- Category search: inventory search now matches by macro-category key
  and translated label (e.g. 'biscotti' finds all cookie items)
- Brand fast-path in guessCategoryFromName (Oreo, Barilla, Lavazza…)
- Fix: duplicate banner alerts — _bannerLoading guard + _queuedItemIds Set
- Fix: mapToLocalCategory with en:dairies (dairi stem added)
- Fix: mapToLocalCategory no longer blocks on 'altro' — falls back to
  guessCategoryFromName(productName) before returning 'altro'
- Fix: 'Tonno all'olio' was resolving to condimenti — moved tonno\b
  check before olio\b in conserve regex block
- AI guards: _refineCategoryBadgesAsync and fetchAllPrices now check
  _geminiAvailable (JS); getShoppingPrice returns no_api_key (PHP)
  when GEMINI_API_KEY is not set — all AI functions are now explicit
2026-05-11 05:53:15 +00:00
github-actions[bot] b65e381329 chore: auto-merge develop → main
Triggered by: 763b7fd fix: bilancia ricette attende ≥5g di variazione; sale spurio in Bring!
2026-05-10 15:47:36 +00:00
dadaloop82 763b7fd057 fix: bilancia ricette attende ≥5g di variazione; sale spurio in Bring!
- Recipe use modal: reset _scaleLastConfirmedGrams al peso attuale prima
  di aprire il modale, così la tara ha tempo; soglia ridotta 10→5g
- PHP useFromInventory: prima di auto-aggiungere a Bring! un prodotto esaurito,
  controlla se la famiglia shopping_name ha scorte da altri prodotti (es.
  'Sale marino iodato' esaurito ma 3kg di altri sali in dispensa → non aggiunge)
  JS, così il cron bringCleanupObsolete può auto-rimuovere
- Rimosso manualmente 'Sale' da Bring! (aggiunto senza marker dalla vecchia logica)
2026-05-10 15:45:56 +00:00
github-actions[bot] 8bff68dd33 chore: auto-merge develop → main
Triggered by: d1139a7 fix: falso alert burro; JSON traduzioni corrotte; allineamento inventario
2026-05-10 15:35:57 +00:00
dadaloop82 d1139a7e4b fix: falso alert burro; JSON traduzioni corrotte; allineamento inventario
- Smart shopping: aggiungi family-coverage check per prodotti 'quasi finiti'.
  Se il shopping_name family ha scorte da altri prodotti (es. Burro conf)
  con unità diff (g/ml vs conf), l'alert 'sta finendo' viene soppresso.
- Corretto bug traduzioni: sezione 'action' duplicata in de/en/it.json
  causava JSONDecodeError in CI/CD (line 944 column 2).
- DB: allineamento inventario burro — rimossi 30g residui (usati),
  pulito opened_at da pacco nuovo Burro conf (comprato 2026-05-08).
2026-05-10 15:34:29 +00:00
dadaloop82 5fccb5309c feat: Crea una ricetta per ingrediente + fix bottone Apri ricetta + meal non categorizzato
- Bottone 'Apri la ricetta': il transfer btn si trasforma direttamente in
  '📖 Apri la ricetta' dopo il successo (invece di aggiungere un elemento DOM separato)
- meal null: chatToRecipe e recipe_from_ingredient non auto-categorizzano il pasto;
  renderRecipe mostra il tag meal solo se presente
- Nuovo endpoint recipe_from_ingredient: genera una ricetta con l'ingrediente
  selezionato come protagonista, stessa pipeline di chatToRecipe (Gemini + fuzzy-match)
- Bottone '👨‍🍳 Crea una ricetta con questo' nel pannello azione degli alimenti
  (span-2 sotto la griglia 2x2), apre overlay Ricette in loading state
2026-05-10 15:21:21 +00:00
github-actions[bot] a99e2cb80b chore: auto-merge develop → main
Triggered by: 63ede4f fix: increase maxOutputTokens to 8192 in chatToRecipe; add 'Apri la ricetta' button after transfer
2026-05-10 15:10:08 +00:00
dadaloop82 63ede4fb53 fix: increase maxOutputTokens to 8192 in chatToRecipe; add 'Apri la ricetta' button after transfer
Fixes parse_error on complex recipes (JSON was truncated at 2048 tokens).
After successful transfer, shows 'Apri la ricetta' button inline in chat
alongside the ' Aggiunta alle Ricette!' button.
Closes #27
2026-05-10 15:08:24 +00:00
github-actions[bot] 5028fb0e72 chore: auto-merge develop → main
Triggered by: 370a5a6 fix: robust JSON extraction in chatToRecipe — handles Gemini preamble text + nested fences
2026-05-10 15:04:32 +00:00
dadaloop82 370a5a62b0 fix: robust JSON extraction in chatToRecipe — handles Gemini preamble text + nested fences 2026-05-10 15:02:58 +00:00
github-actions[bot] 75eb77c9b1 chore: auto-merge develop → main
Triggered by: ac7368e fix: button outside chat bubble + showToast on success/error in chatTransferToRecipes
2026-05-10 15:01:48 +00:00
dadaloop82 ac7368e49d fix: button outside chat bubble + showToast on success/error in chatTransferToRecipes 2026-05-10 15:00:19 +00:00
github-actions[bot] 2db01b8cd3 chore: auto-merge develop → main
Triggered by: 2f04543 fix: use 'persons' field (not 'servings') in chatToRecipe for renderRecipe compatibility
2026-05-10 14:56:07 +00:00
dadaloop82 2f04543de3 fix: use 'persons' field (not 'servings') in chatToRecipe for renderRecipe compatibility 2026-05-10 14:54:29 +00:00