Перейти к основному содержимому

Панель управления — Tools API

Версия: 1.3
Дата: 22.04.2026
Статус: Утверждён

Панель управления документацией — браузерный интерфейс для запуска всех скриптов системы без терминала. Состоит из двух частей: API-сервер (tools/cms-tools-api.js) и страница интерфейса (static/admin/tools.html).

Открывается по адресу: http://localhost:3000/admin/tools.html
Из CMS-редактора — кнопка Инструменты в правом верхнем углу шапки.


Архитектура

Браузер (tools.html)

├── GET /projects — список проектов из docs/
├── GET /run/<script> — запуск скрипта, SSE-поток вывода
├── GET /convert — конвертация SVG или возврат к SVG
├── GET /deploy-convert — деплой с опциональной конвертацией
└── POST /import — upload файла + запуск import_bundle.sh

CMS Tools API (порт 8084)
└── запускает bash-скрипты из tools/ в корне репозитория

SSE (Server-Sent Events) — вывод скрипта стримится в браузер построчно в реальном времени. Соединение закрывается когда скрипт завершается.


Установка и запуск

Зависимости

npm install --save-dev express multer

Устанавливается один раз. Пакеты express и multer нужны только API-серверу.

Ручной запуск

node tools/cms-tools-api.js
# или с кастомным портом:
PORT=8084 node tools/cms-tools-api.js

Автозапуск через pm2

API-сервер уже добавлен в ecosystem.config.js — стартует автоматически вместе с остальными процессами:

# Первый запуск (все три процесса):
pm2 start ecosystem.config.js

# Только API:
pm2 start ecosystem.config.js --only cms-tools-api

# Перезапуск после обновления кода:
pm2 restart cms-tools-api

Конфигурация в ecosystem.config.js:

{
name: 'cms-tools-api',
script: 'tools/cms-tools-api.js',
cwd: '/home/alex/sites/cms-docs',
env: { PORT: '8084' },
}

Автостарт при перезагрузке системы

# Выполнить один раз — генерирует systemd unit:
pm2 startup

# Сохранить список процессов:
pm2 save

После этого все три процесса (cms-docs-dev, cms-decap-server, cms-tools-api) запустятся автоматически при старте системы.

Настройка

Порт

По умолчанию API слушает порт 8084. Изменить через переменную окружения PORT:

PORT=9000 node tools/cms-tools-api.js

Или в ecosystem.config.js:

{
name: 'cms-tools-api',
script: 'tools/cms-tools-api.js',
cwd: '/home/alex/sites/cms-docs',
env: { PORT: '8084' },
}

Если порт 8084 занят — проверить:

ss -tlnp | grep 8084

Занятый порт — поменять в ecosystem.config.js и обновить константу API в static/admin/tools.html:

const API = 'http://localhost:8084'; // строка 2 блока <script>

Путь к репозиторию

API определяет корень репозитория автоматически через path.resolve(__dirname, '..') — то есть на директорию выше tools/. Если скрипт запускается из другого места — путь всё равно будет правильным, так как привязан к расположению файла, а не к рабочей директории.


ecosystem.config.js — полный пример

Файл в корне репозитория управляет всеми тремя процессами:

module.exports = {
apps: [
// Docusaurus dev-сервер — сайт + CMS
{
name: 'cms-docs-dev',
script: 'npm',
args: 'start',
cwd: '/home/alex/sites/cms-docs',
watch: false,
autorestart: true,
env: { NODE_ENV: 'development' },
},
// Decap CMS прокси для git-операций
{
name: 'cms-decap-server',
script: 'npx',
args: 'decap-server',
cwd: '/home/alex/sites/cms-docs',
watch: false,
autorestart: true,
env: { PORT: '8083' },
},
// Tools API — панель управления
{
name: 'cms-tools-api',
script: 'tools/cms-tools-api.js',
cwd: '/home/alex/sites/cms-docs',
watch: false,
autorestart: true,
env: { PORT: '8084' },
},
],
};

Параметры:

ПараметрЗначениеНазначение
nameстрокаИмя процесса в pm2 — используется в командах pm2 restart/stop/logs
scriptпуть или командаЧто запускать
argsаргументыПередаются в script
cwdабсолютный путьРабочая директория — обязательно абсолютный путь
watchfalseНе перезапускать при изменении файлов (dev-сервер сам следит)
autorestarttrueПерезапускать если процесс упал
env.PORTчислоПорт для процесса

