237 lines
6.0 KiB
Markdown
237 lines
6.0 KiB
Markdown
# Platform Administration
|
|
|
|
Cross-cutting admin operations that don't belong to a specific domain.
|
|
|
|
### User Management
|
|
|
|
```
|
|
GET /admin/users → { "users": [...], "total": N }
|
|
POST /admin/users ← { "username", "password", "email", "role" }
|
|
PUT /admin/users/:id/role ← { "role": "admin|user" }
|
|
PUT /admin/users/:id/active ← { "is_active": false }
|
|
DELETE /admin/users/:id
|
|
POST /admin/users/:id/reset-password ← { "password": "..." }
|
|
POST /admin/users/:id/vault/reset → destroys user's UEK (BYOK keys lost)
|
|
```
|
|
|
|
`PUT /admin/users/:id/role` refuses to demote the last remaining admin
|
|
(returns 409). `DELETE /admin/users/:id` also refuses if the target is
|
|
the last admin, and destroys the user's vault before deleting the row.
|
|
|
|
### Global Settings & Policies
|
|
|
|
Settings are key-value pairs in `global_settings`. Policies are
|
|
boolean flags that gate features.
|
|
|
|
```
|
|
GET /admin/settings → all settings
|
|
GET /admin/settings/:key → single setting
|
|
PUT /admin/settings/:key ← { "value": ... }
|
|
```
|
|
|
|
The handler auto-detects: if the value is a string and the key is a
|
|
known policy name, it writes to the `policies` table. Otherwise it
|
|
writes to `global_config` as JSON.
|
|
|
|
**Public settings** (non-admin, for FE bootstrapping):
|
|
|
|
```
|
|
GET /settings/public
|
|
```
|
|
|
|
```json
|
|
{
|
|
"banner": { "enabled": true, "text": "DEVELOPMENT", "bg": "#007a33", "fg": "#ffffff", "position": "both" },
|
|
"branding": { "instance_name": "Switchboard", "logo_url": "...", "tagline": "..." },
|
|
"has_admin_prompt": true,
|
|
"storage_configured": true,
|
|
"paste_to_file_chars": 2000,
|
|
"policies": {
|
|
"allow_registration": "true",
|
|
"allow_user_byok": "true",
|
|
"allow_user_personas": "true",
|
|
"channel_retention_mode": "flexible"
|
|
}
|
|
}
|
|
```
|
|
|
|
Note: policy values are strings (`"true"` / `"false"`), not booleans.
|
|
|
|
### Banner Configuration
|
|
|
|
The environment banner is stored as a single `global_config` entry
|
|
under the key `"banner"`. It's a simple object:
|
|
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"text": "DEVELOPMENT",
|
|
"position": "both|top|bottom",
|
|
"bg": "#007a33",
|
|
"fg": "#ffffff"
|
|
}
|
|
```
|
|
|
|
Set via `PUT /admin/settings/banner` with `{ "value": { ... } }`.
|
|
The admin UI provides a color picker, position selector, and preset
|
|
dropdown. The Go template base layout reads the banner from
|
|
`PageData` and renders top/bottom strips with CSS custom properties.
|
|
|
|
### Platform Stats
|
|
|
|
```
|
|
GET /admin/stats
|
|
```
|
|
|
|
```json
|
|
{
|
|
"users": 42,
|
|
"channels": 156,
|
|
"messages": 12847
|
|
}
|
|
```
|
|
|
|
### Storage & Vault
|
|
|
|
**Storage status:**
|
|
|
|
```
|
|
GET /admin/storage/status → { "backend", "healthy", "file_count", "total_bytes", ... }
|
|
GET /admin/storage/orphans → { "count": 3 }
|
|
POST /admin/storage/cleanup → removes orphaned blobs
|
|
GET /admin/storage/extraction → extraction queue status
|
|
```
|
|
|
|
**Vault:**
|
|
|
|
```
|
|
GET /admin/vault/status → { "encryption_key_set", "user_vaults_count", ... }
|
|
```
|
|
|
|
### Audit Log
|
|
|
|
```
|
|
GET /admin/audit?page=1&per_page=50&action=user.create&actor_id=uuid&resource_type=...
|
|
GET /admin/audit/actions → { "actions": ["user.create", "policy.update", ...] }
|
|
```
|
|
|
|
The list endpoint returns a paginated envelope:
|
|
|
|
```json
|
|
{
|
|
"data": [...],
|
|
"total": 128,
|
|
"page": 1,
|
|
"per_page": 50
|
|
}
|
|
```
|
|
|
|
Audit entry shape:
|
|
|
|
```json
|
|
{
|
|
"id": "uuid",
|
|
"actor_id": "uuid",
|
|
"actor_name": "admin",
|
|
"action": "user.create",
|
|
"resource_type": "user",
|
|
"resource_id": "uuid",
|
|
"metadata": "{}",
|
|
"ip_address": "10.0.0.1",
|
|
"created_at": "..."
|
|
}
|
|
```
|
|
|
|
### Usage & Pricing
|
|
|
|
```
|
|
GET /admin/usage → { "totals", "results" }
|
|
GET /admin/usage/teams/:id → { "results": [...] }
|
|
GET /admin/usage/users/:id → { "results": [...] }
|
|
GET /admin/pricing → [ ... ]
|
|
PUT /admin/pricing ← { "provider_config_id", "model_id", "input_per_m", "output_per_m" }
|
|
DELETE /admin/pricing/:provider_config_id/:model_id
|
|
```
|
|
|
|
`GET /admin/pricing` returns a bare array (no envelope).
|
|
|
|
`PUT /admin/pricing` accepts the full `PricingEntry` shape:
|
|
|
|
```json
|
|
{
|
|
"provider_config_id": "uuid",
|
|
"model_id": "gpt-4o",
|
|
"input_per_m": 2.50,
|
|
"output_per_m": 10.00,
|
|
"cache_create_per_m": 1.25,
|
|
"cache_read_per_m": 0.50,
|
|
"currency": "USD"
|
|
}
|
|
```
|
|
|
|
Pricing cannot be set for personal BYOK providers (403).
|
|
|
|
**Personal usage** (non-admin):
|
|
|
|
```
|
|
GET /usage → { "totals", "results" }
|
|
```
|
|
|
|
Scoped to the user's BYOK provider usage only.
|
|
|
|
### Roles (Platform)
|
|
|
|
```
|
|
GET /admin/roles → { "roles": [...] }
|
|
GET /admin/roles/:role
|
|
PUT /admin/roles/:role ← { "permissions": {...} }
|
|
POST /admin/roles/:role/test ← test role permissions
|
|
```
|
|
|
|
### Email Test
|
|
|
|
```
|
|
POST /admin/notifications/test-email
|
|
```
|
|
|
|
No request body required. Sends a test email to the authenticated
|
|
admin's own email address using the configured SMTP settings.
|
|
|
|
---
|
|
|
|
### Archived Channels
|
|
|
|
```
|
|
GET /admin/channels/archived → { "channels": [...], "total", "page", "per_page", "retention_mode" }
|
|
DELETE /admin/channels/:id/purge → permanent delete (ignores retention)
|
|
```
|
|
|
|
Both endpoints require platform admin auth. `GET` accepts
|
|
`?page=1&per_page=50` query parameters (max 100 per page).
|
|
`DELETE` verifies the channel is archived before purging and cleans
|
|
up associated file storage blobs.
|
|
|
|
### Surfaces Admin
|
|
|
|
See [surfaces.md](surfaces.md) for the full surface management API.
|
|
|
|
```
|
|
GET /admin/surfaces → all surfaces (including disabled)
|
|
GET /admin/surfaces/:id → surface with manifest
|
|
POST /admin/surfaces/install ← multipart .surface archive
|
|
PUT /admin/surfaces/:id/enable
|
|
PUT /admin/surfaces/:id/disable
|
|
DELETE /admin/surfaces/:id
|
|
```
|
|
|
|
### Tasks Admin
|
|
|
|
See [tasks.md](tasks.md) for the full task management API.
|
|
|
|
```
|
|
GET /admin/tasks → all tasks across all users/teams
|
|
POST /admin/tasks/:id/run → force run
|
|
POST /admin/tasks/:id/kill → cancel active run
|
|
DELETE /admin/tasks/:id → delete task
|
|
```
|