A Modern MERN Stack Blogging Platform with Studio Ghibli-Inspired Design
- About
- Features
- Tech Stack
- Screenshots
- Getting Started
- Project Structure
- API Documentation
- Deployment
- Future Enhancements
- Contributing
- License
- Contact
- Acknowledgments
QuillStack is a feature-rich, full-stack blogging platform built with the MERN stack and TypeScript. Inspired by the whimsical aesthetics of Studio Ghibli, it offers a delightful user experience with a warm, inviting interface in both light and dark themes.
This project serves as a comprehensive portfolio piece, demonstrating modern web development practices, including authentication, authorization, file uploads, rich text editing, and responsive design.
Key Highlights:
- ๐จ Studio Ghibli-inspired design system with custom light/dark themes
- ๐ Rich text editor powered by Tiptap
- ๐ Secure JWT-based authentication with refresh tokens
- ๐ผ๏ธ Image upload and management via Cloudinary
- ๐จโ๐ผ Comprehensive admin dashboard for content management
- ๐ฑ Fully responsive design across all devices
- โก Optimized performance with compression and rate limiting
- ๐ก๏ธ Security-first approach with Helmet.js and input validation
- ๐ Browse Blogs: Explore published blog posts with pagination
- ๐ Search & Filter: Find blogs by title or content
- ๐ Blog Details: Read full blog posts with formatted content
- ๐ Theme Switching: Toggle between light, dark, and system themes
- ๐ฑ Responsive Design: Seamless experience across all devices
- ๐ Dashboard: Overview of site statistics and metrics
- โ๏ธ Blog Management: Create, edit, and delete blog posts
- ๐ผ๏ธ Image Uploads: Upload and manage blog banner images via Cloudinary
- ๐ฅ User Management: View and manage registered users
- ๐ฌ Comment Moderation: Review and manage blog comments
- ๐ Rich Text Editor: Tiptap-powered WYSIWYG editor with:
- Multiple heading levels
- Text formatting (bold, italic, strikethrough)
- Lists (ordered, unordered, task lists)
- Blockquotes and code blocks
- Links and horizontal rules
- Tables
- ๐ Draft System: Save blogs as drafts before publishing
- ๐ Secure Authentication: JWT-based auth with HTTP-only cookies
- ๐ก๏ธ Authorization: Role-based access control (Admin/User)
- โก Rate Limiting: Protection against brute-force attacks
- ๐๏ธ Compression: Gzip compression for faster load times
- ๐งน Input Sanitization: XSS protection with DOMPurify
- ๐ Password Hashing: Bcrypt for secure password storage
- ๐ CORS Protection: Whitelisted origins only
- Framework: React 19
- Language: TypeScript 5.9
- Routing: React Router 7
- Styling: Tailwind CSS 4 with custom Ghibli-inspired theme
- UI Components: shadcn/ui (Radix UI primitives)
- Rich Text Editor: Tiptap 3
- Form Handling: React Hook Form with Zod validation
- HTTP Client: Axios
- Animations: Motion (Framer Motion)
- Notifications: Sonner
- Build Tool: Vite 7
- Runtime: Node.js
- Framework: Express 5
- Language: TypeScript 5.9
- Database: MongoDB with Mongoose
- Authentication: JWT (jsonwebtoken)
- File Upload: Multer + Cloudinary
- Validation: Express Validator
- Security: Helmet.js, bcryptjs
- Logging: Winston
- Rate Limiting: express-rate-limit
- Compression: compression middleware
- Package Manager: pnpm 10
- Deployment: Render (Free Tier)
- Version Control: Git
- Runtime Execution: tsx (for TypeScript)
Comprehensive admin dashboard with metrics
- Node.js (v18 or higher)
- pnpm (v10.24.0)
- MongoDB (local or Atlas)
- Cloudinary account (for image uploads)
-
Clone the repository
git clone https://github.com/KeepSerene/quill-stack-blog-site-mern.git cd quill-stack-blog-site-mern -
Install dependencies
pnpm install
-
Install backend dependencies
cd backend pnpm install -
Install frontend dependencies
cd ../frontend pnpm install cd ..
Create a .env file in the backend directory:
# Server Configuration
PORT=3000
NODE_ENV=development
# Client URL (for CORS)
CLIENT_URL=http://localhost:5173
# Database
DB_URI=mongodb://localhost:27017/quill-stack-db
# Or use MongoDB Atlas:
# DB_URI=mongodb+srv://username:password@cluster.mongodb.net/quill-stack-db
# JWT Secrets (generate strong random strings)
JWT_ACCESS_SECRET=your-super-secret-access-key-min-32-chars
JWT_REFRESH_SECRET=your-super-secret-refresh-key-min-32-chars
JWT_ACCESS_EXPIRES_IN=1h
JWT_REFRESH_EXPIRES_IN=1w
# Admin Emails (comma-separated)
ADMIN_EMAILS=admin@example.com,another@example.com
# Cloudinary Configuration
CLOUDINARY_CLOUD_NAME=your-cloud-name
CLOUDINARY_API_KEY=your-api-key
CLOUDINARY_API_SECRET=your-api-secret
# Logging
WINSTON_LOG_LEVEL=infoCreate a .env file in the frontend directory:
# API Base URL
VITE_API_BASE_URL=http://localhost:3000/api/v1-
Start the backend server
cd backend pnpm dev -
Start the frontend dev server (in a new terminal)
cd frontend pnpm dev -
Open your browser
- Frontend:
http://localhost:5173 - Backend:
http://localhost:3000
- Frontend:
# Build both frontend and backend
pnpm build
# Start the production server
pnpm startquill-stack/
โโโ backend/
โ โโโ src/
โ โ โโโ configs/ # Configuration files
โ โ โโโ controllers/ # Request handlers
โ โ โ โโโ v1/
โ โ โ โโโ auth/ # Authentication controllers
โ โ โ โโโ blogs/ # Blog controllers
โ โ โ โโโ comments/ # Comment controllers
โ โ โ โโโ likes/ # Like controllers
โ โ โ โโโ users/ # User controllers
โ โ โ โโโ views/ # View controllers
โ โ โโโ lib/ # Utility libraries
โ โ โ โโโ cloudinary.ts # Cloudinary integration
โ โ โ โโโ jwt.ts # JWT utilities
โ โ โ โโโ mongoose.ts # MongoDB connection
โ โ โ โโโ winston.ts # Logging configuration
โ โ โโโ middlewares/ # Express middlewares
โ โ โ โโโ authenticate.middleware.ts
โ โ โ โโโ authorize.middleware.ts
โ โ โ โโโ upload.middleware.ts
โ โ โ โโโ validation-errors.middleware.ts
โ โ โโโ models/ # Mongoose schemas
โ โ โ โโโ User.ts
โ โ โ โโโ Blog.ts
โ โ โ โโโ Comment.ts
โ โ โ โโโ Like.ts
โ โ โ โโโ View.ts
โ โ โโโ routes/ # API routes
โ โ โ โโโ v1/
โ โ โ โโโ auth.route.ts
โ โ โ โโโ blogs.route.ts
โ โ โ โโโ comments.route.ts
โ โ โ โโโ likes.route.ts
โ โ โ โโโ users.route.ts
โ โ โ โโโ views.route.ts
โ โ โ โโโ index.ts
โ โ โโโ @types/ # TypeScript type definitions
โ โ โโโ server.ts # Express app entry point
โ โโโ package.json
โ โโโ tsconfig.json
โโโ frontend/
โ โโโ public/
โ โ โโโ favicon.svg
โ โ โโโ screenshots/ # App screenshots
โ โโโ src/
โ โ โโโ components/ # React components
โ โ โ โโโ ui/ # shadcn/ui components
โ โ โ โโโ ... # Custom components
โ โ โโโ layouts/ # Layout components
โ โ โ โโโ Root.tsx
โ โ โ โโโ Admin.tsx
โ โ โโโ pages/ # Page components
โ โ โ โโโ auth/ # Authentication pages
โ โ โ โโโ users/ # User pages
โ โ โ โโโ admins/ # Admin pages
โ โ โ โโโ errors/ # Error pages
โ โ โโโ routes/ # React Router configuration
โ โ โ โโโ actions/ # Form actions
โ โ โ โโโ loaders/ # Data loaders
โ โ โ โโโ router.ts
โ โ โโโ lib/ # Utilities
โ โ โ โโโ api/ # API client setup
โ โ โโโ types/ # TypeScript types
โ โ โโโ index.css # Global styles
โ โ โโโ main.tsx # App entry point
โ โโโ index.html
โ โโโ package.json
โ โโโ tsconfig.json
โ โโโ vite.config.ts
โโโ package.json # Root package.json
โโโ README.md
- Development:
http://localhost:3000/api/v1 - Production:
https://quill-stack.onrender.com/api/v1
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| POST | /auth/register |
Register a new user | No |
| POST | /auth/login |
Login user | No |
| POST | /auth/refresh-token |
Refresh access token | Yes (Cookie) |
| POST | /auth/logout |
Logout user | Yes |
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /blogs |
Get all published blogs | No | - |
| GET | /blogs/:slug |
Get blog by slug | No | - |
| POST | /blogs |
Create a new blog | Yes | Admin |
| PUT | /blogs/:slug |
Update blog by slug | Yes | Admin |
| DELETE | /blogs/:slug |
Delete blog by slug | Yes | Admin |
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /users |
Get all users | Yes | Admin |
| GET | /users/current |
Get current user | Yes | User/Admin |
| GET | /users/:userId |
Get user by ID | Yes | Admin |
| PUT | /users/current |
Update current user | Yes | User/Admin |
| DELETE | /users/current |
Delete current user | Yes | User/Admin |
| DELETE | /users/:userId |
Delete user by ID | Yes | Admin |
| GET | /users/:userId/blogs |
Get blogs by user | Yes | User/Admin |
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| GET | /comments |
Get all comments | Yes | Admin |
| GET | /comments/blogs/:blogId |
Get comments by blog | Yes | User/Admin |
| POST | /comments/blogs/:blogId |
Create a comment | Yes | User/Admin |
| DELETE | /comments/:commentId |
Delete a comment | Yes | User/Admin |
| Method | Endpoint | Description | Auth Required | Role |
|---|---|---|---|---|
| POST | /likes/blogs/:blogId |
Like a blog | Yes | User/Admin |
| DELETE | /likes/blogs/:blogId |
Unlike a blog | Yes | User/Admin |
| POST | /views/blogs/:blogId |
Increment blog view | Yes | User/Admin |
POST /api/v1/auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePass123",
"role": "user"
}
# Response
{
"message": "Registration successful!",
"accessToken": "eyJhbGc...",
"user": {
"username": "user",
"email": "user@example.com",
"role": "user"
}
}POST /api/v1/blogs
Authorization: Bearer <access_token>
Content-Type: multipart/form-data
title: My First Blog Post
content: <p>This is the content...</p>
status: published
banner-image: <file>
# Response
{
"message": "Blog created successfully!",
"blog": {
"_id": "...",
"title": "My First Blog Post",
"slug": "my-first-blog-post",
"author": {...},
"banner": {
"url": "https://res.cloudinary.com/...",
"publicId": "...",
"width": 1920,
"height": 1080
},
"status": "published",
"publishedAt": "2025-01-15T10:30:00.000Z"
}
}QuillStack is deployed on Render using the free tier. The deployment configuration is optimized for a monorepo structure where both frontend and backend are served from a single service.
-
Build Command:
pnpm build- Installs and builds both backend and frontend
- Frontend static files are copied to
backend/dist/frontend/dist
-
Start Command:
pnpm start- Runs the backend server with
tsx - Serves frontend static files in production
- Runs the backend server with
-
Environment Variables: Set all required environment variables in Render dashboard
- Create a new Web Service on Render
- Connect your GitHub repository
- Configure build settings:
- Build Command:
pnpm build - Start Command:
pnpm start
- Build Command:
- Add environment variables (same as local
.env) - Deploy!
- Frontend assets are served from the Express backend
- Client-side routing is handled with a catch-all route
- Static file compression is enabled
- Security headers are set with Helmet.js
- Rate limiting is active to prevent abuse
The following features are planned for future releases:
- Likes Functionality: Complete implementation of blog liking system
- Views Tracking: Display and track blog view counts
- User Profiles: Public user profile pages
- Comment System: Frontend interface for commenting on blogs
- Search Enhancement: Advanced search with filters (author, date, tags)
- Bookmarks: Save favorite blogs for later reading
- Reading Progress: Track reading progress on long articles
- Blog Categories/Tags: Organize blogs with categories and tags
- Email Notifications: Notify users of new comments, likes, etc.
- Blog Categories: Full category system implementation
- Blog Tags: Tagging system for better organization
- Analytics: Detailed analytics for admins
- API Rate Limiting Per User: More granular rate limiting
- Progressive Web App (PWA): Offline support and installability
- Infinite Scroll: Replace pagination with infinite scroll
- Skeleton Loaders: Better loading states
- Optimistic Updates: Immediate UI feedback for user actions
- Code Splitting: Lazy load routes and components
- Two-Factor Authentication: Optional 2FA for admins
- Account Verification: Email verification on registration
- Content Moderation: Automated content filtering
Contributions are welcome! This is a portfolio project, but I'm open to suggestions and improvements.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Follow existing code patterns
- Use TypeScript for type safety
- Write meaningful commit messages
- Add comments for complex logic
- Test your changes thoroughly
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Copyright 2025 Dhrubajyoti Bhattacharjee
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Live Demo: https://quill-stack.onrender.com
- Studio Ghibli for the beautiful aesthetic inspiration
- shadcn/ui for the amazing UI component library
- Tiptap for the powerful rich text editor
- Tailwind CSS for the utility-first CSS framework
- Render for reliable free hosting
- Cloudinary for image hosting and optimization
- All the amazing open-source contributors whose libraries made this possible
โญ Star this repository if you found it helpful! โญ
Made with โค๏ธ and ๐ by Dhrubajyoti Bhattacharjee
