Empowering learners and educators β one course at a time.
StudyNotion is a full-stack EdTech platform where Students can discover, purchase, and stream courses, Instructors can build and monetize their content, and Admins can govern the entire ecosystem β all in one seamless, cloud-powered experience.
π The application is live and fully functional. Click below to try it out!
| π Service | π URL |
|---|---|
| Frontend (React App) | https://study-notion-blue-mu.vercel.app |
| Alternate URL | https://study-notion-git-main-arjuns-projects-c804732d.vercel.app |
- Live Demo
- Project Overview
- Key Features
- System Architecture
- Application Flow Diagram
- Tech Stack
- Folder Structure
- Installation & Setup
- Security Practices
- Performance & Optimizations
- API Documentation
- Deployment
- Author
StudyNotion is a production-grade, full-stack EdTech SaaS platform built on the MERN stack (MongoDB, Express, React, Node.js). It replicates the core experience of platforms like Udemy or Coursera, offering:
- π Students β browse categories, enroll in courses via Razorpay, stream video lectures, and track their progress.
- π§βπ« Instructors β create structured courses with sections & video sub-sections, manage drafts, publish content, and view earnings analytics.
- π‘οΈ Admins β manage course categories and platform governance.
The platform supports OTP-based email verification, JWT authentication, Cloudinary media uploads, Razorpay payment gateway, and automated email notifications β making it a complete, real-world EdTech solution.
| Role | Features |
|---|---|
| π Student | Browse & search courses by category, cart & checkout via Razorpay, video lecture streaming, progress tracking, ratings & reviews |
| π§βπ« Instructor | Course creation wizard (sections + video sub-sections), draft/publish toggle, earnings dashboard via Chart.js, edit/delete courses |
| π‘οΈ Admin | Create & manage categories, platform-wide oversight |
| π Auth | OTP email verification on signup, JWT-based sessions, forgot/reset password flow |
| βοΈ Media | Cloudinary CDN for all video and image uploads with express-fileupload |
| π§ Email | Nodemailer transactional emails for OTP, enrollment confirmation, and payment success |
| π³ Payments | Razorpay order creation, payment capture, and webhook-style server-side verification |
The app follows a classic ClientβServerβDatabase three-tier architecture with cloud services integrated at the server layer.
graph TD
subgraph Client ["π₯οΈ Client (React 18 + Redux)"]
UI[React Pages & Components]
RTK[Redux Toolkit Store]
Axios[Axios HTTP Layer]
end
subgraph Server ["βοΈ Server (Node.js + Express)"]
Routes[REST API Routes]
Middleware[Auth Middleware\nJWT + Role Guard]
Controllers[Business Logic Controllers]
Utils[Utils: OTP, Email, Cloudinary]
end
subgraph Database ["ποΈ Database (MongoDB Atlas)"]
User[(User)]
Course[(Course)]
Section[(Section)]
SubSection[(SubSection)]
Category[(Category)]
CourseProgress[(CourseProgress)]
Rating[(RatingAndReview)]
OTP[(OTP)]
Profile[(Profile)]
end
subgraph CloudServices ["βοΈ Cloud Services"]
Cloudinary[Cloudinary CDN\nImages & Videos]
Razorpay[Razorpay\nPayment Gateway]
Nodemailer[Nodemailer\nSMTP Email]
end
UI --> Axios
Axios -->|HTTPS REST| Routes
Routes --> Middleware
Middleware --> Controllers
Controllers --> Database
Controllers --> CloudServices
RTK --> UI
sequenceDiagram
participant U as π§ User (Browser)
participant C as React Client
participant S as Express Server
participant DB as MongoDB
participant Mail as Nodemailer
U->>C: Clicks Sign Up
C->>S: POST /api/v1/auth/sendotp {email}
S->>DB: Check if email exists
S->>DB: Save OTP (TTL: 5 min)
S->>Mail: Send OTP email
Mail-->>U: OTP delivered to inbox
U->>C: Enters OTP + form details
C->>S: POST /api/v1/auth/signup {otp, ...details}
S->>DB: Verify OTP
S->>DB: Create User + Profile documents
S-->>C: { success: true, token, user }
C->>C: Store token in localStorage + Redux
U->>C: Clicks Login
C->>S: POST /api/v1/auth/login {email, password}
S->>DB: Find user, bcrypt.compare(password)
S-->>C: JWT token (signed with JWT_SECRET)
C->>C: Persist token, redirect to Dashboard
sequenceDiagram
participant S as Student
participant C as React Client
participant API as Express API
participant RZ as Razorpay
participant DB as MongoDB
participant Mail as Nodemailer
S->>C: Click "Buy Now"
C->>API: POST /api/v1/payment/capturePayment (auth + isStudent)
API->>RZ: Create Order (amount, currency)
RZ-->>API: { orderId, amount }
API-->>C: Order details
C->>RZ: Open Razorpay Checkout
S->>RZ: Completes payment
RZ-->>C: { razorpay_payment_id, razorpay_signature }
C->>API: POST /api/v1/payment/verifyPayment
API->>API: HMAC-SHA256 signature verification
API->>DB: Enroll student in course
API->>Mail: Send enrollment confirmation email
API-->>C: { success: true }
C->>C: Navigate to enrolled courses
erDiagram
USER {
ObjectId _id
String firstName
String lastName
String email
String password
String accountType
Boolean active
String image
String token
Date resetPasswordExpires
}
PROFILE {
ObjectId _id
String gender
String dateOfBirth
String about
String contactNumber
}
COURSE {
ObjectId _id
String courseName
String courseDescription
String whatYouWillLearn
Number price
String thumbnail
String[] tag
String[] instructions
String status
Date createdAt
}
SECTION {
ObjectId _id
String sectionName
}
SUBSECTION {
ObjectId _id
String title
String timeDuration
String description
String videoUrl
}
CATEGORY {
ObjectId _id
String name
String description
}
RATINGANDREVIEW {
ObjectId _id
Number rating
String review
}
COURSEPROGRESS {
ObjectId _id
ObjectId[] completedVideos
}
OTP {
ObjectId _id
String email
String otp
Date createdAt
}
USER ||--|| PROFILE : "additionalDetails"
USER ||--o{ COURSE : "courses (enrolled)"
USER ||--o{ COURSEPROGRESS : "courseProgress"
COURSE ||--|| USER : "instructor"
COURSE ||--o{ SECTION : "courseContent"
COURSE ||--|| CATEGORY : "category"
COURSE ||--o{ RATINGANDREVIEW : "ratingAndReviews"
COURSE ||--o{ USER : "studentsEnrolled"
SECTION ||--o{ SUBSECTION : "subSection"
COURSEPROGRESS ||--o{ SUBSECTION : "completedVideos"
RATINGANDREVIEW ||--|| USER : "user"
RATINGANDREVIEW ||--|| COURSE : "course"
flowchart LR
A([Browser Request]) --> B[React Axios\naxiosToastError interceptor]
B -->|HTTPS| C[Express Router]
C --> D{Route\nPublic?}
D -->|Yes| G[Controller]
D -->|No| E[auth middleware\nJWT Verify]
E --> F{Role\nCheck}
F -->|isStudent| G
F -->|isInstructor| G
F -->|isAdmin| G
F -->|Fail 401| Z([Error Response])
G --> H{Operation\nType}
H -->|DB Query| I[(MongoDB)]
H -->|File Upload| J[Cloudinary]
H -->|Email| K[Nodemailer]
H -->|Payment| L[Razorpay]
I --> M([JSON Response])
J --> M
K --> M
L --> M
M --> N[Redux\nState Update]
N --> O([UI Re-render])
| Technology | Purpose |
|---|---|
| React 18 | UI framework with hooks |
| React Router v6 | Client-side routing & protected routes |
| Redux Toolkit | Global state management (auth, cart, course) |
| Tailwind CSS | Utility-first styling |
| Axios | HTTP client with interceptors |
| React Hook Form | Form handling & validation |
| Chart.js + react-chartjs-2 | Instructor earnings analytics |
| Swiper.js | Course carousels |
| video-react | In-browser video player |
| react-hot-toast | Toast notifications |
| react-type-animation | Animated hero text |
| react-otp-input | OTP verification input UI |
| Technology | Purpose |
|---|---|
| Node.js + Express | REST API server |
| MongoDB + Mongoose | NoSQL database & ODM |
| JSON Web Token (JWT) | Stateless auth tokens |
| bcryptjs | Password hashing |
| Cloudinary | Cloud media storage (images & videos) |
| Razorpay | Payment gateway |
| Nodemailer | Transactional emails |
| otp-generator | Secure OTP generation |
| express-fileupload | Multipart file handling |
| cookie-parser | Cookie-based token support |
| dotenv | Environment variable management |
| cors | Cross-origin request handling |
StudyNotion-main/
β
βββ Client/ # React Frontend
β βββ public/
β βββ src/
β βββ App.js # Root component & routes
β βββ Assests/ # Static images & logos
β βββ components/
β β βββ Common/ # Navbar, Footer, Spinner
β β βββ core/
β β βββ Auth/ # PrivateRoute, OpenRoute
β β βββ Dashboard/ # My Profile, Settings,
β β β β # Cart, Enrolled Courses,
β β β β # AddCourse, MyCourses,
β β β βββ InstructorDashboard/
β β βββ HomePage/ # Hero, banners, stats
β β βββ Catalog/ # Course listing
β β βββ ViewCourse/ # Video player, sidebar
β βββ data/ # Static data (navbar links, etc.)
β βββ hooks/ # Custom React hooks
β βββ pages/ # Page-level components
β β βββ Home.jsx
β β βββ Login.jsx
β β βββ Signup.jsx
β β βββ Dashboard.jsx
β β βββ CourseDetails.jsx
β β βββ ViewCourse.jsx
β β βββ Catalog.jsx
β β βββ About.jsx
β β βββ Contact.jsx
β β βββ ForgotPassword.jsx
β β βββ UpdatePassword.jsx
β β βββ VerifyEmail.jsx
β βββ reducer/ # Redux store setup
β βββ slice/ # Redux slices (auth, cart, course, etc.)
β βββ Services/ # API call functions (axios wrappers)
β βββ utils/ # Constants, helper functions
β
βββ Server/ # Node.js + Express Backend
βββ index.js # App entry point
βββ config/
β βββ database.js # MongoDB connection
β βββ cloudinary.js # Cloudinary setup
βββ controllers/
β βββ Auth.js # signup, login, sendOTP, changePassword
β βββ ResetPassword.js # resetPasswordToken, resetPassword
β βββ Course.js # CRUD for courses
β βββ Section.js # CRUD for sections
β βββ SubSection.js # CRUD for sub-sections + video upload
β βββ Category.js # Category management
β βββ Profile.js # User profile management
β βββ Payments.js # Razorpay integration
β βββ RatingAndReview.js # Rating & review logic
β βββ courseProgress.js # Progress tracking
β βββ ContactUs.js # Contact form handler
βββ middlewares/
β βββ auth.js # JWT auth + role guards
βββ models/
β βββ User.js
β βββ Profile.js
β βββ Course.js
β βββ Section.js
β βββ SubSection.js
β βββ Category.js
β βββ OTP.js
β βββ RatingAndReview.js
β βββ CourseProgress.js
βββ routes/
β βββ User.js # /api/v1/auth
β βββ Profile.js # /api/v1/profile
β βββ Course.js # /api/v1/course
β βββ Payments.js # /api/v1/payment
β βββ ContactUs.js # /api/v1/contact
βββ mail/
β βββ templates/ # HTML email templates
βββ utils/
βββ mailSender.js # Nodemailer helper
βββ imageUploader.js # Cloudinary uploader
βββ secToDuration.js # Duration formatter
- Node.js β₯ 18.x
- npm β₯ 9.x
- MongoDB Atlas account
- Cloudinary account
- Razorpay test/live keys
- Gmail SMTP or any SMTP provider
git clone https://github.com/your-username/StudyNotion.git
cd StudyNotionCreate Server/.env:
PORT=4000
MONGODB_URL=mongodb+srv://<user>:<password>@cluster.mongodb.net/studynotion
JWT_SECRET=your_super_secret_jwt_key
# Cloudinary
CLOUD_NAME=your_cloud_name
API_KEY=your_api_key
API_SECRET=your_api_secret
# Razorpay
RAZORPAY_KEY=rzp_test_xxxxxxxx
RAZORPAY_SECRET=your_razorpay_secret
# Nodemailer
MAIL_HOST=smtp.gmail.com
MAIL_USER=your_email@gmail.com
MAIL_PASS=your_app_passwordCreate Client/.env:
REACT_APP_BASE_URL=http://localhost:4000/api/v1# From root
npm install
# Install client deps
cd Client && npm install
# Install server deps
cd ../Server && npm install# From root β runs both client and server concurrently
npm run dev| Service | URL |
|---|---|
| React Frontend | http://localhost:3000 |
| Express Backend | http://localhost:4000 |
| Practice | Implementation |
|---|---|
| Password Hashing | bcryptjs with salt rounds β passwords are never stored in plain text |
| JWT Authentication | Signed tokens validated on every protected route via auth middleware |
| Role-Based Access Control | Middleware guards: isStudent, isInstructor, isAdmin β enforced at route level |
| OTP Expiry | OTPs are stored in MongoDB with a TTL index; they auto-expire after 5 minutes |
| CORS Whitelist | Only approved origins (Vercel deployments + localhost) are accepted; all others are blocked |
| Environment Variables | All secrets (JWT, DB URI, API keys) are stored in .env and never committed to version control |
| Cookie Security | cookie-parser used; tokens are extracted from cookies, headers, or request body |
| Signature Verification | Razorpay payments are verified server-side using HMAC-SHA256 before enrollment |
| Optimization | Details |
|---|---|
| Lazy Loading | React Router enables code-splitting at the page level |
| Redux State Management | Centralized store avoids prop drilling and redundant API calls |
| CDN Media Delivery | All course videos and thumbnails are served via Cloudinary CDN for low-latency global delivery |
| Axios Interceptors | Centralized error handling prevents duplicate error-handling logic across services |
| Temp File Upload | express-fileupload uses /tmp for temporary storage before streaming to Cloudinary |
| MongoDB Indexing | OTP model uses a TTL index (createdAt) to auto-purge expired documents |
| Concurrent Dev Server | concurrently runs both React and Express in one terminal, reducing developer friction |
Progress Bar (@ramonak/react-progress-bar) |
Visual lecture progress feedback without heavy re-renders |
Base URL: http://localhost:4000/api/v1
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/sendotp |
β | Send OTP to email for verification |
POST |
/signup |
β | Register new user (OTP required) |
POST |
/login |
β | Login and receive JWT token |
POST |
/changepassword |
β | Change authenticated user's password |
POST |
/reset-password-token |
β | Generate password reset token |
POST |
/reset-password |
β | Reset password using token |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
DELETE |
/deleteProfile |
β | Delete user account |
PUT |
/updateProfile |
β | Update user profile details |
GET |
/getUserDetails |
β | Get authenticated user's details |
GET |
/getEnrolledCourses |
β | Get all enrolled courses |
PUT |
/updateDisplayPicture |
β | Upload/update profile picture |
GET |
/instructorDashboard |
β Instructor | Get instructor analytics |
| Method | Endpoint | Auth | Role | Description |
|---|---|---|---|---|
POST |
/createCourse |
β | Instructor | Create a new course |
POST |
/editCourse |
β | Instructor | Update course details |
DELETE |
/deleteCourse |
β | Instructor | Delete a course |
GET |
/getAllCourses |
β | β | Get all published courses |
POST |
/getCourseDetails |
β | β | Get course info & sections |
POST |
/getFullCourseDetails |
β | β | Get full details with videos |
GET |
/getInstructorCourses |
β | Instructor | Get instructor's own courses |
POST |
/addSection |
β | Instructor | Add section to course |
POST |
/updateSection |
β | Instructor | Update a section |
POST |
/deleteSection |
β | Instructor | Delete a section |
POST |
/addSubSection |
β | Instructor | Add video sub-section |
POST |
/updateSubSection |
β | Instructor | Update sub-section |
POST |
/deleteSubSection |
β | Instructor | Delete sub-section |
POST |
/updateCourseProgress |
β | Student | Mark a lecture complete |
POST |
/createCategory |
β | Admin | Create category |
GET |
/showAllCategories |
β | β | List all categories |
POST |
/getCategoryPageDetails |
β | β | Category with courses |
POST |
/createRating |
β | Student | Submit rating & review |
GET |
/getAverageRating |
β | β | Get average course rating |
GET |
/getReviews |
β | β | Get all reviews |
| Method | Endpoint | Auth | Role | Description |
|---|---|---|---|---|
POST |
/capturePayment |
β | Student | Create Razorpay order |
POST |
/verifyPayment |
β | Student | Verify & process payment |
POST |
/sendPaymentSuccessEmail |
β | Student | Send payment confirmation email |
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/contactUs |
β | Submit contact form |
StudyNotion is deployed as two separate services on Vercel.
- Push
Client/to a GitHub repository - Import the repo into Vercel
- Set Root Directory to
Client - Add environment variable:
REACT_APP_BASE_URL=<your-backend-url>/api/v1 - Deploy β Vercel auto-detects Create React App
- Push
Server/to GitHub - Deploy on Vercel (with
vercel.json) or Render/Railway - Add all environment variables from
Server/.env - Set start command:
node index.js
| Service | URL | Status |
|---|---|---|
| Frontend | study-notion-blue-mu.vercel.app | β Live |
| Frontend (Alt) | study-notion-git-main-arjuns-projects-c804732d.vercel.app | β Live |
| Backend API | https://your-backend.vercel.app/api/v1 |
βοΈ Self-hosted |
Note: MongoDB Atlas allows connections only from whitelisted IPs. For production, whitelist
0.0.0.0/0or your server's static IP.
| Name | Arjun |
| Project | StudyNotion β Full Stack EdTech Platform |
| Stack | MERN (MongoDB, Express, React, Node.js) |
| Deployment | Vercel (Frontend + Backend) |
Made with β€οΈ and lots of β by Arjun
β Star this repo if you found it helpful!