Skip to content

cusaldmsr/RecipeApp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

79 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🍽️ RecipeVault

A Smart MERN Stack Recipe Management Dashboard

CI Security Audit MongoDB Express React Vite TailwindCSS Node License


Search millions of recipes. Save your favourites. Create your own.
Powered by intelligent smart-caching proxy β€” checks your local database first, fetches from the DummyJSON API only when needed, and saves new results automatically.


RecipeVault Dashboard


πŸ“Œ Table of Contents


✨ Features

Feature Description
πŸ” Smart Search Searches local DB first, falls back to DummyJSON API, auto-saves new results
πŸ’‘ Typeahead Suggestions 300ms debounced dropdown with thumbnail previews, source badges & keyboard navigation
♾️ Infinite Scroll Paginated recipe grid (8 per page) with Intersection Observer β€” no buttons needed
πŸ‘οΈ Recipe Detail Modal Full view with hero image, ingredient checklist, numbered instruction steps
✏️ Full CRUD Create, Read, Update, Delete recipes with a polished modal form
🏷️ Source Badges Every card shows whether a recipe came from your vault or the DummyJSON API
🎨 GSAP Animations Page-load hero animation + staggered card entrance effects
πŸ“± Responsive Design Mobile-first grid layout with glassmorphism dark UI
πŸ” CI/CD Pipeline Full GitHub Actions pipeline with lint, build, audit, and deploy stages

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        BROWSER                            β”‚
β”‚                                                           β”‚
β”‚   React + Vite + Tailwind CSS + Shadcn UI + GSAP         β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚  SearchBar  β”‚  β”‚  RecipeGrid  β”‚  β”‚ RecipeDetail  β”‚  β”‚
β”‚   β”‚ (typeahead) β”‚  β”‚(infinite     β”‚  β”‚    Modal      β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β”‚  scroll)     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚          β”‚         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚  HTTP (Vite proxy in dev / direct in prod)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   EXPRESS REST API                        β”‚
β”‚                   Node.js Β· ES Modules                    β”‚
β”‚                                                           β”‚
β”‚   GET  /api/recipes          ← paginated all recipes      β”‚
β”‚   GET  /api/recipes/search   ← smart hybrid search        β”‚
β”‚   GET  /api/recipes/suggestions ← typeahead               β”‚
β”‚   POST /api/recipes          ← create                     β”‚
β”‚   PUT  /api/recipes/:id      ← update                     β”‚
β”‚   DELETE /api/recipes/:id    ← delete                     β”‚
β”‚   GET  /api/health           ← health check               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
           β”‚                          β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  MongoDB    β”‚          β”‚  DummyJSON API  β”‚
    β”‚   Atlas     β”‚          β”‚ (external data) β”‚
    β”‚  (primary)  β”‚          β”‚  fetched only   β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚  on cache miss  β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ› οΈ Tech Stack

Backend

Technology Version Purpose
Node.js 20.x LTS Runtime
Express.js 4.x REST API framework
Mongoose 8.x MongoDB ODM
MongoDB Atlas Cloud Database
Axios 1.x External API calls
dotenv 16.x Environment config
cors 2.x Cross-origin requests

Frontend

Technology Version Purpose
React 19 UI framework
Vite 8 Build tool & dev server
Tailwind CSS v4 Utility-first styling
Shadcn UI latest Component primitives
GSAP 3.x Animations
Axios 1.x HTTP client
Lucide React latest Icon library

DevOps

Technology Purpose
GitHub Actions CI/CD pipeline
Render.com Backend hosting
Vercel Frontend hosting
Dependabot Automated dependency updates

πŸ“ Project Structure

RecipeApp/
β”‚
β”œβ”€β”€ .github/
β”‚   β”œβ”€β”€ workflows/
β”‚   β”‚   β”œβ”€β”€ ci.yml                 # πŸ” CI β€” runs on every push & PR
β”‚   β”‚   β”œβ”€β”€ cd-production.yml      # πŸš€ CD β€” deploys main β†’ Render + Vercel
β”‚   β”‚   β”œβ”€β”€ cd-staging.yml         # πŸ§ͺ CD β€” deploys develop β†’ preview
β”‚   β”‚   └── security-audit.yml     # πŸ” Weekly security scans
β”‚   └── dependabot.yml             # πŸ€– Auto dependency updates
β”‚
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   └── Recipe.js              # Mongoose schema & model
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   └── recipes.js             # All API route handlers
β”‚   β”œβ”€β”€ server.js                  # Express app entry point
β”‚   β”œβ”€β”€ .env.example               # Environment variable template
β”‚   └── package.json
β”‚
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ components/
β”‚   β”‚   β”‚   β”œβ”€β”€ Navbar.jsx          # Top navigation bar
β”‚   β”‚   β”‚   β”œβ”€β”€ SearchBar.jsx       # Search input + portal dropdown
β”‚   β”‚   β”‚   β”œβ”€β”€ RecipeGrid.jsx      # Masonry card grid with GSAP
β”‚   β”‚   β”‚   β”œβ”€β”€ RecipeCard.jsx      # Individual recipe card
β”‚   β”‚   β”‚   β”œβ”€β”€ RecipeModal.jsx     # Create / Edit form modal
β”‚   β”‚   β”‚   β”œβ”€β”€ RecipeDetailModal.jsx # Full recipe viewer
β”‚   β”‚   β”‚   └── ui/                 # Shadcn UI primitives
β”‚   β”‚   β”œβ”€β”€ hooks/
β”‚   β”‚   β”‚   └── useRecipes.js       # Axios API hook
β”‚   β”‚   β”œβ”€β”€ lib/
β”‚   β”‚   β”‚   └── utils.js            # cn() helper
β”‚   β”‚   β”œβ”€β”€ App.jsx                 # Root component + state management
β”‚   β”‚   β”œβ”€β”€ main.jsx                # React entry point
β”‚   β”‚   └── index.css              # Global styles + Tailwind directives
β”‚   β”œβ”€β”€ .env.example
β”‚   β”œβ”€β”€ vite.config.js
β”‚   └── package.json
β”‚
β”œβ”€β”€ .gitignore
└── README.md

