You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A production-style RESTful backend for a YouTube/Twitter-hybrid video platform, built with Node.js, Express, and MongoDB (Mongoose). It implements complete user authentication, video publishing, social engagement (likes, comments, subscriptions), micro-blogging (tweets), playlists, and a creator analytics dashboard — all backed by MongoDB aggregation pipelines and Cloudinary media storage.
This project is the backend service layer for a full-featured video-sharing platform (in the spirit of YouTube), extended with lightweight social features similar to Twitter (tweets, likes on tweets). It exposes a versioned REST API (/api/v1/...) consumed by a frontend client, and is designed around clean separation of concerns: routes → controllers → models, with reusable middleware and utility layers for cross-cutting concerns like authentication, file uploads, and standardized responses.
Key Features
User Management — registration with avatar/cover image upload, login, logout, JWT-based session handling with access & refresh tokens, password change, profile updates.
Channel Profiles — MongoDB aggregation pipelines compute a user's subscriber count, subscriptions count, and whether the current viewer is subscribed — in a single database query.
Video Management — upload (video + thumbnail) to Cloudinary, paginated & searchable video listing, view-count tracking, ownership-gated update/delete, publish/unpublish toggle.
Engagement System — polymorphic Likes (videos, comments, and tweets share one Like model), threaded Comments on videos, and channel Subscriptions.
Micro-blogging — Twitter-style Tweets with full CRUD, scoped to the authenticated owner.
Every controller is wrapped in a shared asyncHandler utility, so asynchronous errors are automatically forwarded to Express's error pipeline instead of requiring per-route try/catch blocks. All successful responses and errors are normalized through ApiResponse and ApiError classes, giving the API a predictable, self-documenting contract:
Aggregated total views, videos, subscribers, likes
GET
/:channelId/videos
All videos uploaded by a channel
Note: the dashboard router is implemented but not yet mounted in app.js — see Roadmap.
Authentication & Security
JWT dual-token strategy — short-lived access tokens authorize requests; long-lived refresh tokens (stored on the User document and set as an httpOnly cookie) allow silent renewal via /refresh-token without forcing re-login.
Password hashing — handled in a Mongoose pre("save") hook using bcrypt, so plaintext passwords never touch the database.
Cookie-based + header-based auth — verifyJWT middleware accepts a token from either an httpOnly cookie or an Authorization: Bearer header, supporting both browser and non-browser clients.
Ownership checks — mutation endpoints (video update/delete, publish toggle) verify req.user._id against the resource's owner before allowing the action.
Request size limiting — JSON and URL-encoded body size is capped (constants.js) to reduce payload-based abuse.
Getting Started
Prerequisites
Node.js ≥ 18
A MongoDB instance (local or Atlas)
A Cloudinary account (for media storage)
Installation
git clone https://github.com/Tennobis/Project-Backend.git
cd Project-Backend
npm install
The server starts on http://localhost:<PORT> (default 8000) and connects to MongoDB using MONGODB_URI from your .env file.
Environment Variables
Variable
Description
PORT
Port the Express server listens on
MONGODB_URI
MongoDB connection string (DB name is appended automatically)
CORS_ORIGIN
Allowed origin for cross-origin requests
ACCESS_TOKEN_SECRET
Secret used to sign JWT access tokens
ACCESS_TOKEN_EXPIRY
Access token lifetime (e.g. 1d)
REFRESH_TOKEN_SECRET
Secret used to sign JWT refresh tokens
REFRESH_TOKEN_EXPIRY
Refresh token lifetime (e.g. 10d)
CLOUDINARY_CLOUD_NAME
Cloudinary cloud name
CLOUDINARY_API_KEY
Cloudinary API key
CLOUDINARY_API_SECRET
Cloudinary API secret
Design Highlights
A few implementation details worth calling out in an interview walkthrough:
Polymorphic Like model — rather than three separate like collections, a single Like schema with optional video / comment / tweet references keeps the like/toggle logic (and future extension to new likeable types) in one place.
Aggregation-driven read models — channel profiles and dashboard statistics are computed with MongoDB $lookup + $addFields pipelines rather than N+1 application-level queries, keeping expensive joins on the database side.
Reusable async error handling — asyncHandler is a higher-order function that wraps every controller, so a single throw new ApiError(...) anywhere in the call stack is enough to produce a correctly-shaped error response.
Two-stage file upload — Multer first writes uploads to a local temp directory; a Cloudinary utility then streams the file to the CDN and deletes the local copy, keeping the server stateless with respect to media storage.
Known Limitations / Roadmap
This project was built as a hands-on learning exercise in backend architecture, and there are a few areas intentionally left open for future iteration:
Mount the dashboard router in app.js (currently defined but not wired up).
Add automated tests (unit tests for controllers/models, integration tests for routes).
Add rate limiting and helmet-based HTTP header hardening for production readiness.
Delete the user's previous avatar/cover image from Cloudinary when replaced (currently only new uploads are handled).
Author
Tanveer Hossain — Full Stack Developer
Built as a backend engineering project to practice REST API design, JWT authentication, MongoDB aggregation pipelines, and cloud media handling with Node.js and Express.