Изменить cwd если репозиторий лежит в другой папке — иначе процессы не найдут файлы.


Где хранит настройки pm2

pm2 хранит свои данные в ~/.pm2/:

~/.pm2/
dump.pm2 — сохранённый список процессов (pm2 save)
logs/ — логи всех процессов
cms-tools-api-out.log
cms-tools-api-error.log
pids/ — PID-файлы запущенных процессов

Полезные команды:

pm2 logs cms-tools-api # хвост логов в реальном времени
pm2 logs cms-tools-api --lines 100 # последние 100 строк
pm2 flush # очистить все логи
pm2 show cms-tools-api # подробная информация о процессе
pm2 monit # интерактивный мониторинг CPU/RAM

Переменные окружения

API наследует весь process.env от pm2/shell и передаёт его в дочерние скрипты. Если скрипты деплоя используют переменные окружения (SSH-ключи, токены) — добавить их в секцию env в ecosystem.config.js:

env: {
PORT: '8084',
SSH_AUTH_SOCK: process.env.SSH_AUTH_SOCK, // пробросить ssh-agent
}

Или задать глобально через ~/.bashrc / ~/.profile — pm2 подхватит при запуске через systemd только если --hp указывает на правильный home.


tools.html — где менять настройки интерфейса

Файл static/admin/tools.html. Все настраиваемые параметры в начале блока <script>:

const API = 'http://localhost:8084'; // адрес API-сервера

Если изменили порт API — поменять здесь. Остальные параметры (список скриптов, логика) живут в tools/cms-tools-api.js.

Проверка работы

# Статус процессов:
pm2 list

# Логи API:
pm2 logs cms-tools-api

# Быстрая проверка через curl:
curl http://localhost:8084/projects

Ответ должен вернуть JSON со списком проектов.


Три запущенных процесса

Имя pm2ПортНазначение
cms-docs-dev3000Docusaurus dev-сервер, сайт и CMS
cms-decap-server8083Decap CMS прокси для git-операций
cms-tools-api8084API для запуска скриптов из браузера

Интерфейс панели

Шапка

Тёмная полоса вверху. Содержит название и ссылку ← CMS — возврат в редактор.

Строка выбора проекта

Проект: [ выпадающий список ] [ badge с текущим slug ]

Список проектов загружается автоматически при открытии страницы — читаются все папки docs/ у которых есть _project_.json. При открытии панели из CMS-редактора (через кнопку "Инструменты") slug определяется автоматически из URL редактора.

Выбор проекта влияет на все операции блока Текущий проект.


Блок: Текущий проект

Операции над выбранным проектом. Перед нажатием — выбрать проект в строке выше.

КнопкаСкриптЧто делает
Экспорт архиваexport_project.sh <slug>Создаёт exports/<slug>-YYYY-MM-DD.tar.gz без паролей и .gitkeep. Архив можно передать другому человеку.
Бандл для ревьюbundle_for_review.sh <slug>Склеивает все MD-файлы проекта в один текстовый файл и упаковывает в .tar.gz. Для передачи документации проекта в AI с большим контекстным окном.
Пересобрать index.mdbuild_project_index.sh <slug>Регенерирует docs/<slug>/index.md на основе _project_.json и _category_.json разделов. Нужно запускать после добавления новых документов или разделов.
Синхр. assetssync_assets.sh <slug>Копирует файлы из docs/<slug>/assets/ в static/<slug>/. Нужно после добавления новых медиафайлов чтобы они стали доступны на сайте.

Конвертация изображений

Позволяет конвертировать SVG-диаграммы проекта в растровый формат и обратно. SVG-исходники при этом никогда не удаляются — они остаются рядом как мастер-файлы.

Зачем это нужно. SVG отлично работают на современных браузерах, но некоторые платформы (почта, PDF, мессенджеры, старые просмотрщики) их не поддерживают. Конвертация позволяет задеплоить сайт с растровыми изображениями, не теряя векторные исходники.

Как работает конвертация:

  1. Скрипт tools/convert_svg.sh находит все .jpg файлы в docs/<slug>/assets/
  2. Рендерит каждый через Inkscape (DPI 150, белый фон) → экспортирует в PNG
  3. Для JPEG — дополнительно конвертирует PNG → JPEG через ImageMagick (качество 85)
  4. Результат кладёт рядом с SVG: vitrip_xxx.jpgvitrip_xxx.jpg
  5. Дублирует файл в static/<slug>/ если там есть SVG-оригинал (чтобы сайт подхватил)
  6. Патчит все MD-файлы проекта: заменяет расширение .jpg.jpg / .jpg в ссылках
КнопкаЧто делает
SVG → JPEGКонвертирует все SVG проекта в JPEG, патчит ссылки в MD на .jpg
SVG → PNGКонвертирует все SVG проекта в PNG, патчит ссылки в MD на .jpg
↩ Вернуть SVGУдаляет конвертированные файлы (только если есть SVG-оригинал), патчит ссылки обратно на .jpg

После конвертации — MD-файлы проекта ссылаются на JPEG/PNG, сайт показывает растровые изображения. SVG рядом, можно вернуть в любой момент.

Зависимости: inkscape и imagemagick должны быть установлены на машине:

sudo apt install inkscape imagemagick

Деплой проекта

Публикация одного выбранного проекта на сервер. Полная пересборка сайта происходит всегда — Docusaurus не умеет собирать частично. Но на сервер уходит только папка выбранного проекта плюс общие assets (JS/CSS/img). Это экономит трафик и время передачи данных.

Зачем нужно. Когда проектов много, а изменился только один — нет смысла заливать всё целиком. Деплой проекта синхронизирует именно его папку без риска затронуть другие проекты на сервере.

Таблица кнопок аналогична полному деплою — 3 метода × 3 формата изображений. Логика та же: JPEG/PNG сначала конвертирует SVG только этого проекта, затем деплоит.

МетодSVGJPEGPNG
Sharedrsync только build/<slug>/ + assets+ конвертация перед деплоем+ конвертация перед деплоем
VPS dockerrsync + docker compose up -d+ конвертация+ конвертация
VPS pm2rsync + pm2 restart+ конвертация+ конвертация

При деплое одного проекта --delete не передаётся в rsync — удалённые файлы других проектов на сервере не затрагиваются. При полном деплое --delete есть — сервер синхронизируется полностью.

Добавить пользователя в проект

[ логин ] [ пароль ] [ Добавить ]

Вызывает add_user.sh <slug> <username> <password>. Генерирует два хэша и записывает в access[] файла docs/<slug>/_project_.json:

  • cms_hash — SHA-256 от username:password для JS-аутентификации в браузере
  • password_hash — SHA-512 htpasswd-совместимый хэш (генерируется для совместимости, текущей аутентификацией не используется)

Если пользователь уже существует — оба хэша обновляются. После добавления система автоматически вызывает build_auth.sh для обновления JS-модуля.


Блок: Глобальные операции

Операции на всю систему, не зависят от выбранного проекта.

КнопкаСкриптЧто делает
Пересобрать главнуюbuild_index.shРегенерирует docs/index.md — главную страницу со списком всех публичных проектов (public: true). Запускать после добавления нового проекта или изменения его метаданных.
Синхр. все assetssync_assets.shСинхронизирует assets/ всех проектов в static/ — без аргумента скрипт обрабатывает все проекты сразу.
Экспорт публичныхexport_public.shЭкспортирует все проекты с public: true — вызывает export_project.sh для каждого. Архивы сохраняются в exports/.
Пересобрать доступыbuild_auth.shРегенерирует src/auth/project-access.js из всех _project_.json. Запускать после добавления/изменения пользователей если не хочется делать полную сборку. Автоматически вызывается как prebuild при npm run build.
Бандл всех для ревьюbundle_for_review.sh --allСклеивает все MD-файлы каждого проекта в один текстовый файл и упаковывает в .tar.gz. Нужна для передачи всей документации в AI с большим контекстным окном. Архивы сохраняются в exports/.

JS-аутентификация

Система защиты проектов работает на стороне браузера — поверх статического сайта, без серверной логики.

Схема:

_project_.json (access[].cms_hash)

tools/build_auth.sh

src/auth/project-access.js ← ES-модуль, встраивается в сборку

src/clientModules/authGuard.js ← хук onRouteUpdate, проверяет каждый переход
src/pages/login.tsx ← страница /login, SHA-256 верификация

Жизненный цикл токена:

  • При успешном входе: localStorage['docs-auth:<slug>'] = cms_hash
  • При каждом переходе: authGuard.js сравнивает токен с project-access.js
  • Разные проекты — независимые токены
  • Токен живёт до смены браузера или явной очистки

prebuild в package.json гарантирует что build_auth.sh запускается автоматически перед каждым npm run build. Кнопка Деплой в панели это учитывает.

