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/README.md
2026-03-12 10:22:08 +00:00

204 lines
6.8 KiB
Markdown

# ICD-API — Chat Switchboard Backend API Contract
**Version:** 0.28.0
**Updated:** 2026-03-11
**Audience:** Frontend developers, integrators, API consumers
> **Organization principle:** Each file is one domain — the complete story.
> Every endpoint that touches Knowledge Bases is in `knowledge.md`, every
> endpoint that touches Personas is in `personas.md`, etc.
## Files
| File | Domain | Endpoints |
|------|--------|-----------|
| [auth.md](auth.md) | Auth — login, register, refresh, OIDC, mTLS | 6 |
| [channels.md](channels.md) | Channels, messages, completions, participants, folders, presence | ~35 |
| [personas.md](personas.md) | Personas, persona groups, avatars, KB bindings, tool grants | ~20 |
| [knowledge.md](knowledge.md) | Knowledge bases, documents, search, channel/persona bindings | ~12 |
| [notes.md](notes.md) | Notes, wikilinks, graph, search, folders | ~10 |
| [workspaces.md](workspaces.md) | Workspaces, file ops, git, credentials | ~20 |
| [projects.md](projects.md) | Projects, channel/KB/note associations | ~14 |
| [memory.md](memory.md) | Memory extraction, review, admin | 7 |
| [providers.md](providers.md) | Provider configs, health, capabilities, routing policies | ~25 |
| [models.md](models.md) | Enabled models, user preferences | 4 |
| [notifications.md](notifications.md) | Notifications, preferences | 7 |
| [extensions.md](extensions.md) | Extensions, user settings, admin | 8 |
| [profile.md](profile.md) | User profile, avatar, password, app settings | 7 |
| [teams.md](teams.md) | Teams, members, groups, permissions, grants | ~25 |
| [admin.md](admin.md) | Platform admin — users, settings, stats, audit, usage, vault | ~25 |
| [utility.md](utility.md) | Health, export, files, storage | ~12 |
| [workflows.md](workflows.md) | Workflow definitions, stages, instances, assignments, entry | ~20 |
| [tasks.md](tasks.md) | Task definitions, runs, scheduler, team tasks | ~14 |
| [surfaces.md](surfaces.md) | Surface registry, extension surfaces | 6 |
| [websocket.md](websocket.md) | WebSocket protocol, events, rooms | — |
| [enums.md](enums.md) | All enum values, policies | — |
## Conventions
### Base URL
```
{scheme}://{host}{BASE_PATH}/api/v1
```
`BASE_PATH` is empty by default. In path-routed K8s deployments (e.g.
`/staging/`), all routes shift accordingly. The frontend reads `BASE_PATH`
from a `<meta>` tag injected by the Go template engine.
### Authentication
JWT bearer tokens. Every request to a `protected` or `admin` route requires:
```
Authorization: Bearer {access_token}
```
**Access token:** HS256 JWT, 15-minute TTL. Claims: `user_id`, `email`,
`role`, `exp`, `iat`, `jti`.
**Refresh token:** Opaque, DB-stored, 7-day TTL. Used to obtain new
access tokens without re-login.
**WebSocket fallback:** `?token={access_token}` query parameter when
the `Authorization` header isn't available.
**Cookie sync:** On every token save/refresh, the frontend writes
`sb_token` as a cookie. Go template page routes read this cookie via
`AuthOrRedirect` middleware for server-rendered surfaces.
### Auth Modes
| Mode | `AUTH_MODE` | How it works |
|------|------------|--------------|
| Builtin | `builtin` (default) | Username/password, bcrypt, JWT |
| mTLS | `mtls` | Reverse proxy cert headers, auto-provision |
| OIDC | `oidc` | Authorization code flow (Keycloak etc.) |
All three modes issue the same JWT after authentication. Downstream
middleware is auth-mode-agnostic.
### Authorization Tiers
| Tier | Middleware | Who |
|------|-----------|-----|
| Public | none | Anyone (health, login, register, public settings) |
| Session | `AuthOrSession()` | JWT user OR anonymous session cookie (workflow visitors) |
| Authenticated | `Auth()` | Any logged-in user |
| Permission | `RequirePermission(perm)` | User whose groups grant `perm` |
| Team Admin | `RequireTeamAdmin()` | Admin of the specific team |
| Platform Admin | `RequireAdmin()` | Users with `role = "admin"` |
### Error Envelope
All errors return:
```json
{ "error": "human-readable message" }
```
Standard HTTP status codes: 400 (bad request), 401 (not authenticated),
403 (not authorized), 404 (not found), 409 (conflict), 500 (server error),
502 (upstream provider failure).
### Response Envelopes
Three patterns. Every endpoint uses exactly one.
**List (returns an array)** → always wrap in `{"data": []}`:
```json
{
"data": [...]
}
```
If paginated, pagination fields sit alongside `data`:
```json
{
"data": [...],
"page": 1,
"per_page": 50,
"total": 142
}
```
Query params: `?page=1&per_page=50`. Not all list endpoints paginate —
unpaginated lists still use `{"data": [...]}`.
This is a hard rule: `data` is the only array wrapper key. No
domain-specific keys (`teams`, `members`, `configs`, etc.) for arrays.
Clients parse every list response identically.
**Single object (GET by ID, profile, health)** → return the object directly:
```json
{
"id": "uuid",
"name": "...",
...
}
```
No wrapping. The response *is* the resource.
**Composite (multiple named values, not an array)** → named keys:
```json
{
"active": 5,
"pending": 2
}
```
Used for stats, counts, status endpoints — anything returning
multiple named scalars or heterogeneous data. The key names are
domain-specific and documented per endpoint.
**Empty arrays** must serialize as `[]`, never `null`. Go handlers
must guard nil slices before serialization:
```go
if result == nil {
result = []MyType{}
}
c.JSON(http.StatusOK, gin.H{"data": result})
```
### ID Format
All resource IDs are UUIDv4 strings, generated application-side via
`store.NewID()` (Go `uuid.New()`). This ensures compatibility across
both Postgres and SQLite backends.
### Timestamps
ISO 8601 with timezone: `"2025-06-15T14:30:00Z"`. Stored as
`TIMESTAMPTZ` (Postgres) or `TEXT` (SQLite).
## Page Routes (Non-API)
Server-rendered Go template surfaces. Not REST endpoints — return HTML.
| Route | Surface | Description |
|-------|---------|-------------|
| `/login` | Login | Standalone login/register page |
| `/` | Chat | Main chat interface |
| `/chat/:chatID` | Chat | Chat with specific channel loaded |
| `/editor` | Editor | Workspace file editor |
| `/editor/:wsId` | Editor | Editor with specific workspace |
| `/notes` | Notes | Notes interface |
| `/notes/:noteId` | Notes | Notes with specific note loaded |
| `/admin` | Admin | Platform administration |
| `/admin/:section` | Admin | Admin with specific section |
| `/settings` | Settings | User settings |
| `/settings/:section` | Settings | Settings with specific section |
| `/w/:id` | Workflow Landing | Branded workflow entry page |
| `/w/:id/:slug` | Workflow Landing | Slug-suffixed workflow entry |
| `/s/:slug` | Extension Surface | Dynamic surface from registry |
All page routes (except `/login`, `/w/`) require authentication via
`AuthOrRedirect` middleware. Admin routes additionally require
`RequireAdminPage()`. Workflow landing pages use `AuthOrSession`.