A full-stack, production-grade video streaming and creator platform built with the MERN stack (MongoDB, Express, React 19, Node.js) with Cloudinary media storage, JWT-based secure authentication, and MongoDB aggregation pipelines.
- Overview
- Tech Stack
- Key Features
- Project Architecture
- Folder Structure
- Getting Started
- Environment Variables
- API Reference
- Design Decisions & Architecture
- License
VividStream is a modern video sharing platform inspired by YouTube, designed with a backend-first architecture. It supports media uploads (video & images) via Cloudinary, real-time community engagement (likes, comments, tweets, subscriptions), playlist management, watch history tracking, and an analytics dashboard for creators.
- Framework & Build: React 19, Vite
- Routing: React Router v7
- State Management: Zustand (auth persistence & session state)
- Forms: React Hook Form
- Styling: SCSS / Sass Embedded (modular, component-based styling)
- HTTP Client: Axios (with interceptors & cookie credentials)
- UI & Notifications: React Icons, React Toastify
- Runtime & Framework: Node.js (ES Modules), Express 5
- Database & ODM: MongoDB, Mongoose 8
- Pagination & Queries:
mongoose-aggregate-paginate-v2& custom MongoDB aggregation pipelines - Authentication: JSON Web Tokens (JWT Access & Refresh tokens),
bcryptjs,cookie-parser - File Handling & Storage: Multer (local temporary buffer) & Cloudinary (cloud media storage)
- CORS:
corsconfigured with credentials for cookie exchange
- Secure user registration with avatar and cover image uploads.
- Access & Refresh token rotation with
HttpOnlysecure cookies andAuthorizationheader fallback. - Profile management (update account details, update avatar/cover image, change password).
- Channel profile page displaying subscriber counts, subscribed channels, and channel videos.
- Video upload with custom thumbnails, title, and description.
- Video playback player with real-time view count tracking.
- Video updating (title, description, thumbnail) and deletion.
- Toggle publish / unpublish status.
- Video list with pagination, search queries, and sorting (by views, creation date).
- Likes: Like and unlike videos, comments, and community tweets.
- Comments: Full CRUD on video comments (add, edit, delete, list with author details).
- Subscriptions: One-click channel subscribe/unsubscribe toggle and subscriber counts.
- Community Tweets: Creator microblogging / tweet feed with like counters and timeline.
- Create custom playlists with title and description.
- Add and remove videos from playlists.
- Fetch user playlists and dedicated playlist detail views.
- Automated watch history tracking (most recent first).
- Dedicated Liked Videos feed for authenticated users.
- Channel stats analytics (total video views, subscriber count, total likes).
- Video management table with status toggles and direct actions.
graph TD
Client["React 19 Frontend (Vite)"] <-->|"REST API / Cookies (Credentials)"| Express["Express Backend (/api/v1)"]
Express <-->|"Mongoose & Aggregations"| Mongo[("MongoDB Database")]
Express <-->|"Multer Temp File"| LocalFS["Local Disk (public/temp)"]
LocalFS -->|"Media Upload"| Cloudinary[("Cloudinary Media CDN")]
vivid-stream/
βββ backend/
β βββ public/temp/ # Multer temporary buffer directory
β βββ src/
β β βββ controllers/ # Request handlers (user, video, comment, etc.)
β β βββ db/ # MongoDB connection setup
β β βββ middlewares/ # Auth (verifyJWT) & upload (multer) middlewares
β β βββ models/ # Mongoose schema definitions
β β βββ routes/ # Express route definitions
β β βββ utils/ # ApiError, ApiResponse, asyncHandler, cloudinary
β β βββ app.js # Express app configuration & middleware pipeline
β β βββ constants.js # DB name & application constants
β β βββ index.js # Backend server entry point
β βββ package.json
β βββ .env.sample
β
βββ frontend/
β βββ public/ # Static frontend assets
β βββ src/
β β βββ api/ # Axios API client functions
β β βββ components/ # Reusable UI components & layouts
β β β βββ layout/ # AppLayout, Navbar, Sidebar
β β β βββ video/ # VideoCard, VideoPlayer, etc.
β β βββ hooks/ # Custom React hooks
β β βββ pages/ # Application views (Home, Watch, Channel, etc.)
β β βββ routes/ # ProtectedRoute and navigation guards
β β βββ stores/ # Zustand state stores (auth.store.js)
β β βββ styles/ # Modular SCSS stylesheets
β β βββ utils/ # Frontend utility functions
β β βββ App.jsx # Route declarations & auth initialization
β β βββ main.jsx # React DOM mount point
β βββ package.json
β βββ vite.config.js
β
βββ PROJECT_CONTEXT.md
βββ Readme.md
- Node.js (v18 or higher recommended)
- MongoDB (Local instance or MongoDB Atlas URI)
- Cloudinary Account (Cloud Name, API Key, API Secret)
-
Navigate to the backend directory:
cd backend -
Install dependencies:
npm install
-
Configure Environment Variables: Create a
.envfile inbackend/:PORT=8000 CORS_ORIGIN=http://localhost:5173 MONGODB_URI=mongodb+srv://<username>:<password>@cluster0.mongodb.net ACCESS_TOKEN_SECRET=your_access_token_secret_key ACCESS_TOKEN_EXPIRES_IN=1d REFRESH_TOKEN_SECRET=your_refresh_token_secret_key REFRESH_TOKEN_EXPIRES_IN=10d CLOUDINARY_CLOUD_NAME=your_cloud_name CLOUDINARY_API_KEY=your_api_key CLOUDINARY_API_SECRET=your_api_secret
-
Start the backend development server:
npm run dev
Server will run on
http://localhost:8000.
-
Navigate to the frontend directory:
cd frontend -
Install dependencies:
npm install
-
Configure Environment Variables (Optional): Create a
.envfile infrontend/if needed:VITE_API_BASE_URL=http://localhost:8000/api/v1
-
Start the frontend development server:
npm run dev
Vite will serve the app on
http://localhost:5173.
| Variable | Description | Example |
|---|---|---|
PORT |
Port number for Express server | 8000 |
CORS_ORIGIN |
Allowed client origin for CORS | http://localhost:5173 |
MONGODB_URI |
MongoDB connection URI | mongodb+srv://... |
ACCESS_TOKEN_SECRET |
Secret key for signing JWT access tokens | your_access_token_secret |
ACCESS_TOKEN_EXPIRES_IN |
Expiry duration for access token | 1d |
REFRESH_TOKEN_SECRET |
Secret key for signing JWT refresh tokens | your_refresh_token_secret |
REFRESH_TOKEN_EXPIRES_IN |
Expiry duration for refresh token | 10d |
CLOUDINARY_CLOUD_NAME |
Cloudinary account cloud name | your_cloud_name |
CLOUDINARY_API_KEY |
Cloudinary API Key | 1234567890 |
CLOUDINARY_API_SECRET |
Cloudinary API Secret | your_api_secret |
Base URL: /api/v1
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/register |
Register new user (avatar & cover upload) | β |
POST |
/login |
Authenticate user & set JWT cookies | β |
POST |
/logout |
Invalidate refresh token & clear cookies | β |
POST |
/refresh-token |
Regenerate access & refresh tokens | β |
POST |
/change-password |
Update current user's password | β |
GET |
/current-user |
Fetch currently authenticated user | β |
PATCH |
/update-account |
Update full name and email | β |
PATCH |
/avatar |
Update user avatar image | β |
PATCH |
/cover-image |
Update user channel cover image | β |
GET |
/c/:username |
Fetch channel profile details & subscription status | β |
GET |
/history |
Fetch authenticated user's watch history | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/ |
Get published videos (search, paginate, sort) | β |
POST |
/ |
Upload video & thumbnail to Cloudinary | β |
GET |
/:videoId |
Get video details, owner, like & subscriber stats | β |
PATCH |
/:videoId |
Update video title, description, or thumbnail | β |
DELETE |
/:videoId |
Delete video from database | β |
PATCH |
/toggle/publish/:videoId |
Toggle publish / unpublish status | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/:videoId |
Get comments for a video (paginated) | β |
POST |
/:videoId |
Add a comment to a video | β |
PATCH |
/c/:commentId |
Update comment content | β |
DELETE |
/c/:commentId |
Delete a comment | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/toggle/v/:videoId |
Toggle like status on a video | β |
POST |
/toggle/c/:commentId |
Toggle like status on a comment | β |
POST |
/toggle/t/:tweetId |
Toggle like status on a tweet | β |
GET |
/videos |
Get list of videos liked by the current user | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/c/:channelId |
Toggle subscribe / unsubscribe to a channel | β |
GET |
/c/:channelId |
Get list of subscribers for a channel | β |
GET |
/u/:subscriberId |
Get channels subscribed to by a user | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/ |
Create a new playlist | β |
GET |
/:playlistId |
Get playlist details and video list | β |
PATCH |
/:playlistId |
Update playlist name and description | β |
DELETE |
/:playlistId |
Delete a playlist | β |
PATCH |
/add/:videoId/:playlistId |
Add a video to a playlist | β |
PATCH |
/remove/:videoId/:playlistId |
Remove a video from a playlist | β |
GET |
/user/:userId |
Get all playlists created by a user | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/ |
Post a community tweet | β |
GET |
/ |
Fetch all community tweets (feed) | β |
GET |
/user/:userId |
Fetch tweets authored by a specific user | β |
PATCH |
/:tweetId |
Update tweet content | β |
DELETE |
/:tweetId |
Delete a tweet | β |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/api/v1/dashboard/stats |
Channel stats (views, subscribers, likes) | β |
GET |
/api/v1/dashboard/videos |
Get all videos uploaded by the channel | β |
GET |
/api/v1/healthcheck |
Service health status | β |
- Backend as Source of Truth: Counts (subscribers, likes, views) and relational statuses are calculated dynamically via optimized MongoDB aggregation pipelines rather than being hardcoded or guessed on the frontend.
- Robust Error Handling: Standardized
ApiErrorclass andApiResponseenvelope ensure consistent status codes, error messaging, and data payloads across all endpoints. - Safe Media Lifecycle: Multipart uploads are buffered locally to
public/tempby Multer before being streamed to Cloudinary, with automatic filesystem cleanup on success or error. - Zustand State Persistence: Lightweight client-side session management that automatically revalidates authentication on startup through
/api/v1/users/current-user.
This project is licensed under the ISC License.