πŸš€ Getting Started

Prerequisites

1 β€” Clone the Repository

git clone https://github.com/cusaldmsr/RecipeApp.git
cd RecipeApp

2 β€” Backend Setup

cd backend

# Install dependencies
npm install

# Create your environment file
cp .env.example .env

Edit .env with your values (see Environment Variables below):

# Start the development server
npm run dev
# β†’ Backend running at http://localhost:5000
# β†’ API available at http://localhost:5000/api/recipes

3 β€” Frontend Setup

Open a new terminal:

cd frontend

# Install dependencies
npm install

# Start the Vite dev server
npm run dev
# β†’ Frontend running at http://localhost:5173

4 β€” Open the App

http://localhost:5173

Note: The Vite dev server proxies all /api/* requests to http://127.0.0.1:5000 automatically. Both servers must be running.


βš™οΈ Environment Variables

Backend β€” backend/.env

# MongoDB Atlas connection string
# Get it from: Atlas dashboard β†’ Connect β†’ Drivers β†’ copy URI
MONGO_URI=mongodb+srv://<username>:<password>@cluster0.xxxxxx.mongodb.net/recipeDB?retryWrites=true&w=majority&appName=Cluster0

# Express server port (default: 5000)
PORT=5000

Frontend β€” frontend/.env (only needed for production build)

# Your deployed backend URL β€” NOT needed for local dev (Vite proxy handles it)
VITE_API_BASE_URL=https://your-backend-url.onrender.com

⚠️ Never commit real .env files. Only .env.example files are tracked by git.


πŸ“‘ API Reference

Base URL (local): http://localhost:5000/api

Health Check

GET /health
{ "status": "OK", "message": "Recipe API is running 🍽️" }

Get All Recipes (paginated)

GET /recipes?page=1&limit=8
Query Param Type Default Description
page number 1 Page number
limit number 8 Results per page (max 50)

Response:

{
  "source": "database",
  "recipes": [ { "...recipe objects..." } ],
  "total": 42,
  "page": 1,
  "totalPages": 6,
  "hasMore": true
}

Smart Search

GET /recipes/search?q=pasta

Runs a parallel query against local DB and DummyJSON API. Returns categorised results.

Response:

{
  "dbRecipes":  [ { "...already saved recipes..." } ],
  "apiRecipes": [ { "...new results fetched from API..." } ],
  "total": 12
}

Typeahead Suggestions

GET /recipes/suggestions?q=pas

Returns up to 6 matching recipes from local DB for the dropdown (requires β‰₯ 2 chars).

Response:

{
  "suggestions": [
    { "_id": "...", "name": "Pasta Carbonara", "image": "...", "source": "DummyJSON" }
  ]
}

Create Recipe

POST /recipes
Content-Type: application/json
{
  "name": "Spaghetti Bolognese",
  "ingredients": ["500g mince", "1 onion", "2 garlic cloves", "400g canned tomatoes"],
  "instructions": ["Brown the mince.", "Add onion and garlic.", "Simmer with tomatoes."],
  "prepTimeMinutes": 10,
  "cookTimeMinutes": 30,
  "servings": 4,
  "image": "https://example.com/image.jpg"
}

Response: 201 Created β†’ saved recipe object.


Update Recipe

PUT /recipes/:id
Content-Type: application/json

Pass any fields to update. Returns updated recipe.


Delete Recipe

DELETE /recipes/:id
{ "message": "Recipe deleted successfully.", "id": "..." }

πŸ”„ Smart Caching Logic

This is the core intelligence of RecipeVault. On every search:

User searches "pasta"
       β”‚
       β”œβ”€β”€β”€ 1. Query local MongoDB (fast, always)
       β”‚         β†’ dbRecipes  (already saved)
       β”‚
       └─── 2. Query DummyJSON API (parallel, always)
                 β”‚
                 β”œβ”€β”€ Filter: remove recipes already in DB (by external ID)
                 β”‚         β†’ only truly NEW results
                 β”‚
                 β”œβ”€β”€ Upsert new results into MongoDB
                 β”‚         (next search for "pasta" hits DB only)
                 β”‚
                 └── Return new results as apiRecipes

Frontend displays:
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  5 from your vault  Β·  3 new from API             β”‚
  β”‚  [DB results first]    [API results after]         β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Result: The first search for any keyword is slightly slower (fetches from API). Every subsequent search for the same keyword is instant (served from MongoDB).


πŸ” CI/CD Pipeline

Four GitHub Actions workflows run automatically:

Every push / PR to any branch
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     πŸ” ci.yml  (Continuous Integration)        β”‚
β”‚                                                β”‚
β”‚  backend-validate  ──┐                         β”‚
β”‚  backend-audit     ───                         β”‚
β”‚  backend-test      ──┼──► βœ… CI Quality Gate  β”‚
β”‚  frontend-build    ───        (blocks PR merge β”‚
β”‚  frontend-audit    ───         if any fail)    β”‚
β”‚  frontend-test     β”€β”€β”˜                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚ CI passes on `main`
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   πŸš€ cd-production.yml                         β”‚
β”‚                                                β”‚
β”‚   [Manual Approval Required]                   β”‚
β”‚   deploy-backend  β†’ Render.com                 β”‚
β”‚   deploy-frontend β†’ Vercel                     β”‚
β”‚   smoke-test      β†’ health check endpoints     β”‚
β”‚   create-release  β†’ GitHub Release + changelog β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

CI passes on `develop`
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   πŸ§ͺ cd-staging.yml                            β”‚
β”‚                                                β”‚
β”‚   deploy-backend  β†’ Render Staging service     β”‚
β”‚   deploy-frontend β†’ Vercel Preview URL         β”‚
β”‚   PR comment      β†’ posts preview URL on PR    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Every Monday 08:00 UTC
        β”‚
        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   πŸ” security-audit.yml                        β”‚
β”‚                                                β”‚
β”‚   audit-backend   β†’ npm audit (JSON report)    β”‚
β”‚   audit-frontend  β†’ npm audit (JSON report)    β”‚
β”‚   secret-scan     β†’ detect committed .env filesβ”‚
β”‚   outdated-report β†’ npm outdated for both      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Required GitHub Secrets

Go to Settings β†’ Secrets and variables β†’ Actions and add:

Secret Description
RENDER_BACKEND_DEPLOY_HOOK_URL Render deploy hook URL for the backend service
RENDER_BACKEND_SERVICE_URL Your Render backend public URL
VERCEL_TOKEN Vercel personal access token
VERCEL_ORG_ID Vercel org/team ID
VERCEL_PROJECT_ID Vercel project ID
VITE_API_BASE_URL Production backend URL injected at build time

CI works with zero secrets. Secrets are only required to activate the CD (deploy) workflows.


🌿 Branching Strategy

main        ← production branch (protected, requires PR + CI pass)
  β”‚
  └── develop ← staging branch (auto-deploys to preview)
        β”‚
        β”œβ”€β”€ feature/recipe-ratings
        β”œβ”€β”€ fix/search-dropdown-zindex
        └── chore/update-dependencies

Workflow:

  1. Create a feature branch from develop
  2. Open a PR β†’ CI runs automatically
  3. Merge to develop β†’ staging auto-deploys
  4. Open PR from develop β†’ main β†’ manual approval β†’ production deploys

🀝 Contributing

Contributions are welcome! Here's how:

# 1. Fork the repository on GitHub

# 2. Clone your fork
git clone https://github.com/<your-username>/RecipeApp.git
cd RecipeApp

# 3. Create a feature branch
git checkout -b feature/your-feature-name

# 4. Make your changes, then commit
git add .
git commit -m "feat: describe your change"

# 5. Push and open a Pull Request
git push origin feature/your-feature-name

Commit Convention

This project follows Conventional Commits:

Prefix Use for
feat: New features
fix: Bug fixes
ci: CI/CD changes
chore: Maintenance, dependency updates
docs: Documentation only
refactor: Code restructuring

Adding Tests

Backend (Jest):

cd backend
npm install -D jest supertest
# Add tests to backend/tests/

Frontend (Vitest):

cd frontend
npm install -D vitest @testing-library/react @testing-library/jest-dom
# Add tests to frontend/src/__tests__/

πŸ“„ License

This project is licensed under the MIT License.

MIT License β€” Copyright (c) 2026 cusaldmsr

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software.

Made with ❀️ using the MERN Stack

⬆ Back to top

About

Smart MERN stack recipe dashboard - search millions of recipes with intelligent DB-first caching, infinite scroll, typeahead suggestions, and full CRUD. Built with React, Vite, Express, MongoDB Atlas & Tailwind CSS. Includes a full GitHub Actions CI/CD pipeline.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors