A full-stack portfolio application built with the MERN stack, featuring a public website and a protected admin dashboard for content management.
This project includes:
- A responsive public homepage with dynamic bio and projects
- A contact form that stores messages in MongoDB
- A JWT-protected admin dashboard for managing projects, inbox messages, and profile settings
- React (Vite)
- React Router
- Tailwind CSS
- Axios
- Node.js
- Express.js
- MongoDB (Mongoose)
- JWT authentication
- bcrypt password hashing
- Dynamic About Me section (loaded from API)
- Dynamic Projects grid (loaded from API)
- Contact form (
name,email,message) persisted to MongoDB
- Admin login/logout with JWT
- Project management: add, list, edit, delete
- Inbox view for contact form submissions
- Admin settings:
- Update username, email, profile image
- Update portfolio bio
- Change password
- Reset password
project-admin/
├─ frontend/ # React client
└─ backend/ # Express API
cd backend
cp .env.example .env
npm install
npm run devSet values in backend/.env:
MONGO_URIJWT_SECRET- Optional:
ADMIN_USERNAME,ADMIN_EMAIL,ADMIN_PASSWORD,ADMIN_PROFILE_IMAGE
cd frontend
cp .env.example .env
npm install
npm run devSet value in frontend/.env:
VITE_API_URL(default:http://localhost:5000/api)
- Frontend:
http://localhost:5173 - Backend API:
http://localhost:5000 - Health check:
GET /api/health
- Admin logs in via
POST /api/admin/login - Backend signs JWT using
JWT_SECRET - Frontend stores token and sends
Authorization: Bearer <token> - Protected admin routes validate token in middleware
GET /api/public/bioGET /api/public/projectsPOST /api/public/messages
POST /api/admin/loginGET /api/admin/mePUT /api/admin/profilePUT /api/admin/bioPUT /api/admin/passwordPUT /api/admin/password/resetGET /api/admin/projectsPOST /api/admin/projectsPUT /api/admin/projects/:idDELETE /api/admin/projects/:idGET /api/admin/messages
- The backend auto-creates a default admin if the configured admin email does not already exist.
- For production, use a strong
JWT_SECRET, strong admin password, and restricted MongoDB network access.