Teams & Multi-tenancy
The teams module provides multi-tenant organization support. Users can create teams, invite members with role-based access, and switch between teams at runtime.
Endpoints
All endpoints require authentication (JwtAuthGuard).
| Method | Path | Description |
|---|---|---|
| POST | /teams | Create a new team (creator becomes OWNER) |
| GET | /teams | List all teams the current user belongs to |
| GET | /teams/:id | Get team details with member list |
| PATCH | /teams/:id | Update team name or slug (OWNER/ADMIN) |
| DELETE | /teams/:id | Delete a team (OWNER only) |
| POST | /teams/:id/invite | Invite a member by email (OWNER/ADMIN) |
| POST | /teams/invite/accept | Accept a team invite token |
| DELETE | /teams/:id/members/:memberId | Remove a member (OWNER/ADMIN) |
| PATCH | /teams/:id/members/:memberId | Update a member's role (OWNER only) |
| POST | /teams/:id/leave | Leave a team |
Roles
| Role | Permissions |
|---|---|
| OWNER | Full control -- update team, manage members, change roles, delete team |
| ADMIN | Invite members, remove members, update team details |
| MEMBER | View team details and member list |
When a user creates a team they are automatically assigned the OWNER role. The last owner cannot leave or be demoted.
Invitations
Inviting a member sends an email with a unique token. Key behaviors:
- Invite tokens expire after 7 days.
- If the invited email is already a team member, the API returns a
409 Conflict. - The invited user calls
POST /teams/invite/acceptwith the token to join the team. - The
rolefield on the invite defaults toMEMBERbut can be set toADMINby the inviter.
Team Switching
Users who belong to multiple teams can switch context via POST /auth/switch-team (in the auth module). The server verifies membership and returns new JWT tokens that include the active teamId in the payload. This allows downstream guards and services to scope data to the current team.
// Request
POST /auth/switch-team
{ "teamId": "clxyz..." }
// Response
{
"accessToken": "eyJ...",
"refreshToken": "abc..."
}