BackendWorkspaces & Teams
Overview
Multi-tenancy with workspaces, teams, and role-based access.
HyperSaaS uses workspace-based multi-tenancy. Every resource (chats, documents, knowledge bases) belongs to a workspace. Users access workspaces through memberships.
Core Models
Workspace
class Workspace(BaseModel):
id = models.UUIDField(primary_key=True)
name = models.CharField(max_length=200, default="Default Workspace")
slug = models.SlugField(max_length=255, unique=True) # Auto-generated
owner = models.ForeignKey(User, on_delete=models.CASCADE)
members = models.ManyToManyField(User, through="WorkspaceMembership")
status = models.CharField(choices=[ACTIVE, ARCHIVED])
subscription = models.ForeignKey(Subscription, null=True, blank=True)A workspace's plan comes from its subscription while that grants access, and is Free otherwise. Credit, documents and storage are counted per workspace.
WorkspaceMembership
class WorkspaceMembership(BaseModel):
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
role = models.CharField(choices=ROLE_CHOICES, default="member")
# unique_together = ("workspace", "user")Team
Teams are sub-groups within a workspace for fine-grained access control:
class Team(BaseModel):
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=150)
owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
members = models.ManyToManyField(User, through="TeamMembership")Folder
Folders organize resources within a workspace:
class Folder(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
workspace = models.ForeignKey(Workspace, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
type = models.CharField(max_length=50, null=True) # 'chat', 'file', 'prompt', 'agent'Roles
| Role | Capabilities |
|---|---|
| Owner | Everything an admin can do, plus delete the workspace and transfer ownership |
admin | Invite and remove people, change roles, manage teams, change settings, archive the workspace, buy a plan |
member | Use chats and documents; manage what they created |
The owner is a field on the workspace, not a role: the owner also has an admin membership. See Permissions for the full table.
Joining and Leaving
- People join only by accepting an invitation. There's no endpoint that adds someone directly. See Invitations.
- Members can leave (
POST /api/workspaces/{id}/leave/). The owner can't, until they transfer ownership. - Removing someone, or their leaving, also removes their team memberships in that workspace, clears them as owner of its teams, and deletes pending invitations to them.
- Transferring ownership (
POST /api/workspaces/{id}/transfer-ownership/) makes another member the owner. Both stay on as admins. A subscription stays with whoever pays for it. - Deleting a workspace is refused while it has an active subscription, or if it's the owner's only workspace.
Data Isolation
Every workspace-scoped API endpoint:
- Extracts
workspace_pkfrom the URL - Verifies the user is a member of that workspace
- Filters all queries to that workspace
# Example: Chat sessions are always scoped to a workspace
GET /api/workspaces/{workspace_id}/chats/