Files
pantry/CLAUDE.md
Eric Wagoner 731e9ac58c Add ownership warning to deploy --reset-data
The script now prints the chown command needed after pushing data,
since uploaded files are owned by admin and the web server can't
write to them. Updated docs to match.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-24 14:40:41 -05:00

123 lines
4.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
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
- `categories.json` - Item category definitions (Flours, Spices, Pasta, etc.)
- `og-image.png` - OpenGraph image for social sharing
- `deploy` - Rsync deployment script
## Architecture
**Frontend (`index.html`)**:
- 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 loaded from `containers.json` at startup into `containerTypes` object
- Item categories loaded from `categories.json` at startup into `itemCategories` 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`
- `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)")
**Item Categories (`categories.json`)**:
- Defines item categories for organizing inventory (Flours, Spices, Pasta, Baking, etc.)
- Each category has: key (e.g., `flours`), `name`, `color`
- Category tabs are dynamically generated in the nav bar
- Items display their category as a colored tag
**Data Storage**:
- `data/inventory.json` - Inventory items
- `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
This is a no-build project. To test locally:
```bash
php -S localhost:8000
```
Then open `http://localhost:8000` in a browser.
## Deployment
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
- Using `--reset-data` uploads files as admin — you must fix ownership afterward (the script shows the command)
- If edits aren't saving, check ownership with `ls -la` and fix with:
`sudo chown -R my_webapp__2:my_webapp__2 /var/www/my_webapp__2/www/data/`
## Key Implementation Details
**Data model:**
- Items have: `id`, `name`, `container` (type ID), `category` (category key), `outOfStock` (boolean)
**Filtering:**
- `currentFilter` - Tab filter: 'all', 'in-stock', 'out', 'category', 'recent', 'qr'
- `categoryFilter` - Category filter (null or category key), set by clicking category tabs
- `containerFilter` - Container type filter (null or container ID), set by clicking legend items
- All 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.