Skip to content

SunilBhadu/mini-blog-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mini Blog App — MERN Stack

A full-featured blog application built with MongoDB, Express, React, and Node.js.


Features

Core

  • Create, read, and delete blog posts
  • Search posts by title or tags (case-insensitive)
  • Pagination (5 posts per page) with automatic rollback when a page empties
  • Responsive 2026 SaaS-style UI with dark/light mode

Advanced

  • JWT Authentication — signup/login; only the post creator can delete their post
  • Likes — like/unlike posts with optimistic UI updates and rollback
  • Comments — add/delete comments per post with author + timestamp
  • Image Uploads — drag-and-drop image upload (Multer + optional Cloudinary, max 5 MB)
  • Dark/Light Mode — toggle with persistence via localStorage
  • Toast Notifications — global success/error/info toasts for all user actions
  • Rate Limiting — 10 req/15 min on auth, 30/10 min on post creation, 200/min global
  • Input Validation — server-side express-validator on all mutation endpoints

Project Structure

mini-blog-app/
├── client/                       # React frontend (Create React App)
│   ├── src/
│   │   ├── api/axios.js          # Axios instance with JWT interceptor
│   │   ├── context/
│   │   │   ├── AuthContext.js    # Global JWT auth state (login/signup/logout)
│   │   │   ├── ThemeContext.js   # Dark/light theme with localStorage persistence
│   │   │   └── ToastContext.js   # Global toast notification system
│   │   ├── components/
│   │   │   ├── Navbar.js         # Sticky nav; "New Post" → /?write=true
│   │   │   ├── PostCard.js       # Post display with optimistic like/delete + toasts
│   │   │   ├── PostForm.js       # Create post with drag-and-drop image upload
│   │   │   ├── CommentSection.js # Per-post comment add/delete section
│   │   │   ├── Pagination.js     # Page navigation component
│   │   │   └── Toast.js          # Floating toast notification renderer
│   │   └── pages/
│   │       ├── Home.js           # Feed: search, URL-param form open, pagination
│   │       ├── Login.js          # JWT login form
│   │       └── Signup.js         # JWT signup form
│   └── .env                      # REACT_APP_API_URL, REACT_APP_SERVER_URL
└── server/                       # Node/Express backend
    ├── config/db.js               # MongoDB connection via Mongoose
    ├── controllers/
    │   ├── postController.js      # CRUD + like + comment handlers
    │   └── authController.js      # signup, login (JWT)
    ├── middleware/
    │   ├── errorHandler.js        # Centralized Express error handler
    │   └── authMiddleware.js      # protect() — verifies JWT token
    ├── models/
    │   ├── Post.js                # Post schema (with text index + indexes)
    │   └── User.js                # User schema (bcrypt pre-save hook)
    ├── routes/
    │   ├── postRoutes.js          # All post routes + Multer upload
    │   └── authRoutes.js          # /signup, /login
    ├── uploads/                   # Uploaded images (local)
    └── server.js                  # Express entry point

Setup Instructions

Prerequisites

  • Node.js v18+
  • MongoDB running locally (mongod) or a MongoDB Atlas connection string

1. Clone the repository

git clone <repo-url>
cd mini-blog-app

2. Configure environment variables

Server — create/edit server/.env:

PORT=5000
MONGO_URI=mongodb://localhost:27017/mini-blog
JWT_SECRET=replace_with_a_long_random_secret
NODE_ENV=development

Client — create/edit client/.env:

REACT_APP_API_URL=http://localhost:5000/api
REACT_APP_SERVER_URL=http://localhost:5000

Set NODE_ENV=production to suppress stack traces in API error responses.

3. Install all dependencies

npm run install-all

Or manually:

cd server && npm install
cd ../client && npm install

4. Start development servers

# From project root — runs both concurrently
npm run dev

# Or individually:
npm run server    # Express API on http://localhost:5000
npm run client    # React app on http://localhost:3000

API Documentation

Authentication

Pass JWT token in the Authorization header for protected routes:

Authorization: Bearer <token>

Auth Endpoints

Method Endpoint Body Description
POST /api/auth/signup {username, email, password} Register a new user
POST /api/auth/login {email, password} Login — returns JWT token

Post Endpoints

Method Endpoint Auth Description
GET /api/posts No Fetch posts (paginated, 5/page) sorted newest first
GET /api/posts?search=term No Search title or tags (case-insensitive)
GET /api/posts?page=2 No Get a specific page
POST /api/posts Optional Create post (multipart/form-data)
DELETE /api/posts/:id Required Delete post — creator only
PUT /api/posts/:id/like Required Toggle like on a post
POST /api/posts/:id/comments Required Add a comment
DELETE /api/posts/:id/comments/:commentId Required Delete own comment

GET /api/posts Response

{
  "posts": [...],
  "currentPage": 1,
  "totalPages": 3,
  "total": 15
}

Post Schema (MongoDB)

{
  "title":    "String — required, trimmed",
  "content":  "String — required, trimmed",
  "username": "String — required, trimmed",
  "tags":     ["String"],
  "image":    "String (URL path, e.g. /uploads/filename.jpg)",
  "author":   "ObjectId (ref: User) — null if unauthenticated",
  "likes":    ["ObjectId (ref: User)"],
  "comments": [
    {
      "user":      "ObjectId (ref: User)",
      "username":  "String",
      "text":      "String",
      "createdAt": "Date"
    }
  ],
  "createdAt": "Date"
}

Error Response Format

{
  "message": "Human-readable error"
}

In development (NODE_ENV=development) a stack field is also included for debugging.


Production Checklist

# Item Notes
1 Set NODE_ENV=production Hides stack traces in error responses
2 Set strong JWT_SECRET (32+ chars) Change from the default placeholder
3 Set CORS_ORIGIN=https://your-domain.com Restricts CORS to your frontend URL
4 Configure Cloudinary env vars Enables cloud image storage
5 Use MongoDB Atlas Replace MONGO_URI with Atlas connection string

Notes & Assumptions

  • Images stored locally in server/uploads/; set Cloudinary env vars to use cloud storage.
  • JWT tokens expire after 7 days.
  • If a post has no author (created without auth), any logged-in user can delete it.
  • Pagination is 5 posts per page, configurable via PAGE_SIZE in postController.js.
  • Search input is regex-escaped server-side to prevent ReDoS attacks.
  • Login uses constant-time bcrypt compare even for non-existent users to prevent email enumeration.

About

Build a Mini Blog App using the MERN (MongoDB, Express, React, Node.js) stack.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors