Update documentation with all features and learnings
- Updated README with all features: spices filter, shopping list export, clickable container legend, category prefixes - Added deployment troubleshooting for file ownership issues - Updated CLAUDE.md with architecture details, filtering logic, common issues and fixes - Added live URL reference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
91
CLAUDE.md
91
CLAUDE.md
@@ -4,9 +4,17 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
Pantry is a simple web app for tracking kitchen pantry items. It's a single-page application with no build step, consisting of just two files:
|
||||
Pantry is a simple web app for tracking kitchen pantry items. It's a single-page application with no build step.
|
||||
|
||||
**Live URL:** https://pantry.kestrelsnest.social
|
||||
|
||||
## File Structure
|
||||
|
||||
- `index.html` - Frontend (HTML/CSS/JS all in one file)
|
||||
- `api.php` - Backend API (JSON file-based storage)
|
||||
- `containers.json` - Container type definitions with categories
|
||||
- `og-image.png` - OpenGraph image for social sharing
|
||||
- `deploy` - Rsync deployment script
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -14,18 +22,24 @@ Pantry is a simple web app for tracking kitchen pantry items. It's a single-page
|
||||
- Vanilla JavaScript, no frameworks
|
||||
- Uses QRCode.js from CDN for QR code generation
|
||||
- Custom CSS with CSS variables for theming (earthy color palette: cream, terracotta, forest green)
|
||||
- Container types defined in `containerTypes` object (around line 754) - must be kept in sync with backend
|
||||
- Container types loaded from `containers.json` at startup into `containerTypes` object
|
||||
- All API calls go through the `apiCall()` function which POSTs to `api.php`
|
||||
|
||||
**Backend (`api.php`)**:
|
||||
- JSON file-based storage in `data/` directory
|
||||
- Endpoints: `get`, `add`, `update`, `delete`, `setPin`, `verifyPin`
|
||||
- Default inventory defined in `$defaultInventory` array (lines 31-64)
|
||||
- Container types should match frontend when modified
|
||||
- `sanitize()` function only trims whitespace - do NOT add HTML encoding (causes double-encoding issues)
|
||||
|
||||
**Container Configuration (`containers.json`)**:
|
||||
- Defines container types organized by category
|
||||
- Each container has: `id`, `name`, `color`
|
||||
- Categories have: `name`, `containers[]`
|
||||
- Frontend displays as "Category: Container Name" (e.g., "Glass Spice Jars: Hex (Large)")
|
||||
|
||||
**Data Storage**:
|
||||
- `data/inventory.json` - Inventory items
|
||||
- `data/pin.txt` - 4-digit PIN for edit mode (plain text, view-only protection)
|
||||
- `data/pin.txt` - 4-digit PIN for edit mode (plain text)
|
||||
- `data/` directory must be owned by web server user (my_webapp__2), not admin user
|
||||
|
||||
## Development
|
||||
|
||||
@@ -37,14 +51,63 @@ php -S localhost:8000
|
||||
|
||||
Then open `http://localhost:8000` in a browser.
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
- PIN system is view-only protection (anyone can view, PIN required to edit)
|
||||
- PIN stored in plain text - adequate for household use only
|
||||
- Items have: `id`, `name`, `container` (type), `outOfStock` (boolean)
|
||||
- Frontend sorts items: in-stock first, then alphabetically
|
||||
- 8 container types with color-coded dots in UI
|
||||
|
||||
## Deployment
|
||||
|
||||
Designed for YunoHost "My Webapp" deployment. Upload `index.html` and `api.php` to the `www/` folder. The `data/` directory is created automatically and must be writable by the web server.
|
||||
The `deploy` script uses rsync to push to YunoHost:
|
||||
|
||||
```bash
|
||||
# Deploy code, pull data from server
|
||||
./deploy
|
||||
|
||||
# Deploy code AND push local data to server
|
||||
./deploy --reset-data
|
||||
```
|
||||
|
||||
**Important deployment notes:**
|
||||
- Files in `data/` must be owned by the web server user (`my_webapp__2`) for PHP to write to them
|
||||
- If deploying with `--reset-data`, the uploaded files get admin ownership - the web server then can't edit them
|
||||
- Fix with: `sudo chown my_webapp__2:my_webapp__2 /var/www/my_webapp__2/www/data/inventory.json`
|
||||
- Adding admin to the my_webapp__2 group allows the deploy script to write while keeping web server access
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
**Data model:**
|
||||
- Items have: `id`, `name`, `container` (type ID), `outOfStock` (boolean)
|
||||
|
||||
**Filtering:**
|
||||
- `currentFilter` - Tab filter: 'all', 'in-stock', 'out', 'spices', 'qr'
|
||||
- `containerFilter` - Container type filter (null or container ID), set by clicking legend items
|
||||
- Both filters combine with search text
|
||||
|
||||
**Container legend:**
|
||||
- Clickable - filters inventory by that container type
|
||||
- Shows count of items per container type
|
||||
- Active filter highlighted in forest green
|
||||
|
||||
**Shopping list:**
|
||||
- Tap "Out of Stock" stat to copy all out-of-stock item names to clipboard
|
||||
- Sorted alphabetically, one per line
|
||||
|
||||
**UI patterns:**
|
||||
- `renderInventory()` - Re-renders the item list
|
||||
- `renderContainerLegend()` - Re-renders legend with counts, called from `updateStats()`
|
||||
- `showToast(message)` - Shows temporary notification
|
||||
- `escapeHtml(text)` - Escapes text for safe HTML display (used on item names)
|
||||
|
||||
## Common Issues
|
||||
|
||||
**Apostrophes/special characters showing as HTML entities:**
|
||||
- Caused by double-encoding: API was using `htmlspecialchars()` AND frontend uses `escapeHtml()`
|
||||
- Fix: `sanitize()` in api.php should only `trim()`, not HTML-encode
|
||||
- Affected items need to be re-saved through UI
|
||||
|
||||
**Edits not saving:**
|
||||
- Usually file ownership issue - web server can't write to files owned by admin
|
||||
- Check ownership of `data/inventory.json`
|
||||
|
||||
## OpenGraph
|
||||
|
||||
Meta tags in `<head>` point to `og-image.png` at:
|
||||
- `https://pantry.kestrelsnest.social/og-image.png`
|
||||
|
||||
If URL changes, update the `og:image` and `twitter:image` meta tags.
|
||||
|
||||
138
README.md
138
README.md
@@ -2,14 +2,45 @@
|
||||
|
||||
A simple web app for tracking kitchen pantry items across your household.
|
||||
|
||||
**Live demo:** https://pantry.kestrelsnest.social
|
||||
|
||||
## Features
|
||||
|
||||
- **Search** - Instantly filter ingredients by name
|
||||
- **Container tracking** - 8 container types with color-coded indicators
|
||||
- **Filter tabs** - View All, In Stock, Out of Stock, or Spices only
|
||||
- **Container filtering** - Click any container type in the legend to filter by it
|
||||
- **Container tracking** - Multiple container types organized by category with color-coded indicators
|
||||
- **Stock status** - Mark items as in-stock or out-of-stock
|
||||
- **Shopping list** - Tap the "Out of Stock" count to copy all out-of-stock items to clipboard
|
||||
- **PIN protection** - Anyone can view, but editing requires a 4-digit PIN
|
||||
- **QR Code** - Generate a scannable code to post on your pantry shelf
|
||||
- **Shared data** - All household members see the same inventory
|
||||
- **OpenGraph card** - Nice preview when sharing on social media
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
index.html - Frontend (HTML/CSS/JS, no build step)
|
||||
api.php - Backend API (reads/writes JSON files)
|
||||
containers.json - Container type definitions with categories
|
||||
og-image.png - OpenGraph image for social sharing
|
||||
deploy - Deployment script (rsync to server)
|
||||
data/ - Created automatically, excluded from git
|
||||
inventory.json - Your inventory data
|
||||
pin.txt - Stored PIN
|
||||
```
|
||||
|
||||
## Container Types
|
||||
|
||||
Container types are defined in `containers.json` and organized by category:
|
||||
|
||||
| Category | Types |
|
||||
|----------|-------|
|
||||
| Glass Jars | Flip Top (Large/Medium Tall/Medium Squat/Small), Canning Jar (Quart/Pint/Small) |
|
||||
| Plastic Containers | OXO Large, Flip Top, Clamp Top (Large/Tall) |
|
||||
| Glass Spice Jars | Hex (Large/Small), Flip Top (Tiny) |
|
||||
| Other | Original Packaging |
|
||||
|
||||
To add container types, edit `containers.json`.
|
||||
|
||||
## Deployment on YunoHost (My Webapp)
|
||||
|
||||
@@ -19,107 +50,92 @@ In YunoHost admin panel:
|
||||
1. Go to **Applications** → **Install**
|
||||
2. Search for "My Webapp"
|
||||
3. Configure:
|
||||
- **Label**: Pantry (or whatever you prefer)
|
||||
- **Domain/Path**: e.g., `yourdomain.com/pantry`
|
||||
- **Label**: Pantry
|
||||
- **Domain/Path**: e.g., `pantry.yourdomain.com`
|
||||
- **PHP version**: 8.2 or higher
|
||||
- **Database**: None needed
|
||||
4. Install
|
||||
|
||||
### 2. Upload Files
|
||||
|
||||
Connect via SFTP using the credentials shown after installation, then upload to the `www` folder:
|
||||
|
||||
```
|
||||
www/
|
||||
├── index.html (the main app)
|
||||
├── api.php (backend API)
|
||||
└── data/ (created automatically)
|
||||
├── inventory.json
|
||||
└── pin.txt
|
||||
```
|
||||
Upload to the `www` folder:
|
||||
- `index.html`
|
||||
- `api.php`
|
||||
- `containers.json`
|
||||
- `og-image.png`
|
||||
|
||||
### 3. Set Permissions
|
||||
|
||||
The `data` folder needs to be writable by the web server. This should happen automatically, but if you have issues:
|
||||
The `data` folder needs to be writable by the web server user (typically `my_webapp__X`):
|
||||
|
||||
```bash
|
||||
# SSH into your YunoHost server
|
||||
cd /var/www/pantry/www # adjust path as needed
|
||||
cd /var/www/my_webapp__X/www
|
||||
mkdir -p data
|
||||
chmod 755 data
|
||||
sudo chown my_webapp__X:my_webapp__X data
|
||||
chmod 775 data
|
||||
```
|
||||
|
||||
**Important:** Files in `data/` must be owned by the web server user, not your admin user, or edits won't save.
|
||||
|
||||
### 4. First Use
|
||||
|
||||
1. Visit your app URL (e.g., `https://yourdomain.com/pantry`)
|
||||
2. The app loads with a pre-populated inventory based on your photos
|
||||
3. Tap the lock icon → Set a 4-digit PIN for your household
|
||||
1. Visit your app URL
|
||||
2. Tap the lock icon → Set a 4-digit PIN
|
||||
3. Add your pantry items
|
||||
4. Share the PIN with family members who need edit access
|
||||
5. Go to the QR Code tab and print it for your pantry
|
||||
5. Print the QR code for your pantry shelf
|
||||
|
||||
## File Structure
|
||||
## Deploy Script
|
||||
|
||||
```
|
||||
index.html - Frontend (HTML/CSS/JS, no build step)
|
||||
api.php - Backend API (reads/writes JSON files)
|
||||
data/
|
||||
inventory.json - Your inventory data
|
||||
pin.txt - Stored PIN (hashed would be better for production)
|
||||
If you have SSH access, the `deploy` script uses rsync:
|
||||
|
||||
```bash
|
||||
# Deploy code only (pulls current data from server)
|
||||
./deploy
|
||||
|
||||
# Deploy code AND push local data to server
|
||||
./deploy --reset-data
|
||||
```
|
||||
|
||||
## Container Types
|
||||
|
||||
The app supports these container types (edit in both index.html and api.php if you want to change them):
|
||||
|
||||
| ID | Name |
|
||||
|----|------|
|
||||
| glass-bail-large | Glass Bail Jar (Large) |
|
||||
| glass-bail-medium | Glass Bail Jar (Medium) |
|
||||
| glass-bail-small | Glass Bail Jar (Small) |
|
||||
| oxo-large | OXO Container (Large) |
|
||||
| oxo-medium | OXO Container (Medium) |
|
||||
| oxo-small | OXO Container (Small) |
|
||||
| original-package | Original Package |
|
||||
| mason-jar | Mason Jar |
|
||||
Edit the script to set your `HOST` and `DIR` variables.
|
||||
|
||||
## Customization
|
||||
|
||||
### Adding Container Types
|
||||
|
||||
1. In `index.html`, find the `containerTypes` object and add your new type
|
||||
2. In the `<select>` dropdown for containers, add a new `<option>`
|
||||
Edit `containers.json` to add new categories or container types. The frontend loads this file automatically.
|
||||
|
||||
### Changing the Default Inventory
|
||||
### Changing Colors
|
||||
|
||||
Edit the `$defaultInventory` array in `api.php`. This only applies on first run (before `inventory.json` exists).
|
||||
Edit CSS variables at the top of `index.html`:
|
||||
- `--cream`, `--warm-white` - Background colors
|
||||
- `--terracotta` - Accent color
|
||||
- `--forest` - Primary color (buttons, active states)
|
||||
|
||||
### Resetting Everything
|
||||
|
||||
Delete the `data` folder contents to start fresh:
|
||||
Delete the `data` folder contents:
|
||||
```bash
|
||||
rm data/inventory.json data/pin.txt
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- The PIN is stored in plain text. This is fine for a household app where you just want to prevent accidental edits, but don't use this for anything sensitive.
|
||||
- There's no authentication beyond the PIN - anyone with the URL can view your inventory.
|
||||
- For a more secure setup, you could put the app behind YunoHost's SSO.
|
||||
|
||||
## Backup
|
||||
|
||||
YunoHost's My Webapp will backup the entire `www` folder including `data/`. Your inventory and PIN are automatically included in YunoHost backups.
|
||||
- The PIN is stored in plain text - adequate for household use to prevent accidental edits
|
||||
- Anyone with the URL can view your inventory
|
||||
- For more security, put the app behind YunoHost's SSO
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Connection error" message**
|
||||
- Check that PHP is enabled for your My Webapp instance
|
||||
- Verify the `data` folder is writable
|
||||
- Verify the `data` folder exists and is writable
|
||||
|
||||
**PIN not working**
|
||||
- Check that `data/pin.txt` exists and contains exactly 4 digits
|
||||
- Try deleting `data/pin.txt` to reset
|
||||
**Edits not saving**
|
||||
- Check that `data/inventory.json` is owned by the web server user, not your admin user
|
||||
- Run: `sudo chown my_webapp__X:my_webapp__X data/inventory.json`
|
||||
|
||||
**Inventory not saving**
|
||||
- Check `data/inventory.json` permissions
|
||||
- Look for PHP errors in YunoHost logs
|
||||
**Special characters displaying as HTML entities**
|
||||
- The API's `sanitize()` function should only trim whitespace, not HTML-encode
|
||||
- Re-save affected items through the UI to fix
|
||||
|
||||
Reference in New Issue
Block a user