Munch-n-Merge is a recipe social media platform that allows users to create their own recipes, discover recipes from friends within their social network, and use AI to merge recipes together to create new recipe.
-
Frontend:
- Next.js 15 with App Router
- React 19
- TypeScript
- Tailwind CSS for styling
- Server/Client Component architecture
-
Backend:
- Next.js API Routes
- Server Actions for data mutation
- Neon PostgreSQL database with prepared statements
-
Authentication:
- Session-based authentication
- Secure password storage using
bcrypt - Session token encryption with JSON Web Tokens
-
Features:
- AI-powered recipe merging
- Social networking capabilities
- Recipe feed with pagination
- Like and favorite system
- Create recipes with name, description, ingredients, and instructions
- Edit existing recipes
- Delete recipes
- View detailed recipe information
- Add friends to build your cooking network
- See recipes from friends in your feed
- Like recipes to show appreciation
- Favorite recipes to save them for later
- Select multiple recipes to combine
- Adjust AI creativity level with temperature control
- Get AI-generated merged recipes with combined ingredients and instructions
- Save merged recipes to your collection
- Responsive design works on desktop and mobile
- Clear navigation with intuitive UI
- Real-time feedback for actions
-
Install dependencies
npm install # or yarn install -
Database Setup (Neon PostgreSQL)
Follow these steps to set up your database:
a. Create a Neon Account and Project
- Go to https://neon.tech and sign up or log in
- Click "New Project" in your dashboard
- Fill in requested details (project/database name, server region, etc.)
- Click "Create Project"
b. Obtain Your Database Connection String
- Once your project is created, you'll be taken to the project dashboard
- Click the "Connect" button and select the .env tab to view the connection URL.
- It should look like:
postgresql://username:password@hostname/database?sslmode=require
c. Set Up Environment Variables Create a
.envfile in the root directory with the following variables:# Database Connection (REQUIRED) # Replace with your actual Neon PostgreSQL connection string NEON_DATABASE_URL="postgresql://username:password@hostname/database?sslmode=require" # Authentication (REQUIRED) # Generate a secure random string for JWT token signing SESSION_SECRET="your-secure-random-string" # Google Gemini API (REQUIRED for recipe merging) # Get this from Google Cloud Console with Gemini API enabled (next step) GOOGLE_GENAI_API_KEY="your-google-gemini-api-key"d. Initialize the Database Schema Run the database initialization script to create all required tables:
npm run db:init
This script will:
- Connect to your Neon database using the connection string
- Create all necessary tables (AppUser, Recipe, Friend, Session, etc.)
- Set up proper relationships and constraints
- Display success confirmation when complete
Note: Make sure your
NEON_DATABASE_URLis correctly set in the.envfile before running this command. -
Google Gemini API Setup
Follow these steps to obtain your Google Gemini API key for recipe merging:
a. Create a Google Cloud Project
- Go to Google Cloud Console
- Sign in with your Google account
- Click "Select a project" dropdown and then "New Project"
- Enter a project name and click "Create"
b. Enable the Gemini API
- In your Google Cloud Console, navigate to "APIs & Services" > "Library"
- Search for "Generative Language API" (this is the API for Gemini)
- Click on it and then click "Enable"
c. Create API Credentials
- Go to "APIs & Services" > "Credentials"
- Click "Create Credentials" > "API Key"
- Copy the generated API key
- (Optional but recommended) Click "Restrict Key" to limit usage to the Generative Language API
d. Add to Environment Variables
- Add your API key to the
.envfile:GOOGLE_GENAI_API_KEY="your-copied-api-key-here"
Note: Keep your API key secure and never commit it to version control. The recipe merging feature will not work without this key.
-
Start the development server
npm run dev # or yarn dev -
Open your browser and navigate to
http://localhost:3000
We use Neon PostgreSQL, a serverless Postgres service, for our database. The connection is established through the @neondatabase/serverless package, which allows for efficient connection pooling and low-latency queries.
Our authentication system uses:
- bcrypt for secure password hashing, which performs one-way salted hashing of user passwords
- jose for JWT (JSON Web Token) handling, used to securely store session information in cookies
- Next.js cookies API for managing secure HTTP-only cookies
- Session-based authentication with database validation to ensure tokens remain valid
The authentication flow works as follows:
- User registers with username, email, and password
- Password is hashed using bcrypt with a cost factor of 10
- Upon login, a JWT token containing a session ID is created
- Session is stored in the database and linked to the user
- JWT token is stored in an HTTP-only cookie
- Server validates the token and session on each protected request
The recipe merging feature is powered by Google's Gemini API (gemini-2.0-flash model). We use the @google/genai SDK to:
- Format and serialize recipes for AI processing
- Send them to the Gemini model with custom prompts
- Control creativity with temperature settings (0.0 to 2.0)
- Process and structure the AI response into a new recipe
- Validate and clean the results before storing in the database
munch-n-merge/
├── public/ # Static assets
│ └── images/ # Images used in the application
├── src/ # Source code
│ ├── app/ # Next.js App Router pages
│ │ ├── feed/ # Recipe feed page
│ │ ├── friends/ # Friend management
│ │ ├── merge-recipes/ # Recipe merging feature
│ │ ├── my-recipes/ # User's recipes management
│ │ ├── search/ # Search functionality
│ │ ├── settings/ # User settings
│ │ └── favorites/ # User's favorite recipes
│ ├── components/ # Shared React components
│ │ └── Navbar.tsx # Navigation component
│ └── lib/ # Utility functions and backend logic
│ ├── actions/ # Server Actions for data mutation
│ │ ├── auth.ts # Authentication functions
│ │ ├── feed.ts # Feed management
│ │ ├── recipe.ts # Recipe CRUD operations
│ │ ├── friend.ts # Friend management
│ │ ├── favorite.ts # Favorites management
│ │ └── types.ts # Shared TypeScript interfaces
│ ├── contexts/ # React context providers
│ ├── genai.ts # Google Gemini AI integration
│ └── sql.ts # SQL server initilization
├── package.json # Project dependencies
└── README.md # Project documentation
- Establishes a connection to our Neon PostgreSQL database using the
@neondatabase/serverlesspackage - Exports a
sqltagged template function for secure parameterized SQL queries - Handles connection pooling and serverless optimization
Server actions are organized by domain/entity for better maintainability:
-
auth.ts: Handles all authentication-related operations- User registration with bcrypt password hashing
- Login with JWT token generation
- Session management
- User validation
-
user.ts: Manages user profile operations- Username updates
- Email changes
- Password changes with security validation
-
recipe.ts: Contains all recipe CRUD operations- Creating recipes
- Reading recipe details
- Updating recipe information
- Deleting recipes
- Recipe search functionality
- Recipe merging functionality (coordinates with AI)
-
feed.ts: Manages social feed functionality- Gets recipes from user's social network
- Implements multi-level friendship traversal (up to 5 degrees)
- Handles pagination and sorting
-
friend.ts: Manages social connections- Friend request creation
- Request acceptance/rejection
- Friend removal
- Friend list retrieval
-
favorite.ts: Handles recipe favoriting system- Adding recipes to favorites
- Removing favorites
- Retrieving user's favorite recipes
-
like.ts: Manages the recipe like system- Adding likes to recipes
- Removing likes
- Retrieving user's liked recipes
-
types.ts: Provides shared TypeScript interfaces used across actions
- Connects to Google's Gemini AI using the
@google/genaiSDK - Implements the recipe merging algorithm
- Handles data preprocessing for AI input
- Processes AI responses into structured recipe objects
- Includes error handling and retry mechanisms
- Implements React Context providers for state management
- User context for authentication state
- Theme context for UI preferences
- Other application-wide states
- Client-side: User interacts with React components in the
/appdirectory - Server Actions: Components call server actions from
/lib/actions/ - Database Operations: Server actions use the SQL utility from
/lib/sql.tsto interact with the database - AI Processing: For recipe merging, the server actions coordinate with
/lib/genai.ts - Response: Data is returned to the client for rendering through the server actions
This architecture allows us to have clear separation of elements, type safety throughout the applicationl, secure database operations with parameterized queries, scalable codebase organization, maintainable and testable code components.
- Navigate to "My Recipes"
- Click "Create New Recipe"
- Fill in the recipe details:
- Name (required)
- Description (optional)
- Ingredients (optional)
- Instructions (optional)
- Click "Create Recipe"
- Navigate to "Merge Recipes"
- Select at least 2 recipes you want to merge
- Adjust the "AI Creativity Level" slider:
- Lower values (0-0.5): More predictable combinations
- Mid values (0.6-1.2): Balanced creativity
- Higher values (1.3-2.0): More innovative results
- Click "Merge Selected Recipes"
- The merged recipe will appear in your "My Recipes" collection
- Navigate to "Friends"
- Search for users by username
- Send friend requests
- Accept or decline incoming friend requests
- View and manage your current friends
The application uses Next.js Server Actions for data operations. Key endpoints include:
-
Recipe Operations:
createRecipe: Create a new recipegetRecipe: Fetch a single recipegetUserRecipes: Get all recipes created by the userupdateRecipe: Update an existing recipedeleteRecipe: Remove a recipemergeWithExternalRecipes: Merge multiple recipes
-
Social Operations:
requestFriend: Send a friend requestacceptFriendRequest: Accept an incoming requestdeleteFriendRequest: Decline or cancel a requestremoveFriend: Remove an existing friend
-
Feed Operations:
getRecipeFeed: Get recipes from user's networklikeRecipe: Like a recipeunlikeRecipe: Remove a likeaddFavorite: Favorite a reciperemoveFavorite: Remove from favorites
-
Database Connection Errors:
- Issue:
NEON_DATABASE_URL environment variable is not set- Solution: Ensure you have a
.envfile in the root directory with the correctNEON_DATABASE_URL
- Solution: Ensure you have a
- Issue:
Connection failedorInvalid connection string- Solution: Double-check your Neon connection string format and credentials
- Ensure your Neon project is active (not suspended due to inactivity)
- Issue:
Database initialization failed- Solution: Run
npm run db:initto set up the database schema - Check that your database user has sufficient permissions to create tables
- Solution: Run
- Issue:
-
Database Setup Issues:
- Issue:
npm run db:initfails- Solution:
- Verify your
NEON_DATABASE_URLis correct in the.envfile - Ensure your Neon database is accessible and not suspended
- Check your internet connection
- Verify your
- Solution:
- Issue: Tables already exist errors
- Solution: The init script uses
CREATE TABLE IF NOT EXISTS, so this shouldn't occur. If it does, you may need to drop existing tables first
- Solution: The init script uses
- Issue: Permission denied errors
- Solution: Ensure your Neon database user has CREATE privileges
- Issue:
-
Authentication Issues:
- Clear browser cookies and try logging in again
- Verify JWT_SECRET in environment variables
-
Recipe Merge Failures:
- Check your Gemini API key is valid
- Ensure at least 2 recipes are selected
- Ahmad Wajid
- Najm Hoda
- Omar Lejmi
- Adam Omarbasha
- Abdulrahman Albedawy