public schema and appear in both Prisma schema files.
Studio
Table studios. The tenant root. Every domain row hangs off a studio, directly or through a client.
How a studio row is created
The web lane middlewarewebUserContext (apps/core-api/src/middleware/web-context.ts) resolves x-studio-id, which carries the organization id, to a studio. If none exists it creates one with externalOrgId, name, slug and the default content categories. It then upserts the calling owner as a HEAD_COACH in ensureOwnerCoach. Results are cached in memory per process.
Relations
Studio has a back-relation to nearly every studio-scoped model. All of them cascade on studio delete. In practice studios are archived with deletedAt, and a hard delete goes through the admin purge recorded in AdminDeletion (see CRM, audit and misc).
StudioApiKey
Table studio_api_keys. A studio-scoped secret for the partner API, the automation API and the MCP server.
Relations:
studio, and automationHooks. A hook belongs to the key that registered it and is deleted with it.
Lifecycle: created and revoked from the web lane at /v1/web/studios/current/api-keys by OWNER or HEAD_COACH. The create response is the only place the plaintext secret appears. Details are in Partner API and studio API keys.
Coach
Table coaches. A staff member inside one studio.
Unique on
(studioId, externalUserId). Index on studioId.
Relations: clients (legacy single-coach link through Client.coachId), clientAssignments (ClientCoach), inboxItems, leads (as Lead.ownerCoachId).
CoachRole
Coach.permissions
Validated by coachPermissions in apps/core-api/src/modules/coaches/coaches.schema.ts:
readCoachPermissions(role, stored) is the only reader. Its rules:
HEAD_COACHalways getsUNRESTRICTED_COACH_PERMISSIONS.- A
SUB_COACHwith no stored blob also gets unrestricted permissions. Coaches created before the permission model existed could see the whole studio, and restricting them on deploy would have cut them off from their trainees. - A blob that fails to parse falls back to unrestricted.
- Only a member configured through the team screen is narrowed.
ClientCoach
Table client_coaches. The many-to-many assignment of coaches to trainees.
Unique on
(clientId, coachId).
Client.coachId still exists as the older single-coach column and relation. Treat ClientCoach as the full list of a trainee’s coaches. It is what trainee scoping for a trainees: "assigned" coach, joint tasks and the coach multi-select read.