- Project Overview
- Architecture
- File Structure Explained
- Database Models
- API Endpoints
- Authentication & Authorization
- Setup & Installation
- Environment Variables
- Usage Examples
This is a Medical Clinic Management System backend API built with:
- Node.js & Express.js (ES6 Modules)
- MongoDB & Mongoose (Database)
- JWT (Authentication)
- Bcrypt (Password Hashing)
- Joi (Input Validation)
- Nodemailer (Email Notifications)
- Multer & Sharp (File Upload & Image Processing)
✅ Role-based access control (Admin, Doctor, Patient) ✅ JWT authentication with token-based security ✅ Email notifications for appointments ✅ Doctor availability management ✅ Appointment booking system ✅ User status management (Active, Blocked, Pending) ✅ Image upload with processing ✅ Input validation on all routes
The project follows a modular architecture with clear separation of concerns:
┌─────────────────────────────────────────────────┐
│ Client (React) │
└─────────────────────┬───────────────────────────┘
│ HTTP Requests
↓
┌─────────────────────────────────────────────────┐
│ Express.js Server │
│ ┌──────────────────────────────────────────┐ │
│ │ Middlewares (CORS, Auth, Validation) │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ Routes (User, Doctor, Appointment) │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ Controllers (Business Logic) │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ Models (Mongoose Schemas) │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────┬───────────────────────────┘
│
↓
┌─────────────────────────────────────────────────┐
│ MongoDB Database │
└─────────────────────────────────────────────────┘
Purpose: Server entry point
- Imports the Express app
- Connects to MongoDB database
- Starts the server on specified port
- Logs server status
import app from './app.js';
import connectDB from './Database/connection.js';Purpose: Express application configuration
- Sets up middlewares (CORS, JSON parser, etc.)
- Defines all API routes
- Configures error handling
- Serves static files (uploads)
Purpose: Project configuration
- Lists all dependencies
- Defines npm scripts (
start,dev) - Sets
"type": "module"for ES6 support
Purpose: Environment variables (sensitive data)
- Database connection string
- JWT secret key
- Email configuration
- Port number
Purpose: JavaScript/TypeScript configuration
- Enables ES6 module resolution
- Enforces consistent file name casing
- Provides better IDE support
Purpose: MongoDB connection handler
- Uses Mongoose to connect to MongoDB
- Handles connection errors
- Exits process if connection fails
const connectDB = async () => {
await mongoose.connect(process.env.MONGO_URI);
};Contains all Mongoose schemas and models.
Purpose: User schema for all users (Admin, Doctor, Patient)
- Fields: userName, email, password, role, status, phone
- Hooks: Pre-save hook to hash passwords with bcrypt
- Methods:
matchPassword()to compare passwords - Roles: Admin, Doctor, Patient
- Status: Pending, Active, Blocked
Purpose: Doctor profile information
- Fields: user (ref to User), specialty, bio, experience, consultationFee, availability
- Availability: Array of days with time slots
- Relationships: References User model
Purpose: Patient profile information
- Fields: user (ref to User), dateOfBirth, gender, address, medicalHistory
- Relationships: References User model
Purpose: Appointment booking data
- Fields: patient, doctor, appointmentDate, timeSlot, status, notes, reason
- Status: Pending, Confirmed, Completed, Cancelled
- Relationships: References User and Doctor models
Contains Express middleware functions.
Purpose: Authentication & Authorization
protect: Verifies JWT token from Authorization header- Extracts token from "Bearer "
- Verifies token with JWT_SECRET
- Attaches user to
req.user - Returns 401 if invalid
authorize(...roles): Checks if user has required role- Returns 403 if unauthorized role
Purpose: Input validation using Joi
- Takes a Joi schema as parameter
- Validates
req.bodyagainst schema - Returns 400 with error messages if validation fails
Purpose: Global error handler
- Catches all errors from routes
- Returns consistent error response format
- Shows stack trace in development mode
Purpose: 404 handler for undefined routes
- Creates error with 404 status
- Passes to error handler
Purpose: File upload configuration with Multer
- Configures storage (saves to
uploads/folder) - Generates unique filenames
- Filters file types (only images: jpeg, jpg, png, gif)
- Sets file size limit (5MB)
Contains utility/helper functions.
Purpose: JWT token generation
- Takes user ID as parameter
- Signs token with JWT_SECRET
- Sets expiration time (default 30 days)
- Returns signed token string
Purpose: Email sending with Nodemailer
- Configures SMTP transporter
- Sends HTML emails
- Used for welcome emails and appointment confirmations
Purpose: Image processing with Sharp
- Resizes images to specified dimensions
- Compresses images (JPEG quality)
- Deletes original file after processing
- Returns processed file path
Feature-based modules (each domain has its own folder).
user.model.js: User schema (duplicate of Models/user.model.js for module organization)
user.validation.js: Joi validation schemas
registerValidation: Validates registration dataloginValidation: Validates login credentials
user.controller.js: User business logic
register: Creates new user, hashes password, sends welcome email, returns JWTlogin: Validates credentials, checks if blocked, returns JWTgetProfile: Returns authenticated user's profile
user.routes.js: User API routes
POST /api/users/register- Register (with validation)POST /api/users/login- Login (with validation)GET /api/users/profile- Get profile (protected)
doctor.model.js: Doctor schema (duplicate of Models/doctor.model.js)
doctor.controller.js: Doctor business logic
createDoctorProfile: Creates doctor profile (Doctor role only)getDoctors: Lists all doctors with optional specialty filtersetAvailability: Updates doctor's available time slots
doctor.routes.js: Doctor API routes
POST /api/doctors/profile- Create profile (Doctor only)GET /api/doctors- List doctors (public)PUT /api/doctors/availability- Set availability (Doctor only)
appointment.model.js: Appointment schema
appointment.controller.js: Appointment business logic
bookAppointment: Books appointment, checks availability, sends emailgetAppointments: Lists appointments (filtered by role)updateAppointmentStatus: Updates status and notes (Doctor/Admin)
appointment.routes.js: Appointment API routes
POST /api/appointments- Book appointment (Patient only)GET /api/appointments- List appointments (role-based filtering)PUT /api/appointments/:id- Update status (Doctor/Admin)
admin.controller.js: Admin business logic
getAllUsers: Lists all users (without passwords)updateUserStatus: Changes user status (Active/Blocked/Pending)getAllAppointments: Lists all appointments with populated data
admin.routes.js: Admin API routes
GET /api/admin/users- List all users (Admin only)PUT /api/admin/users/:id/status- Update user status (Admin only)GET /api/admin/appointments- List all appointments (Admin only)
patient.model.js: Patient schema (for future patient-specific features)
{
userName: String (3-20 chars),
email: String (unique, lowercase),
password: String (hashed, min 6 chars),
role: Enum ['Admin', 'Doctor', 'Patient'],
status: Enum ['Pending', 'Active', 'Blocked'],
phone: String,
timestamps: true
}{
user: ObjectId (ref: User),
specialty: String (required),
bio: String (max 500 chars),
experience: Number (years),
consultationFee: Number (required),
availability: [{
day: Enum [Monday-Sunday],
slots: [{
startTime: String,
endTime: String,
isBooked: Boolean
}]
}],
timestamps: true
}{
patient: ObjectId (ref: User),
doctor: ObjectId (ref: Doctor),
appointmentDate: Date (required),
timeSlot: {
startTime: String,
endTime: String
},
status: Enum ['Pending', 'Confirmed', 'Completed', 'Cancelled'],
notes: String,
reason: String (required),
timestamps: true
}-
Registration/Login:
- User sends credentials
- Server validates and creates/finds user
- Server generates JWT token with user ID
- Token sent back to client
-
Protected Routes:
- Client sends token in header:
Authorization: Bearer <token> protectmiddleware verifies token- User data attached to
req.user - Request proceeds to controller
- Client sends token in header:
-
Role-Based Access:
authorize('Admin', 'Doctor')checks user role- Returns 403 if role not allowed
{
id: "user_mongodb_id",
iat: 1234567890, // issued at
exp: 1234567890 // expiration
}- Node.js (v14+)
- MongoDB (local or Atlas)
- npm or yarn
# 1. Clone/Download project
cd project
# 2. Install dependencies
npm install
# 3. Create .env file
cp .env.example .env
# Edit .env with your values
# 4. Start MongoDB (if local)
mongod
# 5. Run development server
npm run dev
# 6. Server runs on http://localhost:3000Create a .env file in the root:
# Server Configuration
PORT=3000
NODE_ENV=development
# Database
MONGO_URI=mongodb://localhost:27017/medicalClinicDB
# JWT Configuration
JWT_SECRET=your_super_secret_key_here_change_in_production
JWT_EXPIRE=30d
# Email Configuration (Gmail example)
EMAIL_SERVICE=gmail
EMAIL_USER=your-email@gmail.com
EMAIL_PASS=your-app-specific-password- Enable 2-Factor Authentication on Gmail
- Go to Google Account → Security → App Passwords
- Generate password for "Mail"
- Use generated password in EMAIL_PASS
POST http://localhost:3000/api/users/register
Content-Type: application/json
{
"userName": "John Doe",
"email": "john@example.com",
"password": "password123",
"role": "Patient",
"phone": "1234567890"
}Response:
{
"success": true,
"data": {
"_id": "65abc123...",
"userName": "John Doe",
"email": "john@example.com",
"role": "Patient",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}POST http://localhost:3000/api/users/login
Content-Type: application/json
{
"email": "john@example.com",
"password": "password123"
}Response:
{
"success": true,
"data": {
"_id": "65abc123...",
"userName": "John Doe",
"email": "john@example.com",
"role": "Patient",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}GET http://localhost:3000/api/users/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Response:
{
"success": true,
"data": {
"_id": "65abc123...",
"userName": "John Doe",
"email": "john@example.com",
"role": "Patient",
"status": "Active",
"phone": "1234567890"
}
}POST http://localhost:3000/api/doctors/profile
Authorization: Bearer <doctor_token>
Content-Type: application/json
{
"specialty": "Cardiology",
"bio": "Experienced cardiologist with 10 years of practice",
"experience": 10,
"consultationFee": 100
}PUT http://localhost:3000/api/doctors/availability
Authorization: Bearer <doctor_token>
Content-Type: application/json
{
"availability": [
{
"day": "Monday",
"slots": [
{ "startTime": "09:00", "endTime": "10:00", "isBooked": false },
{ "startTime": "10:00", "endTime": "11:00", "isBooked": false }
]
},
{
"day": "Tuesday",
"slots": [
{ "startTime": "14:00", "endTime": "15:00", "isBooked": false }
]
}
]
}GET http://localhost:3000/api/doctors
# Optional: Filter by specialty
GET http://localhost:3000/api/doctors?specialty=CardiologyResponse:
{
"success": true,
"data": [
{
"_id": "65abc456...",
"user": {
"_id": "65abc123...",
"userName": "Dr. Smith",
"email": "smith@example.com",
"phone": "9876543210"
},
"specialty": "Cardiology",
"bio": "Experienced cardiologist...",
"experience": 10,
"consultationFee": 100,
"availability": [...]
}
]
}POST http://localhost:3000/api/appointments
Authorization: Bearer <patient_token>
Content-Type: application/json
{
"doctorId": "65abc456...",
"appointmentDate": "2024-03-15",
"timeSlot": {
"startTime": "09:00",
"endTime": "10:00"
},
"reason": "Regular checkup"
}GET http://localhost:3000/api/appointments
Authorization: Bearer <token>- Patient: Returns only their appointments
- Doctor: Returns appointments for that doctor
- Admin: Returns all appointments
PUT http://localhost:3000/api/appointments/65abc789...
Authorization: Bearer <doctor_or_admin_token>
Content-Type: application/json
{
"status": "Confirmed",
"notes": "Patient confirmed via phone"
}GET http://localhost:3000/api/admin/users
Authorization: Bearer <admin_token>PUT http://localhost:3000/api/admin/users/65abc123.../status
Authorization: Bearer <admin_token>
Content-Type: application/json
{
"status": "Blocked"
}- Password Hashing: Bcrypt with salt rounds (10)
- JWT Tokens: Signed with secret key, expiration time
- Role-Based Access: Middleware checks user roles
- Input Validation: Joi validates all inputs
- Status Management: Can block malicious users
- CORS: Configured for cross-origin requests
- Error Handling: Doesn't expose sensitive info
{
"success": true,
"data": { ... }
}{
"success": false,
"message": "Error description",
"errors": ["Validation error 1", "Validation error 2"]
}- Import collection (create one with all endpoints)
- Set environment variable for token
- Test each endpoint
# Register
curl -X POST http://localhost:3000/api/users/register \
-H "Content-Type: application/json" \
-d '{"userName":"Test","email":"test@test.com","password":"123456"}'
# Login
curl -X POST http://localhost:3000/api/users/login \
-H "Content-Type: application/json" \
-d '{"email":"test@test.com","password":"123456"}'Solution: Check MongoDB is running and MONGO_URI is correct
Solution: Include Authorization: Bearer <token> header
Solution: Check EMAIL_USER and EMAIL_PASS in .env
Solution: Change PORT in .env or kill process using port
- Understand Express basics: Routes, middleware, request/response
- Learn MongoDB & Mongoose: Schemas, models, queries
- Study JWT authentication: Token generation, verification
- Practice API testing: Postman, cURL
- Explore advanced topics: File uploads, email, validation
For questions or issues:
- Check this documentation
- Review code comments
- Test with Postman
- Check console logs for errors
Last Updated: February 2024 Version: 1.0.0