Clinic Management System
A Spring Boot + React clinic management system with real-time appointment booking, queue tracking, and role-based access control.

The dashboard that the patient sees upon login
MediQ is a clinic queue and appointment management system. We picked healthcare because the queue management problem is genuinely complex: patients booking appointments across multiple clinics, staff managing live queues with priority levels, admins needing analytics on the whole operation. The object-oriented patterns we wanted to use actually mapped to real entities and workflows in this domain, which made the design feel earned rather than academic.
The backend is Spring Boot 3.5 on Java 21. Seven JPA entities form the data model, and we used JOINED inheritance strategy for the user hierarchy: a base User entity with Patient and Staff as subclasses. That inheritance decision drove a lot of downstream design. Patients carry medical history, allergies, blood type, and emergency contacts. Staff are assigned to clinics. The separation is clean in the database (8 PostgreSQL tables on Supabase) and in the code (distinct repositories, services, and controllers for each).
The queue system is the core of the project. Patients check in to a clinic queue and get a live position number. Staff see a queue management board where they can call the next patient, mark them done, or handle missed appointments. Priority ordering means Emergency patients jump ahead of Elderly, who jump ahead of Normal. The real-time updates use Server-Sent Events: when the queue changes, every connected patient gets their new position pushed to the browser without polling. We also built a dedicated display board view designed for TV screens in waiting rooms, showing the currently serving number and the queue list with a 5-second auto-refresh.
Email notifications run through SendGrid. Patients get a confirmation when they book, an alert when they're 3 positions away, and a "your turn" notification when the staff calls their number. The notification triggers are event-driven: QueueService publishes a QueueChangedEvent via Spring's ApplicationEventPublisher, and QueueSseService listens to it, checks position thresholds, and fires the appropriate email. I first encountered that pattern, publishing domain events and letting listeners react independently, in this project, and I've used it in every backend I've built since.
The appointment system handles double-booking prevention (max 3 per slot per doctor), full status tracking from booking through completion or cancellation, and clinic filtering by region, specialty, and type. The admin dashboard aggregates everything into charts: appointments by status, trends over time, clinic-level breakdowns, and user role distributions. We also built PDF report generation with iText7, a full backup and restore system, and a patient self-registration flow with validation.
The healthcare domain is what made the OOP patterns feel earned instead of forced. A Patient really is a specialisation of a User, and a QueueChangedEvent really is the right way to decouple queue state from notification delivery. Realising the domain's shape was doing most of the design work for us was probably the most useful thing I took from this project.
- ROLE
- School Project
STACK




