SavoryNotes is a modern, full-stack food recipes blog that allows users to discover and share their favorite recipes with an intelligent AI cooking assistant powered by Google's Gemini AI.
This Recipe Sharing Platform is a comprehensive web application designed for food enthusiasts who want to discover, create, and share recipes within a vibrant community. It features a modern, intuitive interface for seamless discovery, robust search and filtering capabilities, and complete user authentication. Our core differentiator is the integrated AI Chef Bot—an intelligent assistant ready to answer any cooking question, from suggesting ingredient substitutions and providing precise nutritional counts to offering step-by-step cooking tips. This platform makes personalized, successful cooking accessible to everyone.
- 🔐 Secure user authentication with role-based access control
- 📝 Admin can create, edit, and delete recipes
- 🔍 Advanced search with category and difficulty filters
- 🤖 AI-powered cooking assistant using Google Gemini
- 📱 Fully responsive design for mobile and desktop
- 🖼️ Multiple image support with image carousel
- 🏷️ Tag-based recipe organization
- ⏱️ Pagination for optimal performance
- 👥 "Admin panel for managing user registration requests (approve/reject)
- Node.js (v16 or higher)
- MongoDB (local or MongoDB Atlas)
- Google Gemini API Key
- npm or yarn package manager
git clone https://github.com/zrahadiz/SavoryNotes.git
cd SavoryNotescd backend
npm installCreate a .env file in the backend directory with the following configuration:
# Server Configuration
PORT=5000
# Database
MONGODB_URI=mongo_uri
# Or use MongoDB Atlas:
# MONGODB_URI=mongo_atlas_uri
# JWT Secret
JWT_SECRET=your_super_secret_jwt_key_here_change_in_production
REFRESH_TOKEN_SECRET=your_super_secret_jwt_refresh_key_here_change_in_production
# Reset Password Token
RESET_TOKEN_EXPIRES_MIN=60
# Google Gemini AI
GOOGLE_GENAI_API_KEY=your_gemini_api_key_here
# Client URL
FRONTEND_URL=http://localhost:5173
# Cloudinary (Optional - for image uploads)
CLOUD_NAME=your_cloud_name
CLOUD_API_KEY=your_api_key
CLOUD_API_SECRET=your_api_secret
# Resend Mail API
RESEND_API_KEY=re_your_api_key_here
RESEND_FROM_EMAIL=onboarding@resend.devnpm run devThe backend server will run on http://localhost:5000 (or your configured PORT).
Email functionality in the deployed version is now available my Resend domain verification now verified.
You can test email features in your local environment:
- Sign up for a free account at resend.com
- Get your API key from the Resend dashboard
Add these to your .env file:
RESEND_API_KEY=re_your_api_key_here
RESEND_FROM_EMAIL=onboarding@resend.dev- Emails can only be sent to email addresses you've added to your Resend account
- To add test recipients:
- Go to Resend Dashboard → Settings → Team
- Invite the email addresses you want to test with
- The sender will show as
onboarding@resend.dev(Resend's test domain)
Once domain verification is complete, emails will be sent from noreply@savorynotes.biz.id and can reach any recipient.
Status: ✅ Domain Verified
cd ../frontend
npm installCreate a .env file in the frontend directory:
VITE_API_URL=http://localhost:5000Start the frontend development server:
npm run dev- Frontend:
http://localhost:5173 - Backend API:
http://localhost:5000
- React 19.2
- React Router DOM - Client-side routing
- Zustand - State Management Library
- Tailwind CSS - Utility-first CSS framework
- Daisy UI - UI Component Library
- React Icons - Icon library (HeroIcons)
- Axios - HTTP client
- Vite - Build tool and dev server
- Node.js - Runtime environment
- Express.js - Web application framework
- MongoDB - NoSQL database
- Mongoose - MongoDB ODM
- JWT (jsonwebtoken) - Authentication
- bcryptjs - Password hashing
- Google Generative AI (Gemini) - AI chatbot integration
- cors - Cross-origin resource sharing
- dotenv - Environment variable management
- Cloudinary - File Cloud Storage
- Multer - File upload handling
- Slugify - URL-friendly slug generation
- Express Validator - Request validation
SavoryNotes/
├── backend/
│ ├── config/
│ │ ├── db.js # MongoDB connection
│ │ └── cloudinary.js # Cloudinary configuration
│ ├── controllers/
│ │ ├── ai.controller.js # AI (Chef Bot, Generate Description and Tags) logic
│ │ ├── auth.contoller.js # Authentication logic
│ │ ├── post.controller.js # Recipe CRUD operations
│ │ └── users.controller.js # Users approval logic
│ ├── middlewares/
│ │ ├── authorization.js # JWT authentication
│ │ └── uploadImage.js # Upload image to cloudinary
│ ├── models/
│ │ ├── User.js # User schema
│ │ └── Post.js # Recipe schema
│ ├── routes/
│ │ ├── ai.routes.js # AI endpoints
│ │ ├── auth.routes.js # Auth endpoints
│ │ ├── post.toutes.js # Recipe endpoints
│ │ └── users.routes.js # User endpoints
│ ├── utils/
│ │ ├── formatResponse.js # Standardized API responses
│ │ ├── generateToken.js # generate reset token
│ │ ├── jwt.js # generate JWT token
│ │ ├── sendMail.js # email setup
│ │ ├── password.js # pass hash and compare helper
│ │ └── slugify.js # Slug generation
│ ├── .env # Environment variables
│ ├── .env.example # Environment template
│ ├── index.js # Express app setup
│ ├── package-lock.json
│ └── package.json
│
├── frontend/
│ ├── src/
│ │ ├── api/
│ │ │ └── axios.js # Axios configuration
│ │ ├── assets/ # Images and static files
│ │ ├── components/ # Reusable UI components
│ │ ├── lib/
│ │ │ └── toast.js # Toast notifications
│ │ ├── pages/ # Application pages
│ │ ├── store/ # Global state management files
│ │ │ └── authStore.js # Handles authentication-related state, including user data, login status, and auth actions.
│ │ ├── App.jsx # Main app component
│ │ ├── main.jsx # Entry point
│ │ └── index.css # Global styles
│ ├── .env # Environment variables
│ ├── .env.example # Environment template
│ ├── vite.config.js # Vite configuration
│ ├── package-lock.json
│ └── package.json
│
└── README.md
POST /api/ai/generate-desc # Generate an AI-recommended description based on recipe title
POST /api/ai/generate-tags # Generate AI-recommended tags based on recipe title, ingredients, and instruction
POST /api/ai/chatBot # Chat with AI about recipe
POST /api/auth/register # Register a new user
POST /api/auth/login # User login
POST /api/auth/logout # User logout
POST /api/auth/refresh # Refresh access token
POST /api/auth/forgot-password # Send password reset link
POST /api/auth/reset-password # Reset user password
GET /api/auth/me # Get authenticated user info (Protected)
GET /api/auth/check # Check authentication status
POST /api/posts/ # Create a new post (Admin, Protected, with images)
GET /api/posts/ # Get all posts
GET /api/posts/:slug # Get a single post by slug
PUT /api/posts/:slug # Update a post by slug (Admin, Protected, with images)
DELETE /api/posts/:slug # Delete a post by slug (Admin, Protected)
GET /api/users/pending # Get list of pending user registration requests (Admin, Protected)
POST /api/users/approve # Approve a pending user (Admin, Protected)
- ✅ User registration with email validation
- ✅ User forgot and reset password
- ✅ Secure login with JWT authentication
- ✅ Create recipes with multiple images (Admin)
- ✅ Edit and delete recipes (Admin)
- ✅ Rich recipe details (ingredients, instructions, prep/cook time)
- ✅ Category and difficulty level classification
- ✅ Tag-based organization
- ✅ SEO-friendly URL slugs
- ✅ Image carousel for multiple recipe photos
- ✅ Advanced search functionality (Title, Description, and Tags)
- ✅ Filter by category (breakfast, lunch, dinner, dessert, etc.)
- ✅ Filter by difficulty level (easy, medium, hard)
- ✅ Pagination for better performance
- ✅ Real-time search with debouncing
Registration Process:
- 👤 User registers → Account created with
pendingstatus - 🚫 Login blocked → User cannot login until approved
- 📧 Confirmation email → User receives "Registration received" notification
- ⏳ Awaits approval → Admin reviews the registration request
Admin Review Process:
- 👨💼 Admin reviews → Pending users appear in Admin Panel
- ✅/❌ Admin decides → Approve or reject the registration
- 📨 Automated notification → User receives email with decision
Post-Approval:
- ✅ If Approved → User receives "Account Approved" email and can now login
- ❌ If Rejected → User receives "Request Rejected" email and cannot login
- ✅ Pending user approval system
- ✅ User management (view, approve, reject)
- ✅ Paginated user list
- ✅ Search users by name/email
- ✅ Automated email notifications for registration and approval status
- ✅ Fully responsive design
- ✅ Modern, clean interface with Tailwind CSS
- ✅ Smooth animations and transitions
- ✅ Loading states and error handling
- ✅ Toast notifications for user feedback
- ✅ Mobile-optimized navigation
- ✅ AI Smart Description and Tags Generation
- ✅ AI cooking assistant chatbot
- ✅ Recipe-specific context awareness
- ✅ Ingredient substitution suggestions
- ✅ Cooking technique explanations
- ✅ Timing and temperature guidance
- 🤖 AI Cooking Assistant - Integrated Google Gemini AI for recipe Q&A
- 📱 Progressive Web App (PWA) Ready - Optimized for mobile installation
- 🎨 Advanced UI Design - Modern gradient designs and micro-interactions
- 📊 Admin User Managements - User management and approval workflow
- Recipe rating and review system
- User favorites and bookmarks
- RAG-based recipe suggestions (Based on User favorites, bookmarks, and history)
- Social features (follow users, like recipes)
- Meal planning calendar
- Nutrition information calculator
- Recipe scaling (adjust servings)
- Video recipe support
- Multi-language support
This project integrates Google Gemini 2.5 Flash to power several intelligent recipe features, including:
- Recipe Description Generator
- Recipe Tag Generator
- Cooking Assistant Chatbot
All AI logic is implemented in
Location: backend/controllers/ai.controller.js
POST /api/ai/generate-desc
Generates a short, appealing recipe description based on the recipe title.
- Accepts a request body containing:
{ "title": "Recipe Title" } Sends a prompt to Gemini to create a max 250-character appetizing description.
Returns AI-generated text as the description.
Create a short, appetizing description (max 250 characters) for this recipe: Chicken Curry
A rich, aromatic chicken curry simmered with warm spices and a creamy sauce.
POST /api/ai/generate-tags
Generates exactly 5 relevant tags based on the recipe's title, ingredients, and content.
Requires the following body:
-
Accepts a request body containing:
{ "title": "Recipe Title", "ingredients": ["item 1", "item 2"], "content": "Full recipe instructions..." }
Instructs Gemini to return tags as a:
- comma-separated list
- lowercase
- no numbering
- no explanation
Converts the string to an array before returning it.
Suggest exactly 5 relevant tags for this recipe. Return ONLY comma-separated lowercase tags.
Title: Spaghetti Bolognese Ingredients: beef, tomato, garlic Content: simmer until thick and flavorful
italian, pasta, dinner, savory, comfort food
→ Returned as:
["italian", "pasta", "dinner", "savory", "comfort food"]POST /api/ai/chatBot
How It Works:
- Context Injection: The chatbot receives the full recipe context including title, ingredients, instructions, cooking times, and tags
- Conversation History: Maintains last 6 messages for context-aware responses
- Optimized Prompts: Recipe context is condensed to avoid token limits
- Structured Responses: AI is instructed to provide concise, helpful answers (2-3 paragraphs)
Configuration:
generationConfig: {
maxOutputTokens: 500, // Limit response length
temperature: 0.7, // Balance between creativity and consistency
}Features:
- Recipe Q&A
- Ingredient substitution suggestions
- Cooking technique explanations
- Timing and temperature guidance
- Dietary modification suggestions (vegan, gluten-free, etc.)
- Troubleshooting cooking issues
Token Optimization Strategies:
- Keep only recent message history (6 messages)
API Key Setup:
Get your free Gemini API key from Google AI Studio and add it to your .env file.
🔗 Frontend: https://savorynotes.pages.dev/
🔗 Backend API: ttps://savorynotes-production.up.railway.app
Admin Account:
Email: test@admin.com
Password: 12345678
Email: test2@admin.com
Password: admin123
# Backend tests
cd backend
npm test
# Frontend tests
cd frontend
npm testBackend:
cd backend
npm run build
npm startFrontend:
cd frontend
npm run build
# Output will be in the 'dist' folderRahadi Fauzan - rahadifauzan7@gmail.com
Project Link: https://github.com/zrahadiz/SavoryNotes.git
Made with ❤️ and 🍕
⭐ Star this repo if you found it helpful!