# 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: ```json { "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`): ```json { "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](enums.md) for the full permission constant list.