- Update UI immediately when adding/removing tags without full page reload - Fetch updated recipe data in background to get proper tag IDs - Revert optimistic update on error and reload - Maintains scroll position and focus in tag input field Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Basil 🌿
A modern, full-stack recipe manager with web and mobile support. Import recipes from any URL, manage your recipe collection, and access them from anywhere.
Features
- Recipe Import: Automatically import recipes from URLs using schema.org markup
- Add tags during import for instant organization
- Works with 600+ supported recipe sites plus any site with schema.org markup
- Preview recipe before saving with immediate tag management
- Full Recipe Management: Create, read, update, and delete recipes
- Rich Recipe Data: Store ingredients, instructions, prep/cook times, servings, images, and more
- Tag Organization: Quick tagging system with autocomplete for rapid recipe organization
- Add/remove tags inline on recipe detail view
- Tag recipes during import
- Filter recipes by tags
- Recipe Scaling: Adjust serving sizes with automatic ingredient scaling
- Cookbooks: Organize recipes into collections with auto-filtering by tags and categories
- Search & Filter: Find recipes by title, cuisine, category, or tags
- Multiple Images: Add multiple images to each recipe
- User Authentication: Secure multi-user support with email/password and OAuth
- Backup & Restore: Complete data backup including recipes, cookbooks, and images
- Flexible Storage: Local filesystem storage by default, optional S3 support
- Docker Support: Easy deployment with Docker Compose
- API-First Design: RESTful API for web and future mobile apps
Tech Stack
- Backend: Node.js, TypeScript, Express, Prisma ORM, PostgreSQL
- Frontend: React, TypeScript, Vite, React Router
- Infrastructure: Docker, Docker Compose, nginx
- Monorepo: npm workspaces with shared types
Quick Start
Prerequisites
- Node.js 20+
- PostgreSQL 16+ (or use Docker)
- Python 3.x with pip (for recipe scraper)
- Docker (optional, for containerized deployment)
Python Dependencies:
The recipe import feature requires Python 3 and the recipe-scrapers package:
pip3 install recipe-scrapers
For Docker deployments, Python dependencies are automatically installed in the container.
Development Setup
-
Clone the repository
git clone <repository-url> cd basil -
Install dependencies
npm install -
Set up environment variables
cp packages/api/.env.example packages/api/.env # Edit packages/api/.env with your database credentials -
Start PostgreSQL (if not using Docker)
# Create a database named 'basil' createdb basil -
Run database migrations
cd packages/api npm run prisma:migrate npm run prisma:generate cd ../.. -
Start development servers
npm run devThis starts:
- API server at http://localhost:3001
- Web frontend at http://localhost:5173
Docker Deployment
For production or easy local setup:
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
Services will be available at:
- Web: http://localhost:5173
- API: http://localhost:3001
- PostgreSQL: localhost:5432
Project Structure
basil/
├── packages/
│ ├── api/ # Backend API server
│ │ ├── prisma/ # Database schema and migrations
│ │ └── src/ # Express routes, services, config
│ ├── web/ # React web application
│ │ └── src/ # Components, pages, services
│ └── shared/ # Shared TypeScript types
├── docker-compose.yml
└── package.json # Workspace root
Usage
Importing a Recipe
- Navigate to "Import Recipe" in the web app
- Paste a recipe URL (supports 600+ sites including AllRecipes, Food Network, King Arthur Baking, etc.)
- Click "Import Recipe" to fetch and parse the recipe
- Preview the imported recipe details
- Add tags using the quick tag input at the top (with autocomplete)
- Press Enter after each tag for rapid multi-tag addition
- Save to your collection
The recipe importer works with any website that uses schema.org Recipe markup, even if not officially supported by recipe-scrapers.
Managing Tags
Quick Tag Management:
- On recipe detail pages, use the inline tag input next to the servings adjuster
- Press Enter after typing each tag for rapid multi-tag addition
- Focus stays in the input field for quick consecutive tagging
- Autocomplete suggests existing tags as you type
- Click the × button on any tag to remove it
Tag-based Organization:
- Filter recipe list by tag name
- Use tags to organize recipes by cuisine, meal type, dietary restrictions, etc.
- Tags are automatically created when first used
- Rename or delete unused tags from the Tags page
API Examples
Import recipe from URL:
curl -X POST http://localhost:3001/api/recipes/import \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/recipe"}'
Get all recipes:
curl http://localhost:3001/api/recipes
Create a recipe:
curl -X POST http://localhost:3001/api/recipes \
-H "Content-Type: application/json" \
-d '{
"title": "Chocolate Chip Cookies",
"ingredients": [
{"name": "flour", "amount": "2", "unit": "cups", "order": 0}
],
"instructions": [
{"step": 1, "text": "Preheat oven to 350°F"}
],
"tags": ["dessert", "cookies", "quick"]
}'
Update recipe tags:
curl -X PUT http://localhost:3001/api/recipes/:id \
-H "Content-Type: application/json" \
-d '{
"tags": ["italian", "dinner", "vegetarian"]
}'
Filter recipes by tag:
curl http://localhost:3001/api/recipes?tag=dessert
Testing
Basil includes comprehensive test coverage with unit and integration tests:
# Run all tests
npm test
# Run tests with coverage report
cd packages/api
npm run test -- --coverage
# Run specific test file
npx vitest run src/routes/recipes.routes.test.ts
Test Coverage
- Overall: 77.6% coverage
- Routes: 84% coverage
- recipes.routes.ts: 87%
- tags.routes.ts: 92%
- cookbooks.routes.ts: 88%
- backup.routes.ts: 74%
- auth.routes.ts: 37%
- Services: 66% coverage
- Utils: 100% coverage
Test suite includes:
- 377+ passing tests across 21 test files
- Unit tests for all route handlers
- Integration tests for API endpoints
- Real integration tests for recipe scraper (live URL testing)
- Authentication and authorization tests
- Backup and restore functionality tests
Configuration
Storage Options
Local Storage (Default):
STORAGE_TYPE=local
LOCAL_STORAGE_PATH=./uploads
S3 Storage:
STORAGE_TYPE=s3
S3_BUCKET=your-bucket-name
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-access-key
S3_SECRET_ACCESS_KEY=your-secret-key
Database
Default PostgreSQL connection:
DATABASE_URL=postgresql://basil:basil@localhost:5432/basil?schema=public
For external database services (AWS RDS, DigitalOcean, etc.), update the connection string.
Development
Commands
# Install dependencies
npm install
# Start all services in development mode
npm run dev
# Build all packages
npm run build
# Lint all packages
npm run lint
# Docker commands
npm run docker:up
npm run docker:down
npm run docker:build
Database Migrations
cd packages/api
# Create a new migration
npm run prisma:migrate
# Generate Prisma client
npm run prisma:generate
# Open Prisma Studio (GUI for database)
npm run prisma:studio
Future Enhancements
- Mobile apps (React Native for iOS and Android)
- Recipe sharing and social features
- Meal planning and grocery lists
- Nutritional information calculation
- Print-friendly recipe view with custom formatting
- Recipe ratings and reviews
- Shopping list generation from recipes
- Ingredient substitution suggestions
- Recipe notes and personal modifications
- Advanced search with multiple filters
- Recipe version history
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
When contributing:
- Write tests for new features (maintain 80%+ coverage)
- Follow existing code style and conventions
- Update documentation as needed
- Ensure all tests pass before submitting PR