This repository has been archived on 2026-04-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
core/docs/ICD/teams.md
2026-03-12 10:22:08 +00:00

6.9 KiB

Teams & Access Control

My Teams

GET /teams/mine                     → { "data": [...] }

Auth: Authenticated user.

Returns teams the current user is a member of (active teams only).

Each team object:

{
  "id": "uuid",
  "name": "Engineering",
  "description": "...",
  "is_active": true,
  "settings": "{}",
  "my_role": "admin|member",
  "member_count": 5
}

Team Administration

Team CRUD (platform admin):

GET    /admin/teams                  → { "data": [...], "total": N, "page": N, "per_page": N }
POST   /admin/teams                  ← { "name", "description" }  → { "id", "name" }
GET    /admin/teams/:id              → team object (unwrapped)
PUT    /admin/teams/:id              ← { "name"?, "description"?, "is_active"?, "settings"? }
DELETE /admin/teams/:id

Auth: RequireAdmin (platform admin).

POST returns 201. PUT/DELETE return {"ok": true}. PUT with no fields returns 400. Duplicate name returns 409.

Members (admin routes):

GET    /admin/teams/:id/members         → { "data": [...] }
POST   /admin/teams/:id/members         ← { "user_id", "role" }  → { "id" }
PUT    /admin/teams/:id/members/:memberId   ← { "role" }
DELETE /admin/teams/:id/members/:memberId

Auth: RequireAdmin.

role must be admin or member. Duplicate membership returns 409.

Team-scoped routes (team admin self-service):

GET    /teams/:teamId/members
POST   /teams/:teamId/members        ← { "user_id", "role" }
PUT    /teams/:teamId/members/:memberId
DELETE /teams/:teamId/members/:memberId

Auth: RequireTeamAdmin.

Same handlers as admin routes; the getTeamID() helper reads either :id or :teamId.

Team Providers:

GET    /teams/:teamId/providers          → { "data": [...], "allow_team_providers": bool }
POST   /teams/:teamId/providers          ← { "name", "provider", "endpoint", "api_key", ... }
PUT    /teams/:teamId/providers/:id
DELETE /teams/:teamId/providers/:id
GET    /teams/:teamId/providers/:id/models  → { "models": [...], "provider": "name" }

Auth: RequireTeamAdmin.

GET returns provider configs scoped to the team. The models endpoint performs a live query to the upstream provider.

Team Models:

GET /teams/:teamId/models           → { "models": [...] }

Auth: RequireTeamAdmin.

Returns all models available to this team: global admin models with visibility IN ('enabled', 'team') plus live-queried team provider models with source field ("global" or "team").

Team Groups:

GET /teams/:teamId/groups           → { "data": [...] }

Auth: RequireTeamAdmin.

Returns groups scoped to this team.

Team Personas: See personas.md §Team Personas.

Team Roles:

GET    /teams/:teamId/roles          → { "data": {...} }
PUT    /teams/:teamId/roles/:role    ← RoleConfig object
DELETE /teams/:teamId/roles/:role

Auth: RequireTeamAdmin.

GET returns the team's model_roles settings map (composite object, not an array). Initially empty {}. Each key is a role name, value is a RoleConfig. PUT validates the role name. DELETE removes the override, falling back to the global role definition.

Team Audit:

GET /teams/:teamId/audit             → { "data": [...], "total": N, "page": N, "per_page": N }
GET /teams/:teamId/audit/actions     → { "actions": [...] }

Auth: RequireTeamAdmin.

Audit log is scoped to actions performed by team members. Supports query filters: ?action=, ?actor_id=, ?resource_type=.

Team Usage:

GET /teams/:teamId/usage             → { "totals": {...}, "results": [...] }

Auth: RequireTeamAdmin.

Returns usage against team-owned providers. Supports query params for date range filtering.

Groups & Resource Grants

Groups are ACL containers that decouple access from team membership. A resource grant controls who can see a Persona or KB beyond its base scope.

My Groups:

GET /groups/mine                     → { "data": [...] }

Auth: Authenticated user.

Admin Group CRUD:

GET    /admin/groups                 → { "data": [...] }
POST   /admin/groups                 ← { "name", "scope", "team_id"? }
GET    /admin/groups/:id             → group object (unwrapped)
PUT    /admin/groups/:id             ← { "name"?, "description"?, "permissions"?, ... }
DELETE /admin/groups/:id

Auth: RequireAdmin.

POST returns 201. Duplicate name returns 409. Deleting a system-sourced group (e.g. Everyone) returns 400.

Group Members:

GET    /admin/groups/:id/members     → { "data": [...] }
POST   /admin/groups/:id/members     ← { "user_id" }
DELETE /admin/groups/:id/members/:userId

Auth: RequireAdmin.

Resource Grants:

GET    /admin/grants/:type/:id       → grant object (unwrapped)
PUT    /admin/grants/:type/:id       ← { "grant_scope", "granted_groups"?: [...] }
DELETE /admin/grants/:type/:id

Auth: RequireAdmin.

:type is persona or kb. :id is the resource ID.

Grant scopes:

grant_scope Visibility
team_only Only the owning team
global All authenticated users
groups Members of specified groups

Setting grant_scope: "groups" without granted_groups returns 400.

Permissions

Groups carry fine-grained permissions. Permission resolution: union of all group permissions + Everyone group permissions.

List all permissions:

GET /admin/permissions               → { "permissions": ["model.use", "kb.read", ...] }

Auth: RequireAdmin.

Get user's effective permissions:

GET /admin/users/:id/permissions     → { "permissions": [...], "user_id": "...", "groups": [...] }

Auth: RequireAdmin.

Returns the resolved permission set and contributing group IDs (always includes the Everyone group).

Group permission fields (set via PUT /admin/groups/:id):

{
  "permissions": ["model.use", "kb.read", "channel.create"],
  "token_budget_daily": 100000,
  "token_budget_monthly": 3000000,
  "allowed_models": ["claude-sonnet-4-20250514", "gpt-4o"]
}
Field Type Description
permissions string[] Permission constants granted to members
token_budget_daily int/null Daily token ceiling (NULL = unlimited)
token_budget_monthly int/null Monthly token ceiling (NULL = unlimited)
allowed_models string[]/null Model allowlist (NULL = unrestricted)

Everyone group: System-seeded group (ID 00000000-0000-0000-0000-000000000001) whose permissions apply to all authenticated users implicitly (no membership row needed). Editable by admins, cannot be deleted (source=system).

RequirePermission middleware: Routes gated by permission check user's resolved permission set. Returns 403 if the required permission is not present.

See enums.md for the full permission constant list.