Skip to content

ankitdoi-coder/Hospital_System_Backend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

64 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ₯ Smart Healthcare System β€” Backend

A production-ready, secure, and scalable RESTful API for a Smart Healthcare Appointment & Records System, built with Java 17 + Spring Boot 3.5. Implements real-world engineering practices including JWT-based auth, role-based access control, centralized exception handling, request validation, OAuth2 social login, Razorpay payment gateway integration, billing management, Cloudinary-backed cloud file storage, and automated API documentation.

Java Spring Boot Spring Security MySQL Maven Swagger Razorpay Cloudinary

License Build PRs Welcome Made with Java

Frontend Repository: πŸ”— HealthCare-Frontend β€” React 19 | Vite | Redux Toolkit | Tailwind CSS | Razorpay Checkout


πŸŽ₯ Video Walkthroughs (Explained by Me)

I've recorded short walkthroughs breaking down some of the trickier features and bugs in this project β€” not just showing that it works, but explaining the reasoning behind the implementation.

# Topic Link
1 πŸ”” Notification Feature β€” Overview β–Ά Watch
2 🧩 Notification Feature β€” Service & Repository Layer β–Ά Watch
3 βœ… In-App Notification Feature β€” Completed Walkthrough β–Ά Watch
4 🐞 JWT Authentication Bug Fix β€” Root Cause & Resolution β–Ά Watch
5 βœ… Bean Validation & Global Exception Handler β–Ά Watch
6 πŸ“§ OTP-Based Registration Flow β–Ά Watch
7 πŸ”‘ OTP Email-Based Password Reset β–Ά Watch

πŸ’‘ These videos are meant to give reviewers a look into my thought process β€” how I debug, design, and reason through real backend problems, not just the final code.


✨ Key Highlights (What Makes This Stand Out)

Feature Details
πŸ” JWT Auth + Role-Based Access Stateless authentication with role-scoped endpoints (ADMIN / DOCTOR / PATIENT)
πŸ“§ Email OTP Verification 6-digit OTP sent via email before registration; 10-minute expiry, single-use, auto-cleared on resend
🌐 Google OAuth2 Social Login Patients and doctors can sign in with Google via Spring OAuth2 client
πŸ’³ Razorpay Payment Gateway Real, verified online payments for appointment billing β€” UPI, Cards & Netbanking, with server-side signature verification
☁️ Cloudinary Cloud Media Storage Profile pictures uploaded via multipart requests are validated, streamed, and persisted to Cloudinary β€” no local disk dependency, fully production-portable
πŸ›‘οΈ Global Exception Handler @RestControllerAdvice catches all exceptions β€” validation, auth, not-found, duplicates β€” and returns consistent JSON error responses with timestamp
βœ… Bean Validation @Valid + Jakarta Validation annotations (@NotNull, @NotBlank, @Email, @Digits) on all request DTOs
🩺 Doctor Approval Workflow Doctors register but are locked out until an Admin approves their account
πŸ”‘ Password Reset Flow Forgot-password β†’ token generation β†’ reset-password via secure token
πŸ’° Billing & Revenue Module Appointments auto-generate billing records; Admin can view daily/monthly revenue stats
πŸ“ Role-Aware File Management Multipart profile picture upload/retrieval shared across PATIENT and DOCTOR roles, backed by Cloudinary
πŸ”” Real-time Appointment Notifications Dual-channel notifications (in-app + email) for appointment creation & status tracking; includes time & reason details
πŸ“¬ Notification Entity In-app notification system with read/unread tracking and multi-type support (Appointment, Prescription, Payment, Registration)
πŸ“š Swagger / OpenAPI Docs Auto-generated interactive API docs via SpringDoc OpenAPI 2.5
🌍 CORS Configured Whitelisted for React frontend at localhost:5173 and localhost:3000 via allowedOriginPatterns, safely combined with credentialed requests
⚑ Stateless Sessions SessionCreationPolicy.STATELESS β€” no server-side session state

πŸ—οΈ Auditing & Persistence Infrastructure

To maintain professional-grade data traceability, the system implements JPA Auditing.

  • Automatic Metadata: Every core entity automatically records when it was created/modified and who performed the action.
  • Traceability: Integrated with Spring Security to capture the currently logged-in user via AuditorAware.
  • Implementation: Utilizes @MappedSuperclass with BaseAuditEntity to eliminate boilerplate, ensuring consistent created_at, updated_at, created_by, and updated_by fields across the entire database schema.

