Документация только реализованных endpoints. Полный планируемый набор (DMs, files, reactions, edit/delete и т.д.) — в ROADMAP.md.
Base URL (dev): http://localhost:3001
Защищённые endpoints требуют:
Authorization: Bearer <access_token>
Response format: JSON без обёрток. Ошибки — { "error": "..." }
с соответствующим HTTP-кодом. (Envelope { ok, data } упоминавшийся
в ранних docs — НЕ применён, см. ROADMAP § housekeeping.)
Простой ping без префикса /api.
{ "ok": true, "service": "eclipse-chat-server" }Ping + проверка БД.
{ "ok": true, "service": "eclipse-chat-server", "database": true }{ "name": "@eclipse-chat/server", "version": "0.3.0" }Все endpoints требуют Bearer JWT и membership в :id. Полный контракт и trust boundary:
contracts/growth-run-v1.md.
Возвращает до 30 последних импортированных материалов и server-owned review status.
Требует header Idempotency-Key и body { "run": <growth.run.v1> }. При новом импорте
возвращает 201; идентичный повтор возвращает существующую запись; конфликт содержимого — 409.
Требует permission TASK_APPROVE. Body:
{
"version": 1,
"decision": "APPROVE",
"humanConfirmed": true,
"note": "Ссылки и CTA проверены"
}Stale version или повторное решение возвращают 409. Endpoint утверждает только текстовый
артефакт и не запускает публикацию.
Все endpoints требуют Bearer JWT и membership в :id. Полный контракт и trust boundary:
contracts/deck-job-v1.md.
Возвращает до 30 последних презентаций и независимый server-owned review status.
Требует permission TASK_CREATE, header Idempotency-Key и body
{ "job": <deck.job.v1> }. Принимает только upstream-статус approved, но сбрасывает
его в ready_for_review; идентичный повтор безопасен, конфликт содержимого возвращает 409.
Требует permission TASK_APPROVE, точную version и независимый checklist. Для APPROVE
обязательны claimsVerified, rightsConfirmed и finalReviewComplete; для REJECT —
комментарий не короче трёх символов. Endpoint меняет только review status и не публикует материалы.
Требует permission TASK_APPROVE и запись со статусом APPROVED в том же workspace.
Возвращает editable 16:9 .pptx с text shapes и speaker notes. Renderer не загружает
evidence URLs, не вызывает внешние tools, не включает sourceText, ограничивает результат 4 МБ
и возвращает 404 для чужого или неутверждённого review. Rate limit — 5 файлов за 15 минут.
Все endpoints требуют Bearer JWT и membership в :id. Полный контракт и trust boundary:
contracts/builder-project-v1.md.
Возвращает до 30 последних server-owned проектов. Source approval не переносится.
Требует TASK_CREATE, Idempotency-Key и body { "project": <builder.project.v1> }.
Принимает только upstream approved, сбрасывает approval и повторно блокирует build queue.
Требует TASK_APPROVE и точную version. Approval требует три подтверждения: требования,
security boundary и preview. Rejection требует комментарий. Endpoint не запускает build или deploy.
Access token живёт 15 минут. Refresh token хранится в БД как
SHA-256 hash, ротация при каждом /refresh.
// Request
{
"email": "pavel@example.com",
"password": "atleast8chars",
"displayName": "Pavel"
}
// Response 200
{
"accessToken": "eyJhbGciOi...",
"refreshToken": "raw-refresh-token-string",
"token": "eyJhbGciOi...", // = accessToken, legacy duplicate
"user": {
"id": "ckxxx",
"email": "pavel@example.com",
"displayName": "Pavel",
"createdAt": "2026-05-11T16:00:00.000Z"
}
}
// Errors
// 400 — invalid body (zod validation)
// 409 — email already registered// Request
{ "email": "pavel@example.com", "password": "atleast8chars" }
// Response 200 — same shape as register
// Side effect: все предыдущие refresh-токены этого user'а инвалидируются
// Errors
// 400 — invalid body
// 401 — invalid email or password// Request
{ "refreshToken": "raw-refresh-token-string" }
// Response 200
{
"accessToken": "eyJhbGciOi...",
"refreshToken": "new-rotated-refresh-token",
"token": "eyJhbGciOi..." // = accessToken, legacy duplicate
}
// Errors
// 400 — invalid body
// 401 — invalid refresh token (expired / not found / user deleted)Ротация: старый refresh-token удаляется, новый выдаётся. Если клиент теряет refresh между запросом и ответом — нужно делать login заново.
Требует Bearer. Body может быть пустым.
// Response 200
{ "ok": true }
// Side effect: ВСЕ refresh-токены user'а удаленыТребует Bearer.
// Response 200
{
"user": {
"id": "ckxxx",
"email": "pavel@example.com",
"displayName": "Pavel",
"createdAt": "2026-05-11T16:00:00.000Z"
}
}
// Если access невалиден → 401 (без user wrapper)Сервера — контейнеры каналов и участников. Создатель автоматически
становится Member с role = "OWNER". Один user — один Member на server
(unique userId+serverId).
role принимает значения: "OWNER" | "ADMIN" | "MODERATOR" | "MEMBER"
(хранится как String в SQLite — нативный enum появится в v0.6
после PG-миграции).
Требует Bearer. Возвращает серверы, в которых current user — Member.
{
"servers": [
{
"id": "ckxxx",
"name": "Default Server",
"icon": null,
"inviteCode": "ckcccc",
"ownerId": "cksss",
"createdAt": "2026-05-11T16:00:00.000Z",
"memberCount": 1,
"channelCount": 1,
"role": "OWNER"
}
]
}Требует Bearer. Body: { name, icon? }. Создаёт server +
Member(role="OWNER") для current user в одной транзакции.
// Request
{ "name": "My Server", "icon": null }
// Response 200
{
"server": {
"id": "ckxxx",
"name": "My Server",
"icon": null,
"inviteCode": "ckcccc",
"ownerId": "ckuser",
"createdAt": "2026-05-11T16:00:00.000Z",
"role": "OWNER"
}
}
// Errors: 400 invalid body, 401 UnauthorizedТребует Bearer + membership.
{
"server": {
"id": "ckxxx",
"name": "My Server",
"icon": null,
"inviteCode": "ckcccc",
"ownerId": "ckuser",
"createdAt": "...",
"memberCount": 3,
"channelCount": 5,
"role": "MEMBER"
}
}
// Errors: 401 Unauthorized, 403 Not a member, 404 Server not foundТребует Bearer + role = "OWNER". Cascade удалит channels, members,
messages.
// Response 200
{ "ok": true }
// Errors: 401, 403 (not owner), 404Требует Bearer. Вступление по инвайт-коду. Idempotent: если user
уже Member — возвращает alreadyMember: true без ошибки.
// Response 200
{
"server": { "id": "...", "name": "...", "icon": null, "ownerId": "..." },
"member": { "id": "...", "role": "MEMBER" },
"alreadyMember": false
}
// Side effect (если новое присоединение):
// Socket emit `member:joined` в room `server:${serverId}`
// Errors: 401, 404 Invite not foundТребует Bearer + membership + не OWNER (owner не может leave — сначала delete server или transfer ownership).
// Response 200
{ "ok": true }
// Side effect: Socket emit `member:left`
// Errors: 401, 403 (owner cannot leave), 404Требует Bearer + membership.
{
"members": [
{
"id": "ckmember",
"userId": "ckuser",
"role": "OWNER",
"joinedAt": "...",
"user": { "id": "...", "displayName": "Pavel", "email": "...", "createdAt": "..." }
}
]
}Сортировка: по role (OWNER first lexicographically), затем по joinedAt asc.
Требует Bearer + membership.
{
"channels": [
{
"id": "ckchan",
"name": "general",
"slug": "general",
"position": 0,
"createdAt": "...",
"_count": { "messages": 42 }
}
]
}Требует Bearer + membership. Любой Member может создать канал (role permissions для ADMIN+ — в v1.0).
// Request
{ "name": "announcements" }
// Response 200
{
"channel": {
"id": "ckchan",
"name": "announcements",
"slug": "announcements",
"position": 0,
"createdAt": "..."
}
}
// Side effect: Socket emit `channel:created` в room `server:${serverId}`
// Errors: 400, 401, 403 (not a member), 404GET /api/channels и POST /api/channels — legacy aliases для
backward compat с фронтендом до Step 2 split. Работают на "Default
Server" (созданный seed-миграцией). Будут deprecate'нуты когда
frontend перейдёт на /api/servers/:id/channels.
GET/POST /api/channels/:id/messages остаются как сейчас (работают
по channelId, не зависят от server scope).
Открытый endpoint (без auth).
{
"channels": [
{
"id": "ckxxx",
"name": "General",
"slug": "general",
"createdAt": "2026-05-11T16:00:00.000Z",
"_count": { "messages": 42 }
}
]
}Требует Bearer.
// Request
{ "name": "Announcements" }
// Response 200
{
"channel": {
"id": "ckxxx",
"name": "Announcements",
"slug": "announcements", // auto-generated, ASCII slug с retry на коллизии
"createdAt": "2026-05-11T16:00:00.000Z"
}
}
// Errors
// 400 — invalid body (name пустое или >80 символов)
// 401 — UnauthorizedSlug-генерация: lowercase, NFKD-нормализация (убирает диакритику),
только [a-z0-9-], max 48 символов. При коллизии — добавляется случайный
суффикс. Кириллица превращается в channel (TODO: нормальная
транслитерация в roadmap-housekeeping).
Открытый endpoint. Возвращает последние N сообщений в хронологическом порядке (старые первые).
GET /api/channels/ckxxx/messages?take=80
{
"channel": { "id": "ckxxx", "name": "General", "slug": "general" },
"messages": [
{
"id": "ckmmm",
"content": "Hello",
"createdAt": "2026-05-11T16:00:00.000Z",
"user": { "id": "ckuuu", "displayName": "Pavel" }
}
]
}Параметры:
take(optional) — сколько сообщений вернуть. Default50, max100, min1. Сейчас без cursor-пагинации (planned для v0.12).
Errors:
- 404 — канал не найден
Требует Bearer.
// Request
{ "content": "Hello, world!" }
// Response 200
{
"message": {
"messageId": "ckmmm",
"content": "Hello, world!",
"channelId": "ckxxx",
"userId": "ckuuu",
"displayName": "Pavel",
"createdAt": "2026-05-11T16:00:00.000Z"
}
}Side effect: Socket.io emit message:new всем подключённым к
room channel:${id} с тем же payload.
Membership check (с v0.4): если channel.serverId задан, current
user должен быть Member этого server, иначе 403. Legacy каналы без
serverId (которых после seed-миграции не существует) — без проверки.
Errors:
- 400 — invalid body (content пустой или >8000 символов)
- 401 — Unauthorized / Invalid token
- 403 — Not a member of this server
- 404 — Channel not found / User not found
Все ошибки:
{ "error": "Описание ошибки" }| HTTP | Когда |
|---|---|
| 400 | zod validation failed |
| 401 | нет токена / токен невалиден / истёк |
| 404 | ресурс не найден |
| 409 | конфликт (e.g. email уже зарегистрирован) |
Rate limiting — не реализован. Запланирован для v1.4 production.
Что НЕ реализовано (в ROADMAP)
- ✅
/api/servers/*— добавлено в v0.4 (выше) - ❌
/api/dm/:userId— Direct Messages (v0.8) - ❌
/api/files/upload— MinIO загрузки (v0.9) - ❌
/api/users/*— поиск пользователей, profile updates (v1.0) - ❌
PATCH /api/messages/:id— edit (v0.12) - ❌
DELETE /api/messages/:id— delete (v0.12) - ❌ Cursor-пагинация
?before=для messages (v0.12) - ❌
PATCH /api/servers/:id— изменение имени / иконки / inviteCode (v0.4+) - ❌
POST /api/servers/:id/transfer-ownership(v1.0) - ❌
DELETE /api/servers/:id/members/:memberId— kick (v1.0) - ❌ Response envelope
{ ok, data }— решение: НЕ применять (см. ROADMAP housekeeping)
Updated 2026-05-11 — v0.4 (Server/Member/invite) добавлен в Step 1.
Синхронизировано с реальным кодом apps/server/src/routes/.