The capstone is where every concept from the previous 27 chapters comes together into a single, deployable application. Rather than introducing new technology, the capstone exercises your ability to make architectural decisions, reason about data relationships, plan an API surface, and structure a full-stack project before writing a single line of code. In this lesson you will define the complete feature scope for the MERN Blog/CMS, design the MongoDB schema for every collection, map every API endpoint, and set up the monorepo project structure โ producing a blueprint that the next four lessons will build from.
Capstone Feature Scope
| Feature Area | Included Features |
|---|---|
| Authentication | Register, login, logout, email verification, password reset, refresh token, profile update |
| Posts | Create, read, update, delete, publish/draft toggle, featured flag, tag filtering, full-text search, pagination |
| Comments | Create, delete, list by post, live updates via Socket.io, typing indicator |
| Tags | Auto-created on post save, tag cloud on home page, filtered post list by tag |
| Media | Avatar upload (user profile), cover image upload (post), Cloudinary CDN storage |
| Welcome + verification, password reset, password changed alert | |
| Admin | Admin dashboard โ all users, all posts, delete any post, promote/demote role |
| Analytics | Post view count (increment on GET), like count, comment count |
MongoDB Schema Design
// โโ User โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
{
_id, name, email, password (hashed), role ('user'|'editor'|'admin'),
avatar (Cloudinary URL), bio, isEmailVerified,
emailVerifyToken (select:false), emailVerifyExpires (select:false),
passwordResetToken (select:false), passwordResetExpires (select:false),
passwordChangedAt (select:false),
createdAt, updatedAt
}
// โโ Post โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
{
_id, title, slug (unique, auto-generated from title),
body (HTML string), excerpt, coverImage (Cloudinary URL),
author (ref: User), tags ([String]),
published (Boolean, default:false), featured (Boolean, default:false),
viewCount (Number, default:0), likedBy ([ref: User]),
createdAt, updatedAt
}
// โโ Comment โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
{
_id, body, post (ref: Post), author (ref: User),
createdAt, updatedAt
}
// โโ Tag (optional โ derived from posts, or a separate collection) โโโโโโโโโโโโโโ
// Option A: tags stored as string arrays on Post โ simpler, no separate collection
// Option B: Tag collection for tag descriptions and post count caching
// Recommendation: start with Option A (strings on Post), add Tag collection if needed
API Endpoint Map
โโ Auth โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
POST /api/auth/register Register + send verification email
POST /api/auth/login Login โ access token + refresh cookie
POST /api/auth/logout Clear refresh token cookie
POST /api/auth/refresh Issue new access token from refresh cookie
GET /api/auth/me Get current user (protected)
GET /api/auth/verify-email Verify email with token
POST /api/auth/forgot-password Send password reset email
POST /api/auth/reset-password/:t Reset password with token
โโ Posts โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GET /api/posts List (published, paginated, filterable by tag/search)
POST /api/posts Create (protected)
GET /api/posts/:id Get single post + increment viewCount
PATCH /api/posts/:id Update (owner or admin)
DELETE /api/posts/:id Delete (owner or admin)
PATCH /api/posts/:id/publish Toggle published (owner or editor/admin)
POST /api/posts/:id/like Like / unlike toggle (protected)
GET /api/posts/featured Get featured posts (public)
GET /api/posts/search?q= Full-text search (public)
โโ Comments โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GET /api/posts/:postId/comments List comments for a post
POST /api/posts/:postId/comments Create comment (protected) โ Socket.io emit
DELETE /api/comments/:id Delete comment (owner or admin)
โโ Users โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GET /api/users/:id Public profile
PATCH /api/users/:id Update profile (own account)
POST /api/users/avatar Upload avatar (protected, Multer+Cloudinary)
GET /api/users/:id/posts Posts by user (public)
โโ Admin โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GET /api/admin/users List all users (admin only)
PATCH /api/admin/users/:id/role Change role (admin only)
DELETE /api/admin/users/:id Delete user (admin only)
GET /api/admin/stats Site stats โ post/user/comment counts
โโ Upload โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
POST /api/posts/:id/cover Upload cover image (owner, Cloudinary)
โโ Health โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
GET /api/health Health check
Monorepo Project Structure
mern-blog/
โโโ server/ Express API
โ โโโ src/
โ โ โโโ config/ db.js, cloudinary.js, multer.js, socket.js
โ โ โโโ controllers/ authController.js, postController.js, ...
โ โ โโโ middleware/ auth.js, authorize.js, errorHandler.js, rateLimiter.js
โ โ โโโ models/ User.js, Post.js, Comment.js
โ โ โโโ routes/ auth.js, posts.js, comments.js, users.js, admin.js
โ โ โโโ utils/ asyncHandler.js, AppError.js, jwt.js, sendEmail.js, ...
โ โโโ index.js
โ โโโ package.json
โ โโโ .env (gitignored)
โ
โโโ client/ React + Vite SPA
โ โโโ src/
โ โ โโโ components/ layout/, posts/, ui/, auth/
โ โ โโโ context/ AuthContext.jsx, NotificationContext.jsx
โ โ โโโ hooks/ useSocket.js, useFetch.js, useDebounce.js
โ โ โโโ pages/ HomePage, PostDetailPage, LoginPage, ...
โ โ โโโ services/ api.js, postService.js, authService.js
โ โ โโโ utils/ validators.js, formatters.js
โ โโโ public/_redirects /* /index.html 200
โ โโโ package.json
โ โโโ vite.config.js
โ
โโโ e2e/ Playwright E2E tests
โ โโโ auth.spec.js, posts.spec.js
โโโ .github/workflows/ci.yml GitHub Actions
โโโ playwright.config.js
โโโ README.md
Development Setup
# Clone or initialise the monorepo
mkdir mern-blog && cd mern-blog
# Server
mkdir server && cd server
npm init -y
npm install express mongoose dotenv bcryptjs jsonwebtoken cors helmet \
compression multer cloudinary multer-storage-cloudinary \
nodemailer express-rate-limit socket.io express-validator
npm install --save-dev nodemon jest supertest mongodb-memory-server
cd ..
# Client
npm create vite@latest client -- --template react
cd client
npm install axios react-router-dom socket.io-client dompurify
npm install --save-dev vitest @testing-library/react @testing-library/jest-dom \
@testing-library/user-event jsdom msw
cd ..
# E2E
npm install --save-dev @playwright/test
npx playwright install chromium
Common Mistakes
Mistake 1 โ Starting to code without a schema design
โ Wrong โ adding fields to models as you discover you need them:
// Adding likedBy to Post three weeks after building the Post model
// โ requires a database migration, breaks existing data, wastes time
โ Correct โ design the complete schema upfront. It is much easier to add a field you planned than to retrofit one you forgot.
Mistake 2 โ Building all API routes before starting React
โ Wrong โ horizontal build: all Express, then all React, then integration.
โ Correct โ vertical build: register endpoint + register form + test end-to-end. Then login. Then post creation. Each vertical slice is testable and gives immediate feedback on API design flaws.
Mistake 3 โ Not planning the auth flow before writing a single line
โ Wrong โ building posts before auth is complete:
// Post routes require req.user โ but auth middleware is not yet built
// All post tests fail until auth is finished โ wasted work
โ Correct โ always build auth first. Every protected route depends on it. A working auth system with register, login, and protect middleware is the bedrock everything else stands on.
Quick Reference โ Build Order
| Phase | Build in This Order |
|---|---|
| 1 โ Foundation | Express setup, MongoDB connection, error handler, asyncHandler, AppError |
| 2 โ Auth | User model, register, login, protect middleware, AuthContext, login/register forms |
| 3 โ Posts (core) | Post model, CRUD API, PostList, PostDetail, CreatePost form |
| 4 โ Media | Multer + Cloudinary, avatar upload, cover image upload, ImageUploader component |
| 5 โ Comments | Comment model, comment API, Socket.io, live comment list, typing indicator |
| 6 โ Email | Nodemailer, email verification, password reset |
| 7 โ Polish | Search, pagination, tags, admin panel, dark mode, responsive layout |
| 8 โ Launch | Tests, CI/CD, Atlas, Render, Netlify |