DesignDevelopmentBackendIntegrationsMaintenanceConsulting
01
Clinic SaaS

Callidus OS

Multi-tenant SaaS that replaced a failed FlutterFlow attempt — UK aesthetic clinics, shipped solo in six weeks.

See live website

Introduction

Callidus OS is a multi-tenant SaaS platform built for UK aesthetic clinics — scheduling, patient records, consent forms, invoicing, and patient deposits collected directly through each clinic's own Stripe account. I built the entire platform solo from design to production deploy in roughly six weeks, inheriting a previously-failed FlutterFlow attempt with approximately 200 unresolved errors and rebuilding the whole thing on React, TypeScript, and Firebase.

Background

Callidus is the software company. The product is sold as a monthly subscription to independent UK aesthetic clinics — each clinic becomes a tenant in a strictly-isolated multi-tenant system. Every clinic has its own staff, patients, appointments, consent forms, and Stripe account. Pricing is kept deliberately accessible: £15/month on the Starter plan, £50/month on the Aesthetics plan, with a seat add-on at £25/month per extra user on a 0-to-50 range, plus a 14-day free trial.

I was introduced through a Discord community. The founder had tried to build the app in FlutterFlow first — ended up with three or four Firestore collections, a written plan document, and hundreds of unresolved errors. We agreed to start again from scratch on a real stack. I handled the design concept in Google Stitch before a line of code, then moved into implementation.

The Challenge

Five problems shaped the whole project.

Face mapping had no off-the-shelf solution. Aesthetic clinics need clinical-grade face diagrams where practitioners mark injection sites with dose and product, then attach the annotated diagram to a patient record. Nothing on the market fit the workflow. The editor had to be built from scratch.

Patient deposits had to flow to each clinic's own Stripe account, not Callidus'. Each clinic is the legal merchant-of-record for medical services they perform. Pooling deposits on Callidus' account would transfer liability in the wrong direction. This meant Stripe Connect Standard with Direct Charges, per-tenant Connect onboarding, application-fee logic, the full webhook matrix including 3D Secure escalation, and regulatory isolation baked into every flow.

Six roles had to coexist without drift. Super admin, owner, admin, manager, practitioner, receptionist — each with distinct access to clinical data, financial data, settings, and billing. Inline role checks rot the moment the matrix changes. The codebase is built around role helpers (hasClinicalAccess, hasManagerAccess, hasAdminAccess) so every access gate stays consistent.

Clinics had to embed a booking widget on their own marketing sites. That meant Shadow DOM isolation, an unhashed bundle name for stability across deploys, a Service Worker with NetworkOnly strategy for Firebase and Stripe to stay GDPR-compliant, tenant binding by slug, and a scroll-trap fix for iframe behaviour on arbitrary host pages.

Trial-to-active-to-suspended had to run itself. A 14-day trial with a four-stage email and grace lifecycle: 3-day reminder, 1-day reminder, expiry with a 3-day grace window, then suspension. Payment escalation for active tenants running past due. Grace-period mutations blocked server-side, pages viewable but writes refused — belt-and-braces between client route gates and Firestore rules.

Our Solution

Custom face mapping editor. Built on react-konva with a canvas model that stores annotations as positioned markers tied to a patient ID. Injection markers carry dose, product, and timestamp. The output serializes to Firestore and rehydrates into the editor on reload.

Stripe Connect Standard with Direct Charges. Each clinic onboards its own Stripe account. Patient deposits collected at the booking widget flow to the clinic directly; Callidus takes a 0.1% application fee. Twenty webhook events are handled end-to-end, including customer.subscription.trial_will_end, invoice.payment_action_required (which triggers 3D Secure escalation and emails the owner a hosted invoice URL), and the full checkout → subscription → cancellation flow. Annual pricing blocks promo codes via an explicit ANNUAL_PRICE_IDS allowlist to prevent 100%-off abuse.

Multi-tenant architecture with role helpers. Everything lives under tenants/{tenantId}/… in Firestore. JWT claims carry tenantId and role. All mutations are gated by a !isTenantArchived() guard in the Firestore rules. Access helpers replace inline role checks everywhere — changes to the access matrix ripple consistently instead of drifting.

Embeddable booking widget with widget isolation. Shadow DOM portal, unhashed bundle path, Service Worker scoped only to the widget path, NetworkOnly for Firebase and Stripe to satisfy GDPR, tenant bound by slug via a strict regex. The widget scroll-trap fix lives in a standalone overlay script that works across any host page.

Four-stage subscription lifecycle. Coordinator Cloud Function runs daily at 09:00 UTC and fans out one Cloud Task per trialing tenant. The pipeline is 3-day email → 1-day email → expiry with 3-day grace → suspension. A second scheduled function at 09:30 UTC escalates payment-failed tenants. During grace period, pages viewable but mutations blocked at both route and Firestore rules layers — no single-layer bypass.

Supporting systems. Calia AI chat on Vertex AI Gemini 2.5 Flash with thirteen injection regex patterns, 30/100-per-hour rate limits, and a 90-day GDPR cleanup. Native TOTP MFA, no SMS. Single-session enforcement: log in on device B and device A's session ends. Audit logging with three-tier TTL retention (90 days routine, 1 year financial, 2 years GDPR-sensitive; PATIENT_DATA_ERASED has no expiry). Public booking and consent endpoints guarded by App Check. Sentry in strict GDPR mode: sendDefaultPii: false, Replay masks all text, blocks all media, masks all inputs.

Outcome

Callidus shipped to production after six weeks of solo work, replacing the failed FlutterFlow attempt. As of late April 2026 the platform has twenty clinics on the waitlist, three clinics with accounts created, and one clinic running real production data — appointments booked, patients managed, invoicing flowing end-to-end.

The codebase runs to roughly 426 KB gzipped across 37 lazy routes and 17 manual chunks, with progressive loading throughout — no full-page skeletons, chrome renders immediately, per-section loaders only where data is arriving. Test coverage runs to approximately 1,058 Vitest tests, 72 Playwright end-to-end scenarios, and 100% coverage of Firestore rules.

A marketing module, Calia AI Pro tier, vouchers, waitlist auto-schedule, and several integration surfaces (accounting, SMS via Twilio, reviews, finance) are on the roadmap. I'm maintaining the platform in production under an ongoing engagement.

Conclusion

Callidus proves two things at once. First: a solo developer with the right stack can ship a real-world multi-tenant SaaS in six weeks — one that handles GDPR, Stripe Connect, regulatory isolation, and a bespoke clinical feature nobody else offers. Second: inherited project debt doesn't have to survive the rewrite. The fastest way to recover from 200 FlutterFlow errors was to drop FlutterFlow.

The platform ships, it's live, it's growing. Everything else is iteration.

More live work

More live work