Medspa architecture and workflows
Keystone schema by domain, the booking-to-checkout lifecycle, clinical gates, named GraphQL operations, and role capabilities.
Architecture
| Layer | Location | Role |
|---|---|---|
| Keystone schema | features/keystone/models/** | 98 lists, all scoped to a Practice |
| Workflow mutations and projections | features/keystone/mutations/**, features/keystone/extendGraphqlSchema/** | Named GraphQL operations registered in features/keystone/mutations/index.ts |
| Access | features/keystone/access.ts, features/keystone/models/tenantAccess.ts | Capability checks and practice tenancy |
| Operator dashboard | features/dashboard (shell), features/platform (Medspa workspaces), app/dashboard/** (routes) | Staff UI |
| Storefront | features/storefront, app/(storefront)/(main)/** | Client UI |
| Payments | features/integrations/payment | Manual and Stripe adapters |
Almost every list is write-locked. The lists with direct GraphQL CRUD are Service, ServiceCategory, ServiceVariant, MedSpaImage, WidgetConfiguration (canManagePractice), Vendor (canManageInventory), MessageTemplate (canManageCommunications), and PaymentProvider (canManageIntegrations). Practice and User allow updates only. Everything else is written by a named mutation or as a side effect of one, and a dashboard page for those lists must call the mutation rather than create<List>.
Data model
- Practice and access:
Practice(tenant),Location,StorefrontSetting,WidgetConfiguration,User,Role,StaffInvitation,PracticeMembership,Provider,AuditEvent. - Catalog:
ServiceCategory,Service(duration, price, deposit, cleanup buffer, and flags such asrequiresConsultation,requiresIntakeReview,staffAuthorizationRequired,requiresLotTraceability),ServiceVariant,MedSpaImage,Resource(rooms and devices with a readiness status),ResourceScheduleBlock,DeviceReadinessEvent. - Availability and booking:
ProviderSchedule(recurring, one-time, time off),Client,Appointment,AppointmentLineItem(service snapshot),AppointmentResourceReservation,AppointmentSupervisorReservation,WaitlistEntry. - Clinical record:
IntakeForm,FormTemplate,FormSubmission,IntakeReviewAction,Consultation,ContraindicationFinding,ContraindicationDecision,TreatmentPlan,TreatmentPlanItem,ClinicalOrder,ClinicalOrderAction,ConsentTemplateVersion,ConsentRecord,ConsentAction,TreatmentSession,TreatmentAdministration,AdministrationLot,ClientNote,ClientAsset,AssetAccessEvent,PhotoConsent,PhotoConsentAction,ProviderCredential,ProviderAuthorization,ClinicalAuthorityEvent,FollowUpTask,FollowUpAction. - Money and benefits:
MedSpaTransaction,MedSpaTransactionLineItem,Payment,PaymentSession,Refund,PaymentProvider,PaymentWebhookEvent,WebhookInbox,Commission,GiftCard,GiftCardTransaction,Membership,ClientMembership,MembershipAgreement,MembershipLedgerEntry,ServicePackage,ClientPackage,ClientPackageUsage,ClientPackageAdjustment, and the schema-onlyLoyaltyProgram,ClientPoints,Referral. - Inventory:
Product,Vendor,PurchaseOrder,PurchaseOrderLine,GoodsReceipt,GoodsReceiptLine,InventoryLot,StockMovement(lot level),InventoryMovement(product level), and the legacyProductSale. - Safety and governance:
Incident,IncidentAction,RecallCase,RecallExposure,RecallAction,PatientRightsRequest,PatientRightsAction,LegalHold,RetentionPolicy,BreakGlassEvent. - Communications and system:
MessageTemplate,MessageLog,Review,DomainEvent,OutboxEvent.
The repository's docs/schema-map.md lists each model's key fields, who creates it, and its states.
Booking to checkout workflow
- Book. A client books on the storefront, or staff book from
/dashboard/platform/appointments/new.bookAppointmentchecks availability, creates theClientandUserif needed, theAppointmentinpending,AppointmentLineItemsnapshots, and room, device, and supervisor reservations. A guest booking returns a link token that lets the guest view and cancel that request (storefrontAppointment,cancelGuestAppointment). No payment is taken at booking. - Waitlist. Demand without a slot goes to
WaitlistEntrythroughjoinWaitlist(staff) orrequestWaitlistSpot(storefront). Entries moveactivetonotifiedtoconvertedorremovedthroughtransitionWaitlistEntry. - Confirm and arrive.
transitionAppointmentallowspendingtoconfirmed,cancelled, orno_show;confirmedtoin_progress,cancelled, orno_show; andin_progresstocancelled. Changes are revision-checked. - Intake. The client submits intake from
/account/intake/[appointmentId]or staff record it (submitIntake). Clinical staff review it withreviewIntake(submitted,in_review,reviewed,superseded). - Check out.
completeAppointmentCheckoutaccepts aconfirmedorin_progressappointment, applies membership, package, and manual discounts, retail lines, tip, and tax, records theMedSpaTransaction,Payment, andPaymentSession, writes retailInventoryMovementandCommissionrecords, and sets the appointment tocompleted. Current checkout supports operator-recorded cash only. - Aftercare.
scheduleFollowUpcreates aFollowUpTask; staff append actions and clients reply withsubmitFollowUpResponse. Clients can review a completed visit withsubmitAppointmentReview, and staff approve or hide reviews withmoderateReview.
Clinical treatment workflow
Treatments flagged as clinical pass through recorded gates before execution. The treatment workspace at /dashboard/platform/appointments/[id]/treatment drives these mutations:
recordConsultationrecords the assessment and candidacy (candidate,deferred,declined,referred).recordContraindicationFindinganddecideContraindicationrecord rule hits and the clinician's disposition.approveTreatmentPlancreates theTreatmentPlanand items (draft,active,paused,completed,cancelled).issueClinicalOrderauthorizes a performer;transitionClinicalOrdermoves it throughactive,partially_fulfilled,fulfilled,held,revoked,expired, orentered_in_error.signTreatmentConsentrecords consent against a publishedConsentTemplateVersion(publishConsentTemplate);withdrawTreatmentConsentwithdraws it.prepareTreatmentSessionandstartTreatmentSessionmove theTreatmentSessionfromplannedtoreadytoin_progress.recordTreatmentAdministrationrecords what was administered and, for lot-traced products, theAdministrationLotandStockMovement.appendSignedClinicalNoteadds an append-only, supersedableClientNote.
Before a session can run, features/keystone/mutations/clinicalExecutionReadiness.ts checks that the exact approved plan, item, and consultation still authorize the booked encounter; that a current clinical order and matching consent exist; that current reviewed intake covers every required template version; that no contraindication review blocks treatment; that the session falls inside the appointment window; and that no required resource has an overlapping maintenance or unavailable block. Provider credentials (registerProviderCredential) and per-treatment, per-location authority (configureProviderAuthorization, transitionProviderAuthority) are checked separately.
These checks confirm that records exist and match. They do not verify a license with an issuing board, judge clinical appropriateness, or replace the supervising clinician.
Other operator workflows
- Staff:
upsertAccessRole,inviteStaff,acceptStaffInvitation,createProviderProfile,updateProviderProfile. - Practice setup:
upsertLocation,upsertResource,setResourceAvailability,transitionDeviceReadiness,upsertProviderSchedule,setProviderScheduleAvailability,scheduleAppointmentResources,publishStorefrontSettings. - Forms:
upsertIntakeForm,upsertFormTemplate,publishConsentTemplate. - Benefits:
upsertMembershipPlan,enrollClientMembership,acceptMembershipAgreement,transitionMembership,upsertServicePackage,sellClientPackage,redeemClientPackage,reverseClientPackageUsage,issueGiftCard,applyGiftCardBalance. - Inventory:
upsertProduct,draftPurchaseOrder,transitionPurchaseOrder(draft,submitted,partially_received,received,cancelled),receivePurchaseOrder(createsGoodsReceiptandInventoryLotrecords),dispositionInventoryLot,returnRetailLot,adjustMedSpaInventory. - Money:
refundPayment,distributeTip,payoutCommissions. - Clients:
updateClientProfile. - Safety:
reportIncident,appendIncidentAction,openRecallCase,appendRecallAction. - Privacy:
requestPatientRights,appendPatientRightsAction,placeLegalHold,releaseLegalHold,publishRetentionPolicy,openBreakGlass. - Clinical assets:
grantPhotoConsent,withdrawPhotoConsent,createClinicalAssetIntent,markClinicalAssetReady,authorizeClinicalAssetAccess,releaseClinicalAsset,tombstoneClinicalAsset.
Custom GraphQL queries
- Storefront:
publicStorefrontSettings,storefrontServices,storefrontProviders,storefrontProvider,checkAvailability,storefrontReviews,storefrontAppointment,clientPortal,clientIntakeForms. - Operator projections:
medspaOperationsWorkspace,medspaAppointmentSchedule,medspaAppointmentClinicalHeader,medspaPlanJourney,medspaConsultationQueue,medspaClientDirectory,medspaClientRecord,medspaWaitlistBoard,medspaMessageLog,medspaReviewBoard,calculateCommission. - Auth:
registerCustomerplus Keystone's password authentication and reset mutations.
Mutations that change money or clinical state take an idempotency key and, where relevant, a record revision, and many run in serializable transactions (serializableWorkflow.ts).
Roles and access control
Each Role carries these capabilities: canManagePeople, canManageRoles, canAccessDashboard, canManageOnboarding, canManagePractice, canSchedule, canReadClients, canManageClinical, canManageSensitiveRecords, canManageInventory, canManageFinance, canManageCommunications, canViewReports, and canManageIntegrations.
Access checks re-read the user and role on each request and deny access when the user is disabled, has moved practice, or the role no longer grants the flag carried in the session. Clinical and governance lists (ClientNote, consent, incidents, patient rights, legal holds) require canManageClinical or canManageSensitiveRecords rather than general dashboard access.