diff --git a/.dockerignore b/.dockerignore
index d6122cd..19774dd 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,5 +1,5 @@
# Docker runtime files
-data/dispensa.db
+data/evershelf.db
data/*.db-wal
data/*.db-shm
data/backups/
diff --git a/.env.example b/.env.example
index 9fec62c..16bb48a 100644
--- a/.env.example
+++ b/.env.example
@@ -1,4 +1,4 @@
-# Dispensa Manager - Configuration
+# EverShelf - Configuration
# Copy this file to .env and fill in your values
# cp .env.example .env
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d6ab44b..978f32b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -40,14 +40,14 @@ jobs:
- uses: actions/checkout@v4
- name: Build Docker image
- run: docker build -t dispensa-test .
+ run: docker build -t evershelf-test .
- name: Test container starts
run: |
- docker run -d --name test-dispensa -p 8080:80 dispensa-test
+ docker run -d --name test-evershelf -p 8080:80 evershelf-test
sleep 5
curl -f http://localhost:8080/ || exit 1
- docker stop test-dispensa
+ docker stop test-evershelf
validate-translations:
name: Validate Translation Files
diff --git a/.gitignore b/.gitignore
index 36ad6c6..925deaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
.env
# Data directory (user-specific runtime data)
+data/evershelf.db
data/dispensa.db
data/*.db-wal
data/*.db-shm
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e1d040..3bd46d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,30 @@
# Changelog
-All notable changes to Dispensa Manager will be documented in this file.
+All notable changes to EverShelf will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.2.0] - 2026-04-13
+
+### Changed
+- **Project renamed** from "Dispensa Manager" to **EverShelf**
+- Contact email updated to `evershelfproject@gmail.com`
+- Docker service, container, and volume renamed to `evershelf`
+- SQLite database renamed from `dispensa.db` to `evershelf.db`
+- All localStorage keys migrated: `dispensa_*` β `evershelf_*`
+- Apache config file renamed to `evershelf.conf`
+- CI workflow Docker image/container names updated
+- App name updated in all translations (it, en, de)
+- Navigation title updated to EverShelf across all languages
+
+### Added
+- Version badge (`v1.2.0`) in the app header
+
+### Fixed
+- JS file truncation caused by `sed` in-place edit on large files
+- Browser cache invalidation via bumped asset version strings (`?v=20260413a`)
+
## [1.0.0] - 2026-04-10
### Added
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f306e87..39cafa1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-# Contributing to Dispensa Manager
+# Contributing to EverShelf
Thank you for your interest in contributing! This guide will help you get started.
@@ -7,8 +7,8 @@ Thank you for your interest in contributing! This guide will help you get starte
1. **Fork** the repository
2. **Clone** your fork:
```bash
- git clone https://github.com/YOUR_USERNAME/dispensa.git
- cd dispensa
+ git clone https://github.com/YOUR_USERNAME/EverShelf.git
+ cd EverShelf
```
3. **Create a branch** from `develop`:
```bash
@@ -55,7 +55,7 @@ Translations are one of the easiest ways to contribute! Each language is a singl
```json
{
- "app.title": "Dispensa Manager",
+ "app.title": "EverShelf",
"nav.dashboard": "Dashboard",
"nav.inventory": "Inventario",
...
@@ -110,7 +110,7 @@ node -c assets/js/app.js
python3 -c "import json; json.load(open('translations/it.json'))"
# Test Docker build
-docker build -t dispensa-test .
+docker build -t evershelf-test .
```
## π Pull Request Process
diff --git a/Dockerfile b/Dockerfile
index e70304d..5b272a9 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -29,8 +29,8 @@ RUN [ ! -f /var/www/html/.env ] && cp /var/www/html/.env.example /var/www/html/.
RUN echo '\n\
AllowOverride All\n\
Require all granted\n\
-' > /etc/apache2/conf-available/dispensa.conf \
- && a2enconf dispensa
+' > /etc/apache2/conf-available/evershelf.conf \
+ && a2enconf evershelf
# Expose port 80
EXPOSE 80
diff --git a/README.md b/README.md
index 7bfebb2..f58bdcb 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# π Dispensa Manager
+# π EverShelf
> **Self-hosted pantry management system** β Track your food inventory, scan barcodes, get AI-powered recipe suggestions, and reduce waste.
@@ -71,8 +71,8 @@
```bash
# 1. Clone the repository
-git clone https://github.com/dadaloop82/dispensa.git
-cd dispensa
+git clone https://github.com/dadaloop82/EverShelf.git
+cd EverShelf
# 2. Create configuration file
cp .env.example .env
@@ -88,8 +88,8 @@ docker compose up -d
```bash
# 1. Clone the repository
-git clone https://github.com/dadaloop82/dispensa.git
-cd dispensa
+git clone https://github.com/dadaloop82/EverShelf.git
+cd EverShelf
# 2. Create configuration file
cp .env.example .env
@@ -127,7 +127,7 @@ TTS_ENABLED=true
The app works out of the box with Apache if placed in the web root or a subdirectory. Make sure `mod_rewrite` is enabled and `AllowOverride All` is set.
```apache
-
+
AllowOverride All
Require all granted
@@ -142,7 +142,7 @@ The app works out of the box with Apache if placed in the web root or a subdirec
server {
listen 80;
server_name your-server.local;
- root /var/www/html/dispensa;
+ root /var/www/html/evershelf;
index index.html;
location /api/ {
@@ -176,7 +176,7 @@ Set up a cron job for smart shopping predictions:
```bash
# Run every 5 minutes
-*/5 * * * * php /path/to/dispensa/api/cron_smart_shopping.php >> /path/to/dispensa/data/cron.log 2>&1
+*/5 * * * * php /path/to/evershelf/api/cron_smart_shopping.php >> /path/to/evershelf/data/cron.log 2>&1
```
### Backup (Optional)
@@ -185,7 +185,7 @@ The included `backup.sh` creates local daily backups of your database:
```bash
# Run daily at 3 AM
-0 3 * * * /path/to/dispensa/backup.sh
+0 3 * * * /path/to/evershelf/backup.sh
```
---
@@ -193,7 +193,7 @@ The included `backup.sh` creates local daily backups of your database:
## ποΈ Architecture
```
-dispensa/
+evershelf/
βββ index.html # Single-page application (SPA)
βββ manifest.json # PWA manifest
βββ .env.example # Configuration template
@@ -211,7 +211,7 @@ dispensa/
β βββ img/ # Static images
β
βββ data/ # Runtime data (gitignored)
- βββ dispensa.db # SQLite database (auto-created)
+ βββ evershelf.db # SQLite database (auto-created)
βββ backups/ # Local DB backups
βββ *.json # Token/cache files
```
@@ -255,7 +255,7 @@ dispensa/
```bash
# Run PHP's built-in server for local development
-php -S localhost:8080 -t /path/to/dispensa
+php -S localhost:8080 -t /path/to/evershelf
# Check PHP syntax
php -l api/index.php
@@ -315,6 +315,6 @@ This project is licensed under the **MIT License** β see the [LICENSE](LICENSE
## π¨βπ» Author
-**Stimpfl Daniel** β [dadaloop82@gmail.com](mailto:dadaloop82@gmail.com)
+**Stimpfl Daniel** β [evershelfproject@gmail.com](mailto:evershelfproject@gmail.com)
- GitHub: [@dadaloop82](https://github.com/dadaloop82)
diff --git a/api/cron_smart_shopping.php b/api/cron_smart_shopping.php
index 64b1718..1b97d1b 100644
--- a/api/cron_smart_shopping.php
+++ b/api/cron_smart_shopping.php
@@ -2,7 +2,7 @@
/**
* Cron: pre-compute smart shopping list and save to cache.
* Install with: crontab -e
- * *\/5 * * * * php /var/www/html/dispensa/api/cron_smart_shopping.php >> /var/www/html/dispensa/data/cron.log 2>&1
+ * *\/5 * * * * php /var/www/html/evershelf/api/cron_smart_shopping.php >> /var/www/html/evershelf/data/cron.log 2>&1
*/
// Only allow CLI execution β block HTTP access
diff --git a/api/database.php b/api/database.php
index 55ad99f..badc715 100644
--- a/api/database.php
+++ b/api/database.php
@@ -1,13 +1,13 @@
+ * @author Stimpfl Daniel
* @license MIT
*/
-define('DB_PATH', __DIR__ . '/../data/dispensa.db');
+define('DB_PATH', __DIR__ . '/../data/evershelf.db');
function getDB(): PDO {
$isNew = !file_exists(DB_PATH);
diff --git a/api/index.php b/api/index.php
index 678e876..7fa7207 100644
--- a/api/index.php
+++ b/api/index.php
@@ -1,10 +1,10 @@
+ * @author Stimpfl Daniel
* @license MIT
*/
diff --git a/assets/css/style.css b/assets/css/style.css
index ee895da..023af77 100644
--- a/assets/css/style.css
+++ b/assets/css/style.css
@@ -1,8 +1,8 @@
/**
- * Dispensa Manager - UI Styles
+ * EverShelf - UI Styles
* Mobile-first PWA design with CSS custom properties.
*
- * @author Stimpfl Daniel
+ * @author Stimpfl Daniel
* @license MIT
*/
@@ -81,6 +81,16 @@ body {
font-size: 1.3rem;
font-weight: 700;
cursor: pointer;
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+}
+
+.header-version {
+ font-size: 0.6rem;
+ font-weight: 400;
+ opacity: 0.7;
+ letter-spacing: 0.03em;
}
.header-btn {
diff --git a/assets/js/app.js b/assets/js/app.js
index 9cd78b7..293b7f7 100644
--- a/assets/js/app.js
+++ b/assets/js/app.js
@@ -1,9 +1,9 @@
/**
- * Dispensa Manager - Main Application JS
+ * EverShelf - Main Application JS
* Complete pantry management with barcode scanning, AI identification,
* Bring! shopping list integration, recipe generation, and TTS cooking mode.
*
- * @author Stimpfl Daniel
+ * @author Stimpfl Daniel
* @license MIT
*/
@@ -61,7 +61,7 @@ const API_BASE = 'api/index.php';
// ===== i18n TRANSLATION SYSTEM =====
let _i18nStrings = null; // current language translations (flat)
let _i18nFallback = null; // Italian fallback (flat)
-let _currentLang = localStorage.getItem('dispensa_lang') || navigator.language?.slice(0, 2) || 'it';
+let _currentLang = localStorage.getItem('evershelf_lang') || navigator.language?.slice(0, 2) || 'it';
const _SUPPORTED_LANGS = { it: 'Italiano', en: 'English', de: 'Deutsch' };
if (!_SUPPORTED_LANGS[_currentLang]) _currentLang = 'it';
@@ -107,7 +107,7 @@ async function loadTranslations(lang) {
else _i18nStrings = _i18nFallback;
}
_currentLang = lang;
- localStorage.setItem('dispensa_lang', lang);
+ localStorage.setItem('evershelf_lang', lang);
_applyI18nToLabels();
translatePage();
} catch (e) {
@@ -170,7 +170,7 @@ function _populateLanguageSelector() {
// Change language and reload the page
function changeLanguage(lang) {
if (lang === _currentLang) return;
- localStorage.setItem('dispensa_lang', lang);
+ localStorage.setItem('evershelf_lang', lang);
location.reload();
}
@@ -728,7 +728,7 @@ let _settingsDirty = false;
function getSettings() {
if (!_settingsCache) {
try {
- _settingsCache = JSON.parse(localStorage.getItem('dispensa_settings') || '{}');
+ _settingsCache = JSON.parse(localStorage.getItem('evershelf_settings') || '{}');
} catch(e) { _settingsCache = {}; }
}
const s = _settingsCache;
@@ -746,7 +746,7 @@ function getSettings() {
function saveSettingsToStorage(settings) {
_settingsCache = settings;
- localStorage.setItem('dispensa_settings', JSON.stringify(settings));
+ localStorage.setItem('evershelf_settings', JSON.stringify(settings));
// Persist to DB
_settingsDirty = true;
_debouncedSyncSettings();
@@ -798,7 +798,7 @@ async function syncSettingsFromDB() {
if (db[key] !== undefined) s[key] = db[key];
}
_settingsCache = s;
- localStorage.setItem('dispensa_settings', JSON.stringify(s));
+ localStorage.setItem('evershelf_settings', JSON.stringify(s));
}
if (res.settings.review_confirmed) {
_reviewConfirmedCache = res.settings.review_confirmed;
@@ -7716,7 +7716,7 @@ async function testTTS() {
s.tts_rate = parseFloat(document.getElementById('setting-tts-rate')?.value) || 1;
s.tts_pitch = parseFloat(document.getElementById('setting-tts-pitch')?.value) || 1;
saveSettingsToStorage(s);
- _speakBrowser('Test vocale Dispensa Manager. La sintesi vocale funziona correttamente.');
+ _speakBrowser('Test vocale EverShelf. La sintesi vocale funziona correttamente.');
if (statusEl) { statusEl.style.display = 'block'; statusEl.className = 'settings-status success'; statusEl.textContent = 'β
Riproduzione in corso β controlla l\'audio del dispositivo.'; }
return;
}
@@ -7740,7 +7740,7 @@ async function testTTS() {
}
if (statusEl) { statusEl.style.display = 'block'; statusEl.className = 'settings-status'; statusEl.textContent = 'β³ Invio in corsoβ¦'; }
try {
- const req = _buildTtsRequest('Test vocale Dispensa Manager', formSettings);
+ const req = _buildTtsRequest('Test vocale EverShelf', formSettings);
const res = await _ttsViaProxy(req);
const data = await res.json().catch(() => ({}));
const httpCode = data.status || res.status;
@@ -8932,7 +8932,7 @@ function _getMissingSetupSteps(serverSettings) {
const srv = serverSettings || {};
// Step 0 β language: missing only if never set at all (fresh install)
- if (!localStorage.getItem('dispensa_lang') && !localStorage.getItem('dispensa_setup_done')) {
+ if (!localStorage.getItem('evershelf_lang') && !localStorage.getItem('evershelf_setup_done')) {
missing.push(0);
}
// Step 1 β Gemini API key (check both localStorage and server .env)
@@ -9083,10 +9083,10 @@ function setupWizardNav(dir) {
// If language changed, apply it
if (realIndex === 0 && dir === 1 && _setupData.lang !== _currentLang) {
- localStorage.setItem('dispensa_lang', _setupData.lang);
- localStorage.setItem('dispensa_setup_step', String(_setupStep + 1));
- localStorage.setItem('dispensa_setup_pending', JSON.stringify(_setupPendingSteps));
- localStorage.setItem('dispensa_setup_data', JSON.stringify(_setupData));
+ localStorage.setItem('evershelf_lang', _setupData.lang);
+ localStorage.setItem('evershelf_setup_step', String(_setupStep + 1));
+ localStorage.setItem('evershelf_setup_pending', JSON.stringify(_setupPendingSteps));
+ localStorage.setItem('evershelf_setup_data', JSON.stringify(_setupData));
location.reload();
return;
}
@@ -9112,24 +9112,24 @@ async function _finishSetup() {
});
} catch(e) { /* will work locally */ }
- localStorage.setItem('dispensa_setup_done', '1');
- localStorage.removeItem('dispensa_setup_step');
- localStorage.removeItem('dispensa_setup_data');
+ localStorage.setItem('evershelf_setup_done', '1');
+ localStorage.removeItem('evershelf_setup_step');
+ localStorage.removeItem('evershelf_setup_data');
document.getElementById('setup-wizard').style.display = 'none';
}
async function _initApp() {
// Check for setup wizard resume (after language change)
- const resumeStep = localStorage.getItem('dispensa_setup_step');
- const resumeData = localStorage.getItem('dispensa_setup_data');
- const resumePending = localStorage.getItem('dispensa_setup_pending');
+ const resumeStep = localStorage.getItem('evershelf_setup_step');
+ const resumeData = localStorage.getItem('evershelf_setup_data');
+ const resumePending = localStorage.getItem('evershelf_setup_pending');
if (resumeStep && resumePending) {
try { Object.assign(_setupData, JSON.parse(resumeData)); } catch(e) {}
try { _setupPendingSteps = JSON.parse(resumePending); } catch(e) {}
_setupStep = parseInt(resumeStep) || 0;
- localStorage.removeItem('dispensa_setup_step');
- localStorage.removeItem('dispensa_setup_data');
- localStorage.removeItem('dispensa_setup_pending');
+ localStorage.removeItem('evershelf_setup_step');
+ localStorage.removeItem('evershelf_setup_data');
+ localStorage.removeItem('evershelf_setup_pending');
document.getElementById('setup-wizard').style.display = '';
_renderSetupStep();
} else {
diff --git a/backup.sh b/backup.sh
index e52ed95..5ffe046 100755
--- a/backup.sh
+++ b/backup.sh
@@ -1,23 +1,23 @@
#!/bin/bash
-# Daily backup of Dispensa database (local only)
+# Daily backup of EverShelf database (local only)
# The database is NOT pushed to remote repositories.
# Runs via cron: creates a local timestamped backup copy
#
# Example crontab entry:
-# 0 3 * * * /var/www/html/dispensa/backup.sh
+# 0 3 * * * /var/www/html/evershelf/backup.sh
INSTALL_DIR="$(cd "$(dirname "$0")" && pwd)"
BACKUP_DIR="${INSTALL_DIR}/data/backups"
mkdir -p "$BACKUP_DIR"
-DB_FILE="${INSTALL_DIR}/data/dispensa.db"
+DB_FILE="${INSTALL_DIR}/data/evershelf.db"
if [ ! -f "$DB_FILE" ]; then
exit 0
fi
DATE=$(date '+%Y-%m-%d_%H%M')
-cp "$DB_FILE" "${BACKUP_DIR}/dispensa_${DATE}.db"
+cp "$DB_FILE" "${BACKUP_DIR}/evershelf_${DATE}.db"
# Keep only the last 7 backups
-ls -t "${BACKUP_DIR}"/dispensa_*.db 2>/dev/null | tail -n +8 | xargs -r rm --
+ls -t "${BACKUP_DIR}"/evershelf_*.db 2>/dev/null | tail -n +8 | xargs -r rm --
diff --git a/docker-compose.yml b/docker-compose.yml
index fb808bf..cdbefa0 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,12 +1,12 @@
services:
- dispensa:
+ evershelf:
build: .
- container_name: dispensa
+ container_name: evershelf
ports:
- "8080:80"
volumes:
# Persist database and runtime data
- - dispensa_data:/var/www/html/data
+ - evershelf_data:/var/www/html/data
# Mount your local .env configuration
- ./.env:/var/www/html/.env:ro
restart: unless-stopped
@@ -14,5 +14,5 @@ services:
- TZ=Europe/Rome
volumes:
- dispensa_data:
+ evershelf_data:
driver: local
diff --git a/docs/openapi.yaml b/docs/openapi.yaml
index 4e1447e..96f4aba 100644
--- a/docs/openapi.yaml
+++ b/docs/openapi.yaml
@@ -1,8 +1,8 @@
openapi: "3.1.0"
info:
- title: Dispensa Manager API
+ title: EverShelf API
description: |
- REST API for Dispensa Manager β a self-hosted pantry management system.
+ REST API for EverShelf β a self-hosted pantry management system.
All endpoints use the query parameter `action` to determine the operation.
**Base URL:** `api/index.php?action={action_name}`
@@ -11,10 +11,10 @@ info:
- General: 120 requests/minute
- AI endpoints: 15 requests/minute
- Login endpoints: 5 requests/minute
- version: "1.0.0"
+ version: "1.2.0"
contact:
name: Stimpfl Daniel
- email: dadaloop82@gmail.com
+ email: evershelfproject@gmail.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
diff --git a/index.html b/index.html
index a827ecd..daf069d 100644
--- a/index.html
+++ b/index.html
@@ -8,10 +8,10 @@
- Dispensa Manager
+ EverShelf
-
+
@@ -20,7 +20,7 @@