I built a custom Next.js and Postgres app, in phases, each verified before the next starts. Each doctor is set to either slots or queue mode. The public site shows live doctor status, and a four-step flow takes a new or returning patient from choosing a doctor to a confirmation.
Double-booking is prevented where it can't be bypassed: in the database. Partial unique indexes ignore cancelled rows, so a cancellation frees its slot at once. A row lock on the schedule keeps queue capacity and numbering from racing.
Staff get a dashboard with three roles. The secretary runs the day, doctors see and update only their own patients and status, and an admin can do everything. Every page and API call re-checks the session in the database, and sensitive actions are written to an audit log.
Messaging is deliberately not in Phase 1. The site makes no promise of reminders until SMS and Messenger actually exist.