Platform Glossary
Single source of truth for terminology. Every term used in code, docs, or UI lands here with a one-line definition and the architectural category it belongs to.
Authority. Where the codebase, comments, or other docs disagree with this glossary, the glossary wins and the divergence is a rename target — not a competing definition. The taxonomy here is what we are building toward; drift gets corrected, not accommodated.
Scope. Cross-cutting terms that span multiple features or layers. Domain-specific terms that only matter inside one feature live in that feature's own docs. The test for inclusion: would mis-defining this term cause confusion across two or more files?
How to read this doc
- Each term has a one-line definition followed by a pointer to the canonical deep doc.
- Bracketed tags
[arch],[domain],[compliance], etc., classify the term. - The Forbidden terms section at the end is the enforcement teeth — any usage of a forbidden term in new code or docs is a rename target.
Architectural building blocks
These define how every feature in the platform is structured.
Capability [arch] An internal Go interface that does one bounded thing, with a stable contract. The unit of architecture the platform is built from. Examples: email.Channel, video.Provider, pdf.Renderer, ai.LLM, webhook.Deliverer. Lives in internal/core/{name}/. Has a stable interface, a swappable implementation strategy, and standard hooks for audit, metering, permission gating, and error classification.
Feature [arch] User-facing functionality, composed of one or more capabilities. What the user sees, what the marketing page lists, what the changelog announces. Has UI surfaces in clinic, portal, or console. Built ON TOP of capabilities — never IS a capability. Examples: telerehab session, appointment booking, treatment plan editor, AI clinical drafting, webhook subscriptions marketplace.
Entitlement [arch] [billing] What the platform sells per plan/tier — gates access to features (boolean gates) and sets quotas (numeric limits). The umbrella covers two parallel families in the schema, both conceptually entitlements but kept distinct because their runtime semantics differ:
Boolean family ("is X enabled?") — renamed in 1C.9:
entitlements— catalog of boolean entitlements (e.g.,telerehab_enabled,ai_assistant,custom_domain).tier_entitlements— which plans grant which entitlements.organization_entitlements— per-org current state, including overrides above the plan's defaults.
The snapshot tables that ride alongside subscriptions follow the same naming: organization_subscription_entitlements, patient_tier_entitlements, patient_subscription_entitlements. The Go gates that read these tables are middleware.RequireTierEntitlement (plan-level) and middleware.RequireOrgEntitlement (regulated org-level projection); on principal.Subject, the corresponding methods are HasTierEntitlement and HasOrgEntitlement.
Quota family ("how many X allowed?") — unchanged in 1C.9, no rename:
limit_definitions— catalog of quota entitlements (e.g.,max_emails_per_month,max_locations,max_webhook_subscriptions).tier_limits— which plans grant which quotas with what value.organization_subscription_limits— per-org snapshot of quota grants.organization_subscription_overrides— per-org per-quota adjustments above plan defaults.
The Go gate is middleware.EnforceLimit(code) which reads from organization_subscription_limits (or its overrides). At runtime, the metering layer (1C.7) reads the same source to populate usage_quotas.limit_units for live counter checks.
Why two families instead of one merged table: boolean entitlements gate via binary check (return 402 if disabled); quotas gate via counter check (return 402 if exceeded). Different code paths; clean schema split mirrors that. The boolean half got renamed because features/capabilities collided with architectural words ("Feature" = user-facing functionality, "Capability" = internal Go interface). The quota half uses limits, which doesn't collide with anything architectural — no rename needed.
Implementation strategy [arch] How a capability is implemented. Not a thing on its own — a description of where the work happens. Five flavors:
- Internal Library — pure Go code in our process, no external calls. Examples: PDF rendering, HMAC signing, encryption helpers, JSON schema validation.
- Curated Provider (Cat A) — external API call with platform-owned credentials. Examples: SES for email, Daily.co for video, Anthropic for LLM. Clinic never sees the provider name; switchable behind the capability interface.
- Connected Account (Cat B) — external API call with clinic-owned credentials, configured by clinic admin via OAuth or API key. Examples: Google Calendar, Slack, HubSpot, Salesforce.
- Outbound Webhook (Cat C) — POST to a clinic-configured URL with a signed payload. Examples: Make.com scenario URL, Zapier webhook, custom clinic backend.
- In-browser code — runs on the patient's device, returns a value to our API like any other input. Examples: TensorFlow.js posture analysis, MediaPipe goniometer.
A capability picks one strategy or composes several. The same capability may have multiple Curated Provider impls (e.g., ai.LLM could route to Anthropic or OpenAI), selected at runtime by config.
Implementation-strategy code identifiers (the internal/core/capabilities wrap helpers) follow the same axis: Curated Provider impl strategy is wrapped by WrapProvider (unmetered) or WrapMeteredProvider (metered); Outbound Webhook by WrapOutbound; Internal Library by WrapInternal. Connected Account and In-browser code don't have wrap helpers — Cat B credentials are platform-resolved on a separate per-org code path, and In-browser code runs on the client and returns a value through the regular API surface.
Integration [arch] External system touchpoint. An umbrella term covering the five external categories: Curated Provider (Cat A), Connected Account (Cat B), Outbound Webhook (Cat C), Inbound Webhook (Cat D), External API Access (Cat F). Internal Events (Cat E) are NOT integrations — they're internal.
Internal Library [arch] A Go package that implements a capability with no external API calls. Pure code in our process.
Principal-type-agnostic primitive [arch] Cross-cutting design property that every foundation primitive (capability framework, metering, audit, quotas, RLS, permissions, events) treats all principal types the same — humans, agents, service_accounts, and the system principal flow through identical code paths. Audit attribution carries actor_id + actor_type for observability; the primitive's behavior does NOT branch on actor type.
Rationale: the platform supports four principal types (1B.1) and any of them may trigger any operation in principle (a clinic admin sends an invitation; an AI agent generates a treatment plan draft; a service_account syncs patients via Cat F API access; the system principal runs a scheduled cron). If primitives accidentally hardcoded "human" assumptions, agent and service_account flows would silently fail to audit / meter / authorize correctly when they light up.
How to apply: when designing or reviewing a foundation primitive, ask "would this work the same way if the actor were an agent or service_account?" If not, the primitive has a hidden human assumption that needs surfacing. This property is enforceable via integration tests that run the same operation as different principal types and assert identical observable behavior.
Exceptions are explicit and documented (e.g., OAuth flows in 1C.5 require human consent because the dance involves a browser redirect — call this out where it occurs). Default state is principal-type-agnostic.
Integration categories
The six distinct categories of touchpoints (five external + one internal). Confusing them is a common source of design drift.
Cat A — Curated Provider [arch] [integration] External service we depend on, with platform-owned credentials. Clinic never sees the provider name. Switchable behind a capability interface (s.email.Send(...) not s.ses.Send(...)). Credentials in env / Secrets Manager + the foundation provider-resolution table (platform_service_providers) for per-org overrides (e.g., SES sender identity, Twilio sender ID, Daily.co subdomain — available on either tenancy mode as a paid customisation). Examples: SES, Daily.co, Twilio, Anthropic, Stripe, AWS S3, Clerk, KMS.
Cat B — Connected Account [arch] [integration] External service the clinic admin connects via OAuth or API key. Clinic owns the credentials; we call the third party's API on the clinic's behalf. Lives in organization_integrations table (per-org instance rows referencing the platform-defined integration_services catalog). Examples: Google Calendar, Microsoft 365, Slack, HubSpot, Salesforce, future EHRs.
Cat C — Outbound Webhook Subscription [arch] [integration] Clinic configures a URL + signing secret + event-type filter. We POST signed payloads to that URL when matching events fire on events.Bus. The same row type whether the URL points at Make.com, Zapier, n8n, a custom clinic backend, or a Slack incoming webhook — they're all just URLs to us.
Cat D — Inbound Webhook [arch] [integration] Third party POSTs to one of our /webhooks/{provider} endpoints. We verify signature per provider's scheme, update internal state, and emit Internal Events. Examples: Stripe payment_intent.succeeded, SES bounce/complaint notifications, Daily.co recording.ready, Clerk user lifecycle, Google Calendar push notifications.
Cat E — Internal Event [arch] Domain event fired on events.Bus (1A.9) when state changes. Internal-only — no network call. Subscribers include the audit log, the notification dispatcher, the outbound webhook dispatcher, the automations engine, and future AI agent action logs. Single canonical event registry; webhook docs and automation triggers reference the same registry.
Cat F — External API Access [arch] [integration] External systems calling our REST API as authenticated principals via service-account API keys. Direction is them → us, but distinct from Cat D (which is webhook-shaped notifications). Cat F is full CRUD: an external system (clinic's custom backend, Zapier with action steps that fetch data, EHR sync, partner integration) authenticates with Authorization: Bearer sa_live_..., our auth middleware resolves the key to a principals.id (subtype service_account), and the request flows through normal RBAC + RLS like any other authenticated call. The service_accounts table (1B.1, schema shipped) holds these principal records. Operational flow (key creation, revoke, rotation, admin UI, per-key scoping) is documented in foundation.md → Deferred Foundation Extensions; ships when first concrete external system needs it. Don't confuse with integration_services (Cat B catalog) — that's the menu of "services we connect TO"; Cat F is "actors who call IN to us."
Identity & tenancy
The actor and tenancy model. See decisions.md → Why principals as the root identity for full rationale.
Principal [identity] The root identity in the system. Every actor — human, AI agent, integration service account, scheduled system job — is a row in principals. There is no users table.
Human [identity] A principal subtype representing a person. Profile data (name, email, timezone) lives in humans (PK = principal_id). Patient identity, caregiver, specialist account — all live here.
Agent [identity] A principal subtype representing an AI agent. First-class actor with its own audit trail, permissions, and RLS scope. See ai-agents-runtime.md. Future feature surface; primitive shipped at 1B.6.
Service Account [identity] A principal subtype representing a non-human integration actor (system jobs, API integrations).
Organization (Org / Clinic / Tenant) [identity] [tenancy] The multi-tenant boundary. Every clinic-owned table has organization_id. Patients can hold memberships in multiple orgs. The clinic is the GDPR data controller; the platform is the processor.
Location [identity] [tenancy] Physical/logical site within an organization. One org has one or more locations. Used by scheduling and operational segregation. See 1B.14.
Membership [identity] A principal's relationship with an organization, captured in organization_memberships. Carries a role assignment.
Permission [identity] [security] A per-organization gate code (patients.read, appointments.write, etc.). All authorization decisions go through permission codes — never role-string compares. See reference/rbac-permissions.md.
Role [identity] [security] A bundle of permissions. Roles are per-org; system role templates seed new orgs.
Superadmin [identity] [security] Platform-level role granted via platform_memberships. Human-only by CHECK constraint. Bypasses RLS. Reserved for the platform team. Not a tenant role.
Break-glass [identity] [security] [compliance] Time-bound elevated cross-org access for support, time-limited, justified, audited, with always-on clinic notification. The pattern that lets identifiable cross-tenant access happen without joint-controllership risk. See 1B.11.
Clinical domain
Terms that describe what the platform does for clinics and patients.
Offering [domain] A clinical service the clinic offers patients (e.g., "Initial Assessment," "Group Class," "Follow-up Consultation"). Each has a definition, pricing structure, capacity, and may include treatment plans or appointments. Replaces the previous "service" naming.
Enrollment [domain] A specific patient's instance of an Offering — the row that represents "this patient is enrolled in Offering X at this clinic." Tracks state (active, completed, paused, cancelled), session counts, dates, and links to appointments / treatment plans generated from the offering. Replaces the previous service_plan naming.
Rename deferral
The taxonomy is locked: Offering and Enrollment are the canonical terms. The actual rename of apps/docs/features/services/, the services / service_plans DB tables, and any related Go domain code is deferred until this area is built. No preemptive sweep. Existing references to service / service_plan in those scopes are tagged for rename-on-build, not rename-now. Architectural code added in the meantime never uses the old terms.
Appointment [domain] A scheduled session between a patient and a specialist (or a group session). Has a start/end time, a location or video room, and a state machine (scheduled / started / completed / canceled / noshow).
Treatment Plan [domain] A prescriptive document a specialist creates for a patient — exercises, instructions, schedule. Distinct from an Offering (which is the catalog item) and from an Appointment (which is the scheduled session). Treatment plans require a specialist signature and are immutable once signed.
Form [domain] A questionnaire — intake, clinical, consent, custom — completed by a patient or specialist. Signed forms are immutable.
Patient Profile [domain] Patient's portable, patient-owned identity (patient_profiles — no organization_id). Same row visible at every clinic the patient is enrolled at, propagating updates without per-org duplication. See P6.
Patient (per-clinic record) [domain] A patient's per-clinic clinical identity (patients). Holds clinical state scoped to one clinic — distinct from the portable Patient Profile.
Consent [domain] [compliance] A per-patient, per-org, per-purpose grant or withdrawal recorded in consents. Consent at Clinic A does not extend to Clinic B. Self-withdrawable purposes (marketing, profile-sharing) toggle per-row.
Profile sharing [domain] Patient grants Clinic X access to the portable Patient Profile (DOB, allergies, insurance, etc.). Default profile_shared = false → clinic sees patient name only. See P8.
Caregiver [domain] A human who manages a patient's account (parent for a minor, family member for an elderly patient). The patient may not have their own account.
Compliance & data
GDPR-driven concepts. See decisions.md → Why clinic is controller, platform is processor.
Controller [compliance] Under GDPR, the entity that determines purposes and means of processing. The clinic is controller for patient health data. Patient data is the clinic's responsibility under their own privacy notice.
Processor [compliance] Under GDPR, an entity that processes data on the controller's documented instructions (DPA). The platform is processor. Cross-tenant features operate on anonymised data only; identifiable cross-tenant access goes through Break-glass.
DSAR [compliance] Data Subject Access Request. Routed through the clinic, never the platform. The Cross-Org Account Surface lets patients route their DSAR to each clinic they're at without the platform crossing the processor boundary.
Soft delete [compliance] [domain] Patient records are never hard-deleted. deleted_at column marks deletion; data is anonymized (PII stripped, structure preserved) per GDPR Art. 17(3)(c) medical-record exemption.
Anonymization [compliance] GDPR erasure as anonymization, not deletion — preserves clinical record structure for legal retention while removing identifying data.
RLS (Row-Level Security) [security] [tenancy] Postgres-level enforcement that every query is scoped to the current org context. The load-bearing isolation mechanism. See P1.
Audit log [compliance] [security] Append-only record of every state-changing mutation, plus failed authentication attempts. Range-partitioned monthly (audit_log table). Actor recorded as principal_id + denormalized actor_type. AI provenance columns populated for AI-driven actions. See P11.
Data classification [compliance] [security] Every column has a class (pii, phi, auth_secret, pii_regulated, non_pii, etc.) and a list of allowed egress targets. Default is block. CI fails if a new column is added without a registry entry. See data-classification.md.
Billing & metering
Concepts for charging clinics for platform usage.
Tier (org-side) [billing] A billable subscription product the platform sells to organizations. Lives in tiers table. Carries a base price + entitlements + quotas. Currently three: Free, Pro, Dedicated. Each org holds a current Tier via organization_subscriptions. Tier kind discriminates base (subscription tier) from addon (stackable upsell, foundation-deferred). Tier dedicated maps to tenancy_mode = 'dedicated'; tiers free and pro map to tenancy_mode = 'shared' (and shared is the only mode sellable end-to-end today — dedicated is a schema reservation pending the operational mechanisms). See Tenancy Mode. The earlier docs called this "Plan"; the rename to "Tier" unifies vocabulary with the patient side.
Tier (patient-side) [billing] A billable subscription product a clinic sells to its patients. Lives in patient_tiers table (per-org catalog, clinic-managed). Same engine shape as org-side Tier (entitlements, limits, snapshot-on-subscribe), differing in scope and audience. A clinic on either tenancy mode can offer any patient-side Tiers it wants — patient Tiers are orthogonal to org tenancy mode.
Tenancy Mode [arch] Architecture topology for an organization (organizations.tenancy_mode TEXT NOT NULL DEFAULT 'shared' CHECK IN ('shared', 'dedicated')). Two values: shared (default — pooled platform infrastructure with logical isolation via RLS + prefix scoping + app-layer entitlement checks) and dedicated (reserved — future mode with per-tenant Clerk org as the defining structural feature; optional addons like own-S3-bucket and own-CMK ship later as entitlements when their operational mechanisms exist, not as schema columns). Today only shared is provisionable via API — every creation path lands shared. Set at provisioning; effectively immutable in v1 (see tenant-isolation.md). The dedicated Tier maps to tenancy_mode = 'dedicated'.
Quota [billing] A hard limit on a metered capability (e.g., "max 1000 video minutes/month," "max 10 locations"). Quotas are attached to Tiers — exceeding a quota fails the call at the capability seam, not just emits a warning.
Other "plan"-words live in their feature docs
"Treatment Plan" (clinical-domain prescription document), and any other plan-shaped concept are feature-scoped, not cross-cutting. Their canonical definitions live in the relevant feature spec, not here. The cross-cutting commercial vocabulary is Tier (org-side), Tier (patient-side), Entitlement, Quota.
Usage Record [billing] [arch] An append-only event row capturing one metered capability call: (organization_id, capability, units, unit_type, cost_cents, principal_id, occurred_at, metadata). Range-partitioned monthly (event-shaped per P41).
Usage Summary [billing] Monthly aggregation per (org, capability) rolled from Usage Records by a cron, used for invoicing.
Invoice [billing] Generated from Usage Summaries + plan base price; charged via the payment provider (Stripe / FGO / Netopia depending on org). Lives in billing tables. Tax handling delegated to the invoicing provider — the platform never computes tax rates itself.
Marketplace mediation [billing] Strategic future product offering where the platform mediates patient → clinic payments end-to-end: patient pays platform; platform records balance owed to clinic; on payout schedule, platform pays clinic minus a platform fee. The standard pattern (Stripe Connect, Mollie marketplace, Netopia merchant-of-record) for SaaS marketplaces.
Distinct from the platform → clinic billing flow (which is foundation-accommodated and ships in F12 — clinic pays platform for plan + usage). Marketplace mediation is patient → clinic, with the platform as middleman.
Foundation accommodates marketplace mediation via four Cat A capability skeleton interfaces (payment.Provider, invoicing.Provider, patient_payment.Provider, clinic_payout.Provider) but does NOT build the engine. The marketplace engine is a separate strategic feature that ships when the company is ready (legal/regulatory review, fee model decision, KYB onboarding capacity). Many clinics will use Option A indefinitely (clinic-owned payment provider; platform never sees money) — Option B (marketplace mediation) coexists for clinics that want a turnkey solution. See foundation.md → Deferred Foundation Extensions.
Cross-cutting infrastructure
Patterns that every feature touches.
events.Bus [arch] Internal Go-process event bus (1A.9). Source of all Internal Events (Cat E). Subscribers fan out to audit, notifications, outbound webhooks, automations.
Capability framework [arch] Convention for declaring capabilities, registering implementation strategies, and attaching cross-cutting hooks (audit, metering, permission gating, error classification). Foundation primitive — every capability in the platform follows the same shape.
Provider resolution [arch] [integration] Foundation table (platform_service_providers) + helper that picks which Curated Provider impl handles a Cat A call for a given org. NULL organization_id rows = platform default; specific organization_id rows = per-org override (available on either tenancy mode). Capability interfaces always go through the resolver, even when only platform defaults exist.
Notification dispatcher [arch] Subscribes to events.Bus (Cat E), picks templates from the foundation registry, sends via channel adapters (EmailChannel, future SMSChannel, PushChannel) — each adapter is a Curated Provider (Cat A). See 1A.18.
Outbound webhook dispatcher [arch] [integration] Subscribes to events.Bus (Cat E), reads matching subscriptions from organization_integrations, signs payload, POSTs to clinic-configured URLs (Cat C). Independent code path from notifications — both can fire from the same domain event.
Inbound webhook framework [arch] [integration] Convention for /webhooks/{provider} route mounting + per-provider signature verification + state update + Internal Event emission. Cat D.
Metering middleware [arch] [billing] Wrapper around capability calls that writes a Usage Record per call. Hooked at the capability seam so every metered capability writes consistently.
Naming conventions
Already in CLAUDE.md → Naming Convention, restated for completeness:
- RestartiX = the brand/company. Never a specific app or service.
- Platform = the entire system (backend + frontends + infra).
- Core API = the Go backend (
services/api/). Not "desk API," not "the API." - Clinic app = staff frontend (
apps/clinic/). - Patient Portal = patient frontend (
apps/portal/). - Console = superadmin frontend (
apps/console/). - In code/paths:
core-api,clinic,portal,console,ui.
Forbidden terms
Any usage of these terms in new code, new docs, or commit messages is a rename target. Existing usages get cleaned up via mechanical sweeps.
| Forbidden | Use instead | Why |
|---|---|---|
desk / "Desk API" | core-api / "Core API" | Old naming; bad search hit |
users (table or type) | principals | The actor model is principal-rooted; users doesn't exist |
user_id (in new schema) | principal_id (when any actor) or human_id (when human-required) | FK target enforces actor-type constraint |
services (clinical-domain) | offerings | Architectural-vs-domain word collision. Rename deferred until that area is built; no preemptive sweep. |
service_plans (clinical-domain) | enrollments | Same deferral — taxonomy locked, file/code rename when the area is built. |
services (Cat A naming in code/docs) | "Curated Providers" or just "providers" | Avoid colliding with the clinical Offering domain. |
features (DB table for entitlement catalog) | entitlements | Architectural "feature" means user-facing functionality, not billable gate. Rename completed 2026-05-06 (foundation 1C.9). |
plan_features (plan→feature mapping) | tier_entitlements | Rename follows from features → entitlements. Rename completed 2026-05-06 (foundation 1C.9). |
organization_capabilities (per-org gates) | organization_entitlements | Architectural "capability" means internal interface, not org gate. Same rename family. Rename completed 2026-05-06 (foundation 1C.9). |
| Bare "plan" or "tier" without context | qualify with billing/treatment/patient/etc. | "Plan" alone collides across Tier-vs-Plan, Treatment Plan, and (future) Patient Subscription Plan. Always qualify. |
current_app_user_id() | current_app_principal_id() | RLS helpers reference principals, not users |
| Mixing Cat A/B/C/D as one "integration" | Use the specific category | Confusing them caused historic design drift |
Stewardship
This doc is updated whenever a new term is introduced or an existing term gains/loses a meaning. PRs that introduce new vocabulary without a glossary entry are incomplete. The CI hook (or pre-merge review) for new docs/migrations should grep for unrecognized terms against this glossary.
When a forbidden term appears in a PR, the rule is: rename in this PR or open a tracked rename issue. Don't paper over.