Lil Mosey Hospital
Plain HTML, CSS and JavaScript in front of an Express + MySQL REST API
A hospital needs two very different things from one system: a calm, readable public site for patients, and an internal tool where staff can move records, appointments and applications quickly. I built both — the patient-facing pages as plain HTML, CSS and JavaScript, and a single Express + MySQL service behind all 36 of their endpoints.
The brief
The starting problem was fragmentation. Departments, doctors, services, appointments and billing all lived in separate places, so a patient could not see their own history and staff could not see the whole picture. The requirement was one system that covers the public story, the patient journey and the staff workflow — without pulling in a framework, and without a build step.
What I built
- 13 pages — home, about, services, doctors, appointments, contact, doctor application, login, register, my messages, a live database view, a guidance sheet and the entry point.
- Appointment booking that writes to MySQL and can be read back per patient via GET /api/appointments/mine/:email.
- A doctor application workflow — candidates apply publicly, staff approve or reject, and rejected records can be removed.
- Patient records, billing and inventory as full create/read/delete sets, plus an audit-log and a reports endpoint.
- One-to-one messaging between a patient and the hospital, filtered by the same email used at sign-in.
- A doctor rating endpoint so a rating can be attached to a doctor without editing their whole record.
- A searchable doctor directory — every profile carries a photo, qualification, experience, availability, languages and contact details, with live search, specialization filter and sorting. A shared doctors-data.js module reads the API first and falls back to a built-in roster, so the directory still works when the page is hosted without the backend.
How it works
Everything sits in one server.js with prepared statements through mysql2. Every query is parameterised — no SQL is assembled from user input, so the classic injection route is closed off by construction.
Access is deliberately simple: POST /api/login checks the email and a hashed password, and the returned user is kept client-side in localStorage under hms_user, where a small auth.js guard decides what each page shows. There is also a /api/db-summary endpoint that lets the database page render the live shape of the schema instead of a hardcoded diagram — handy for demonstrating the design without opening phpMyAdmin.
What I would do next
- Move sessions server-side. Right now the client holds the user object, which is fine for a demo but is not how real patient data should be guarded.
- Replace the current single-pass SHA-256 password digest with bcrypt or Argon2 and a per-user salt.
- Add role-based route guards on the API itself — the staff-only endpoints currently rely on the UI hiding them.