A full-stack web application where users can browse, list, save, and chat about real estate properties. Built with React, Node.js, MongoDB, Socket.io, and Leaflet maps.
- Features
- Tech Stack
- Project Structure
- How It Works
- Setup Instructions
- Environment Variables
- API Overview
- Screenshots
- Future Improvements
- User Authentication β Register, log in, and log out securely using JWT (stored in HTTP-only cookies)
- Create Property Listings β Add properties with title, price, address, city, bedrooms, bathrooms, coordinates, and images
- Image Upload β Upload multiple property images via Cloudinary
- Search & Filter β Search properties by city, type (buy/rent), property kind, price range, and number of bedrooms
- Interactive Map β View all matching properties on a Leaflet map with clickable pins and popups
- Save Properties β Logged-in users can save and unsave favourite listings
- Real-Time Chat β Message other users in real time using Socket.io
- User Profile β View and update your profile, see your own listings and saved posts
| Layer | Technology |
|---|---|
| Frontend | React 18, React Router v6, Vite |
| Backend | Node.js, Express.js |
| Database | MongoDB (via Prisma ORM) |
| Authentication | JWT (JSON Web Tokens) + HTTP-only cookies |
| Real-Time Chat | Socket.io |
| Maps | Leaflet, React-Leaflet |
| Image Upload | Cloudinary |
| Styling | Plain CSS (modular per component) |
Real-Estate-Platform/
β
βββ frontend/ # React client (Vite)
β βββ public/ # Static assets (logo, placeholder images)
β βββ src/
β β βββ components/ # Reusable UI components
β β β βββ card/ # Property card shown in listings
β β β βββ chat/ # Real-time chat UI
β β β βββ filter/ # Search filter bar
β β β βββ layout/ # Page layout wrapper (Navbar + Outlet)
β β β βββ map/ # Leaflet map wrapper
β β β βββ navbar/ # Top navigation bar
β β β βββ pin/ # Map pin / popup
β β β βββ requireAuth/ # Route guard (redirect if not logged in)
β β β βββ searchBar/ # Home page search bar
β β β βββ slider/ # Image slider / lightbox
β β βββ context/
β β β βββ AuthContext.jsx # Global auth state (currentUser)
β β β βββ SocketContext.jsx # Socket.io connection & online users
β β βββ lib/
β β β βββ apiRequest.js # Axios instance with base URL & credentials
β β β βββ loaders.js # React Router data loaders
β β βββ pages/
β β β βββ homePage/ # Landing page with search
β β β βββ listPage/ # Property list + map
β β β βββ singlePage/ # Single property detail
β β β βββ profilePage/ # User profile, listings, saved posts, chat
β β β βββ profileUpdatePage/ # Edit profile form
β β β βββ newPostPage/ # Create new property listing
β β β βββ updatePostPage/ # Edit existing listing
β β β βββ login/ # Login form
β β β βββ register/ # Registration form
β β βββ App.jsx # Route definitions
β β βββ main.jsx # React entry point
β β βββ index.css # Global CSS variables and resets
β βββ .env.example # Frontend env template
β βββ index.html
β βββ package.json
β βββ vite.config.js
β
βββ backend/ # Express API server
β βββ controllers/ # Business logic
β β βββ auth.controller.js # Register, login, logout
β β βββ post.controller.js # CRUD for property listings
β β βββ user.controller.js # User profile, saved posts, notifications
β β βββ chat.controller.js # Chat rooms
β β βββ message.controller.js # Messages within chats
β βββ middleware/
β β βββ verifyToken.js # JWT verification middleware
β βββ routes/ # Express routers
β β βββ auth.route.js
β β βββ post.route.js
β β βββ user.route.js
β β βββ chat.route.js
β β βββ message.route.js
β βββ prisma/
β β βββ schema.prisma # Database schema (MongoDB via Prisma)
β βββ lib/
β β βββ prisma.js # Prisma client singleton
β βββ socket/
β β βββ index.js # Socket.io server setup
β βββ utils/
β β βββ cloudinary.js # Cloudinary configuration & upload helper
β βββ .env.example # Backend env template
β βββ app.js # Express app entry point
β βββ package.json
β
βββ .github/
β βββ workflows/
β βββ ci.yml # GitHub Actions CI (install + build)
β
βββ .gitignore
βββ README.md
- A new user fills in the Register form (username, email, password).
- The backend hashes the password with
bcryptand stores the user in MongoDB. - On Login, the backend verifies the password, creates a JWT, and sends it in an HTTP-only cookie.
- The frontend stores the user object in
localStorageviaAuthContext. - Protected routes are guarded by the
RequireAuthcomponent β if no user is logged in, they are redirected to/login. - The JWT cookie is verified on every protected API call by the
verifyTokenmiddleware.
- A logged-in user opens the Add Property page.
- They fill in details (title, price, address, bedrooms, etc.) and upload images.
- Images are uploaded directly to Cloudinary from the browser; the returned secure URLs are stored.
- The form data is sent as a
POST /api/postsrequest. - The backend creates a
Postand a linkedPostDetailin MongoDB via Prisma.
- The frontend sends each image file directly to Cloudinary's upload API using an unsigned upload preset.
- Cloudinary returns a
secure_urlwhich is stored in the post'simagesarray. - No image files are stored on the server.
- The user types a city or selects filters (type, property kind, price range, bedrooms) on the List page.
- Filter values are stored as URL query parameters.
- React Router's data loader fetches
GET /api/posts?city=...&type=...with those params. - The backend queries MongoDB using Prisma's
whereclauses and returns matching posts.
- Every property stores
latitudeandlongitudefields. - The
Mapcomponent renders a LeafletMapContainerand places aMarker(pin) for each property. - Clicking a pin shows a popup with the property image, title, and price linking to the detail page.
- When a logged-in user opens their Profile, existing chats are loaded from the API.
- Clicking a chat opens the
Chatcomponent and loads the message history. - On mount, the client emits
newUserto the Socket.io server with their user ID. - Sending a message calls
POST /api/messages/:chatIdand then emitssendMessageover the socket. - The receiver's client listens for
getMessageevents and appends the new message instantly.
- Node.js v22 LTS (use nvm:
nvm install && nvm useβ the.nvmrcpins v22) - A MongoDB Atlas cluster (free tier works)
- A Cloudinary account (free tier works)
Note on Node version: This project targets Node.js v22 LTS. The backend uses
bcryptjs(pure-JS) instead ofbcryptso there are no native binary dependencies and nourl.parse()deprecation warnings on Node 24+.
git clone https://github.com/akhil16-svg/Real-Estate-Platform.git
cd Real-Estate-Platformcd backend
npm installCopy the example environment file and fill in your values:
cp .env.example .envGenerate the Prisma client:
npx prisma generateStart the backend server:
npm run dev # development (nodemon, auto-restart)
# -- or --
npm start # production
# Server + Socket.io both run on http://localhost:8800Open a new terminal:
cd frontend
npm installCopy the example environment file:
cp .env.example .envStart the frontend dev server:
npm run dev
# App runs on http://localhost:5173| Variable | Description |
|---|---|
DATABASE_URL |
MongoDB connection string from Atlas |
JWT_SECRET_KEY |
A long, random secret string for signing JWTs and CSRF tokens |
CLOUDINARY_CLOUD_NAME |
Your Cloudinary cloud name |
CLOUDINARY_API_KEY |
Your Cloudinary API key |
CLOUDINARY_API_SECRET |
Your Cloudinary API secret |
CLIENT_URL |
Frontend URL for CORS (e.g. http://localhost:5173) |
PORT |
Port for the backend server (default: 8800) |
| Variable | Description |
|---|---|
VITE_API_URL |
Backend API base URL (e.g. http://localhost:8800/api) |
VITE_SOCKET_URL |
Backend Socket.io URL (e.g. http://localhost:8800) |
VITE_CLOUDINARY_NAME |
Your Cloudinary cloud name |
VITE_CLOUDINARY_PRESET |
Your Cloudinary unsigned upload preset name |
All routes are prefixed with /api.
| Method | Endpoint | Description | Auth required |
|---|---|---|---|
POST |
/register |
Create a new user account | No |
POST |
/login |
Log in and receive a JWT cookie | No |
POST |
/logout |
Clear the JWT cookie | No |
| Method | Endpoint | Description | Auth required |
|---|---|---|---|
GET |
/ |
Get all posts (supports query filters) | No |
GET |
/:id |
Get a single post with details | No |
POST |
/ |
Create a new property listing | β Yes |
PUT |
/:id |
Update a listing (owner only) | β Yes |
DELETE |
/:id |
Delete a listing (owner only) | β Yes |
| Method | Endpoint | Description | Auth required |
|---|---|---|---|
GET |
/:id |
Get user info | β Yes |
PUT |
/:id |
Update profile (own account only) | β Yes |
DELETE |
/:id |
Delete account (own account only) | β Yes |
POST |
/save |
Save or unsave a post | β Yes |
GET |
/profilePosts |
Get own posts and saved posts | β Yes |
GET |
/notification |
Get unread chat count | β Yes |
| Method | Endpoint | Description | Auth required |
|---|---|---|---|
GET |
/ |
Get all chats for current user | β Yes |
GET |
/:id |
Get a single chat with messages | β Yes |
POST |
/ |
Start a new chat | β Yes |
PUT |
/:id |
Mark chat as read | β Yes |
| Method | Endpoint | Description | Auth required |
|---|---|---|---|
POST |
/:chatId |
Send a message in a chat | β Yes |
| Page | Preview |
|---|---|
| Home | coming soon |
| Property List | coming soon |
| Property Detail | coming soon |
| User Profile | coming soon |
| Real-Time Chat | coming soon |
- Pagination β Load properties in batches instead of all at once
- Advanced filters β Add floor count, furnished/unfurnished, parking, etc.
- Image compression β Compress images before uploading to Cloudinary
- Admin dashboard β Manage all users and listings
- Email notifications β Notify users when they receive a new message
- Deployment β Deploy frontend to Vercel and backend to Railway or Render
- Unit & integration tests β Add test coverage with Vitest and Supertest
This project is open source and available under the MIT License.





