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

4.5 KiB

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:

php -S localhost:8000

Then open http://localhost:8000 in a browser.

Deployment

The deploy script uses rsync to push to YunoHost:

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