Slavko Babić
All projects

Healthcare / scheduling

Patient scheduling platform

A full-stack scheduling platform for a therapy practice — booking patients against the intersection of therapist, room, device and time-off availability, with role-based access from front desk to therapist.

Status In active development

Overview

A scheduling platform for a therapy practice. On the surface it books patients into appointments; underneath, every booking is a small constraint-satisfaction problem — the right therapist, a free room, sometimes a specific device, and never on someone’s day off. It is a product I am building end to end, from the Prisma schema to the responsive UI.

Problem

Scheduling in a practice looks trivial until you list what a valid appointment actually requires. It needs an available therapist who isn’t already booked and isn’t on leave. It needs a room that isn’t over capacity — and if a therapist is marked as working alone, a room nobody else is using. It may need a particular device that lives in that room. A paper diary or a shared spreadsheet can’t enforce any of that, so the failures are the expensive kind: double-booked staff, over-full rooms, patients turned away, resources sitting idle.

Solution

A full-stack application where a booking is only allowed if it satisfies every constraint at once. Front desk and managers schedule; therapists see their own day; each role sees exactly what it should. Around the calendar sit the CRUD surfaces the schedule depends on — employees and their working hours, rooms and their capacity, the devices in each room, and a click-to-toggle day-off calendar. The whole thing is responsive from a phone at the desk to a desktop in the back office.

Architecture

A TypeScript monorepo: an Express + Prisma backend over PostgreSQL, and a React (Vite) frontend on Material UI. Prisma’s schema is the single source of truth for the domain — Employee, Room, Device, DayOff, Appointment, and the EmployeeRoom link between staff and the rooms they can work in — so the model is expressed once and the types flow out to both ends.

Auth is JWT with a role hierarchy (root, admin, manager, therapist, client). One detail I’m oddly fond of: a legacy EMPLOYEE role is kept as an alias while every row migrates to THERAPIST, so the rename ships without a flag day. The whole stack runs on Docker Compose with four env-driven modes — local dev with hot reload and a mail catcher, staging, and two production shapes (external or bundled database) — so “how do I run it” has one honest answer for every environment.

Technical challenges

The booking validator is the heart of it, and it’s where the interesting bugs live. A single “can I book this?” check has to run four independent guards together — the therapist’s day-off calendar, a time-conflict check against their existing appointments, the room’s occupancy limit, and the room-exclusivity flag for staff who must work alone — and it has to do it atomically, because two receptionists booking the last slot at the same moment is a real race, not a hypothetical. Getting those rules to live in one place, server-side and authoritative, rather than smeared across the UI, was the work that mattered.

Lessons learned

Model the resources and their constraints before you draw a single calendar. Once “an appointment is the intersection of an available therapist, room, device and time” was written down as an explicit rule set, the UI became a thin thing on top and every new constraint had an obvious home. The scheduling grid is the part users see; the validator is the part that makes it trustworthy.

Technologies

  • TypeScript
  • Express
  • Prisma
  • PostgreSQL
  • React
  • Material UI
  • Docker