Document waste reason picker, stable price estimates, DB retry, and kiosk CI fixes in CHANGELOG and README.
Co-authored-by: Cursor <cursoragent@cursor.com>
Price each list line as one retail purchase; learn from discard reasons to cap restock suggestions. Retry inventory_use/shopping_add on SQLITE_BUSY; extend smart_shopping time limit. Reopen feature issues #98/#125; close auto-report bugs #201–#204.
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto-run LAN discovery on server step; serve kiosk updates from releases/ via kiosk_update API; check LAN before GitHub for OTA in-place upgrades. Docker CI retries hub timeouts. Remove non-English feature issue comments; triage script English-only.
Co-authored-by: Cursor <cursoragent@cursor.com>
Discovery no longer aborts after 3s idle, probes priority hosts (.128, gateway) first, accepts ping API and normalizes HTTPS URLs. OTA compares versionCode from release notes; bump kiosk to 1.7.18.
Co-authored-by: Cursor <cursoragent@cursor.com>
Price each list line as one retail purchase instead of 14-day restock qty; convert €/kg AI prices to estimated piece weight; cap smart-shopping suggested conf/pz counts. Stop triage script from bulk-closing feature backlog.
Co-authored-by: Cursor <cursoragent@cursor.com>
Escape apostrophes and normalize multiline strings in de/es/fr/it so assembleDebug no longer fails with invalid unicode escape sequences.
Co-authored-by: Cursor <cursoragent@cursor.com>
Maintenance CLI for finished-product/shopping audit, Bring sync, and
install-transformers-model.sh to fetch the Xenova classifier (model gitignored).
Co-authored-by: Cursor <cursoragent@cursor.com>
Manual AI identification replaces auto-fallback; add duplicate-add guard,
AI product match UI, ZBar/Tesseract offline scanning, expiry averages from
last 3 insertions, family sibling hints, and missing i18n keys.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add depleted products under generic shopping names, unify weekly canonical price total across all surfaces, and fix screensaver amount mismatch.
Co-authored-by: Cursor <cursoragent@cursor.com>
Prevent false ✅ pantry links via strict name matching and full inventory prompts; fix qtyNum crash when reopening archived recipes.
Co-authored-by: Cursor <cursoragent@cursor.com>
Send API token headers on generate_recipe_stream, expiry_history, and tts_proxy after security hardening.
Co-authored-by: Cursor <cursoragent@cursor.com>
Accept Authorization Bearer tokens, expose ha_info for discovery without API token, and report api_token_required in haGetInfo.
Co-authored-by: Cursor <cursoragent@cursor.com>
Block web access to sensitive paths, require API_TOKEN for mutations, encrypt GitHub issue credentials in .env, auto-provision tokens for same-origin clients, and pass api_token in scale relay URLs since EventSource cannot send headers.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Manual barcode input now blocks on invalid EAN checksum (was warning-only)
- Native BarcodeDetector now validates EAN/UPC checksum before confirming
- Renamed duplicate adjustRecipePersons (rescaler) to scaleRecipePersons
to restore +/- buttons in the recipe generation dialog
- Added error.barcode_checksum translation key (all 5 languages)
- Bump version to v1.7.35
stopScanner() is called internally by initScanner() on every restart,
so resetting the flag there caused the AI timer to re-arm on every
internal cycle — creating an infinite 5-second loop.
Flag now resets only in showPage('scan'), which fires exclusively when
the user opens the scanner page (fresh session). Internal stop/restart
cycles leave the flag untouched.
If Gemini cannot identify the product visually, mark _aiFallbackExhausted=true
for the current scanner session so the 5s timer never fires again. The scanner
restarts normally (user can keep trying with the barcode reader) and a persistent
status message is shown: 'AI: product not recognized — try scanning the barcode'.
_aiFallbackExhausted resets to false in stopScanner() so the next camera session
starts fresh.
When the barcode scanner cannot read a code within 5 seconds and Gemini
is available, a camera frame is automatically captured and sent to the
new gemini_barcode_visual endpoint for visual product identification.
The result pre-fills the product form identically to a barcode scan.
- PHP: new geminiBarcodeVisual() function + router case + aiActions entry
- PHP: barcode_ai_fallback setting in getServerSettings() + saveSettings() boolMap
- JS: _aiFallbackTimer (cleared on detection/stop), 5s timer in initScanner()
- JS: _tryGeminiVisualBarcode() — captures JPEG frame, calls API, saves product
- JS: barcode_ai_fallback wired into serverKeys, applyUI, collectUI, POST body
- HTML: AI fallback toggle in Settings → Camera card
- Translations: ai_fallback_* strings in scan + settings.camera (it/en/de/fr/es)
Feature is disabled by default (BARCODE_AI_FALLBACK=false).
- Extended shopping_total cache TTL from 1h to 24h
- Added inline price fallback: when cache is empty/stale, computes total
from shopping_price_cache.json (no AI calls); joins shopping_list with
products to get canonical shopping_name; tries both v3 and legacy v0
key formats to maximise cache hit rate; works in both internal and
Bring shopping modes (removed isShoppingBringMode guard — table is
always populated by sync)
- Fixed haInventorySensor + haRefreshPrices: shopping_list has no
quantity/unit/checked columns; changed to SELECT name with
COALESCE(p.shopping_name, sl.name) join, defaults qty=1/unit=pz
- Extend isExpiringSoon threshold: 3d -> 7d
- Expired items: add isRegular/buyCount>=2 guard so one-off
expired products don't appear in shopping list (expiry
banner already covers them)
- Expiring-soon block: require isRegular for 7-day window;
add 'willExpireBeforeUsed' check (daysLeft > daysToExpiry);
new reason string 'Scade in Ngg — ricompra' when stock is
adequate but won't be consumed in time
When adding a new pack of a product that already has an opened row
in inventory (opened_at IS NOT NULL), the previous code merged the
new stock into the opened row, corrupting opened_at tracking and
hiding the second pack from the anomaly model.
Now: search only for sealed rows (opened_at IS NULL) to merge into.
If only opened rows exist, INSERT a new sealed row instead.
getConsumptionPredictions now aggregates total qty across all
inventory rows for the same product_id before flagging.
If totalQtyAllRows >= expectedQty, the anomaly is suppressed
(stock is healthy, just split across opened+sealed rows).
Also uses aggregated total as the displayed actual_qty.
Products like salt/spices that are never marked per-use now get
consumption rate estimated from the average time between restocks:
avgCycleDays = (lastIn - firstIn) / (buyCount - 1)
estimatedDaysLeft = avgCycleDays - daysSinceLastBuy
Requirements: buyCount >= 3, dailyRate == 0, avgCycle >= 7 days.
Appears in smart shopping list with reason 'Finisce tra ~Ngg (ciclo medio Mgg)'.
Also marks buy-cycle products as isRegular so stock checks apply.