BotForge

Scale

Enterprise

Optional governance layered above Workspace. Every organization-level dashboard is read-aggregation only — zero write paths into workspace-scoped tables.

Organizations & Departments

One Organization row per enterprise customer, aggregating workspaces. Departments are unlimited and fully custom (free-text name), each owning zero or more workspaces, with managers/members and an optional cost center + monthly budget for billing rollups. A workspace is attached only when the caller holds org.manage_workspaces on the organization and is OWNER of the workspace — an organization can never annex a workspace its admin doesn't own.

Cross-workspace aggregation (read-only)

org-console.ts / org-analytics.ts / org-billing.ts / org-security.ts / org-audit.ts / org-search.ts
  → orgWorkspaceIds(organizationId)
  → filter every Prisma query by { workspaceId: { in: wsIds } }
  → zero write paths

SSO

Every identity provider is a metadata entry over the same IdentityProvider row — adding a provider is a registry entry, never a code branch:

Google Workspace (live)Microsoft Entra ID (live)GitHub (live)Auth0 (live)Okta (live)Azure AD (legacy) (live)Generic OpenID Connect (live)Generic SAML 2.0 (config-ready)

All seven OIDC-family providers run the live interactive login flow today; SAML is fully declared (metadata URL, entity ID, SSO URL, signing certificate) but its interactive AuthnRequest/Response codec is not yet wired. Login-time domain discovery and the ticket-exchange flow are covered on the Authentication page.

SCIM

Provider-agnostic SCIM 2.0 (RFC 7643/7644) for automated user/group lifecycle from any compliant IdP (Okta, Entra ID, OneLogin, JumpCloud…). Every request needs Authorization: Bearer <token> — tokens are minted per-organization, shown once, and stored only as a SHA-256 hash.

GET/api/scim/v2/UsersList/filter users
POST/api/scim/v2/UsersProvision a user
GET/api/scim/v2/Users/{id}Fetch one user
PATCH/api/scim/v2/Users/{id}SCIM PatchOp — active (deactivate) / displayName
DELETE/api/scim/v2/Users/{id}Deactivate (soft)
GET/api/scim/v2/GroupsList/filter groups
POST/api/scim/v2/GroupsCreate a group (→ Department) with initial members
PATCH/api/scim/v2/Groups/{id}Add/replace members operations

Groups map to Departments. Deactivating a user via SCIM kills their live sessions.

RBAC

Two independent ladders: WorkspaceRole (9 roles, permission matrix below) governs one workspace; OrganizationRole is a separate system governing the organization itself. Org permissions never grant workspace access, and vice versa — the only bridge is the ownership check in attachWorkspaceToOrg.

RolePermissions
OWNERAll permissions
ADMINview_analytics, manage_bots, manage_modules, view_customers, manage_commerce, manage_broadcast, manage_tickets, manage_referrals, manage_inbox, view_audit, manage_ai, manage_settings, manage_api, manage_prompts, manage_knowledge_base, manage_agents
DEVELOPERview_analytics, manage_bots, manage_modules, manage_api
MODERATORview_analytics, view_customers, manage_tickets, manage_inbox, manage_broadcast, manage_referrals
SUPPORT_AGENTmanage_tickets, manage_inbox, view_customers
AFFILIATE_MANAGERview_analytics, manage_referrals
VIEWERview_analytics
AUDITORview_audit

Policies

Enterprise policies (e.g. AI provider/model allow-lists enforced by assertOrgAiPolicy in the AI Runtime) are declared as registry metadata in src/lib/enterprise/policy-registry.ts and apply consistently across every workspace in the organization — never configured per-workspace.