A modern food recipe sharing platform built with Next.js, where food enthusiasts can discover, share, and explore delicious meals from around the world.
- 🍽️ Browse Meals: Explore a curated collection of delicious recipes
- 📝 Share Recipes: Submit your favorite meals with images and detailed instructions
- 👥 Community: Join a community of food lovers
- 🖼️ Image Slideshow: Beautiful image carousel on the homepage
- 🔍 Meal Details: View detailed recipe instructions and creator information
- ☁️ Cloud Storage: Images are stored in AWS S3
- Framework: Next.js 16.1.6 (App Router)
- Language: TypeScript 5
- React: React 19.0.0
- Database: SQLite (better-sqlite3)
- Storage: AWS S3 (for meal images via @aws-sdk/client-s3)
- Styling: CSS Modules
- Linting: ESLint 8 with eslint-config-next
- Security: XSS protection for user inputs (xss library)
- Package Manager: pnpm
- Build Tool: Turbopack (default in Next.js 16)
- Node.js 20.9+ (required for Next.js 16)
- pnpm (install with
npm install -g pnpm) - AWS S3 bucket (for image storage) - configure in
config.ts
- Clone the repository:
git clone <repository-url>
cd foodies- Install dependencies:
pnpm install- Set up environment variables:
cp .env.local.example .env.localThen edit .env.local and fill in your AWS credentials:
AWS_ACCESS_KEY_ID: Your AWS access key IDAWS_SECRET_ACCESS_KEY: Your AWS secret access key
- IMPORTANT: Initialize the database before running the development server or building:
pnpm run initdbThis script will:
- Create the SQLite database (
meals.db) - Set up the meals table schema
- Populate the database with sample meal data
- Configure AWS S3 (required for sharing meals):
- IMPORTANT: Update
AWS_S3_BUCKET_NAMEinconfig.tswith your actual S3 bucket name - AWS credentials are configured in
.env.local(created in step 3)
- IMPORTANT: Update
After running pnpm run initdb, start the development server:
pnpm run devOpen http://localhost:3000 in your browser to see the application.
IMPORTANT: Make sure to run pnpm run initdb before building:
pnpm run initdb
pnpm run build
pnpm startfoodies/
├── app/ # Next.js App Router directory
│ ├── community/ # Community page
│ │ ├── page.tsx
│ │ └── page.module.css
│ ├── meals/ # Meals pages
│ │ ├── [mealSlug]/ # Dynamic meal detail pages
│ │ │ ├── page.tsx
│ │ │ └── page.module.css
│ │ ├── share/ # Share meal form page
│ │ │ ├── page.tsx
│ │ │ ├── page.module.css
│ │ │ └── error.tsx
│ │ ├── page.tsx # Meals listing page
│ │ ├── page.module.css
│ │ ├── error.tsx # Error boundary
│ │ └── not-found.tsx # 404 page
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Homepage
│ ├── page.module.css
│ ├── globals.css # Global styles
│ ├── not-found.tsx # Root 404 page
│ └── icon.png # App icon
├── components/ # React components
│ ├── ImageWithFallback/ # next/image wrapper with fallback
│ │ └── index.tsx
│ ├── ImageSlideshow/ # Image slideshow component
│ │ ├── index.tsx
│ │ └── image-slideshow.module.css
│ ├── MainHeader/ # Header and navigation
│ │ ├── index.tsx
│ │ ├── main-header.module.css
│ │ ├── MainHeaderBackground/
│ │ │ ├── index.tsx
│ │ │ └── main-header-background.module.css
│ │ └── NavLink/
│ │ ├── index.tsx
│ │ └── nav-link.module.css
│ └── meals/ # Meal-related components
│ ├── ImagePicker/ # Image picker component
│ │ ├── index.tsx
│ │ └── image-picker.module.css
│ ├── MealFormSubmitButton/
│ │ └── index.tsx
│ └── MealGridList/ # Meal grid list component
│ ├── index.tsx
│ ├── meals-grid-list.module.css
│ └── MealGridListItem/
│ ├── index.tsx
│ └── meal-grid-list-item.module.css
├── lib/ # Utility functions and server logic
│ ├── actions.ts # Server actions for form submissions
│ └── meals.ts # Database operations and queries
├── assets/ # Static assets (source images, icons)
│ ├── icons/ # Icon assets
│ └── *.jpg # Meal images
├── public/ # Public assets (served statically)
│ └── images/ # Public image assets
├── config.ts # Configuration (AWS S3 bucket name)
├── initdb.ts # Database initialization script
├── next.config.ts # Next.js configuration
├── tsconfig.json # TypeScript configuration
├── .eslintrc.json # ESLint configuration
├── .env.local.example # Environment variables template
├── package.json # Project dependencies
└── meals.db # SQLite database (created by initdb.ts)
initdb.ts: Database initialization script - must be run before dev/buildconfig.ts: AWS S3 bucket configuration - must updateAWS_S3_BUCKET_NAMEwith your bucket namelib/meals.ts: Database queries and meal operationslib/actions.ts: Server actions for form submissionsnext.config.ts: Next.js configuration (image domains)
The meals table has the following structure:
id: INTEGER PRIMARY KEY AUTOINCREMENTslug: TEXT NOT NULL UNIQUEtitle: TEXT NOT NULLimage: TEXT NOT NULLsummary: TEXT NOT NULLinstructions: TEXT NOT NULLcreator: TEXT NOT NULLcreator_email: TEXT NOT NULL
-
Update
config.ts:- Open
config.tsand update theAWS_S3_BUCKET_NAMEconstant with your actual S3 bucket name - The bucket name should be just the bucket name (e.g.,
my-bucket-name), not a full URL
- Open
-
AWS Credentials:
- Copy
.env.local.exampleto.env.local:
cp .env.local.example .env.local
- Edit
.env.localand fill in your AWS credentials:
AWS_ACCESS_KEY_ID=your_aws_access_key_id AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key
- Note:
.env.localis gitignored and should not be committed to version control
- Copy
pnpm run dev: Start development serverpnpm run build: Build for productionpnpm start: Start production serverpnpm run lint: Run ESLintpnpm run initdb: Initialize the database (creates meals.db and populates with sample data)
- The database file (
meals.db) is created automatically when you runpnpm run initdb - Sample meals are included in the initialization script
- Images are uploaded to AWS S3 when sharing new meals
- User inputs are sanitized using the
xsslibrary to prevent XSS attacks - The project is written in TypeScript for type safety
MIT