A solo genetic counsellor came to me needing a proper patient management system. Booking, notes, documents, all of it currently scattered across inboxes and a spreadsheet. The market had two options: dedicated clinic software, priced and featured for a multi-clinician practice, or generic CRM tools that would need almost as much bespoke work as building from scratch, minus the fit. Neither made sense for one practitioner.
She was already paying for Microsoft 365, and as the sole controller of other people’s genetic health data, she was already bound by GDPR, no industry-specific certification required. So instead of adding a vendor, I built the system inside the tenant she already owned and already had to secure.
Architecture
SharePoint does the data layer: a Patients list, an Appointments list, a Notes list, and a Patient Documents library, linked together with lookup columns rather than duplicated fields. Nothing exotic, but it means every record lives somewhere she can audit, back up, and permission without learning a new admin console.
Microsoft Bookings handles the actual scheduling, because it’s the thing clients see and it already worked. A Power Automate flow bridges Bookings to SharePoint: every new booking becomes a patient record (or updates an existing one) and an appointment record, without anyone re-typing details into a second system.
Power Apps is the planned front end, a canvas app for the day-to-day work of looking up a patient, adding notes, and pulling up documents, so the practice doesn’t need to touch SharePoint’s native UI at all.
Auth runs through Entra ID, same as the rest of the tenant. That’s most of the GDPR case in one sentence: no new identity provider, no new place for access control to drift out of sync, no personal data leaving infrastructure that’s already covered by the client’s existing data processing arrangements. The whole thing costs the price of the Microsoft 365 licences she was paying for anyway.
Gotchas
A few things that cost more time than they should have, in case they save someone else the afternoon:
- The Bookings connector’s calendar dropdown in Power Automate fails with
AADSTS50013. Don’t fight it: type the booking mailbox address directly into the trigger field instead of selecting from the list. - Inline
filter()expressions in Power Automate are flaky when pulling values out ofCustomQuestionAnswers. The Filter array action does the same job and actually works. - The Bookings trigger returns
StartTimeas a plain string, not an object. No?['DateTime']needed, and adding it just breaks the expression. - Array length checks on the dedup branch need “is greater than”, not “is equal to”. Equal to zero silently skips cases it shouldn’t.
- Patient deduplication matches on email address only. That’s a simplification, not an oversight: at this practice’s patient volume, it’s reliable enough, and anything more elaborate would be solving a problem she doesn’t have.
Where it stands
The data layer and the Bookings-to-SharePoint integration are built and tested: bookings flow in, patient and appointment records get created or matched correctly, nothing needs manual re-entry. The Power Apps front end is next.