Кнопка "Пересобрать доступы" (build_auth) — обновляет только JS-модуль без полной пересборки сайта. Удобна после добавления пользователя через "Добавить пользователя", когда нужно проверить результат локально.


Блок: Полный деплой всех проектов

Операции публикации на удалённый сервер. Требуют настроенного cms-config.json с секциями shared или vps.

Блок организован в виде таблицы 3 × 3: три метода деплоя по строкам, три формата изображений по столбцам.

SVG JPEG PNG
Shared ▲ Shared ▲ Shared·jpg ▲ Shared·png
VPS docker ▲ VPS ▲ VPS·jpg ▲ VPS·png
VPS pm2 ▲ VPS ▲ VPS·jpg ▲ VPS·png

Форматы изображений

SVG — деплой без конвертации. Изображения в MD остаются с расширением .jpg, сборка и деплой идут как есть.

JPEG / PNG — перед деплоем автоматически:

  1. Запускается convert_svg.sh --action=convert --format=jpeg --slug=all — конвертирует SVG всех проектов, патчит MD-ссылки
  2. Запускается полный деплой (deploy_site.sh)

MD-файлы и конвертированные изображения остаются в том состоянии после деплоя — ссылки не откатываются назад. Если нужно вернуться к SVG — использовать кнопку ↩ Вернуть SVG в блоке "Текущий проект".

Методы деплоя

МетодСкриптЧто делает
Shareddeploy_site.sh --mode=sharedСборка → rsync на shared хостинг
VPS dockerdeploy_site.sh --mode=vps --method=dockerСборка → rsync → docker compose up -d на VPS
VPS pm2deploy_site.sh --mode=vps --method=pm2Сборка → rsync → pm2 restart на VPS

Метод VPS по умолчанию берётся из cms-config.json → vps.deploy_method. Кнопки явно переопределяют метод флагом --method.

Порядок внутри деплоя: одна кнопка делает всё — sync assets → build index → npm run build (включая prebuild с build_auth.sh) → передача на сервер → перезапуск.

Подробнее о настройке VPS: Деплой на VPS — Docker + Traefik

API-эндпоинты deploy_access_* и deploy_push_* сохранены для совместимости, но являются stub — ничего не генерируют и не заливают. Кнопки в интерфейсе панели удалены. Аутентификация полностью встроена в JS-бандл.


Блок: Импорт документов

Принимает архив с документами от другого человека или системы и создаёт изолированную ветку import/<id> для ревью.

Как использовать

  1. Перетащить файл в область или кликнуть для выбора
  2. Опционально — ввести имя оператора (кто выполняет импорт, для лога)
  3. Нажать Импортировать
  4. В консоли справа появится вывод скрипта с именем созданной ветки

Поддерживаемые форматы:

  • .bundle — git bundle (создаётся через git bundle create)
  • .tar.gz — архив с папкой проекта (с .git или без)
  • .zip — то же самое в формате zip

После импорта — в консоли будет:

Done. Branch 'import/bundle-2026-04-21-v01' created.

Затем в терминале:

git diff main..import/bundle-2026-04-21-v01 --stat # посмотреть изменения
git merge import/bundle-2026-04-21-v01 # принять

Панель вывода (консоль)

Правая тёмная колонка — отображает вывод запущенного скрипта в реальном времени.

Цвета:

  • Синий — команда которая запущена ($ tools/export_project.sh ...)
  • Белый — stdout скрипта
  • Красный — stderr скрипта
  • Бирюзовый — успешное завершение (✓ Завершено)
  • Красный жирный — ошибка (✗ Ошибка)

Статус в правом верхнем углу консоли:

СтатусЗначение
готовОжидает операции
выполняется...Скрипт запущен
готов (синий)Последняя операция завершилась успешно
ошибка (красный)Последняя операция завершилась с ошибкой

Футер консоли:

  • Слева — API: порт 8084 ✓ (зелёный) или API: недоступен (красный) — проверяется при загрузке страницы
  • Справа — кнопка Очистить — очищает вывод

API эндпоинты

Для прямого использования или интеграции.

GET /projects

Возвращает список всех проектов.

curl http://localhost:8084/projects
[
{ "slug": "vitiana-api-platform", "label": "Vitiana API Platform", "public": false },
{ "slug": "cms-system", "label": "Система документации", "public": false }
]

GET /run/:name?slug=<slug>

Запускает скрипт. Возвращает SSE-поток.

curl http://localhost:8084/run/export_project?slug=vitiana-api-platform

