Customer PlaybooksWorkspaces Management (Org Admin)

Workspaces Management (Org Admin)

Settings → Workspaces (/app/settings/workspaces). Lets an org owner/admin manage

Settings → Workspaces (/app/settings/workspaces). Lets an org owner/admin manage every workspace they belong to and see who manages each one.

Why this exists

A B2B account can own multiple workspaces (organizations). Sub-workspaces link to a parent via organization.parentOrgId and inherit the parent's plan. Members need a single place to create, rename, switch between, leave, or delete workspaces, and to see each workspace's owners/admins at a glance.

Granting/revoking a member's admin access to a workspace is done on the Team page (/app/settings/team), not here. This page is for managing the workspaces themselves plus a read-only view of each workspace's admins.

Where it lives in the UI

  • Registered in ADTOSIGN_SETTINGS_NAV (src/config/adtosign-navigation.ts) as Workspaces → it appears in the settings sidebar, command palette, and mobile nav.
  • Also reachable from the org switcher's "+ Create workspace" link (…/workspaces?action=create, which auto-opens the create dialog).

Capabilities (CRUD)

ActionUIAPI
List my workspacesSWR on loadGET /api/app/organizations
Create"New Workspace" dialog (gated on plan.quotas.maxOrganizations > 1 and owner/admin role)POST /api/app/organizations
Renamerow menu → Rename (owner/admin)PATCH /api/app/organizations/[id]
Deleterow menu → Delete (owner only; not the active workspace; type-slug confirm)DELETE /api/app/organizations/[id]
Leaverow menu → Leave (not if sole owner; not the active workspace)DELETE /api/app/organizations/[id]/leave
Switchrow click / Switch buttonuseOrganization().switchOrganization
View admins"Admins:" chips per rowGET /api/app/organizations/admins

API surface

GET /api/app/organizations/admins

Returns the owner/admin members for every workspace the current user belongs to. Auth: withAuthRequired. Demo users are routed to the demo DB via getAuthDb(session.userEmail). Reads only the global DB (memberships, organizations, users).

{
  "byOrg": {
    "<orgId>": [
      { "userId": "u_1", "name": "Ada Lovelace", "email": "ada@acme.com", "role": "owner" },
      { "userId": "u_2", "name": null,           "email": "rob@acme.com", "role": "admin" }
    ]
  }
}
  • Only owner / admin roles are returned; owners are sorted first.
  • The response only contains workspaces the caller is already a member of — no cross-tenant exposure.

Data model

No schema change. Uses existing global tables:

  • organization_membership (orgId, userId, role) — drives membership + role.
  • organization — workspace identity (name, slug, parentOrgId, dataRegion).
  • app_user — admin name / email for display.

Notes / gotchas

  • The settings nav entry is unconditional. On single-org plans the page still renders (one workspace + its admins); the create action shows an upgrade state when maxOrganizations === 1. styling for /app/settings/workspaces — keep that key in sync if the route changes.

Changelog

DateChangeAuthor
2026-06-04Surfaced Workspaces in settings nav; added GET /api/app/organizations/admins + per-workspace admin chipsCascade