Sep 2026

Therapy Booking: Internal Appointment Booking for AAWA

Designed, built, and piloted a full-stack web app that books client therapy sessions straight into therapists' own Outlook calendars, with Microsoft 365 sign-in, recurring series, and server-enforced availability rules.

  • Web Development & Digital Platforms
  • Microsoft 365 & Cloud Administration
  • Business Applications & CRM
  • AI & Intelligent Systems
  • React
  • TypeScript
  • Node.js
  • SQL Server
  • Microsoft Graph
  • Microsoft Entra ID
  • Playwright
  • Claude Code

The brief

Advisors at the Autism Association of Western Australia book therapy sessions into therapists’ Outlook calendars. Microsoft Bookings couldn’t create recurring client appointments and didn’t fit the organisation’s booking rules, and Power Apps would have needed Premium licences plus custom code for the hard parts. As part of the Application Team, I designed, developed, and piloted an internal booking app to close that gap.

The approach

A web app that books client appointments directly into each therapist’s own Outlook calendar. Before it offers a time, it checks working hours, Outlook busy time, staff time off, and WA public holidays; it prevents double bookings; and it keeps client data in the organisation’s own database.

Flow diagram: an advisor picks a client and service, then a time and repeat pattern; each date is checked against working hours, Outlook free/busy, staff time off and WA public holidays; free dates are booked in a locked database transaction, which creates a private Outlook event in the therapist's calendar and sends a confirmation email with an .ics attachment. If Outlook can't be read, no times are offered.
Booking flow: every date is availability-checked before a locked transaction writes it to the database and Outlook.

The app in pilot

Home dashboard: stat tiles for today, this week, booked hours and items needing attention; a bar chart of this week by day; bars by service; today's schedule and a staff table.
Home dashboard — stat tiles, this week by day and by service, today's schedule and staff load.
Appointments calendar in Day by staff view, with a colour-coded column per staff member, staff filters, view switcher, print and export.
Team calendar in "Day by staff" view, with a colour per staff member and time off shown as hatched blocks.
Appointments screen on a phone: view switcher, staff filter chips and a list of the week's appointments.
Responsive on phones.
Add time off dialog with staff member, all-day option, from and to dates, and an optional general reason.
Staff time off blocks booking just like Outlook busy time.

Screenshots from the pilot — all client and staff names are made-up test data.

Key features

  • Four-step booking — client and service → time → repeat → review, with a live summary.
  • Recurring series — weekly, fortnightly, or monthly, up to 52 dates, each checked individually.
  • Team calendar in six views (List, Day, Day by staff, Work week, Week, Month) with a colour per staff member, drag-and-drop rescheduling with preview and confirmation, click-an-empty-slot booking, and print and CSV export.
  • Smart booking from the calendar — if a clicked time isn’t free, the app explains why and offers the nearest free times.
  • Staff time off that blocks booking just like Outlook busy time.
  • Home dashboard with stat tiles, charts by day and by service, today’s schedule, and a staff table.
  • Appointment record with status badges, the whole series, a full change history, and change/cancel actions.
  • Read-only “My appointments” calendar for therapists.
  • Admin settings — staff, working hours and booking readiness; a staff × services assignment grid; services, clients, users and roles; WA public holiday import; email templates with live preview; email settings with an outbox/log; and a “Needs attention” queue for Outlook failures with Retry.
  • Responsive and accessible (WCAG 2.2 AA) — works on phones, keyboard and screen-reader friendly, and follows the organisation’s brand guidelines.

Technology stack

Layer Technologies Role
Front end React 18, TypeScript, Vite, CSS design tokens Single-page app with its own lightweight router — every screen has an address
Back end Node.js 24, Express, TypeScript API with role checks and validation; serves the web app
Domain logic Separate TypeScript package, luxon Perth time zone, recurrence, availability, and conflict rules — no I/O, fully tested
Data SQL Server (production), SQLite (pilot), in-memory (demos) Three swappable data layers behind one interface; plain SQL migrations
Microsoft 365 MSAL Node, Microsoft Graph Single sign-on, Outlook free/busy, calendar events, email
Quality zod, Vitest, supertest, ESLint, Playwright Input validation, 173 automated tests, linting, browser checks
Structure npm workspaces monorepo Web app, API, and core domain package