Доступные значения :name:

nameНужен slugСкрипт
export_projectдаexport_project.sh
build_project_indexдаbuild_project_index.sh
sync_assetsнетsync_assets.sh
build_indexнетbuild_index.sh
build_authнетbuild_auth.sh — регенерирует src/auth/project-access.js
export_publicнетexport_public.sh
serve_previewнетserve_preview.sh
deploy_site_sharedнетdeploy_site.sh --mode=shared
deploy_site_vpsнетdeploy_site.sh --mode=vps
deploy_access_sharedнетdeploy_access.sh --mode=shared (stub — ничего не делает)
deploy_access_vpsнетdeploy_access.sh --mode=vps (stub — ничего не делает)
deploy_push_sharedнетdeploy_push.sh --mode=shared (stub — ничего не делает)
deploy_push_vpsнетdeploy_push.sh --mode=vps (stub — ничего не делает)
add_userдаadd_user.sh (+ username, password)
bundle_for_reviewдаbundle_for_review.sh <slug>
bundle_all_for_reviewнетbundle_for_review.sh --all

Формат SSE-событий:

data: {"type":"start","cmd":"tools/export_project.sh vitiana-api-platform"}
data: {"type":"stdout","text":"Exporting vitiana-api-platform...\n"}
data: {"type":"stderr","text":""}
data: {"type":"done","code":0}

GET /convert

Конвертирует SVG проекта в JPEG/PNG или возвращает обратно к SVG. Возвращает SSE-поток.

Параметры:

ПараметрЗначениеОбязательный
actionconvert или revertда
formatjpeg или pngда (только для convert)
slugslug проекта или allнет — без slug обрабатывает все проекты
# Конвертировать проект в JPEG
curl "http://localhost:8084/convert?action=convert&format=jpeg&slug=vitiana-api-platform"

# Конвертировать все проекты в PNG
curl "http://localhost:8084/convert?action=convert&format=png&slug=all"

# Вернуть к SVG
curl "http://localhost:8084/convert?action=revert&slug=vitiana-api-platform"

Что происходит при convert:

  1. Все .jpg из docs/<slug>/assets/ конвертируются через Inkscape → PNG, затем (для JPEG) через ImageMagick
  2. Результат кладётся рядом: vitrip_xxx.jpgvitrip_xxx.jpg
  3. Файл дублируется в static/<slug>/ если там есть SVG-оригинал
  4. В MD-файлах проекта расширение в ссылках заменяется: .jpg.jpg/.jpg

Что происходит при revert:

  1. Удаляются .jpg/.jpg/.jpg файлы у которых есть SVG-оригинал (конвертированные)
  2. В MD-файлах расширение возвращается обратно: .jpg/.jpg.jpg

SVG-исходники никогда не удаляются.


GET /deploy-convert

Деплой с опциональной предварительной конвертацией SVG. Возвращает SSE-поток.

Параметры:

ПараметрЗначениеОбязательный
modeshared или vpsда
methoddocker или pm2нет (для VPS — берётся из cms-config.json)
formatsvg, jpeg или pngда
# Деплой Shared с изображениями в JPEG
curl "http://localhost:8084/deploy-convert?mode=shared&format=jpeg"

# Деплой VPS Docker с PNG
curl "http://localhost:8084/deploy-convert?mode=vps&method=docker&format=png"

# Деплой Shared без конвертации (SVG как есть)
curl "http://localhost:8084/deploy-convert?mode=shared&format=svg"

Порядок выполнения при format=jpeg/png:

  1. /convert?action=convert&format=<format>&slug=all — конвертирует все проекты
  2. deploy_site.sh --mode=<mode> [--method=<method>] — полный деплой

При format=svg — только деплой, без конвертации.


POST /import

Загружает файл и запускает импорт. Multipart form-data.

curl -X POST http://localhost:8084/import \
-F "file=@bundle.tar.gz" \
-F "operator=alex"

Возвращает SSE-поток аналогично /run.


Безопасность

API работает только на localhost и не слушает внешние интерфейсы. Предназначен исключительно для локального использования.

Если сервер задеплоен на VPS и нужен доступ к панели удалённо — пробросить порт через SSH:

ssh -L 8084:localhost:8084 user@your-server.com

После этого панель будет доступна локально на http://localhost:3000/admin/tools.html как обычно, но скрипты будут выполняться на сервере.

Не открывать порт 8084 наружу — нет аутентификации, любой сможет запускать скрипты.