Changeset 0.28.0.1 (#173)
This commit is contained in:
155
docs/ICD/README.md
Normal file
155
docs/ICD/README.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# 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).
|
||||
|
||||
### Pagination Envelope
|
||||
|
||||
Endpoints that paginate return:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [...],
|
||||
"page": 1,
|
||||
"per_page": 50,
|
||||
"total": 142,
|
||||
"total_pages": 3
|
||||
}
|
||||
```
|
||||
|
||||
Query params: `?page=1&per_page=50`. Not all list endpoints paginate —
|
||||
some return `{ "data": [...] }` or a bare array in a named key.
|
||||
|
||||
### 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`.
|
||||
Reference in New Issue
Block a user