project
Clinic management system (undergraduate thesis)
Web application for medical clinics: scheduling, records, and access control.
context
The project was called med.ai. The name had ambition — the original idea was to integrate AI to record the appointment and automatically generate medical notes. Midway through development my academic coordinator decided to remove AI from the scope. The "med" stayed and the ".ai" became a question mark.
It was my undergraduate thesis in Information Systems and, honestly, the main goal was to learn. It was my first application with React, Node.js and a relational database all working together. The problem the system addresses is real: small clinics that still manage appointments on paper or spreadsheets, with multiple professionals sharing the same schedule.
what was built
Scheduling
- Calendar using FullCalendar with monthly, weekly and daily views
- Working drag-and-drop in week and day views: dragging an event updates the time in the database
- Four-state machine: scheduled, confirmed, started, completed
- Doctors can reopen a completed appointment
- No conflict detection — two appointments in the same slot are technically possible
Medical records
- Rich text editor with draft-js + react-draft-wysiwyg
- Doctors can define a default record template in their profile, loaded automatically when opening a new appointment
- Records stored as TEXT in the database
Email notifications
- Finds next-day appointments that do not yet have a token
- Generates a cryptographic token with crypto.randomBytes(20) and saves it to the appointment
- Sends a confirmation email with a link via nodemailer
- Public endpoint validates the token and marks the appointment as confirmed
Multi-tenant
- The system supports multiple clinics with fully isolated data
- consultorio_id is included in the JWT on login and every query filters by it
- Composite primary keys (id, consultorio_id) across all tables enforce isolation at the database level too
Access control
- Two flags on the user record: doctor and admin
- Doctors see the appointments menu and can open consultations
- Admins see the new user registration form
- Protection is frontend-only — the backend does not validate the role before operations
technical decisions
JWT in httpOnly cookie
The authentication token is stored in a cookie with httpOnly: true. It never touches the frontend JavaScript. This was a conscious security decision, made before I even knew there was a technical name for it.
Multi-tenant in the JWT and in the database
Including consultorio_id in the JWT and filtering every query by it is the decision I am most proud of in this project. It was not planned from the start — it came midway through development when I realized the system could host more than one clinic. The composite key in the database was the reinforcement to ensure that an application layer mistake would not leak data between clinics.
Rate limiting on login
The login endpoint has a limit of 8 attempts per 15 minutes per IP. That came from reading about security while building and wanting to apply what I was learning.
what I learned
AI left the scope and what remained was a basic management system. At first that bothered me, because the project had become something less interesting than planned. But looking at the code today, what stayed has some decisions that were not obvious to me at the time — the multi-tenant architecture, the JWT in httpOnly cookie, the state machine in scheduling.
The most honest part: role-based access control is frontend-only. The backend lets any authenticated user call any route.
It was my first project with this stack and this level of complexity. I learned more about how to organize a backend, model a database and connect the dots with the frontend than in any course.