Melodify is a responsive, feature-rich music streaming web application inspired by Spotify. It is built using the MERN stack (MongoDB, Express, React, Node.js) with modular MVC architecture, custom dark UI styling, JWT authentication, and interactive audio control.
- Vibrant Dark UI: Modern glassmorphic dark theme built with Tailwind CSS.
- Sidebar & Navbar Navigation: Fluid layout with responsive views for desktop and mobile devices.
- Interactive Music Player: Persistent bottom audio dashboard featuring:
- Play, pause, skip next, skip previous.
- Interactive progress bar (click-to-seek).
- Sound volume slider.
- Shuffle and Repeat cycle options.
- Like song shortcut and animated spinning disk artwork.
- Song Grid Browser: Interactive hover play cards, waveform playback animations, and genre tags.
- Search System: Live debounced search querying matching tracks by title or artist.
- Authentication: Fully functional Sign Up, Log In, and profile settings editing.
- My Library: Dynamic creation and deletion of custom playlists.
- Creator Studio: Admin dashboard for publishing audio tracks and custom cover art.
- REST APIs: Clean endpoints separated into Controller, Route, and Model layers.
- Secure Auth: Password hashing via
bcryptjsand token generation viajsonwebtoken(JWT). - Multipart Uploads: Audio files (MP3) and images (JPEG/PNG) stored locally utilizing
multerfile filters. - Recently Played Tracking: Chronological user history stored separately with index compound fields for performance.
- Mongoose Schemas: Relational model references mapping MongoDB ObjectIDs across Users, Playlists, and Songs.
- Frontend: React (Vite), Axios, Tailwind CSS, Lucide React, React Hot Toast, React Router DOM
- Backend: Node.js, Express.js, MongoDB, Mongoose, JWT, BcryptJS, Multer, Morgan, Cors
spotify-clone/
├── client/ # React Frontend (Vite)
│ ├── src/
│ │ ├── api/ # Axios API instance
│ │ ├── components/ # Reusable layouts (Player, Sidebar, Navbar, Toast)
│ │ ├── context/ # AuthContext and PlayerContext state providers
│ │ ├── pages/ # Routed pages (Home, Search, Library, Profile, Admin)
│ │ ├── index.css # Global custom dark-mode Tailwind configuration
│ │ ├── main.jsx # React root mount
│ │ └── App.jsx # Router layout configuration
│ ├── index.html
│ └── tailwind.config.js
│
└── server/ # Express Backend
├── config/ # MongoDB Mongoose connector
├── controllers/ # Route business logic (auth, songs, playlists, admin)
├── middleware/ # JWT auth validation & Multer upload rules
├── models/ # Mongoose schemas (User, Song, Playlist, History)
├── routes/ # Express API endpoints
├── uploads/ # Files local storage (songs/ and thumbnails/)
├── utils/ # Seeding utility (seedData.js)
└── index.js # App entry point
- Open terminal and navigate to the
serverdirectory:cd server - Install dependencies:
npm install
- Initialize the environment variables file:
- Create a
.envfile from the provided.env.example:PORT=5000 MONGO_URI=mongodb://localhost:27017/spotify-clone JWT_SECRET=your_super_secret_jwt_key_change_this_in_production JWT_EXPIRE=7d FRONTEND_URL=http://localhost:5173
- Create a
- Run the seed script to pre-populate default tracks:
npm run seed
- Start the backend dev server:
(The server will start on http://localhost:5000)
npm run dev
- Open a new terminal tab and navigate to the
clientdirectory:cd client - Install dependencies:
npm install
- Launch the Vite dev application:
(The app will start on http://localhost:5173)
npm run dev
- User Login: The client submits user credentials to
/api/auth/login. - Token Sign: The server validates the credentials, hashes the password via
bcrypt.compare, signs a payload containing the User ID using the secretJWT_SECRET, and returns a signed string. - Local Storage: The client receives the JWT token and saves it in
localStorage. - Header Interceptor: Every API call sent using our axios client automatically includes the token in the
Authorizationheader:Authorization: Bearer <your-jwt-token> - Route protection: The backend
protectmiddleware extracts the header, checks the signature, validates expiration, and setsreq.userto the logged-in user before letting the controller proceed.
- User: Stores basic info, a hashed password, and reference arrays:
likedSongs: Reference mapping[{ type: Schema.Types.ObjectId, ref: 'Song' }](Many-to-Many).
- Song: Holds tracks parameters including
fileUrlandthumbnailpaths. - Playlist: Tracks own-ownership:
owner: References a single User(ref: 'User')(One-to-Many).songs: Array of references mapping[{ type: Schema.Types.ObjectId, ref: 'Song' }](Many-to-Many).
- History: Stores track history individually:
user(ref User) andsong(ref Song) linked with a compound database index onuser+playedAtfor rapid retrieval.
Here are sample endpoints you can import and test in Postman:
| Method | Endpoint | Description | Auth Required? |
|---|---|---|---|
| POST | /api/auth/register |
Sign up a new user | No |
| POST | /api/auth/login |
Login user and get JWT | No |
| GET | /api/auth/me |
Fetch logged-in user profile | Yes |
| GET | /api/songs |
Retrieve all public songs | No |
| GET | /api/songs/search?q=query |
Debounced query matching title/artist | No |
| POST | /api/songs/:id/like |
Like or unlike a song | Yes |
| POST | /api/playlists |
Create a new custom playlist | Yes |
| POST | /api/playlists/:id/songs |
Add a song to playlist | Yes |
| POST | /api/admin/songs |
Upload file/image (admin only) | Yes (Admin) |