Leave Localhost logoLeave LocalhostDocs
Admin

Admin: Workspaces

/admin/workspaces lists every workspace (organization) and hosts the admin write surface: suspend and reactivate. It reads app-owned organization_profiles joined with Better Auth organization data.

/admin/workspaces lists every workspace (organization) and hosts the admin write surface: suspend and reactivate. It reads app-owned organization_profiles joined with Better Auth organization data.

Using it

  • Paginated list with a status filter (all / active / suspended / deleted).
  • Manage opens a drawer with the workspace's owner, type, active plans, and members, plus the status action.

Suspend / reactivate

These are the only admin writes. They flip organization_profiles.status between active and suspended. Product permission checks already treat non-active organizations as unavailable, so suspending a workspace immediately blocks its members from using it.

Each write requires two independent checks, in order:

  1. Super-admin access (resolveSuperAdminAccess). A non-admin attempt is rejected and recorded as admin.access_denied. The mutation returns a structured { ok: false, code: "FORBIDDEN" } (rather than throwing) so that denial audit commits — a throwing mutation would roll the audit row back.
  2. Sensitive-action step-up bound to the target workspace. The confirm dialog runs the existing verification ceremony (password or email code); the step-up grant is single-use and level 4, so one verification maps to exactly one write. See Sensitive Action Protection.

Every attempt produces an audit event: organization.suspended / organization.reactivated with result = success or failure.

Deleted workspaces cannot be suspended or reactivated.

Why step-up is bound to the target workspace

A platform admin is usually not a member of the workspace they act on. The sensitive-action grant is therefore bound to the target organization id (passed by the confirm dialog), not the admin's active workspace. This forces a fresh verification per target and keeps the grant scope aligned with enforcement.

Backend

admin.organizations.list / .get / .suspend / .reactivate in convex/admin/organizations.ts. The sensitive actions admin.organizationSuspend / admin.organizationReactivate are defined in convex/security/sensitiveActions.ts with requiresSuperAdmin: true.

Extending the write surface

Keep new admin writes small and explainable. For each one: add a sensitive action id (with requiresSuperAdmin: true), gate the mutation with requireSuperAdminInMutation then requireSensitiveActionInMutation, and emit audit events for success/failure. Avoid impersonation, account deletion, and arbitrary billing edits.

Removing it

See Removing the Admin Panel and Audit Log.

On this page