Openfront Medspa
Self-hosted medical-aesthetics booking, treatment authority, consent, checkout, inventory, memberships, and practice operations.
Openfront Medspa is a self-hosted booking and practice-operations application for medical-aesthetics practices. Clients browse treatments and providers, request appointments, complete intake, and manage visits on a public storefront. Practice staff run the day sheet, consultations, treatment plans, clinical orders, consent, treatment sessions, checkout, inventory, memberships, packages, gift cards, commissions, safety cases, and privacy requests from the operator dashboard.
The source lives at github.com/openshiporg/openfront-medspa. A hosted demo runs at medspa.openship.org.
Openfront Medspa does not license a practice, credential providers, grant prescribing or treatment authority, or provide regulatory approval. It is not documented as HIPAA compliant or certified for any medical-records, payment, or device standard. Recorded credentials, authorizations, consents, and readiness checks are application records; the practice remains responsible for verifying them and for every clinical decision.
What the codebase contains
- Architecture: Next.js 16 App Router with React 19, Keystone 6 with a GraphQL API at
/api/graphql, Prisma, and PostgreSQL. The Keystone schema has 98 lists infeatures/keystone/models/**and about 90 named workflow mutations infeatures/keystone/mutations/**. - Write model: almost every list is write-locked (
create,update, anddeletereturnfalse). Business writes go through named mutations that check the actor, practice scope, record revision, and idempotency key. Only a small set of configuration lists (services, categories, variants, vendors, message templates, payment providers, catalog images, widget configuration) allow direct CRUD to roles with the matching capability. - Operator surfaces: 22 platform workspaces under
/dashboard/platform/*(appointments, treatment delivery, checkout, clients, staff, schedules, rooms and devices, inventory, benefits, forms and consent, safety, privacy, payments, commissions, reports, integrations, and more), plus the generic Keystone list screens at/dashboard/[listKey]. - Storefront: public routes for services, providers, team, booking, booking confirmation, client account, intake, appointments, reviews, gallery, contact, and gift cards, implemented in
features/storefront. - Onboarding: a dashboard onboarding dialog runs the
runMedSpaOnboardingmutation with a sample, minimal, or custom setup fromfeatures/platform/onboarding/lib/seed.json.
Getting started
Requirements, environment, migrations, first operator, onboarding, and deployment.
Architecture and workflows
Data model, booking-to-checkout lifecycle, clinical gates, GraphQL operations, and roles.
External dashboard
Platform pages and the skill for building a custom operator dashboard.
External storefront
Customer routes, journeys, and the skill for building a custom storefront.
Integrations and boundaries
Payment adapters, webhooks, SMTP, S3 storage, AI, and MCP status.
Current limitations
What the current source does not do.
Ownership and tenancy
Practice is the tenant. Every list carries a practice relationship, and features/keystone/models/tenantAccess.ts scopes reads to the signed-in user's practice, fills the practice on create from the authenticated actor, and rejects writes that connect or move a record to another practice, including through inverse relationships. Location is the clinic site; staff PracticeMembership records and provider schedules are scoped to locations.
Access is capability-based. Each user has one Role with 14 flags, and features/keystone/access.ts re-reads the user and role from the database on each check, so a disabled user or a changed role loses access immediately. Practice ownership or dashboard access is not a claim of clinical licensure: clinical execution additionally requires a verified ProviderCredential and an active ProviderAuthorization for the treatment and location.
The public storefront serves one practice: the one pinned by MEDSPA_PRACTICE_SLUG, or otherwise the single active practice with a published StorefrontSetting. If several practices are published and none is pinned, the storefront resolves no practice.