πŸ›οΈ Architecture

Architecture Diagram

Classic 3-tier layered architecture:

Controller (REST API)  β†’  Service (Business Logic)  β†’  Repository (JPA / MySQL)

The codebase is organized by domain modules (feature-based packaging), not by layer β€” keeping related code co-located and the project scalable.

com.ankit.HealthCare_Backend/
β”œβ”€β”€ appointment/          # Appointment booking, status updates
β”œβ”€β”€ authentication/       # JWT, OAuth2, Security config, Auth endpoints
β”œβ”€β”€ billing/              # Billing records, payment, revenue stats, Razorpay integration
β”œβ”€β”€ communication/        # Contact Us feature
β”œβ”€β”€ core/                 # Shared enums (AppointmentStatus, BillingStatus), Role entity
β”œβ”€β”€ Exception/            # GlobalExceptionHandler + custom exceptions
β”œβ”€β”€ filemanagement/       # Profile picture upload/retrieval, Cloudinary integration
β”œβ”€β”€ Notification/         # Notification entity & repository
β”œβ”€β”€ prescription/         # Doctor prescriptions
└── usermanagement/       # Admin, Doctor, Patient, User, Profile sub-modules

πŸš€ Technology Stack

Java Spring Boot Spring Security JWT OAuth2 Razorpay Cloudinary JavaMail Hibernate MySQL Validation Swagger Maven Lombok

Component Technology Version
Framework Spring Boot 3.5.7
Security Spring Security + JWT (jjwt) 6.5.7 / 0.11.5
Social Login Spring OAuth2 Client (Google) 6.5.7
Payment Gateway Razorpay Java SDK Latest stable
Media Storage Cloudinary Java SDK Latest stable
Email Spring Boot Starter Mail (JavaMailSender) 3.5.7
ORM Spring Data JPA + Hibernate 3.5.7
Database MySQL (mysql-connector-j) 8.3.0
Validation Spring Boot Starter Validation (Jakarta) 3.5.7
API Docs SpringDoc OpenAPI (Swagger UI) 2.5.0
Build Maven 3.x
Utilities Lombok 1.18.32
Language Java 17

πŸ”’ Security Implementation

