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:
Eric Wagoner
2025-12-23 22:23:23 -05:00
parent 726325e501
commit 08d550b0bd
2 changed files with 154 additions and 75 deletions

View File

@@ -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
View File

@@ -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