Teams & RBAC
Workspace-level isolation with owner, admin, and member roles.
Team Model
Every user gets a Default Team on registration. Additional teams can be created and switched between freely. All subscriptions, API keys, strategy instances, and billing are scoped to a team.
| Resource | Scope |
|---|---|
| Strategy subscriptions | Team |
| Running instances | Team |
| API keys | Team or User |
| Wallet / CRDTS balance | User (team owner pays) |
| Notification preferences | User |
Roles & Permissions
| Role | Capabilities |
|---|---|
| Owner | Full control — billing, team deletion, member management, all settings |
| Admin | Manage members, activate strategies, manage instances |
| Member | View strategies and instances; limited write access |
Permissions are enforced on the API by the rbac middleware:
// apps/api/src/middleware/rbac.ts
router.delete("/teams/:slug", requirePermission("team:delete"), handler);
Team Switching
The sidebar Team Switcher lets users move between teams instantly. The active team is stored in the session cookie so server components always have the right context.
Invitations
Owners and admins can invite users by email with a pre-assigned role. Invitees receive an email with a token-based acceptance link at /teams/join. Ownership can also be transferred to another member.
Data Isolation
Every Mongoose document that belongs to a team carries a teamId index. Queries always filter by the resolved team from the session — there is no cross-tenant data leakage.