---
id: conventions
title: "Конвенции справочника"
kind: shared
---

# Конвенции справочника {#conventions}

Общие понятия, на которые ссылаются страницы методов. Здесь — канон; на страницах
методов даются только ссылки сюда.

## Уровни доступа (middleware)

Каждый эндпоинт защищён одним или несколькими middleware (`server/auth/middleware.js`).
В блоке инвентаря страницы метода поле **Auth** показывает их как есть из кода.

| Middleware | Смысл |
|---|---|
| `optionalAuth` | Аноним (гость) **и** авторизованный допускаются. Гостю PG отдаёт только его guest-данные. |
| `requireAuth` | Только авторизованный пользователь (есть сессия-cookie или валидный токен). |
| `requireProjectAccess` | Загружает проект и проверяет доступ читателя; уровень (`read`/`write`) кладёт в `req.projectAccess`. Точную запись (owner/spaceman/org_admin) досматривает PG-функция. |
| `requireSiteAdmin` | Только site-admin с активной TOTP-сессией. Токену недоступно ни на одном scope. |

Внутри write-хендлеров часто есть дополнительная проверка: для guest-спейса —
заголовок `X-Guest-Projects` (claim на конкретный проект), для владельческих
проектов — `req.projectAccess === 'write'`. Точные правила ролей — в матрице
[RP](../../matrices/rp/) (источник истины разрешений) и в секции «Для человека»
каждого метода.

## Scope токена (агентный доступ)

Агент ходит под токеном владельца — **с теми же правами, что у него в UI**.

| Scope | Что можно |
|---|---|
| `read` | Только `GET`. |
| `read_write` | `GET` + мутации (`POST`/`PUT`/`PATCH`/`DELETE`), в пределах роли владельца. |

Никакому токену на любом scope недоступны **site-admin**-операции (by design).
Часть org-admin write-операций в v1 закрыта на уровне agent-gate
(`server/auth/agentGate.js`). Детали — в [путеводителе для агента](../guides/agents.md).

## Формат ответа для агента

- Cookie-клиент (браузер) всегда получает **JSON**.
- Токен с `Accept: text/markdown` (или `?format=md`) получает **Markdown-зеркало**
  ресурса (`server/agent/negotiate.js`). У ресурсов есть `ETag`; повтор с
  `If-None-Match` → `304` (экономия токенов).
- Блок `## Actions` в Markdown-ответе перечисляет только действия, доступные
  данному токену (его scope и роль владельца) — см. `server/agent/affordances.js`.

## Агентные конвенции записи {#agent-write-conventions}

Эти правила касаются только запросов под токеном (Bearer). Cookie-клиент
(браузер) ими не затронут: у фронта свои подтверждения и оптимистичная блокировка.
Реестр операций и их риск — `server/auth/opRegistry.js`.

### Ось риска (risk)

Каждая write-операция помечена риском. Метка видна в блоке `## Actions`
Markdown-ответа (см. `server/agent/affordances.js`):

| Риск | Что это | Примеры |
|---|---|---|
| `SAFE` | Обычная запись/обновление/восстановление | create/update/upsert, restore из корзины или версии, set-context, cancel-job |
| `DESTRUCTIVE` | Обратимое удаление/снятие/отзыв | soft-delete в корзину, remove участника, revoke, удаление ребра |
| `IRREVERSIBLE` | Необратимое уничтожение/сброс | permanent-delete из корзины, reset спейса к исходному |
| `COSTLY_LLM` | Запускает платную LLM-генерацию | generate/regenerate графа, doc-content generate/inline-edit, suggest-prompt |

### Confirm-гейт (`409`)

Операции с риском `IRREVERSIBLE` или `COSTLY_LLM` требуют от токена явного
подтверждения: пришлите `{"confirm": true}` в теле. Без него — `409` (RFC 9457
`application/problem+json`) с полями `op` и `risk`. Принимается только литеральное
булево `true` собственным свойством тела (не строка `"true"`, не `1`). Гейт стоит
выше роутеров, поэтому SSE-генератор (`COSTLY_LLM`) получает `409` до открытия
`text/event-stream` — ответ приходит обычным JSON (`server/auth/confirmGate.js`).

### Оптимистичная блокировка (`If-Match` → `412`)

Опционально: перед `PUT /api/projects/{id}`, `PUT /api/collections/{id}` или
`PATCH …/doc-content/{node}` можно прислать `If-Match: "<ETag>"` (ETag берётся из
предыдущего чтения ресурса). Если ресурс изменился параллельно — `412`
(`precondition_failed`), перечитайте и повторите. Заголовок опциональный: без него
поведение прежнее. Маркер версии — `updated_at` ресурса; **граф проекта не двигает
`updated_at`** — `If-Match` защищает метаданные (заголовок/промпт/спейс, поля
коллекции, содержимое блока), не топологию графа (`server/agent/ifMatch.js`).

### Асинхронный режим долгих генераций (`?mode=async` → `202` + poll)

Долгие генерации по умолчанию стримят SSE. Токен может вместо этого запросить
фоновую постановку: добавьте `?mode=async` к запросу генерации — вместо SSE придёт
`202 {job_id, poll}`. Дальше опрашивайте статус по `poll`-URL
(`GET …/jobs/{jobId}`); статусы `pending → running → succeeded|failed|canceled`.
Отменить — `POST …/jobs/{jobId}/cancel` (best-effort: генератор без канала
прерывания может доработать, результат сохранится). Poll-ответ **leak-безопасен**:
он не отдаёт `actor_snapshot`, `request_body`, `token_id` — только статус, прогресс
и время. Задача принадлежит своему ресурсу (IDOR-защита по `resource_type` +
`resource_id`). Async-режим доступен только токену; cookie-клиент всегда получает
SSE. Инфраструктура — `server/services/jobRunner.js`, таблица `generation_job`.

### Экспонирующие операции — только через человека (`403`)

Шеринг (`/share`), перенос проекта (`/transfer`, `/transfer-owner`) и публичность
коллекции (`is_public`) **недоступны токену на любом scope** — они делают ресурс
видимым за пределами текущих прав и требуют одобрения человека. Токену такой запрос
отвечает `403` (для `is_public` — жёсткий `400`/`403`). Это не confirm-гейт: агент
не может подтвердить сам, канала внешнего одобрения пока нет
(`server/auth/opRegistry.js` → `WRITE_DENY_HUMAN_APPROVAL`).

## display label ≠ system key

Видимая надпись (заголовок H1, текст кнопки) — это **отображение**; слаг `id:`,
имя PG-функции, ключ в коде — это **системные ключи**. Переименование надписи не
меняет системный ключ, и наоборот. Слаги страниц — системные ключи: они
постоянны, на них ссылаются снаружи.

## Роли

Шесть ролей системы: `guest`, `employee`, `spaceman` (менеджер спейса),
`supervisor` (наблюдатель, read-only), `org_admin`, `site_admin`. Подробно —
[roles](roles.md).

---

Human view: https://docs.vnimanie.ai/specbuilder/v1/shared/conventions/