Request β†’ JwtFilter β†’ Validate Token β†’ Set SecurityContext β†’ @PreAuthorize / hasRole()
  1. Registration β€” POST /api/auth/register with full Bean Validation (@Valid)
  2. Login β€” POST /api/auth/login returns a signed JWT; doctors blocked until approved
  3. Google OAuth2 β€” /oauth2/** flow handled by OAuth2LoginSuccessHandler, redirects with token
  4. JWT Filter β€” JwtFilter intercepts every request, validates signature & expiry
  5. Role Guards β€” /api/patient/** β†’ ROLE_PATIENT, /api/doctor/** β†’ ROLE_DOCTOR, /api/admin/** β†’ ROLE_ADMIN, /api/profile/** β†’ ROLE_PATIENT or ROLE_DOCTOR via hasAnyRole
  6. Email OTP β€” POST /api/auth/send-otp sends a 6-digit OTP; POST /api/auth/verify-otp validates it before allowing registration
  7. Password Reset β€” Secure time-limited token flow via POST /api/auth/forgot-password β†’ POST /api/auth/reset-password
  8. BCrypt β€” All passwords hashed with BCryptPasswordEncoder
  9. Payment Signature Verification β€” Every Razorpay payment is verified server-side via HMAC signature before billing status changes β€” the client can never self-report a payment as successful
  10. Credential-Safe CORS β€” CorsConfigurationSource uses allowedOriginPatterns (never a bare "*") so credentialed requests (JWT-bearing) from the frontend are honored without violating the CORS spec

☁️ Cloudinary β€” Cloud-Based Profile Picture Management

Profile pictures for both Patients and Doctors are uploaded directly to Cloudinary rather than local disk β€” meaning the API remains stateless and horizontally scalable (no shared filesystem needed across instances), and images are served from Cloudinary's CDN.

πŸ“Œ What's Implemented

Capability Status
Multipart image upload (multipart/form-data) βœ… Implemented
Content-type validation β€” only image/* accepted βœ… Implemented
File size validation β€” 5MB max, rejected before upload βœ… Implemented
Direct stream-to-Cloudinary upload (no local temp storage) βœ… Implemented
Role-aware persistence β€” updates Patient or Doctor entity based on logged-in user's role βœ… Implemented
Returns CDN-backed image URL in response for immediate frontend use βœ… Implemented

🧠 Upload Flow

1. Client sends multipart request  ──▢  POST /api/profile/upload-image  (field: profilePicture)
2. JwtFilter authenticates          ──▢  Principal resolved to logged-in user
3. ProfileService validates file    ──▢  content-type check + 5MB size check
4. CloudinaryService.uploadImage()  ──▢  streams file directly to Cloudinary, returns secure URL
5. Service resolves role            ──▢  PATIENT β†’ Patient entity, DOCTOR β†’ Doctor entity
6. profilePicture column updated    ──▢  persisted via @Transactional save
7. Response                         ──▢  { success, message, imageUrl }

Because the upload is wrapped in @Transactional, a failure at any stage (invalid file, Cloudinary error, DB save error) rolls back cleanly rather than leaving a partially-updated profile.


πŸ’³ Payment Gateway Integration (Razorpay)

The billing module integrates Razorpay end-to-end for appointment payments β€” not a mocked checkout, but a real gateway integration with proper order lifecycle and server-side trust boundaries.

πŸ“Œ What's Implemented

Capability Status
Order creation via backend (POST /api/patient/payments/create-order) βœ… Implemented
Razorpay Checkout (UPI, Cards, Netbanking) βœ… Implemented
Server-side payment signature verification (HMAC-SHA256) βœ… Implemented
Real-time billing status sync (UNPAID β†’ PAID) βœ… Implemented
Payment failure & checkout-dismissal handling βœ… Implemented
Revenue reporting (daily / monthly) βœ… Implemented

🧠 Why It's Built This Way

A naive integration trusts the frontend to say "payment succeeded." This one doesn't. The flow is:

1. Frontend requests an order  ──▢  Backend calls Razorpay Orders API, returns order_id
2. Razorpay Checkout opens     ──▢  User pays via UPI / Card / Netbanking
3. Razorpay returns            ──▢  payment_id, order_id, signature  (to frontend)
4. Frontend forwards these     ──▢  Backend verification endpoint
5. Backend recomputes HMAC     ──▢  using Razorpay key secret
6. Only on signature match     ──▢  Billing status flips to PAID

This is the same trust model used by real fintech and healthtech platforms β€” the backend is the single source of truth for what counts as a successful payment, never the client.

πŸ§ͺ Testing the Payment Flow (Test Mode)

Razorpay's Test Mode sandbox reproduces the entire checkout, OTP, and verification flow with zero real money movement β€” used to validate this integration end-to-end.

Card Payment

Field Test Value
Card Number 4111 1111 1111 1111 (Visa) or 5267 3181 8797 5449 (Mastercard)
Expiry (MM/YY) Any future date β€” e.g. 12/30
CVV Any 3 digits β€” e.g. 123
Cardholder Name Any name
OTP Any 4–10 digit number β€” e.g. 1234

Select Success on Razorpay's mock bank page to complete the simulated transaction, or use card 4000 0000 0000 0002 and select Failure to test the failure path.

UPI Payment

Field Test Value
UPI ID success@razorpay

No need to scan the on-screen QR with a real device β€” that only resolves against live, NPCI-registered transactions. Entering the test UPI ID simulates an instant successful payment in sandbox mode.

Going live requires only swapping the test key (rzp_test_...) for a live key (rzp_live_...) post KYC/activation on Razorpay's dashboard β€” no changes to the integration logic itself.


πŸ›‘οΈ Global Exception Handling

A single @RestControllerAdvice class handles all error scenarios and returns a consistent JSON error envelope:

{
  "timestamp": "2025-10-27T14:32:10.123",
  "status": 404,
  "message": "Doctor with id 5 not found"
}
Exception HTTP Status
ResourceNotFoundException 404 Not Found
DuplicateResourceException 409 Conflict
UnauthorizedException 401 Unauthorized
IllegalArgumentException 400 Bad Request
MethodArgumentNotValidException 400 Bad Request (validation errors)
PaymentVerificationException 400 Bad Request (Razorpay signature mismatch)
Exception (fallback) 500 Internal Server Error

βœ… Request Validation

All incoming request DTOs are validated with Jakarta Bean Validation annotations before reaching the service layer:

// RegisterRequestDTO example
@NotNull @NotBlank @Email        private String email;
@NotNull @NotBlank               private String password;
@Digits(integer=10, fraction=0)  private Long contactNumber;

// AppointmentDTO example
@NotNull  private Long patientId;
@NotNull  private Long doctorId;
@NotNull  private LocalDate appointmentDate;

// PaymentVerificationDTO example
@NotNull @NotBlank  private String razorpayOrderId;
@NotNull @NotBlank  private String razorpayPaymentId;
@NotNull @NotBlank  private String razorpaySignature;
@NotNull             private Long appointmentId;

Validation failures are caught by the Global Exception Handler and returned as structured 400 Bad Request responses.


πŸ“‹ API Endpoints

πŸ” Auth β€” /api/auth

Method Endpoint Description Auth
POST /send-otp Send 6-digit OTP to email for verification Public
POST /verify-otp Verify the OTP before registration Public
POST /register Register a new user (Patient/Doctor) Public
POST /login Authenticate and receive JWT Public
POST /forgot-password Request a password reset token Public
POST /reset-password Reset password using token Public
GET /oauth2/callback Google OAuth2 redirect handler Public

πŸ§‘β€βš•οΈ Patient β€” /api/patient (ROLE_PATIENT)

Method Endpoint Description
GET /doctors Browse all approved doctors
POST /appointments/new Book a new appointment
GET /appointments/my View personal appointment history
DELETE /appointments/{id}/cancel Cancel an appointment
PUT /appointments/{id}/pay Make payment for an appointment
POST /payments/create-order Create a Razorpay order for an appointment
POST /payments/verify Verify Razorpay payment signature and mark billing as PAID
GET /prescriptions View personal prescriptions
GET /profile View own patient profile (includes profilePicture URL)

πŸ‘¨β€βš•οΈ Doctor β€” /api/doctor (ROLE_DOCTOR)

Method Endpoint Description
GET /profile View own doctor profile (includes profilePicture URL)
GET /appointments/my View all own appointments
PUT /appointments/{id}/status Update appointment status (triggers in-app + email notifications)
GET /patients View all own patients
POST /prescription Create a prescription
GET /prescriptions View all own prescriptions

πŸ–ΌοΈ Profile / File Management β€” /api/profile (ROLE_PATIENT or ROLE_DOCTOR)

Method Endpoint Description
POST /upload-image Upload a profile picture (multipart/form-data, field: profilePicture) β€” validated, streamed to Cloudinary, and linked to the caller's Patient or Doctor record
DELETE /delete-image Remove the current profile picture

πŸ› οΈ Admin β€” /api/admin (ROLE_ADMIN)

Method Endpoint Description
GET /doctors Get all doctors (including pending)
PUT /doctors/{id}/approve Approve a doctor
PUT /doctors/{id}/reject Reject / revoke a doctor
GET /patients Get all patients
GET /billing View all billing records
PUT /billing/{id}/status Update a billing record's status
GET /revenue/daily Get today's total revenue
GET /revenue/monthly Get current month's total revenue

πŸ”” Notifications β€” /api/notifications (ROLE_PATIENT / ROLE_DOCTOR)

Method Endpoint Description
GET /my Get all notifications for logged-in user (newest first)
GET /unread-count Get count of unread notifications (for UI badge)
PUT /{id}/read Mark a specific notification as read
PUT /mark-all-read Mark all unread notifications as read

πŸ—„οΈ Database Schema

ER Diagram

Core entities: User, Role, Patient, Doctor, Admin, Appointment, Prescription, Billing, ContactUs, Notification, PasswordResetToken

Billing stores the Razorpay orderId, paymentId, and status (UNPAID / PAID) per appointment, giving a full payment audit trail per record.

Patient and Doctor each store a profilePicture column holding the Cloudinary-hosted CDN URL of the user's uploaded profile image.


πŸ“– API Documentation (Swagger)

Once running, the interactive Swagger UI is available at:

http://localhost:8080/swagger-ui/index.html

βš™οΈ Getting Started

βœ… Prerequisites

  • Java 17+
  • Maven 3.x
  • MySQL 8.x
  • A Razorpay account (Test Mode keys are free β€” no business verification needed to start testing)
  • A Cloudinary account (free tier is sufficient for development)

πŸ› οΈ Setup

git clone https://github.com/ankitdoi-coder/healthcare-backend.git
cd healthcare-backend

Create the database:

CREATE DATABASE healthcaredb;

Configure src/main/resources/application.properties:

spring.datasource.url=${DB_URL}
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
app.jwt.secret=${JWT_SECRET}
app.jwt.expiration=${JWT_EXPIRATION_MS}
razorpay.key.id=${RAZORPAY_KEY_ID}
razorpay.key.secret=${RAZORPAY_KEY_SECRET}
cloudinary.cloud-name=${CLOUDINARY_CLOUD_NAME}
cloudinary.api-key=${CLOUDINARY_API_KEY}
cloudinary.api-secret=${CLOUDINARY_API_SECRET}

Run:

mvn spring-boot:run

Server starts at http://localhost:8080


πŸ”§ Environment Variables

Variable Description Example
DB_URL JDBC connection URL jdbc:mysql://localhost:3306/healthcaredb
DB_USERNAME Database username root
DB_PASSWORD Database password your_password
JWT_SECRET Secret key for signing JWTs a-very-long-random-secret-key
JWT_EXPIRATION_MS Token TTL in milliseconds 86400000 (24h)
RAZORPAY_KEY_ID Razorpay API Key ID (test or live) rzp_test_xxxxxxxxxxxx
RAZORPAY_KEY_SECRET Razorpay API Key Secret (test or live) your_razorpay_key_secret
CLOUDINARY_CLOUD_NAME Cloudinary account cloud name your_cloud_name
CLOUDINARY_API_KEY Cloudinary API key 123456789012345
CLOUDINARY_API_SECRET Cloudinary API secret your_cloudinary_secret

πŸ”” Real-time Appointment Notifications

The system sends dual-channel notifications (in-app + email) for all key appointment events. Notifications include appointment time and reason details for full context.

πŸ“… Appointment Creation Notification

When a patient books an appointment:

In-App Notification (stored in database)

  • Sent to: Patient & Doctor
  • Message: "Your Appointment Booked with Doctor: [Name]" (Patient) / "You have new Appointment from Patient: [Name]" (Doctor)
  • Type: APPOINTMENT
  • Read/Unread tracking enabled

Email Notification (via JavaMailSender)

  • Patient receives: Appointment confirmation with doctor name, date, and gratitude message
  • Doctor receives: Appointment alert with patient name, scheduled date, and dashboard reminder
  • Both emails include appointment time (LocalTime) and reason for visit details

πŸ”„ Appointment Status Update Notification

When a doctor updates the appointment status (SCHEDULED β†’ COMPLETED / CANCELED, etc.):

In-App Notification (to patient)

  • Message: "Your appointment status has been updated to: [STATUS] by Dr. [Name]"
  • Type: APPOINTMENT

Email Notification (to patient)

  • Subject: "Appointment Status Update"
  • Contains: Appointment date, doctor name, new status, and dashboard link

πŸ“¬ Notification Management API

Patients and doctors can:

  • Retrieve all notifications sorted by creation date (newest first)
  • Check unread notification count (for UI bell badge)
  • Mark individual notifications as read
  • Mark all notifications as read in one call

🏷️ Notification Types

  • APPOINTMENT β€” Appointment booking and status changes
  • PRESCRIPTION β€” Prescription-related (extensible for future use)
  • PAYMENT β€” Payment status updates (extensible for future use)
  • REGISTRATION β€” Account registration events (extensible for future use)

πŸ‘€ For Reviewers

This project was built to demonstrate practical, production-grade backend engineering rather than tutorial-level CRUD:

  • πŸ” Security-first payment handling β€” billing status is never trusted from the client; it's gated behind server-side HMAC signature verification, mirroring real fintech/healthtech systems.
  • ☁️ Stateless media handling β€” profile pictures stream directly to Cloudinary rather than local disk, keeping the API instance-agnostic and production-portable from day one.
  • πŸͺͺ Stateless, role-scoped JWT auth with a proper OAuth2 social login path alongside it.
  • 🧩 Consistent error contracts across the entire API via a single global exception handler.
  • πŸ—οΈ Domain-driven package structure that scales cleanly as features are added, rather than a flat MVC layout.
  • πŸ”— Real third-party integration experience with Razorpay's order lifecycle (create β†’ checkout β†’ verify) and Cloudinary's upload API β€” not simulated or mocked integrations.
  • πŸŽ₯ Documented engineering process β€” video walkthroughs above show real debugging and design decisions, not just polished final output.

πŸ‘€ Author

Ankit β€” Java Full Stack Developer

GitHub

πŸ’Ό Open to Java Full Stack / Backend / Frontend opportunities. Feel free to connect!

About

A robust Smart Healthcare Management System backend built with Java and Spring Boot. Features strict Role-Based Authorization, stateless JWT/OAuth2 authentication, and seamless Razorpay integration for secure appointment billing.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages