A modern, production-grade, full-stack social media platform inspired by Instagram. PixelFeed enables users to seamlessly register accounts, manage profiles, upload images to a cloud CDN, interact with posts via likes, and follow or unfollow other users to customize their social experience.
PixelFeed is engineered using a robust modern stack split across a decoupled client-server architecture:
- React 19 & React Router 7: Component-driven SPA architecture with client-side routing.
- SCSS: Clean styling with modular layouts, custom responsive breakpoints, CSS variables, and consistent visual branding.
- Axios: Configured client with
withCredentials: trueto support automatic HTTP-only cookie transmission.
- Node.js & Express.js: Fast, stateless REST API architecture with modular routers.
- MongoDB & Mongoose: Flexible, schema-backed Document Database for managing application state.
- JWT & BcryptJS: Industry-standard secure token authentication and salted password hashing (10 salt rounds).
- Multer & ImageKit: Streamlined media ingestion pipeline to upload image assets directly to the cloud.
- Authentication & Security: Complete registration, login, and token validation flow. Passwords are securely hashed before storing, and sessions are persisted via secure browser cookies.
- Stateless Media Uploads: Fast, on-the-fly uploads of post images using memory buffering. No temporary files are stored on the server disk.
- Social Relationships: Follow and unfollow users to adjust follower/following counts in real-time, managed cleanly through independent link models.
- Live Interactions: Single-tap like and unlike options with database-level uniqueness enforcement.
- Comprehensive Profiles: Dedicated user spaces listing user bios, gender metrics, total post counts, follower list sizes, and a visual grid of their uploaded posts.
PixelFeed follows a clean directory separation, organizing the client (Frontend) and API (Backend) separately to make deployment and updates independent.
PixelFeed/
├── Backend/
│ ├── src/
│ │ ├── app.js # Express application initialization & middleware
│ │ ├── config/
│ │ │ └── database.js # Mongoose MongoDB connection helper
│ │ ├── controllers/
│ │ │ ├── auth.controller.js # Registration, login, and current user retrieval
│ │ │ ├── post.controller.js # Post creation, feeds, and likes handlers
│ │ │ └── user.controller.js # Profiles and follower relationship handlers
│ │ ├── middlewares/
│ │ │ └── auth.middleware.js # JWT verification and request injection middleware
│ │ ├── models/
│ │ │ ├── follow.model.js # Schema for follower/followee relationships
│ │ │ ├── like.model.js # Schema mapping users to liked posts
│ │ │ ├── post.model.js # Schema for image URLs and captions
│ │ │ └── user.model.js # Schema for user credentials, details, and default avatars
│ │ └── routes/
│ │ ├── auth.routes.js # Route mappings for registration/login
│ │ ├── post.routes.js # Route mappings for post creation, likes, and feed
│ │ └── user.routes.js # Route mappings for user profile and follows
│ ├── server.js # Main server listener (runs on Port 3000)
│ └── package.json
│
├── Frontend/
│ ├── src/
│ │ ├── main.jsx # React DOM root render
│ │ ├── App.jsx # Main App entry point
│ │ ├── routes.jsx # React Router paths configuration
│ │ └── features/
│ │ ├── auth/ # Auth pages (Login, Register), context API, and CSS
│ │ ├── landing/ # Splash landing page with responsive entry buttons
│ │ ├── posts/ # Feed viewer and new post upload components
│ │ ├── shared/ # Navigation Bar, loading spinners, and global styling
│ │ └── users/ # Profile page displaying metrics and personal posts
│ ├── index.html
│ ├── vite.config.js # Vite development and production configuration
│ └── package.json
All routes except /api/auth/register and /api/auth/login require a valid JWT token passed automatically in the request cookies.
| Method | Endpoint | Auth Required | Payload Format | Description |
|---|---|---|---|---|
POST |
/register |
No | JSON |
Registers a new user, hashes password, sets a JWT cookie, and returns user details. |
POST |
/login |
No | JSON |
Verifies user credentials, sets a JWT cookie, and returns user details. |
GET |
/getMe |
Yes | None | Decodes the JWT token cookie and returns the currently logged-in user's profile. |
| Method | Endpoint | Auth Required | Payload Format | Description |
|---|---|---|---|---|
POST |
/ |
Yes | multipart/form-data |
Uploads post image to ImageKit using memory buffer, and saves post data. |
GET |
/ |
Yes | None | Retrieves all posts authored by the authenticated user. |
GET |
/feed |
Yes | None | Retrieves the global chronological post feed populated with like statuses. |
GET |
/:postId |
Yes | None | Retrieves details for a specific post. |
POST |
/like/:postId |
Yes | None | Registers a like status on the designated post for the logged-in user. |
POST |
/unlike/:postId |
Yes | None | Removes a like status on the designated post. |
| Method | Endpoint | Auth Required | Payload Format | Description |
|---|---|---|---|---|
GET |
/profile/:username |
Yes | None | Fetches profile stats (followers, following, posts) and post list for a username. |
POST |
/follow/:followee |
Yes | None | Creates a follower relationship entry mapping the current user to the followee. |
POST |
/unfollow/:followee |
Yes | None | Deletes the follower relationship entry. |
PixelFeed uses structured Mongoose schemas to establish data models in MongoDB.
{
username: { type: String, required: true, unique: true },
name: { type: String, required: true },
gender: { type: String, enum: ["male", "female", "other"], default: "other" },
email: { type: String, required: true, unique: true },
password: { type: String, required: true, select: false }, // Omitted from query results by default
bio: { type: String, default: "" },
profilePicture: { type: String, default: "default-avatar-url" }
}{
caption: { type: String, default: "" },
imgURL: { type: String, required: true },
user: { type: mongoose.Schema.Types.ObjectId, ref: "users", required: true }
}{
post: { type: mongoose.Schema.Types.ObjectId, ref: "posts", required: true },
username: { type: String, required: true }
}
// Compound Index: Enforces uniqueness for (post, username) to avoid multiple likes{
follower: { type: String, required: true },
followee: { type: String, required: true },
status: { type: String, enum: ["pending", "accepted", "rejected"], default: "pending" }
}
// Compound Index: Enforces uniqueness for (follower, followee) to avoid multiple follow records- The Challenge: Traditional SPA storage (like storing JWT in
localStorageorsessionStorage) is vulnerable to Cross-Site Scripting (XSS) scripts accessing tokens and hijacking user sessions. - The Solution: We implemented cookie-based JWT delivery in the login/registration controller. The server issues a token payload inside an
httpOnlycookie. This makes it impossible for client-side JavaScript to read the token. The browser automatically appends the token to all Axios backend requests, ensuring stateless verification through backend middleware while shielding the credential.
- The Challenge: Storing uploaded user images on the backend server's local file system leads to architectural bloat, renders horizontal server scaling impossible, and risks data loss on server restart.
- The Solution: Multer is configured to use memory storage (
multer.memoryStorage()) rather than disk storage. The incoming image buffer is instantly streamed using@imagekit/nodejsto ImageKit's globally distributed CDN. The server simply stores the resulting ImageKit URL in MongoDB, keeping the API layer completely stateless and fast.
- The Challenge: In high-latency networks, a user might double-tap a follow or like button before the UI disables it. This can bypass standard app-level uniqueness checks, generating duplicate rows, skewing metrics, and corrupting counts.
- The Solution: We created database-level constraints using compound indexes inside MongoDB:
likeSchema.index({ post: 1, username: 1 }, { unique: true })followSchema.index({ follower: 1, followee: 1 }, { unique: true })If a duplicate request passes the controller checks, MongoDB instantly rejects the query with a duplicate key error code (11000), protecting schema statistics.
Follow these steps to set up and run PixelFeed locally:
- Node.js (v18 or higher recommended)
- npm (v9 or higher)
- MongoDB Atlas cluster (or local MongoDB instance)
- ImageKit account (for uploading images)
git clone https://github.com/tejaswasnik/PixelFeed.git
cd PixelFeed- Navigate to the
Backendfolder:cd Backend - Install dependencies:
npm install
- Create a
.envfile in theBackenddirectory:MONGO_URI=mongodb+srv://username:password@cluster.mongodb.net/pixelfeed JWT_SECRET=your_super_secret_jwt_key FRONTEND_URL=http://localhost:5173 IMAGEKIT_PUBLIC_KEY=public_xxxxxxxxxxxxxxxxx IMAGEKIT_PRIVATE_KEY=private_xxxxxxxxxxxxxxxxx IMAGEKIT_URL_ENDPOINT=https://ik.imagekit.io/your_imagekit_id
- Start the backend server in development mode:
npm run dev
- Open a new terminal and navigate to the
Frontendfolder:cd Frontend - Install dependencies:
npm install
- Create a
.envfile in theFrontenddirectory:VITE_AUTH_BASE_URL=http://localhost:3000/api/auth VITE_POST_BASE_URL=http://localhost:3000/api/posts VITE_USER_BASE_URL=http://localhost:3000/api/users
- Start the frontend development server:
npm run dev
- Open your browser and navigate to
http://localhost:5173to explore PixelFeed!