Microsoft Entra ID and single sign-on

  • Registered a single-tenant app in Microsoft Entra ID with a Web platform, redirect and post-logout URIs, and a client secret kept in server-side configuration — never in source control.
  • Granted delegated Microsoft Graph permissions (openid, profile, email, offline_access, User.Read, User.ReadBasic.All, Calendars.ReadWrite, Calendars.ReadWrite.Shared) with organisation-wide admin consent.
  • Implemented the authorization code flow with PKCE through MSAL Node and a server-side session. The session cookie is signed, httpOnly, and SameSite, and state-changing requests have their Origin checked. Tokens stay on the server — never sent to the browser or written to logs.
  • Swappable sign-in: a localhost-only test-user picker for demos, and Microsoft sign-in for the pilot.
  • Learnt to diagnose Entra sign-in errors — AADSTS65001 (consent pending) and AADSTS50105 (user not assigned to the app).

Users, roles, and calendar access

  • Three roles — Admin, Scheduler (advisors), and Staff (therapists) — enforced on the server for every request.
  • Users are created automatically on first sign-in; nominated pilot admins become Admin, and everyone else starts as Staff until an Admin changes their role.
  • Pilot: Outlook delegate access (Editor, including private items).
  • Planned for go-live: Graph application permissions scoped to an IT-managed security group of bookable staff via Exchange Online RBAC for Applications, so staff never have to share calendars.

Email

  • Three delivery modes — an in-app outbox only, sent as the signed-in user via Graph, or sent from a shared mailbox with app-only credentials — plus a safety redirect that routes all test mail to one inbox.
  • Confirmation, change, cancellation, and reminder emails with .ics calendar attachments and configurable reminder timing.
  • Admin-editable templates with live preview, sanitised to block unsafe HTML.
  • Client email consent is respected: no consent, no email.

Security and privacy

  • Booking rules are enforced on the server; nobody gets direct database access.
  • Every query is parameterised and every input validated.
  • Double bookings are prevented with a locked database transaction.
  • Fails safe — if Outlook can’t be read, no times are offered.
  • Outlook events show only the client’s first name, the service, and a reference, and are marked Private (configurable).
  • A full audit history of who booked, changed, or cancelled.

Problems I solved

  • Outlook “access denied” despite a passing access check. Added logging of Microsoft’s error codes, traced the failure to Exchange refusing private events from delegates, and fixed it by having the staff member allow the delegate to see private items — plus a setting to turn private events off.
  • Time off made the whole calendar look unavailable. Fixed how time off was merged with Outlook busy time and added a regression test.
  • Assigning services was slow, one staff member at a time. Replaced it with a single staff × services grid that saves all changes at once.

Engineering practices

  • 25 architecture decision records explaining key choices, plus change summaries and future-phase plans.
  • An AI-agent-ready repository — project instructions, agent rules, and a brand/UI skill — so AI coding assistants follow the project’s conventions.
  • Brand-compliant UI checked at phone and laptop widths, and a pilot presentation built on the corporate PowerPoint template.

Developed with AI-assisted coding (Claude Code), with all design decisions, testing, and Microsoft 365 configuration directed by me.

Outcome

The pilot is running with real Microsoft 365 sign-in and staff Outlook calendars, and the go-live roadmap has been approved for presentation. Next steps on that roadmap:

  • IT-managed calendar access — app permissions limited to one security group.
  • Client data from Salesforce — a nightly sync from the Microsoft Fabric data warehouse.
  • Microsoft 365 Copilot agent — advisors book by asking in Teams or Outlook, with the app still enforcing every rule.
  • Hosting — Azure App Service with Azure SQL Database in Australia East, estimated at about AUD 30–35 a month.

Let’s build something that works

Open to systems and automation roles and projects in Perth, WA, and to project work through WiTEDS — apps, automation and Microsoft 365.