parsley/CLAUDE.md

74 lines
3.4 KiB
Markdown
Raw Normal View History

2026-04-20 13:46:42 -05:00
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Parsley is a personal recipe manager and meal planning app. It is a monolithic Rails 7.2 application with a Vue 3 SPA frontend.
**Backend:** Ruby 4.0.2, Rails 8.1.3, SQLite (dev/test), PostgreSQL (production)
**Frontend:** Vue 3 (Composition API / `<script setup>`), Pinia, Vue Router 4, Bulma CSS
**Asset bundling:** Shakapacker 8 (Webpack 5 + SWC)
**Testing:** RSpec, FactoryBot, Guard
## Common Commands
```bash
# Development
foreman start # Start Rails + Shakapacker dev server together
# Dependencies
bundle install && yarn install
# Database
bundle exec rake db:create db:migrate db:seed
bundle exec rake db:reset # Drop, recreate, seed
# Tests
bundle exec rspec # All tests
bundle exec rspec spec/models/recipe_spec.rb # Single file
bundle exec rspec spec/models/recipe_spec.rb:42 # Single test by line
bundle exec guard # Watch mode
# Build
bundle exec rake shakapacker:compile # Compile assets for production
```
**Test environment note:** Set `FAST=true` to skip FactoryBot linting on startup.
## Architecture
### Backend
**Models follow an `Ingredient` abstraction:** `Recipe` and `Food` both inherit from an abstract `Ingredient` base class. This allows recipes to contain both foods and other recipes as ingredients (`RecipeIngredient` is a polymorphic join). Polymorphic ingredient IDs are encoded as strings: `F{id}` for foods, `R{id}` for recipes.
**Custom unit conversion library** (`lib/unit_conversion/`): The `UnitConversion` module handles all quantity parsing and conversion. It is density-aware (can convert volume ↔ mass if food density is known) and supports custom per-food units defined in `FoodUnit` records. Key entry points: `UnitConversion.parse`, `UnitConversion.auto_unit`, `UnitConversion.with_custom_units`.
**Recipe scaling:** Recipes can be scaled by a factor and converted between unit systems (standard/metric) and unit types (mass/volume). Cache keys incorporate scale and unit system: `recipes/{id}/{scale}/{system}/{unit}`. Memcache is optional; enable with `RAILS_USE_MEMCACHE=true`.
**USDA nutrition data:** The `UsdaImporter` (lib/) imports from `vendor/data/usda/` during `db:seed`. `UsdaFood`/`UsdaFoodWeight` tables are a read-only cache; `Food` records link to them and inherit nutritional data.
**Serializers** (`app/serializers/`) handle all JSON API responses.
### Frontend
Vue 3 components live in `app/javascript/components/`. They use `<script setup>` Composition API style. Pinia stores (`app/javascript/stores/`) hold global state. Vue Router (`app/javascript/router/`) manages navigation.
Page-level components are named `The*` (e.g., `TheRecipeList`, `TheFood`, `TheCalculator`). Shared UI primitives are named `App*` (e.g., `AppModal`, `AppAutocomplete`, `AppIcon`).
### Key Environment Variables
| Variable | Purpose |
|----------|---------|
| `RAILS_USE_MEMCACHE` | Enable Memcache caching |
| `RAILS_MEMCACHE_HOST` | Memcache host (default: `memcache`) |
| `PARSLEY_DB_HOST/USER/PG_PASSWORD/DB_NAME` | Production PostgreSQL config |
### Docker
`docker-compose up` starts PostgreSQL, Memcached, Nginx, and two Rails service instances. See `docker-compose.yml` and `Dockerfile`.
### Seed Data
Default dev user: username `dan`, password `qwerty`. Comes with sample recipes and foods.