# 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 `` 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.