Case studyHealthcare · Patient booking · Bilingual web
Hospital Website & Serial Booking System
A bilingual (English and Bengali) website and patient-booking system for a mother-and-child hospital with 25 consultants. Patients book a serial number online, and reception issues numbers from the same table at the counter, so the two can never hand out the same number.
The hard part is not the website. It is a queue that two channels share without ever clashing, patient data that only the right staff can see, and a system the hospital can run on its own after handover.
Role
Design, engineering & coding
Domain
Healthcare · patient booking
Languages
English · বাংলা
Status
Built · yet to go live
The problem
The hospital had no online booking, and its old website could not be updated without a developer. Any booking system had to fit how the chambers already run: serial numbers, not appointment times.
What was built
Morsalin designed and built a bilingual Nuxt and PostgreSQL platform where patients and reception claim serials from one table, with role-based access, audit logging and SMS and email notifications.
The result
Built and ready for launch, pending the hospital's final information. Staff can run the whole site — consultants, schedules, fees and notices — from the admin, without a developer.
25consultants
2booking channels, one queue
10staff roles
20+admin screens
3SMS gateways
305automated tests
2languages, data included
~27.6klines of code
01The problem
Online booking for a clinic that runs on serial numbers.
01
Patients could not book online.
The hospital had no booking of any kind. Patients phoned or queued at the counter to get a serial number for a consultant’s sitting.
02
The chambers run on serials, not appointments.
A patient is given number 14 for the evening sitting and seen when 14 is called. A clock-time appointment system would promise a precision the clinic cannot keep.
03
Nobody would be there to change it.
There is no technical team after handover. Anything an administrator might need to change — consultants, schedules, fees, notices, images — had to be editable without a developer, or it would never change.
02Serial booking
One queue, shared by the website and the counter.
One table, two channels
Online and counter bookings both claim serials through one function, inside a serializable transaction, with a unique index on sitting, date and serial as the database-level backstop. The website and the front desk cannot issue the same number.
The counter outranks the website
Reception may overfill a sitting and may book one already under way; the website may do neither. A walk-in reserve, bounded by both the online quota and the room physically left, keeps space for patients who arrive in person.
Retired numbers stay retired
A cancelled booking gives up its place but keeps its number, so two paper slips never read the same serial. The search window widens by the retired count, so a sitting for 30 still seats 30.
Each patient gets their own estimate
Patients are told when their serial is expected, not when the next unsold number is. Running-late messages go out only on a real change, so a queue is not re-texted on every “call next”.
03Access & audit
Patient data that only the right staff can see.
10 roles, around 48 permissions
Roles are composed from a permission catalogue. The admin UI shows only what a role can use, but that is a courtesy — the refusal happens in the server route.
“Whose patients” as row-level scope
An assistant and a doctor’s own assistant hold nearly the same permissions and differ only in which doctors’ patients they may see. That scope is enforced on every query, not by a permission.
Every access is audited
Each read or write of patient data is written to an audit log — including denials — so a question about who saw a record has an answer.
Sessions follow the role
Demoting a user revokes their existing sessions, rather than leaving the old permissions live until their next sign-in.
04Notifications
Messages that help, and never block a booking.
Email and SMS, three gateways
SMTP plus three Bangladeshi SMS providers, configured from the admin. Gateway credentials are stored in the database, encrypted at rest with AES-256-GCM.
A failed message never fails a booking
The serial is issued either way. The failure is recorded, so reception has a call list instead of a patient who never heard back.
Secrets stay out of error messages
Gateway errors are caught and rethrown without the request URL, so an outage cannot print a live API key into the admin’s browser or a proxy log.
Mandatory means mandatory
A cancellation SMS is required because the patient may already be travelling; it is not considered delivered just because the email went through.
05Built to degrade
A problem breaks one feature, never the emergency page.
The emergency page outlives the server
It is prerendered and long-cached, so a CDN keeps serving it for a week after the origin goes down — on a bad connection, at 2am.
Missing configuration degrades one feature
The database client is created on first use and a boot check names every missing setting without exiting, so a bad deploy cannot take the static pages down with it.
A broken image library breaks only images
The image library is loaded lazily. With it removed entirely, the site still starts and still serves its pages; only image processing fails.
Uploads are checked four ways
Extension, declared type and file signature must agree, with an image decode as a fourth check. Private files live behind separate routes and are unreachable from the public ones.
06Run by the hospital
Everything staff need, nothing that needs a developer.
Public site
Consultant directory with schedules and fees, departments, centres, packages, a baby-growth tool and an emergency page — in English and Bengali, with separate localised routes.
Patient booking
Choose a consultant and sitting, book a serial at any hour, and look the booking up later by reference and mobile number.
Reception and waiting room
A counter queue for issuing and calling serials, printable slips, and a display board for the waiting room.
Admin without a developer
20+ screens for consultants, schedules, sittings, fees, notices, media, branding, staff, roles and integrations — plus plain-language guides written for staff, one page per job.
07Key decisions
Every non-obvious choice, with its reason.
Serials, not clock times
It is how the chambers run. An estimate per serial is honest; a 3:15pm appointment would not be.
One allocator for both channels
Two allocators would eventually disagree. One function and one unique index make a double-issued number impossible, not just unlikely.
Permissions checked in the route
A hidden menu item is not access control. Every admin endpoint refuses on the server.
Bilingual columns, not a translation layer
A specialty exists in both languages or is honestly missing in one — never silently shown in the wrong language.
Degrade, never crash
A configuration or infrastructure problem may break only what depends on it. The emergency page must survive everything.
Everything editable in the admin
There is no operations team after handover. What cannot be edited will not be kept current.
Notifications are best effort, bookings are not
An SMS outage should cost a phone call, not a patient’s serial.
Two images from one Dockerfile
The web server ships without database tooling; migrations and seeds run from a separate tools image and exit.
08Outcome
Ready to launch, and run by the hospital.
Online booking
Patients can book a serial at any hour, from the same queue reception uses.
One queue, no clashes
Website and counter can never issue the same number for the same sitting.
Audited patient data
Role- and scope-based access, checked on the server, with every access logged.
Owned by the hospital
Content, people, schedules and fees are all editable by staff from the admin.
✓Status: built and reviewed, yet to go live. The remaining work is the hospital’s own information — consultant fees and schedules — not code.
✓Replaces a site with no booking whose contact details were hardcoded, and whose emergency page froze mobile browsers.
✓A deployment runbook, a rehearsed first deployment and a backup-restore drill are part of the handover.
✓Test coverage is stated plainly, including the gaps: concurrency under real load and route-level permission tests are the next things to automate.
My role
I designed, built and coded the whole system: the booking model and its allocator, the access-control and audit design, the notification layer and its failure handling, the bilingual data model, the media pipeline, the admin and staff tools, and the Docker deployment with its runbook and restore drill. I also wrote the technical overview and the plain-language staff guides that go with the handover.