Всё, что видит платформа, доступно снаружи по HTTP: описание API, каталоги операций, состояние оборудования, сухой прогон программы. Правило одно и оно не настраивается — наружу отдаётся чтение и проверка, движение станка остаётся за человеком. Ниже — путь от первого запроса до разобранной программы, с точными адресами и текстами отказов.
Каждый путь под /api/ закрыт токеном. Исключения ровно четыре и они не про
интеграцию: проверка живости, сама ручка входа, гостевой вход и подключение свежего бокса
по одноразовому коду.
curl -s https://cncai.ru/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"…","password":"…"}' Что увидите. Ответ вида
{"access_token":"eyJ…","token_type":"bearer","expires_in":…,"user":"…"}.
Поле expires_in — остаток жизни токена в секундах; срок задаётся на установке
переменной AICNC_JWT_EXPIRES_HOURS, поэтому его не надо зашивать в свой код —
читайте из ответа. Дальше токен идёт заголовком:
Authorization: Bearer <access_token>
Там, где заголовок послать нельзя — ссылка в браузере, картинка, сторонний
генератор клиентов, — тот же токен принимается параметром ?token=…. Это касается
и самой спецификации: /api/openapi.json?token=… открывается инструментом,
который умеет только URL.
Свой рабочий токен наружу отдавать не нужно. Полным токеном выпускается отдельный, читающий — им и живёт интеграция или ассистент:
curl -s -X POST https://cncai.ru/api/auth/assistant-token \ -H 'Authorization: Bearer <ваш полный токен>'
Что увидите. {"access_token":"…","scope":"assistant","expires_in":…}.
Поле scope — и есть ограничение.
GET, HEAD, OPTIONS по всему API;POST /api/automation/validate;POST /api/cad/templates/{id}/manifest;POST /api/cutting-chain/check: арифметика по присланным
числам, ничего не меняющая.Любой другой POST получает 403 с текстом
«Токен ассистента: только чтение и превью (validate/manifest). Исполнение на станке — через
основной UI с человеком». Это закрытый список разрешённого, а не открытый список
запрещённого: новая исполняющая ручка автоматически оказывается запрещена, а не наоборот.
Под запрет попадают пуск стенда, отправка программы, базирование, толчок оси, ручной кадр,
создание станка из конструктора.
Почему это не снимается правами. Читающий токен рассчитан на внешнюю систему и на языковую модель — субъекта, который может ошибиться уверенно. Дописать ему исполнение значило бы отдать движение железа внешнему боту, то есть отменить причину, по которой ограничение вообще заведено.
Описание не пишется руками и не может отстать от кода — оно порождается самим приложением из его же схем:
GET /api/openapi.json машиночитаемое описание: пути, схемы, коды ответов GET /api/docs то же самое человеку — страница с формой «попробовать»
Что увидите. Обычный документ OpenAPI: по нему генератор клиентов соберёт библиотеку на вашем языке, а ассистент — список доступных вызовов с типами полей.
Спецификация лежит именно под /api/, а не в корне: наружу
маршрутизируется только этот префикс, и по корневому адресу описание из-за периметра
не открывалось. Если ваш инструмент по привычке идёт на /openapi.json и
получает 404 — поправьте базовый адрес, ручка не пропала.
Каталог отвечает на вопрос «что оборудование умеет и какие параметры принимает» — и отвечает схемой, а не прозой. Каталогов два, по числу движков генерации:
GET /api/generators операции реза: параметры, единицы, границы GET /api/automation/catalog операции автоматики: шаги, условия, предельные значения
Что увидите у операции реза. Кроме имени и описания — список параметров,
и у каждого: key (как звать в запросе), label (как зовут человеку),
type, default, min / max / step,
unit («мм», «°», «об/мин»), options для списков и
required. Этого хватает, чтобы внешняя система построила форму или проверила
значение до отправки.
Что увидите у операции автоматики. Реестр шагов спецификации, схему условий перехода между шагами и предельные значения безопасности — те самые, которыми программа ограничена при прогоне.
Каталог реза отдаёт операции обоих родов. Различает их поле
discipline: cut — траектория выводится из объёма детали,
motion — траекторию называет автор. Фильтруйте по нему, а не по имени.
Перед тем как что-то отправлять, программу можно разобрать полностью — тем же строгим разбором, который потом валит настоящий прогон:
POST /api/automation/validate {"spec": {"kind":"mode_blocks", …}}
POST /api/automation/preflight то же тело — но про сопоставление с железом Что увидите. validate вернёт
{valid, errors, human_steps}. Поле human_steps — разбор шагов
по дорожкам человеческими словами; его и надо показать оператору перед отправкой, а не
свою пересказанную версию. preflight вернёт
{ok, unmapped} — какие серво и входы-выходы программа использует, но со
слейвами стенда они не связаны.
Сухой прогон отвечает 200 даже когда программа плоха. Вердикт лежит в
valid, а не в коде ответа: разбор состоялся, ошибок в нём — список.
Клиент, читающий только HTTP-код, примет неверную программу за проверенную.
Проходит разбор ≠ поедет на железе. validate ничего не знает
о том, сопоставлены ли оси с приводами и включено ли питание. Это разные вопросы, и
второй задаётся отдельно — preflight.
| Метод и путь | Что делает | Тело | Что вернёт | Кому доступно |
|---|---|---|---|---|
| POST /api/auth/login | Обменять логин и пароль на JWT. | { "username": "…", "password": "…" } | { access_token, token_type: "bearer", expires_in, user } — expires_in в секундах. | без токена |
| GET /api/auth/me | Проверить, что токен ещё жив. Ровно это делает веб-интерфейс при загрузке. | — | { user, ok: true } | любой токен |
| POST /api/auth/assistant-token | Выпустить токен только на чтение — для внешней системы или ассистента. | — | { access_token, token_type: "bearer", expires_in, scope: "assistant" } | только полный токен |
| GET /api/openapi.json | Машиночитаемое описание всего API: пути, схемы тел и ответов, коды. | — | Стандартный документ OpenAPI. Принимает и заголовок Bearer, и ?token=… — второе для инструментов, которые не умеют слать заголовки. | любой токен |
| GET /api/docs | То же описание человеку — интерактивная страница Swagger UI. | — | Страница со списком ручек и формой «попробовать». | любой токен |
| GET /api/generators | Каталог операций: что платформа умеет генерировать и какие параметры берёт. | — | Массив описаний. У каждого: id, name, description, category, discipline и params — список параметров с key, label, type, default, min, max, step, unit, options, required. | любой токен |
| GET /api/generators/{id} | Описание одной операции. | — | То же описание, одной записью. | любой токен |
| GET /api/automation/catalog | Каталог операций автоматики: чем описывается шаг программы узла. | — | Реестр операций спецификации (CSV / CSP / CST / DO / WAIT / PAUSE): параметры с типами, умолчаниями и границами, схема условий перехода, предельные значения безопасности и формат самой спецификации. | любой токен |
| POST /api/automation/validate | Сухой прогон: проверить программу узла, ничего не двигая. | { "spec": { "kind": "mode_blocks", … } } | { valid, errors, human_steps } — human_steps это разбор шагов по дорожкам человеческими словами, для показа оператору ДО отправки. | любой токен, включая читающий |
| POST /api/automation/preflight | Проверить, что все серво и входы-выходы программы сопоставлены с железом узла. | { "spec": { … } } | { ok, unmapped: [ { kind, index, label, reason } ] } — тот же гейт, что валит настоящий прогон, но заранее и списком. | любой токен |
Полный список ручек — в самой спецификации:
/api/openapi.json. Здесь только те, с которых начинается интеграция.
Тексты приведены дословно — по ним отказ и опознаётся в логе.
| Код | Текст | Что это значит | Что делать | Где |
|---|---|---|---|---|
| 401 | Требуется авторизация | Токена в запросе нет, он просрочен или испорчен. | Получить новый через POST /api/auth/login. Заголовок — Authorization: Bearer <токен>. | middleware |
| 401 | Неверный логин или пароль | Ответ один и тот же и на несуществующего пользователя, и на неверный пароль — чтобы перебором нельзя было выяснить, какой логин существует. | Проверить обе строки. По коду ответа отличить одно от другого нельзя, и это сделано намеренно. | POST /api/auth/login |
| 401 | Missing token | Запрос на выпуск читающего токена пришёл вообще без токена. | Сначала войти самому, потом выпускать токен ассистенту. | POST /api/auth/assistant-token |
| 403 | Только полный токен может выпускать ассистентские | Читающий токен попытался выпустить себе ещё один. Ассистент не клонирует сам себя — иначе ограничение обходилось бы одним вызовом. | Выпускать читающие токены только полным токеном человека. | POST /api/auth/assistant-token |
| 403 | Токен ассистента: только чтение и превью (validate/manifest). Исполнение на станке — через основной UI с человеком. | Читающим токеном вызвали что-то исполняющее: пуск, отправку программы, базирование, толчок оси, ручной кадр. | Это не ошибка настройки и не снимается правами: движение станка остаётся за человеком в интерфейсе. Внешней системе доступны чтение, каталоги и сухой прогон. | middleware |
| 404 | Генератор не найден | Запрошен id операции, которого в каталоге нет. | Сверить со списком GET /api/generators — там актуальные id. | GET /api/generators/{id} |
| 200 | { "valid": false, "errors": [ … ] } | Сухой прогон — не отказ HTTP: разбор всегда возвращается со статусом 200, а вердикт лежит в поле valid. | Читать valid, а не код ответа. Тексты в errors — те же, что увидит оператор при настоящем прогоне. | POST /api/automation/validate |
Нужен доступ к интеграции или разбор сценария — напишите нам.