first commit
This commit is contained in:
202
CLAUDE.md
Normal file
202
CLAUDE.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Basil is a full-stack recipe manager built with TypeScript. It features a REST API backend, React web frontend, and PostgreSQL database. The application supports importing recipes from URLs via schema.org markup parsing, local/S3 image storage, and comprehensive recipe management (CRUD operations, search, tagging).
|
||||
|
||||
## Architecture
|
||||
|
||||
**Monorepo Structure:**
|
||||
- `packages/shared/` - Shared TypeScript types and interfaces used across all packages
|
||||
- `packages/api/` - Express.js REST API server with Prisma ORM
|
||||
- `packages/web/` - React + Vite web application
|
||||
- Future: `packages/mobile/` - React Native mobile apps
|
||||
|
||||
**Key Technologies:**
|
||||
- Backend: Node.js, TypeScript, Express, Prisma ORM, PostgreSQL
|
||||
- Frontend: React, TypeScript, Vite, React Router
|
||||
- Infrastructure: Docker, Docker Compose, nginx
|
||||
- Recipe Scraping: Cheerio for HTML parsing, Schema.org Recipe markup support
|
||||
|
||||
**Database Schema:**
|
||||
- `Recipe` - Main recipe entity with metadata (prep/cook time, servings, ratings)
|
||||
- `Ingredient` - Recipe ingredients with amounts, units, and ordering
|
||||
- `Instruction` - Step-by-step instructions with optional images
|
||||
- `RecipeImage` - Multiple images per recipe
|
||||
- `Tag` / `RecipeTag` - Many-to-many tagging system
|
||||
|
||||
**Storage Architecture:**
|
||||
- Primary: Local filesystem storage (`./uploads`)
|
||||
- Optional: S3 storage (configurable via environment variables)
|
||||
- Storage service implements strategy pattern for easy switching
|
||||
|
||||
## Development Commands
|
||||
|
||||
```bash
|
||||
# Install all dependencies (root + all packages)
|
||||
npm install
|
||||
|
||||
# Development mode (starts all packages with hot reload)
|
||||
npm run dev
|
||||
|
||||
# Build all packages
|
||||
npm run build
|
||||
|
||||
# Lint all packages
|
||||
npm run lint
|
||||
|
||||
# Docker commands
|
||||
npm run docker:up # Start all services (PostgreSQL, API, web)
|
||||
npm run docker:down # Stop all services
|
||||
npm run docker:build # Rebuild Docker images
|
||||
```
|
||||
|
||||
### Backend-Specific Commands
|
||||
|
||||
```bash
|
||||
cd packages/api
|
||||
|
||||
# Development with auto-reload
|
||||
npm run dev
|
||||
|
||||
# Database migrations
|
||||
npm run prisma:migrate # Create and apply migration
|
||||
npm run prisma:generate # Generate Prisma client
|
||||
npm run prisma:studio # Open Prisma Studio GUI
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
npm start
|
||||
```
|
||||
|
||||
### Frontend-Specific Commands
|
||||
|
||||
```bash
|
||||
cd packages/web
|
||||
|
||||
# Development server
|
||||
npm run dev
|
||||
|
||||
# Production build
|
||||
npm run build
|
||||
npm run preview # Preview production build locally
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
**Environment Variables (packages/api/.env):**
|
||||
```
|
||||
PORT=3001
|
||||
NODE_ENV=development
|
||||
DATABASE_URL=postgresql://basil:basil@localhost:5432/basil?schema=public
|
||||
STORAGE_TYPE=local # or 's3'
|
||||
LOCAL_STORAGE_PATH=./uploads
|
||||
CORS_ORIGIN=http://localhost:5173
|
||||
```
|
||||
|
||||
For S3 storage, add:
|
||||
```
|
||||
S3_BUCKET=basil-recipes
|
||||
S3_REGION=us-east-1
|
||||
S3_ACCESS_KEY_ID=your-key
|
||||
S3_SECRET_ACCESS_KEY=your-secret
|
||||
```
|
||||
|
||||
## Key Features
|
||||
|
||||
### Recipe Import from URL
|
||||
- `POST /api/recipes/import` - Scrapes recipe from URL using schema.org markup
|
||||
- Extracts: title, description, ingredients, instructions, times, images
|
||||
- Handles JSON-LD structured data (primary) with fallback to manual parsing
|
||||
- Downloads and stores images locally or on S3
|
||||
|
||||
### Recipe Management
|
||||
- Full CRUD operations on recipes
|
||||
- Pagination and search (by title, description)
|
||||
- Filtering by cuisine, category
|
||||
- Image upload with multiple images per recipe
|
||||
- Tagging system for organization
|
||||
|
||||
### Storage Service
|
||||
- Abstracted storage interface in `packages/api/src/services/storage.service.ts`
|
||||
- Local storage: Saves to filesystem with timestamped filenames
|
||||
- S3 storage: Placeholder for AWS SDK implementation
|
||||
- Easy to extend for other storage providers
|
||||
|
||||
## Adding New Features
|
||||
|
||||
### Adding a New API Endpoint
|
||||
1. Add route handler in `packages/api/src/routes/*.routes.ts`
|
||||
2. Update shared types in `packages/shared/src/types.ts` if needed
|
||||
3. Rebuild shared package: `cd packages/shared && npm run build`
|
||||
4. Use Prisma client for database operations
|
||||
|
||||
### Adding a New Frontend Page
|
||||
1. Create component in `packages/web/src/pages/`
|
||||
2. Add route in `packages/web/src/App.tsx`
|
||||
3. Create API service methods in `packages/web/src/services/api.ts`
|
||||
4. Import and use shared types from `@basil/shared`
|
||||
|
||||
### Database Schema Changes
|
||||
1. Edit `packages/api/prisma/schema.prisma`
|
||||
2. Run `npm run prisma:migrate` to create migration
|
||||
3. Run `npm run prisma:generate` to update Prisma client
|
||||
4. Update TypeScript types in `packages/shared/src/types.ts` to match
|
||||
|
||||
## Docker Deployment
|
||||
|
||||
The project includes full Docker support for production deployment:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
This starts:
|
||||
- PostgreSQL database (port 5432)
|
||||
- API server (port 3001)
|
||||
- Web frontend served via nginx (port 5173)
|
||||
|
||||
Persistent volumes:
|
||||
- `postgres_data` - Database storage
|
||||
- `uploads_data` - Uploaded images
|
||||
|
||||
## API Reference
|
||||
|
||||
**Recipes:**
|
||||
- `GET /api/recipes` - List all recipes (supports pagination, search, filters)
|
||||
- `GET /api/recipes/:id` - Get single recipe with all relations
|
||||
- `POST /api/recipes` - Create new recipe
|
||||
- `PUT /api/recipes/:id` - Update recipe
|
||||
- `DELETE /api/recipes/:id` - Delete recipe and associated images
|
||||
- `POST /api/recipes/:id/images` - Upload image for recipe
|
||||
- `POST /api/recipes/import` - Import recipe from URL
|
||||
|
||||
**Query Parameters:**
|
||||
- `page`, `limit` - Pagination
|
||||
- `search` - Search in title/description
|
||||
- `cuisine`, `category` - Filter by cuisine or category
|
||||
|
||||
## Important Implementation Details
|
||||
|
||||
### Prisma Relations
|
||||
- All related entities (ingredients, instructions, images, tags) use cascade delete
|
||||
- Ingredients and instructions maintain ordering via `order` and `step` fields
|
||||
- Tags use many-to-many relationship via `RecipeTag` join table
|
||||
|
||||
### Recipe Scraping
|
||||
- Primary: Parses JSON-LD `application/ld+json` scripts for Schema.org Recipe data
|
||||
- Fallback: Extracts basic info from HTML meta tags and headings
|
||||
- Handles ISO 8601 duration format (PT30M, PT1H30M) for cook times
|
||||
- Downloads images asynchronously and stores them locally
|
||||
|
||||
### Frontend Routing
|
||||
- Uses React Router v6 for client-side routing
|
||||
- Vite proxy forwards `/api` and `/uploads` requests to backend during development
|
||||
- Production uses nginx reverse proxy to backend API
|
||||
|
||||
### TypeScript Workspace
|
||||
- Root `package.json` defines npm workspaces
|
||||
- Packages can reference each other (e.g., `@basil/shared`)
|
||||
- Must rebuild shared package when types change for other packages to see updates
|
||||
Reference in New Issue
Block a user