ТЗ: Workbench для API документации¶
1. Цель¶
Нужно реализовать интерактивный модуль Workbench, похожий по идее на Stripe Workbench Console: пользователь находится на странице метода API, видит готовую форму запроса, может изменить параметры, отправить запрос и увидеть ответ без перехода из документации.
Модуль должен покрывать:
- все страницы раздела
docs/tcp/**; - все страницы раздела
docs/client-api/rest/**; - React-интерфейс внутри существующего приложения
app; - небольшой backend-модуль, через который Workbench будет выполнять запросы;
- TCP-вызовы только через backend, так как браузер не может безопасно и напрямую работать с raw TCP.
2. Контекст текущего проекта¶
Проект сейчас устроен так:
- документация собирается через MkDocs Material;
- исходники документации находятся в
docs; - основная навигация описана в
mkdocs.yml; - React-код находится в
app; - Vite собирает
app/main.jsxв UMD bundledocs/assets/app/bundle.js; - React-бандл подключается глобально через
extra_javascriptвmkdocs.yml; - текущие React-модули монтируются по root-элементам:
root_profile,root_login,root_contactи т.д.; - страницы TCP и REST API сейчас являются markdown-страницами с таблицами параметров и JSON-примерами;
- формального OpenAPI/JSON Schema слоя для всех методов сейчас нет.
Вывод: Workbench не должен полагаться на парсинг HTML/markdown как на основной источник схемы метода. Нужен отдельный слой метаданных или сгенерированный manifest.
3. Основное решение¶
Рекомендуемая архитектура:
- В документации появляется machine-readable manifest методов.
- React Workbench загружает manifest/схему текущего метода.
- Пользователь редактирует запрос в UI.
- Frontend отправляет нормализованный запрос в backend Workbench.
- Backend проверяет права, метод, окружение и payload.
- Backend выполняет REST или TCP-вызов к целевому API.
- Frontend показывает нормализованный ответ.
4. Размещение Workbench на страницах¶
Workbench должен отображаться на страницах методов:
/tcp/...;/client-api/rest/....
Workbench не должен автоматически отображаться на обзорных страницах, если метод не описан в manifest.
Рекомендуемый способ монтирования:
- добавить MkDocs hook, который на этапе сборки вставляет контейнер:
<div id="root_workbench" data-workbench-method="tcp.finance.BalanceIn"></div>
- в
app/main.jsxдобавить монтирование React-компонента, если найденroot_workbench.
Альтернатива: React сам проверяет window.location.pathname и динамически создает контейнер. Этот вариант проще для прототипа, но хуже контролирует, на каких страницах появляется модуль.
5. Manifest методов¶
Нужно добавить manifest, например:
docs/assets/workbench/manifest.json
Минимальная структура для TCP:
{
"id": "tcp.finance.BalanceIn",
"page": "/tcp/finance/BalanceIn/",
"protocol": "tcp",
"title": "BalanceIn",
"category": "finance",
"command": "BalanceIn",
"auth": "manager",
"executionMode": "mutating",
"parameters": [
{
"name": "login",
"type": "int",
"required": true,
"location": "body",
"description": "User login ID"
},
{
"name": "amount",
"type": "double",
"required": true,
"location": "body",
"description": "Positive amount"
}
],
"requestExample": {
"login": 123456,
"amount": 1000,
"comment": "Initial deposit"
}
}
Минимальная структура для REST:
{
"id": "rest.trade.OpenTrade",
"page": "/client-api/rest/trade/OpenTrade/",
"protocol": "rest",
"title": "Open Trade",
"method": "POST",
"path": "/trade/open",
"auth": "customer",
"contentType": "application/json",
"executionMode": "mutating",
"parameters": [],
"requestExample": {
"login": 1001,
"cmd": 0,
"volume": 100,
"symbol": "EURUSD",
"sl": 1.08,
"tp": 1.1
}
}
Варианты наполнения manifest:
- вручную описать методы в одном JSON-файле;
- добавить
workbenchfront matter в каждую markdown-страницу; - написать генератор, который извлекает таблицы и JSON-примеры из markdown, а спорные места закрываются override-файлом.
Рекомендуемое решение для первого этапа: начать с manifest.json и 5-10 методов, потом автоматизировать генерацию.
5.1 Синхронизация manifest с документацией¶
Manifest не должен поддерживаться как независимый ручной JSON без проверки, иначе он быстро разойдется с markdown-страницами.
Рекомендуемая модель синхронизации:
- Источник правды находится рядом с документацией метода:
---
title: "ScaleTrade TCP API - Balance In"
workbench:
id: tcp.finance.BalanceIn
protocol: tcp
command: BalanceIn
auth: manager
executionMode: mutating
---
- Markdown-страница продолжает содержать таблицу параметров и
Request Example. - Скрипт сборки
scripts/mkdocs_workbench_manifest.pyчитает front matter, таблицы параметров и JSON-примеры. - Скрипт генерирует
docs/assets/workbench/manifest.json. - Для нестандартных методов используется override-файл, например
docs/assets/workbench/overrides.json. - CI проверяет, что сгенерированный manifest актуален. Если markdown изменился, а manifest не обновлен, сборка падает.
На первом этапе допустим ручной manifest для ограниченного набора методов, но в production-версии нужен генератор и CI-check.
6. React-модуль¶
Рекомендуемая структура:
app/components/Workbench/Workbench.jsx
app/components/Workbench/Workbench.module.css
app/components/Workbench/fields/
app/api/workbench.js
В app/main.jsx добавить:
- импорт
Workbench; - проверку
document.getElementById("root_workbench"); - чтение
data-workbench-method; ReactDOM.render(<Workbench methodId={methodId} />, root).
UI должен содержать:
- badge протокола:
TCPилиREST; - название метода/команды;
- выбранное окружение:
Sandbox,Development,Production, если разрешено; - для TCP: поля
host,port,auth tokenвнутри Workbench; - сохранение TCP-настроек сессии в browser storage только если пользователь явно включил сохранение;
- форму параметров на основе manifest;
- режим raw JSON для сложных payload;
- автозаполнение из
requestExample; - кнопку reset к примеру из документации;
- кнопку отправки;
- копирование request/response;
- отображение ответа в форматированном JSON;
- transport metadata: HTTP status, duration, request id/correlation id;
- понятные ошибки: validation error, auth error, timeout, TCP connection error, upstream API error.
Если пользователь не авторизован, Workbench должен показывать prompt на вход и блокировать отправку.
7. Backend-модуль Workbench¶
Backend нужен обязательно, потому что:
- TCP нельзя вызывать из браузера напрямую;
- браузер должен отправлять TCP-параметры на backend по защищенному WebSocket, а backend уже открывает TCP-соединение;
- нельзя доверять frontend выбору command, execution mode и разрешений;
- нужен audit log и rate limit.
Рекомендуемый стек: Node.js/TypeScript. Основной backend ScaleTrade работает на C++, поэтому Workbench bridge логично делать отдельным небольшим Node.js-модулем, который будет жить рядом со статической документацией и проксироваться через тот же nginx/host/port.
Ключевое deployment-требование:
- Workbench backend должен работать из-под основного Docker image документации;
- внешний порт остается тем же, что сейчас у nginx;
- nginx отдает статические страницы документации;
- nginx проксирует
/workbench/*во внутренний Node.js bridge; - WebSocket
/workbench/tcpдолжен работать через nginx reverse proxy сUpgrade/Connectionheaders; - Node.js bridge слушает только localhost/internal port внутри контейнера, например
127.0.0.1:3100.
Логическая структура Node.js-модуля:
workbench/
package.json
tsconfig.json
src/
server.ts # HTTP endpoints and WebSocket route
tcpBridge.ts # WS session -> TCP connection lifecycle
tcpCodec.ts # ScaleTrade TCP serialize/parse
manifest.ts # method schema loading and validation
security.ts # auth, host policy, rate limits, masking
audit.ts # execution audit log
Минимальные endpoint-ы и каналы:
GET /workbench/config¶
Возвращает только frontend-safe настройки:
{
"enabled": true,
"environments": [
{
"id": "sandbox",
"label": "Sandbox",
"default": true
}
],
"limits": {
"timeoutMs": 10000,
"maxPayloadBytes": 65536
}
}
GET /workbench/methods/:methodId¶
Возвращает схему метода для текущего пользователя.
POST /workbench/execute¶
Выполняет REST или TCP-запрос.
Request:
{
"methodId": "rest.trade.OpenTrade",
"environment": "sandbox",
"payload": {},
"query": {},
"headers": {}
}
Response:
{
"ok": true,
"protocol": "rest",
"status": 200,
"durationMs": 120,
"body": {},
"error": null
}
Error response:
{
"ok": false,
"protocol": "tcp",
"status": null,
"durationMs": 10000,
"body": null,
"error": {
"code": "TCP_TIMEOUT",
"message": "TCP request timed out"
}
}
WS /workbench/tcp¶
WebSocket-канал для TCP-сессии Workbench.
Назначение:
- принять от React
host,port,auth tokenи параметры сессии; - открыть TCP-соединение с указанным endpoint;
- выполнить auth handshake с TCP API;
- принимать команды Workbench;
- возвращать ответы и события состояния соединения.
Frontend не должен открывать raw TCP. Он работает только с WebSocket backend-модуля.
Пример сообщения инициализации:
{
"type": "connect",
"requestId": "req_001",
"host": "tcp.example.com",
"port": 443,
"authToken": "manager-or-api-token",
"tls": true,
"timeoutMs": 10000
}
Пример выполнения TCP-команды:
{
"type": "execute",
"requestId": "req_002",
"methodId": "tcp.finance.BalanceIn",
"payload": {
"login": 123456,
"amount": 1000,
"comment": "Initial deposit"
}
}
Пример ответа:
{
"type": "result",
"requestId": "req_002",
"ok": true,
"durationMs": 84,
"body": {
"accepted": true,
"order": 1242279
}
}
8. REST execution flow¶
- React отправляет запрос в
/workbench/execute. - Backend проверяет авторизацию.
- Backend проверяет, что
methodIdесть в manifest. - Backend проверяет права пользователя и доступность окружения.
- Backend валидирует payload по схеме метода.
- Backend собирает upstream REST-запрос из server-side config.
- Backend отправляет запрос в целевой REST API.
- Backend возвращает нормализованный ответ во frontend.
Важно: frontend не должен иметь возможность передать произвольный URL для REST-вызова.
9. TCP execution flow¶
- React открывает
WS /workbench/tcp. - React отправляет
connectсhost,port,authToken, TLS-флагом и timeout. - Backend проверяет авторизацию пользователя Workbench.
- Backend валидирует
host,port, лимиты и право пользователя открывать TCP-сессии. - Backend открывает TCP-соединение с указанным host/port.
- Backend выполняет auth handshake с TCP API, используя token из Workbench.
- React отправляет
executeсmethodIdи payload. - Backend проверяет
methodId, execution mode, payload и confirmation-флаг для mutating-методов. - Backend сериализует payload в формат ScaleTrade TCP protocol.
- Backend отправляет запрос в TCP API.
- Backend читает ответ с timeout.
- Backend парсит ответ и возвращает нормализованный JSON через WebSocket.
Требования к TCP-адаптеру:
host,port,authTokenзадаются в Workbench UI и передаются на backend только по HTTPS/WSS;- backend не сохраняет
authTokenбез явного требования; - backend маскирует
authTokenво всех логах; - backend валидирует host/port и не должен становиться неограниченным TCP-прокси;
- timeout на connect и read;
- max payload size;
- max response size;
- structured logs;
- запрет логирования токенов, паролей, OTP и секретов;
- connection pool только если протокол поддерживает безопасное переиспользование соединения;
- явная обработка ошибок framing, auth, timeout, connection refused, malformed response.
В качестве основы для формата TCP-команд нужно использовать примеры из страницы https://scaletrade.com/tcp/ и конкретных страниц методов docs/tcp/**.
Открытая зависимость: нужно подтвердить точный TCP framing, auth handshake, request envelope, response envelope и correlation id.
10. Права и безопасность¶
Обязательные требования:
- выполнение запросов доступно только авторизованным пользователям;
- production execution выключен по умолчанию;
- backend хранит allowlist исполняемых методов;
- mutating-методы требуют дополнительного confirmation step;
- dangerous-методы отключены, пока отдельно не разрешены;
- rate limit по user, IP, method, environment;
- audit log на каждую попытку выполнения;
- маскирование sensitive полей: password, token, secret, otp, authorization;
- frontend не является источником правды по правам, endpoint, command и окружению;
- если
host/portвводятся пользователем, нужно отдельно согласовать SSRF-защиту: allowlist доменов, запрет localhost/internal ranges или tenant-level allowlist.
Режимы выполнения метода:
disabled- показываем форму/пример, но не даем отправить;read- read-only выполнение;mutating- выполнение с подтверждением;dangerous- скрыто или доступно только внутренним ролям.
Рекомендуемый rollout:
- Sandbox read-only REST.
- Sandbox read-only TCP.
- Sandbox selected mutating с confirmation.
- Production только после согласования ролей, audit и rollback-политики.
11. Изменения в документации¶
Нужно добавить:
docs/assets/workbench/manifest.json;- опционально страницу
docs/workbench.mdс описанием Workbench; - опционально скрипт
scripts/mkdocs_workbench_manifest.pyдля генерации manifest; - MkDocs hook для вставки
root_workbenchна нужные страницы.
Manifest должен версионироваться вместе с документацией, чтобы форма Workbench соответствовала опубликованной странице метода.
12. Docker и nginx reverse proxy¶
Текущий Dockerfile собирает MkDocs и в runtime stage использует nginx:alpine, который отдает только статику:
FROM nginx:alpine AS prod
EXPOSE 80
COPY --from=build /out/ /usr/share/nginx/html/
CMD ["nginx", "-g", "daemon off;"]
Для Workbench нужно доработать runtime image так, чтобы внутри одного контейнера работали:
- nginx на внешнем порту
80; - Node.js Workbench bridge на внутреннем порту, например
3100; - nginx reverse proxy для
/workbench/.
Варианты запуска процессов:
- использовать
supervisordилиs6-overlayдля запуска nginx и Node bridge; - либо использовать простой entrypoint script, который стартует Node bridge в background и затем запускает nginx foreground.
Для production предпочтительнее process supervisor, потому что он корректнее обрабатывает restart/exit одного из процессов.
Пример nginx location:
location /workbench/ {
proxy_pass http://127.0.0.1:3100/workbench/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 60s;
proxy_send_timeout 60s;
}
Для WebSocket upgrade также нужен map в nginx config:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Dockerfile должен быть расширен:
- добавить stage сборки Workbench bridge через Node.js;
- скопировать собранный bridge в runtime image;
- добавить nginx config;
- добавить supervisor/entrypoint;
- прокинуть environment variables для bridge.
Минимальные переменные:
WORKBENCH_PORT=3100
WORKBENCH_ALLOWED_HOSTS=*.scaletrade.com,*.internal.example
WORKBENCH_MAX_PAYLOAD_BYTES=65536
WORKBENCH_CONNECT_TIMEOUT_MS=10000
WORKBENCH_READ_TIMEOUT_MS=10000
WORKBENCH_AUDIT_ENABLED=true
13. Acceptance criteria¶
Функциональность считается готовой, если:
- Workbench отображается на страницах методов
tcpиclient-api/rest; - Workbench не отображается на нерелевантных страницах;
- request prefilled из manifest;
- пользователь может редактировать поля и raw JSON;
- required-поля валидируются до отправки;
- backend отклоняет неизвестный
methodId; - backend отклоняет произвольные REST URL;
- backend валидирует пользовательские TCP
host/portпо согласованной security policy; - TCP-запросы выполняются только через backend;
- успешный ответ отображается в UI;
- ошибки транспорта и ошибки upstream API различаются;
- неавторизованный пользователь не может выполнить запрос;
- mutating-методы требуют подтверждения;
/workbench/config,/workbench/methods/:methodId,/workbench/executeдоступны через тот же host/port, что и документация;WS /workbench/tcpработает через nginx reverse proxy;- Node.js bridge не доступен напрямую снаружи контейнера;
- текущая сборка
docs/assets/app/bundle.jsиbundle.cssпродолжает работать; - существующие React-виджеты login/profile/contact не ломаются.
14. План реализации¶
Этап 1. Прототип¶
- Создать manifest для 5-10 методов.
- Добавить React-компонент Workbench.
- Добавить mount logic в
app/main.jsx. - Добавить mock/stub backend endpoint.
- Реализовать отображение схемы, JSON editor и локальную валидацию.
Этап 2. REST execution¶
- Реализовать
/workbench/config. - Реализовать
/workbench/methods/:methodId. - Реализовать
/workbench/executeдля REST. - Добавить auth, allowlist, audit log и rate limit.
Этап 3. TCP execution¶
- Реализовать TCP adapter.
- Добавить server-side конфиг окружений.
- Реализовать сериализацию и парсинг TCP envelope.
- Включить несколько read-only TCP-команд в sandbox.
Этап 4. Покрытие документации¶
- Расширить manifest на все
docs/tcp/**иdocs/client-api/rest/**. - Классифицировать методы по
executionMode. - Добавить masking rules.
- Добавить confirmation UX для mutating-методов.
Этап 5. Hardening¶
- Добавить role-based access.
- Добавить метрики и мониторинг.
- Добавить интеграционные тесты против sandbox REST/TCP.
- Принять отдельное решение по production execution.
15. Вопросы для согласования¶
- Node.js bridge запускаем в том же контейнере через
supervisordили через entrypoint script? - Какой точный формат ScaleTrade TCP protocol: framing, auth handshake, envelope, correlation id?
- Какие роли пользователей могут выполнять TCP/server API запросы?
- Workbench должен использовать customer auth, manager auth или оба режима в зависимости от раздела?
- Какие окружения доступны в первом релизе: только sandbox, dev, staging, production?
- Разрешаем ли mutating-операции из документации или стартуем строго с read-only?
- Нужна ли изоляция по brand/company/tenant?
- Нужно ли пользователю сохранять свои environments/tokens или все окружения только server-side?
- Какой срок хранения audit log?
- Manifest делаем вручную на первом этапе или сразу пишем генератор из markdown?
- Какая security policy для пользовательского
host/port: wildcard allowlist, tenant-level allowlist или запрет private/internal ranges?
16. Решения, которые предлагаю принять сейчас¶
- Начать с server-side/static manifest, а не с парсинга markdown в браузере.
- Первый релиз делать sandbox-only.
- Production execution отключить до отдельного security review.
- TCP выполнять только через backend.
- Workbench bridge реализовать на Node.js/TypeScript.
- Запускать Node.js bridge внутри Docker image документации и проксировать
/workbench/через nginx. - Добавлять Workbench на страницы через MkDocs hook с явным
root_workbench. - Для всех mutating-методов требовать подтверждение.
host,port,auth tokenвводятся в Workbench UI и отправляются в bridge по WSS.