Most CMS platforms are built to publish pages, not to hold patient data. WordPress, Webflow, even headless tools like Sanity are optimized for content: articles, images, marketing copy. A polyclinic or private practice site needs that layer too — but the moment it adds online booking, doctor profiles tied to real calendars, or any patient information, the project stops being a content site and becomes a system processing special category personal data under GDPR Article 9.
Treating that system like a marketing CMS with a booking plugin bolted on is where most clinic sites run into trouble later — usually when a data protection officer, an insurer, or a patient complaint forces a rebuild. Here's what actually needs to be different.
Two kinds of data, two access models
A clinic site has two very different kinds of content living side by side: public marketing content — services, specialties, doctor bios — and operational data tied to real people — appointments, medical history references, consent records. These shouldn't share a schema, an access layer, or a backup policy.
Public content can be cached aggressively and edited by non-technical staff. Patient data needs row-level access control, audit logging, and a retention policy independent of how long a blog post stays live. In practice that means a Postgres backend — Supabase, in our stack — with row-level security scoped per practitioner, sitting behind a separate application layer from whatever renders the public site, even inside the same Next.js app. A doctor shouldn't be able to query another doctor's patient list just because the API route exists. RLS enforces that at the database, not in application code someone will eventually forget to check.
Booking is a concurrency problem, not a form problem
Most booking widgets treat scheduling as a form submission: pick a time, submit, done. In production, double-booking is a race condition — two patients confirming the same slot within the same second, especially for a high-demand specialist.





