feat(settings): блок «Статус стека» — на чём всё крутится

На странице Настроек появился блок с состоянием стека системы: версии
компонентов, состояние сервисов и нагрузка. Рендерится из нового блока
stack в ответе GET /api/system-info, в том же стиле, что и соседний
блок системной информации (sys-card / sys-item / sys-bar, точки
worker-dot, полосы загрузки и памяти с порогами 70 % и 90 %).

Карточки: Приложение (версия и коммит, Node.js, PID и RSS, аптайм,
куча, сворачиваемый список библиотек), Сервер (ОС, ядро, архитектура и
число ядер, модель CPU, loadavg, память, аптайм, контейнер), База
данных (PostgreSQL и версия, хост, состояние пула), Кэш (драйвер,
версия Redis, ключи, память, попадания и промахи, операций в памяти) и
Хранилище (драйвер, endpoint, бакет или каталог).

- server.js: getStackInfo() — версии из package.json, node_modules и
  public/version.json, ОС из /etc/os-release, определение Docker,
  SHOW server_version, счётчики пула pg, состояние Redis. Считается вне
  cacheWrap, чтобы версии и нагрузка не отдавались из 30-секундного
  кэша; хосты только через URL.hostname, без учётных данных URL
- settings.html: карточка sec-stack и пункт «Стек» в навигации
- settings.js: renderStackInfo(), форматирование аптаймов с
  русскими склонениями, degrade-состояние «нет связи — в памяти»;
  кнопка обновления перезагружает оба блока одним запросом
- admin.css: .sys-inline для точки статуса рядом с текстом
- api.smoketest.js: контракт блока stack и проверка, что в ответе нет
  учётных данных из DATABASE_URL/REDIS_URL
This commit is contained in:
dev
2026-09-27 12:47:04 +03:00
parent 4d3df1de37
commit f31b8deea2
7 changed files with 323 additions and 12 deletions
+9
View File
@@ -189,6 +189,15 @@ otherwise the list endpoint ships kilobytes of text per row.
Verify Redis state through `GET /api/system-info` → `cache` (`driver`, `ready`, `hits`, `misses`,
`fallbackOps`, `used_memory_human`, `keys`).
`GET /api/system-info` also returns a `stack` block (built by `getStackInfo()`, outside the
response cache so versions and load stay fresh): `app` (Node, PID, RSS/heap, uptime, version from
`package.json` + `public/version.json`), `deps` (installed versions of the main packages), `runtime`
(OS from `/etc/os-release`, kernel, arch, CPU count/model, loadavg, memory, container detection),
`database` (PostgreSQL version, host, pool counters), `cache` (driver, version, ready, keys, memory,
hits/misses, fallback ops) and `storage` (driver, endpoint, bucket). Hosts come from `URL.hostname`
only — credentials from `DATABASE_URL`/`REDIS_URL` must never reach the payload. The «Статус стека»
block on `public/settings.html` renders exactly this payload.
`api.smoketest.js` also locks the auth contract: only `X-Auth-Token` with a session token
authenticates, while `X-Admin-Token`, `Authorization: Bearer` and `ADMIN_PASSWORD` used as a
token must all be rejected with 401. If you change the auth scheme, update this test and the