Last Updated: 2026-02-28
Service Owner
apps/manager (The Platform Core Service)
Why? Team Management is inseparable from Authentication and Tenant Metadata. Splitting it would cause distributed complexity.
Base URL
/manager/team (Proxied through the Gateway, scoped to the current tenant via JWT x-tenant-id)
1. Invitations (Hiring)
POST /invitations
Send an invite to a new member.
- Auth: Required (
team:members.invite) - Body:
{ "email": "chloe@dev.com", "role_id": "role_developer_123" } - Response (201 Created):
{ "data": { "id": "inv_abc123", "token": "secret_token_xyz", // Only returned once! "expires_at": "2026-02-19T10:00:00Z", "status": "pending" } }
GET /invitations/:token (Public)
Validate an invite token (for the landing page).
- Auth: Public
- Response (200 OK):
{ "data": { "tenant_name": "TechStartup", "inviter_name": "Ben", "email": "chloe@dev.com", // The intended recipient "is_valid": true } }
POST /invitations/:token/accept
Accept the invite and join the tenant.
- Auth: Required (User must be logged in)
- Response (200 OK):
{ "data": { "membership_id": "mem_new_123" } }
2. Memberships (Staff Management)
GET /members
List all staff in the current tenant.
- Auth: Required (
team:members.read) - Response (200 OK):
{ "data": [ { "id": "mem_1", "user": { "id": "u1", "name": "Ayva", "email": "ayva@example.com", "avatar": "..." }, "role": { "id": "role_owner", "name": "Owner" }, "joined_at": "2026-01-01..." } ], "meta": { "total": 5, "page": 1 } }
PATCH /members/:id
Update a member's role (Promotion).
- Auth: Required (
team:members.manage) - Body:
{ "role_id": "role_admin_456" } - Response (200 OK): Returns updated membership.
DELETE /members/:id
Remove a staff member (Offboarding).
- Auth: Required (
team:members.remove) - Body (Optional - For Resource Transfer):
{ "transfer_assets_to": "mem_owner_1" // Logic: Transfer posts/files to Owner } - Response (200 OK):
{ "data": { "success": true, "revoked_sessions": 3 } }
3. Roles (RBAC)
GET /roles
List available roles (System + Custom).
- Auth: Required (
team:roles.read) - Response:
{ "data": [ { "id": "role_owner", "name": "Owner", "is_system": true, "permissions": ["*"] }, { "id": "role_dev", "name": "Developer", "is_system": false, "permissions": ["blog:posts.read", "blog:posts.update"] } ] }
4. Error Codes
| Code | HTTP | Meaning |
|---|---|---|
INVITE_EXPIRED |
400 | The token is past its expiration date. |
INVITE_EMAIL_MISMATCH |
403 | The logged-in user email != invite email. |
MEMBER_NOT_FOUND |
404 | Member ID does not exist in this tenant. |
CANNOT_REMOVE_SELF |
400 | You cannot delete your own membership. |
CANNOT_DOWNGRADE_OWNER |
403 | The Owner role cannot be changed. |