# История изменений Все заметные изменения в PVEmanager документируются в этом файле. --- ## [Unreleased] ### 🐛 Исправления - **В образах Rocky Linux, AlmaLinux, CentOS Stream и Fedora разблокирован `guest-exec`** — пакет `qemu-guest-agent` в RHEL-семействе запускает агента с allow-list, в котором нет `guest-exec`, `guest-exec-status` и `guest-file-*` (`FILTER_RPC_ARGS` в `/etc/sysconfig/qemu-ga`; в пакетах постарше то же самое задавалось через `BLOCK_RPCS`/`BLACKLIST_RPC`). Из-за этого в таких ВМ не работали выполнение скриптов, выдача дополнительных IP и расширение ФС после ресайза диска - **Пять образов зеркала пересобраны** — релиз `2026-08-22`, встроенный каталог переключён на него; Ubuntu и Debian не затронуты и остаются в прежних релизах, поэтому старые версии панели продолжают работать - **`patch-cloud-images.sh` снимает ограничение при сборке** (отключается через `UNBLOCK_RPC=0`) и умеет собирать часть каталога — `ONLY="rocky alma centos fedora"`. Панель же, наткнувшись на запрет, объясняет в тексте ошибки, что и где поправить в госте --- ## [v1.18.0] - 2026-08-22 ### 🌐 Несколько IP-адресов на инстанс - **Инстанс больше не ограничен одним адресом** — у гостя может быть основной адрес и любое количество дополнительных. Раньше вся логика исходила из «один гость — одна аллокация»: `find_allocation_by_resource()` возвращал первую попавшуюся запись, `release_ip_by_vmid()` освобождал один адрес (остальные после удаления гостя оставались занятыми навсегда), а инструмент связывания пропускал гостей, у которых аллокация уже была - **На вкладке «Сеть» инстанса появилась карточка «IP-адреса»** — показывает все адреса гостя с их состоянием и позволяет выдать новый (следующий свободный в сети/пуле или введённый вручную), повторить применение, сделать основным или освободить. В колонке IP списка инстансов показывается основной адрес и бейдж **+N** для остальных, а в таблице аллокаций основной помечен - **Дополнительные адреса навешиваются внутри гостя как alias** — через существующий движок скриптов: для LXC это `pct exec`, для ВМ — QEMU guest agent. Адрес поднимается через `ip addr add`, сеть гостя при этом не перезапускается, поэтому работающий гость не теряет связь - **Адреса переживают перезагрузку гостя** — Proxmox пересоздаёт сетевую конфигурацию при каждом старте (pve-container переписывает `/etc/network/interfaces`, `ifcfg` или keyfile NetworkManager из `netN`), стирая любой alias, добавленный в родной стек. Небольшой oneshot systemd-юнит заново поднимает записанные адреса после `network-online.target`; каталог `/etc/systemd` Proxmox не трогает. Родные стеки (ifupdown, netplan, NetworkManager, sysconfig/network-scripts для RHEL-подобных гостей) по-прежнему настраиваются, поэтому состояние может быть составным, например `nm+systemd` - **Адрес резервируется, даже если применить его не удалось** — остановленный гость, отсутствующий guest agent или недоступный SSH к ноде оставляют аллокацию в состоянии `pending` с указанием причины, а кнопка **«Применить»** повторяет попытку позже. Нераспознанный сетевой стек даёт `runtime_only` — предупреждение, что адрес не переживёт перезагрузку - **Новые эндпоинты** — `GET/POST /ipam/api/guests/{server_id}/{vmid}/addresses`, `POST …/{allocation_id}/apply`, `POST …/{allocation_id}/primary`, `DELETE …/{allocation_id}`; список аллокаций принимает фильтры `proxmox_server_id` / `proxmox_vmid`, а список инстансов отдаёт `ips[]` рядом с основным `ip` - **Миграция 43** добавляет в `ipam_allocations` колонки `is_primary`, `assignment_kind`, `target_interface` и `apply_*`, помечая существующие записи основными. Первый адрес гостя теперь помечается автоматически, из какого бы из шести мест выдачи он ни пришёл - **Освобождение адреса сначала снимает его с гостя**, затем освобождает в IPAM; основной адрес задаётся конфигом интерфейса и из этой карточки не освобождается ### 🔍 Исправления определения адресов в IPAM - **LXC-контейнеры наконец показывают свой IP** — `get_container_interfaces()` искал ключи `ipconfigN`, которые бывают только у QEMU-гостей с cloud-init. LXC хранит адрес внутри строки `netN`, поэтому метод не возвращал ничего и колонка IP у всех контейнеров оставалась пустой. Теперь используется парсер `netN`, а для гостей на DHCP — запрос `/nodes/{node}/lxc/{vmid}/interfaces` - **«Сканировать и связать» регистрирует все адреса гостя**, а не только первый, и больше не пропускает уже связанных гостей — сменившийся или добавленный адрес раньше оставался незамеченным навсегда - **MAC-адрес переносится в аллокацию** при связывании — берётся с того интерфейса, на котором найден адрес - **Дублирующийся адрес больше нельзя отобрать у живого гостя** — когда два гостя заявляют один IP (обычно из-за устаревшего `ip=` в конфиге остановленного контейнера), владелец сохраняется, а конфликт возвращается с объяснением вместо тихой перезаписи записи - **Аллокации больше не сопоставляются по имени ресурса** — из-за этого два одноимённых гостя на разных серверах показывали чужой адрес - **История IPAM больше не падает на значениях даты/времени** — раньше это обрывало повторное связывание ошибкой 500 - **IP гостя перепроверяется не чаще раза в 5 минут**, а не при каждом синке кэша (каждые 10 секунд) — это убрало сотни бессмысленных обращений к Proxmox в минуту ### 🐛 Прочие исправления - **Скрипты с не-ASCII текстом снова выполняются на ВМ** — Proxmox кодирует payload для guest agent в base64 силами Perl, а тот падает с `Wide character in subroutine entry`, как только в скрипте встречается не-ASCII (достаточно комментария на кириллице). Теперь payload передаётся байтами - **Поиск следующего свободного IP умеет сканировать всю подсеть**, когда в сети нет пула с auto-assign, пропуская адреса нод и известные адреса гостей — чтобы не выдать адрес, который уже занят в сети --- ### 🖥️ Консоль LXC — ошибки termproxy и чёрный экран - **⚠️ Ломающее изменение: эндпоинт `GET /api/{server_id}/container/{vmid}/terminal` удалён.** WebSocket-эндпоинт `/proxmox/ws/terminal/{server_id}/{node}/{vmid}` создаёт termproxy-сессию сам, поэтому REST-вызов не использовался панелью и при каждом вызове оставлял на ноде висячую сессию. Внешним клиентам следует открывать WebSocket напрямую - **Открытие консоли LXC больше не оставляет на ноде задачу с ошибкой** — `failed waiting for client: timed out` / `TASK ERROR: command '/usr/bin/termproxy 5900 ... vzctlconsole' failed`. Страница консоли создавала termproxy-сессию через REST (используя из ответа только поле `node` и выбрасывая порт и тикет), затем вторую через WebSocket-эндпоинт и подключалась ко второй. К первой не подключался никто — Proxmox ждал клиента ~10 секунд и завершал задачу ошибкой - **Консоль больше не показывает чёрный экран при статусе «connected» в dev-режиме** — React StrictMode монтирует эффект дважды, а connect-функции асинхронны, поэтому cleanup эффекта срабатывал до того, как они записывали `wsRef`/`termRef`, и ничего не чистил. В одном контейнере оказывалось два xterm: видимый был осиротевшим, а живой уходил за границу области с `overflow-hidden`. Теперь у сессии есть флаг отмены, а монтирование и кнопка «Переподключиться» идут через единую точку входа, которая сначала гасит предыдущую сессию. Тот же флаг применён к странице shell ноды --- ### 🔍 Диалог NFS-хранилища — поиск доступных экспортов - **Добавлена кнопка поиска экспортов** рядом с полем «Сервер» при добавлении NFS-хранилища — вызывает `GET /nodes/{node}/scan/nfs` Proxmox и превращает поле пути экспорта из текстового ввода в выпадающий список с реальными экспортами, найденными на целевом сервере, вместо ручного набора пути наугад - Новый эндпоинт `GET /api/backups/scan-nfs/{server_id}?server=` на бэкенде — сканирование выполняется через первую доступную ноду сервера --- ## [v1.17.0] - 2026-08-20 ### 💾 Перенос дисков LXC-контейнера на другое хранилище - **Перенос диска теперь работает для LXC**, а не только для QEMU-ВМ — раньше действие было жёстко привязано к VM-эндпоинту `move_disk` и было недостижимо для контейнеров (нет вкладки «Оборудование», а детектор строк диска распознавал только имена устройств ВМ). `rootfs`/`mp\d+` теперь распознаются как дисковые устройства LXC, на вкладку «Настройки» для LXC-инстансов добавлена карточка **«Перенести диск»** - Новый эндпоинт `POST /api/{server_id}/container/{vmid}/disk/move` вызывает `lxc/{vmid}/move_volume` Proxmox; список целевых хранилищ теперь фильтруется по поддерживаемому типу содержимого (`rootdir` для LXC, `images` для ВМ) вместо показа всех хранилищ подряд - **Перенос заблокирован на запущенных контейнерах — с пошаговым сценарием вместо ошибки** — Proxmox отклоняет `move_volume` на работающем LXC (`move_disk` у QEMU работает «на живую», `move_volume` у LXC — нет). Теперь такая попытка открывает диалог подтверждения, который останавливает контейнер, переносит диск и запускает его обратно, показывая прогресс на каждом шаге; контейнер перезапускается в любом случае, даже если сам перенос завершился ошибкой. Для ВМ и уже остановленных контейнеров показывается обычный диалог подтверждения ### 📊 Список инстансов — сворачиваемая панель метрик - **CPU/RAM/Диск/Сеть/Диск I/O/Аптайм убраны из всегда видимых колонок таблицы** в раскрывающуюся панель под строкой, которая открывается кликом по имени инстанса — по образцу дисклоужер-паттерна из VMmanager. В панели появилась ссылка **«Параметры»**, ведущая прямо на вкладку настроек инстанса, и более понятные карточки для скорости сети/диска - Полосы vCPU/RAM расширены и увеличены (ширина полосы и размер шрифта подписи/деталей) для более быстрого визуального восприятия в свёрнутой панели ### ✨ Страница «Топология сети» - **Новая страница `/topology`** — интерактивная карта инфраструктуры: панель → кластер → нода Proxmox → VM/LXC на базе React Flow. На карточках нод — живые индикаторы CPU/RAM, у гостей видны статус, IP, bridge/VLAN и теги - **Фильтры** — сужение графа до одного подключения, фильтр гостей по статусу (все / запущенные / остановленные) и схлопывание гостей ноды в один узел при превышении настраиваемого порога (запоминается в браузере); свернувшуюся ноду можно раскрыть по отдельности - **Инструменты холста** — зум, панорама, вписать в экран, полноэкранный режим, миникарта, легенда и экспорт всего графа в PNG/SVG - **Новый API `GET /proxmox/api/network/topology`** — один агрегированный запрос вместо обхода серверов/нод/SDN/VM; требует право `network:view`, учитывает рабочие области и изоляцию VM по владельцу. Недоступное подключение отдаёт данные из кэша с предупреждением, а не ломает страницу - **Парсер `netN`** — строки сетевых карт гостей теперь разбираются (bridge, VLAN-тег, MAC, модель, firewall, rate, MTU) для обоих диалектов, QEMU и LXC; доступно через `include_nics=true` --- ## [v1.16.1] - 2026-08-17 ### 🎨 Интерфейс - **Шрифт Inter Variable** — фронтенд переведён на вариативный шрифт Inter с увеличенной шкалой размеров для более чёткой и единообразной типографики по всей панели ### 🔧 Исправления деплоя - **CLI `pve` устанавливается без root** — `deploy.sh` теперь пробует `sudo` для установки CLI в `/usr/local/bin`, а при недоступности root откатывается на `~/.local/bin` (с автоматической настройкой PATH); ранее авто-установка молча пропускалась, и команда `pve` оставалась недоступной после деплоя - **Права файла CLI `pve`** — установленный скрипт теперь явно получает права `755` вместо зависимости от umask; ранее `sudo cp` мог оставить файл без права на чтение для не-root пользователей, вызывая «Permission denied» при каждом запуске - **SSL больше не откатывается при деплое** — `verify_nginx_running` теперь использует `docker compose ps --format '{{.State}}'` (возвращает `"running"` мгновенно) вместо grep по человекочитаемому столбцу STATUS (который показывает `"Up Xs (health: starting)"` первые 30 секунд до первого healthcheck); со старым таймаутом 20 секунд функция всегда завершалась по таймауту и откатывала конфиг на HTTP, хотя SSL-сертификат был успешно получен --- ## [v1.16.0] - 2026-08-14 ### 🌍 i18n — Полный проход по переводам Масштабная зачистка оставшихся захардкоженных и непереведённых строк интерфейса: - **Дашборд и инстансы** — диалоги действий, карточки ресурсов, метки статусов и описания массовых операций полностью переведены (EN + RU) - **Страница «Образы»** — браузер образов, диалоги загрузки/импорта, менеджер зеркал — полный перевод - **App Store** — добавлены недостающие ключи для мастера установки, состояний операций и меток страницы приложения - **Ноды** — метки силовых действий (`Запуск`, `Перезагрузка`, `Выключение`) и общие строки администрирования нод переведены - **Скрипты и сертификаты** — разделы каталога скриптов и TLS-сертификатов добавлены в оба локейла - **Роли** — метки всех RBAC-разрешений, включая `remote_migrate`, переведены на русский - **Графики, мастер, хранилища** — ранее захардкоженные русские строки вынесены в файлы локали и переведены на оба языка - **Массовая миграция и Access realm** — добавлены ключи для действий массовой миграции и меток реалмов Proxmox - **Критические исправления** — несколько строк, молча откатывавшихся на английский в русском интерфейсе, теперь корректно отображаются на русском ### 🔑 SSH-ключи - **Смена SSH-ключей при смене владельца** — когда администратор переназначает VM/LXC другому пользователю, инстанс автоматически получает SSH-ключ нового владельца (ключ предыдущего при этом удаляется), так что учётные данные для доступа всегда соответствуют текущему владельцу ### 📦 Облачные образы - **`patch-cloud-images.sh`** — новый вспомогательный скрипт, который патчит официальные облачные образы, добавляя `qemu-guest-agent`, и публикует их в GitHub-зеркало; позволяет получить живые метрики и функции гостевого агента без установки агента после деплоя - **Каталог образов amd64** — записи образов amd64 по умолчанию теперь указывают на GitHub-зеркало (с предустановленным qemu-guest-agent) и включают контрольные суммы `sha256` для проверки целостности ### 🐛 Исправления - **Обзор дисков VM** — loop-устройства (`/dev/loop*`) и системные разделы (`/dev/sr*`, `/boot`, `/snap`) включались в карточки использования диска; теперь они отфильтровываются и отображаются только диски с данными - **Повторная загрузка облачных образов** — закешированные импортированные образы раздавались с диска даже при наличии контрольной суммы и изменении файла на удалённом источнике; теперь кеш инвалидируется при несовпадении суммы - **Иконка видимости пароля** — значок глаза во всех полях пароля (вход, смена пароля, парольная фраза SSH-ключа, диалоги API-ключей) был инвертирован: открытый глаз отображался, когда значение было скрыто, и наоборот; теперь состояние иконки корректно отражает видимость значения --- ## [v1.15.0] - 2026-08-13 ### 🚀 Установка одной командой - **`bootstrap.sh`** — устанавливает панель одной командой как на обычном хосте Debian/Ubuntu, так и напрямую на хосте Proxmox VE. На хосте PVE скрипт создаёт LXC на Debian 12, устанавливает панель внутри через существующий `deploy.sh`, создаёт локальный API-токен `root@pam` и регистрирует этот хост как первую ноду панели — пароль от Proxmox никуда не передаётся - Скрипт переживает сбой `apt-get update` из-за недоступного enterprise-репозитория на неподписанном хосте PVE вместо того, чтобы прерывать весь bootstrap ещё до установки `git`/`curl` - Регистрация хоста теперь идёт по правильному пути `/proxmox/api/servers` (раньше использовался `/api/servers`, отвечавший 404, — роутер Proxmox подключён под префиксом `/proxmox`) - Убран небезопасный дефолт `pvemanager_secure_password` для `POSTGRES_PASSWORD` в `compose.yml` — на любом пути установки `.env` с реальным паролем уже создаётся до запуска стека ### 💿 Образы и инстансы - **Переработка извлечения/монтирования ISO** — страница «Образы» теперь показывает реальные ISO-файлы, уже лежащие в хранилище ноды (включая те, что появились там до подключения ноды к панели); «Отсоединить» переименовано в **«Извлечь»**, текущий смонтированный образ отображается прямо в списке выбора, а новый чекбокс **«загрузка с диска»** / **«загрузка с этого ISO»** управляет порядком загрузки при извлечении/монтировании - Применение нового порядка загрузки перезагружает гостевую систему через **гибридный рестарт** — штатное ACPI-выключение с откатом на принудительную остановку, затем запуск — что убирает таймаут ping гостя на свежеустановленной ОС, где ещё нет QEMU Guest Agent ### 🔒 RBAC и доступ - **`/profile` отделён от `/settings`** — настройки аккаунта (профиль, пароль, 2FA, SSH-ключи) переехали на собственную страницу `/profile`, не требующую никакого разрешения, и открываются из меню пользователя и Ctrl+K. Теперь отзыв `setting:view`, чтобы не пускать пользователя в настройки панели, больше не блокирует доступ к его собственному аккаунту. `/settings` по-прежнему скрывает общепанельные вкладки за `setting:view`, сохранение — за `setting:update`, безопасность — за `setting:manage`, а SMTP/Telegram — только для админов - **Маршруты теперь защищены по правам**, а не просто скрыты из сайдбара — раньше `/users`, `/logs` и `/settings` (и их вкладки) открывались по прямому переходу на URL кому угодно, а бэкенд лишь отвечал 403 на конкретные запросы; теперь пользователь без доступа перенаправляется на первую доступную ему страницу - Миграция 42 снимает `setting:view` с ролей, у которых нет также `setting:update`/`setting:manage`, — этот доступ раньше выдавался только ради общей страницы настроек, включавшей профиль ### 👤 Владение инстансами и квоты - **Исправлено назначение владельца при создании** — новые VM/LXC оставались с `owner_id = NULL`, потому что задача синхронизации, регистрирующая ещё клонирующуюся VM, опережала флоу деплоя и первой создавала запись в БД; теперь владелец проставляется и на этом пути обновления записи. VM, созданная админом от имени пользователя, теперь получает SSH-ключ именно **этого пользователя**, а не админа - **Миграция для бэкфилла** владельца у инстансов, созданных до исправления выше: владелец восстанавливается из `deploy_tasks` и `audit_logs` и проставляется только тогда, когда все доступные данные указывают на одного и того же существующего пользователя; неоднозначные случаи остаются без владельца — для них нужен ручной запуск `assign_instances_owner.py` - **Кнопка «Создать инстанс» отключается**, когда по какой-то квоте совсем не осталось свободного места, а не только отказывает внутри мастера — подсказка называет, какие именно лимиты исчерпаны (проверка пропускается для админов, чья личная квота не имеет отношения к инстансам, создаваемым для других) - Блокировка перед открытием мастера теперь отделена от блокировки внутри него: полностью исчерпанная квота не даёт открыть мастер вовсе; квота, которую превысит именно выбранная конфигурация, открывает мастер, но блокирует «Далее»/«Развернуть» с указанием превышенного показателя ### 🐛 Исправления - **Продакшн-деплой не отключал открытые порты** — `ports: []` в `compose.prod.yml` на деле ничего не убирал (Compose при слиянии нескольких `-f` файлов не заменяет списковые поля, а объединяет их), поэтому SSL-деплой продолжал отвечать без шифрования на портах `8000`/`3001` параллельно с HTTPS. Исправлено через тег `!reset` - **SSL-деплой сообщал о неудаче даже после успешного выпуска сертификата** — проверка успеха не могла прочитать директорию certbot, принадлежащую root и имеющую права 0700, если деплой запускался не от root; теперь сертификат проверяется изнутри контейнера, а откат на HTTP выполняется только если nginx реально не поднялся с новым конфигом - **Первая загрузка фронтенда могла показать пустую страницу** — общий лимит частоты запросов (`10r/s`) применялся и к статике, отклоняя часть из ~86 подгружаемых чанков SPA с 503; после исправления этого проявился второй лимитер — `limit_conn addr 10` ограничивал всю страницу 10 одновременными HTTP/2-потоками (браузер мультиплексирует всю загрузку страницы через одно соединение), давая тот же эффект пустой страницы. Теперь у статики отдельная зона лимита частоты, а оба лимита `limit_conn` подняты - **Воркеры nginx не могли открыть достаточно файловых дескрипторов** под `worker_connections 2048` — дефолтный `RLIMIT_NOFILE` Docker в 1024 незаметно урезал реальный потолок вдвое; поднят до 8192 - Убраны `listen 443 ssl http2` (устарела с nginx 1.25.1) и `ssl_stapling` (у текущих сертификатов Let's Encrypt нет OCSP-респондера) — обе директивы выдавали предупреждения при периодическом reload nginx - **Аптайм ноды показывался неверно в мультинодовых кластерах** — карточка сервера брала `Math.max` по аптайму всех нод кластера вместо аптайма именно текущей, поэтому перезагрузка одной ноды могла по-прежнему показывать более высокий аптайм другой - **Тост о завершении сессий никогда не переводился** — сообщение собиралось на бэкенде на Python и возвращалось как есть, поэтому в русском интерфейсе показывалось "Terminated 0 sessions"; теперь количество возвращается отдельным полем, а фраза собирается на клиенте (для русского нужно четыре формы множественного числа против двух в английском) --- ## [v1.14.0] - 2026-07-24 ### 🐛 Исправления - **Смена рабочей области не сбрасывала фильтры инстансов** — фильтры по серверу, узлу и столбцам на странице «Инстансы» сохраняли значения, выбранные ещё в предыдущей рабочей области, из-за чего список VM новой области мог отфильтроваться до пустоты. Теперь при переключении рабочей области все эти фильтры сбрасываются - **Фильтр по колонке «Узел» не обновлялся после первого рендера** — список доступных узлов в нём был замемоизирован на объекте `Column` из TanStack, а этот объект сохраняет свою идентичность при обновлении данных таблицы, поэтому список замирал на тех узлах, что были видны при первом открытии — включая узлы серверов из уже покинутой рабочей области. Теперь значение читается напрямую из faceted-данных таблицы при каждом рендере --- ## [v1.13.0] - 2026-07-24 ### 🛒 App Store - **Выбор хранилищ в golden-шаблоне** — в диалоге «Золотой LXC-шаблон» текстовые поля для хранилища шаблона (`vztmpl`) и rootfs (`rootdir`) заменены на выпадающие списки, заполняемые реальными хранилищами выбранного сервера/ноды. По умолчанию подставляются `local`/`local-lvm`, если они есть, иначе — первое доступное хранилище ### 📜 Scripts - **Поиск по названию в каталоге скриптов** — фильтрация ручных, Git и Community-Scripts записей прямо на странице Scripts --- ## [v1.12.0] - 2026-07-24 ### 🔗 Кластер - **Импорт существующего кластера** — ноды, уже объединённые в кластер Proxmox в обход панели (через `pvecm` или веб-интерфейс Proxmox), теперь можно привязать прямо на странице «Кластер», а не только через собственный флоу панели «Создать»/«Присоединить». Обнаружение читает `cluster/config/join` на выбранной ноде, сопоставляет её nodelist с уже известными серверами панели по IP/hostname и привязывает совпавшие записи к этой группе кластера — никакая `pvecm`-операция не выполняется, меняется только учёт внутри панели --- ## [v1.11.0] - 2026-07-24 ### 🔌 Серверы и подключение - **Автосоздание API-токенов** — сервер можно подключить по логину и паролю: панель один раз аутентифицируется, создаёт на ноде собственный API-токен (`privsep=0`) и дальше работает по нему. Токен отзывается из UI Proxmox, не даёт SSH- и веб-логина и виден в аудите PVE под своим именем. Уже подключённые по паролю серверы переводятся на токен без переподключения кнопкой **«Перевести на API-токен»** - **Отклонённые учётные данные vs. недоступная нода** — раньше офлайн-сервер показывал единое «Не удалось подключиться»; теперь протухший/отклонённый токен (401, обычно остаётся после того, как вступление ноды в кластер заменяет `user.cfg`/`token.cfg`) получает собственное состояние `auth_error` с подсказкой о причине - **Доступность storage по нодам** — storage может быть объявлен на весь кластер, но отсутствовать на конкретной ноде (нет volume group или пула); теперь это видно, а не скрыто - **Единые бейджи статуса** — все списки серверов (включая топологию кластера и назначение пользователей) рендерят один `ServerStatusBadge` вместо повторяющегося тернарника online/offline - **Списки в рамках рабочего пространства** — `/api/cluster/topology` и `/api/resources/all` теперь учитывают активное рабочее пространство, а не отдают все серверы панели; живые метрики собираются параллельно, а не последовательно, поэтому один недоступный кластер больше не тормозит весь запрос ### 📊 Мониторинг - **Вкладка «Графики» у ноды** — CPU, IO delay, память, load average, сеть, swap и корневая ФС на странице ноды, с пресетами `1h/24h/7d/30d/1y` ### 💿 Образы и создание инстансов - **Загрузка локального файла** — ISO или `vztmpl` можно загрузить прямо со своего компьютера в storage ноды, в дополнение к загрузке по URL - **Пустая VM для установки с ISO** — новый тип инстанса в мастере создания: VM с пустым диском и смонтированным первым по порядку загрузки ISO, гость сразу попадает в установщик через noVNC; выбор Windows задаёт OVMF, SATA-диск и сетевую карту e1000 - **Загрузка ISO** — ISO можно скачать на ноду по URL со страницы «Образы» или из сохранённого зеркала (зеркала теперь принимают `kind=iso`) ### 🔄 Реалтайм и UX - Списки инстансов и рабочих пространств обновляются сразу после назначения серверов/пользователей, деплоя или удаления VM/контейнера — без ручного обновления - Обзор ноды больше не мигает «нет данных», пока список инстансов ещё загружается ### 🛠 Надёжность - **Самообновление панели восстанавливается после зависшей пересборки** вместо вечного «restarting — 80%»; по таймауту показывается понятное состояние «failed» со ссылкой на логи update-сервиса хоста ### 🎨 Тема - Поверхности тёмной темы (фон, карточки, popover, сайдбар, границы) сдвинуты с нейтрального оттенка на сине-графитовый ### 📖 Документация - Расширен раздел RBAC/Security (формат прав, порядок проверки, полный каталог прав, карта прав по страницам), добавлен полный русский перевод — **WIKI.ru.md** --- ## [v1.10.2] - 2026-07-23 ### 🐛 Исправления - **Шаблоны** — после авто-импорта показывается понятное сообщение вместо `undefined` --- ## [v1.10.0] - 2026-07-22 ### 🧭 Навигация и инстансы - **Командная палитра (Ctrl+K)** — палитра с поиском поверх общего реестра пунктов навигации (со своим store), позволяет перейти на любую страницу с клавиатуры - **Единая навигация** — боковое меню и командная палитра работают от одного общего реестра nav-элементов - **Расширенное меню инстанса** — в меню строки инстанса добавлены **Параметры**, **Мигрировать**, **Изменить ресурсы**, **Создать резервную копию** (новый `BackupDialog`) и **Удалить**; меню больше не закрывается при каждом живом обновлении списка (стабильные `columns` + `getRowId`) - **Реорганизация вкладок инстанса** — для VM «Вычислительные ресурсы», «Опции CPU», «Управление дисками» и «Изменение размера диска» перенесены со вкладки **Настройки** на **Оборудование**; у LXC (где вкладки «Оборудование» нет) они остаются в **Настройках**. Общие карточки вынесены в `ResourceCards.tsx` - **Новые общие UI-примитивы** — `alert`, `breadcrumb`, `checkbox`, `progress`, `switch`, `textarea`; ключи локализации RU/EN для новых пунктов меню и бэкапа ### 🛒 App Store - **Глобальный трей свёрнутых операций** — свёрнутые долгие операции (установка приложения, сборка золотого шаблона) теперь живут в глобальном zustand-сторе (persist в `localStorage`) и рендерятся треем `MinimizedOpsTray` в layout приложения, а не самим диалогом: - плашка **переживает навигацию между страницами и перезагрузку вкладки**; трей опрашивает прогресс сам (REST, каждые 3 с) независимо от диалога - клик по плашке возвращает на страницу операции и разворачивает диалог — установка продолжается в `InstallWizard` (resume-режим через navigation state), шаблон открывает диалог золотого шаблона с предвыбранным сервером - «Свернуть» добавляет операцию в трей и закрывает диалог; крестик на плашке только убирает плашку (операция продолжается на сервере); плашки несуществующих операций (404 после перезагрузки) трей убирает сам - **Файлы данных приложения** — файлы, поставляемые вместе с приложением каталога (`data_files`), доставляются до `compose up`; учитываются `APP_PASSWORD` / `default_credentials` для Umbrel - **Сворачиваемые диалоги установки/сборки** — долгие операции можно свернуть через `MinimizableDialog` - **Надёжность установки/удаления**: - **teardown** — отсутствующий в Proxmox CT считается удалённым, поэтому `orphaned`-приложение теперь можно удалить из БД - **install** — поиск VMID сдвигается мимо занятых записей (`nextid` не резервирует номер, из-за чего retry мог подхватить чужой контейнер) - **retry** — параметры установки (`cores/memory/disk/storage/bridge/ip_config/port`) сохраняются в `installed_apps.install_params` (JSONB, новая миграция) и переиспользуются при повторе вместо жёстких дефолтов - **reconcile** — недоступный сервер больше не помечает все свои приложения `orphaned` - **update** — реально опубликованный порт фиксируется в БД (`url`/health) - **.env** — значения с `#` кавычатся (dotenv-парсер обрезал их как inline-комментарий) - порт `80`, выбранный явно в мастере, публикуется как есть - `useCatalog` — `available_only` включён в query key (устранена коллизия кэша) ### 🔒 Изоляция по владельцу - **Живые ресурсы Proxmox теперь фильтруются по владельцу** — список инстансов (`/api/virtual-machines`) уже фильтровался по `owner_id`, но эндпоинты живых ресурсов `/api/resources/all` (дашборд) и `/api/{server_id}/resources` (страница ноды/сервера) отдавали **все** VM/LXC. Обычный пользователь (`proxmox.view`) через страницу ноды видел чужие инстансы. Оба эндпоинта теперь фильтруют VM/LXC по владельцу для непривилегированных (сверка `vmid` с кэшем `vm_instances`); админы и роли с `vm:manage` по-прежнему видят всё - **`assign_instances_owner.py`** — скрипт массового назначения владельца существующим инстансам с `owner_id = NULL` (синхронизированным из Proxmox до появления владения) ### 🐛 Исправления - **Очистка кэша React Query при login/logout** — при входе под другим пользователем в той же вкладке React Query больше не отдаёт закэшированные данные предыдущего пользователя (список инстансов и др.) до жёсткой перезагрузки. `queryClient` вынесен из `App.tsx` в `lib/query-client.ts` (доступен вне React), а `auth-store` вызывает `queryClient.clear()` при успешном входе и при выходе --- ## [v1.9.1] - 2026-07-17 ### 🛒 App Store - **Золотой шаблон отдельно на каждый сервер** — золотой vztmpl теперь хранится и разрешается по `server_id` Proxmox, а не одним глобальным указателем; сборка на одном сервере больше не перезаписывает/ломает шаблон, настроенный для другого. `APPSTORE_GOLDEN_TEMPLATE` теперь только последний запасной вариант для серверов без собственной сборки. Миграция 37 добавляет `app_operations.server_id` - **Исправление сборки золотого шаблона** — автоматическая сборка (**App Store → золотой шаблон**) больше не падает на финальном шаге экспорта `vzdump` (`unable to parse directory volume name 'vztmpl/probe'`) - **Надёжность DNS** — LXC приложений App Store (и CT сборки золотого шаблона) теперь получают явный `nameserver` (`APPSTORE_NAMESERVER`, по умолчанию `1.1.1.1 8.8.8.8`) вместо наследования резолвера ноды — это устранило таймауты при загрузке образов на нодах, чей DNS доступен только с хоста (например, через Tailscale) - **Права bind-mount** — директории данных из `volumes:` приложения (`${APP_DATA_DIR}/...` или относительные пути) заранее создаются перед `up`, что устраняет `Permission denied` для контейнеров, пишущих под non-root пользователем (например, MariaDB) - **Устранена гонка удаления/переустановки** — удаление приложения теперь ждёт фактического подтверждения Proxmox, что контейнер удалён (до 30 мин, покрывает медленную очистку диска), прежде чем освободить VMID, вместо предположения об успехе после короткого таймаута - **Retry блокировки `pct create`** — временные ошибки «can't lock file ... got lock» сразу после удаления теперь повторяются несколько раз, а не роняют установку - **Полный вывод ошибки** — упавшие шаги пайплайна теперь показывают последние 4000 символов вывода команды (раньше первые 2000), так что реальная причина не теряется под шумом прогресса `docker compose pull` - **UI ошибки установки** — блок ошибки в диалоге установки теперь переносит длинный неразрывный текст (дайджесты образов, пути) и скроллится в своих границах вместо растягивания диалога --- ## [v1.9.0] - 2026-07-09 ### 🌐 IPAM - **Сети привязаны к серверу/ноде и рабочему пространству** — сеть IPAM теперь можно привязать к конкретному серверу/ноде Proxmox и к рабочему пространству; каждое пространство использует одну подсеть, а сеть автоматически выбирается активным пространством в мастерах создания инстанса и установки App Store, так что в типичном случае пользователю больше не нужно выбирать сеть вручную - **Автовыбор в мастерах** — мастера развёртывания определяют целевую сеть/пул из текущего контекста и подставляют их; отсутствие привязки откатывается к ручному выбору - Миграция: столбцы привязки сети IPAM к рабочему пространству + флаг «по умолчанию» через `backend/migrations/migrations.py` ### 🔧 Ноды - **Домен/FQDN в поле хоста Proxmox** — форма добавления/редактирования сервера Proxmox теперь принимает доменное имя или FQDN (не только IP), которое резолвится при подключении --- ## [v1.8.1] - 2026-07-09 ### 🛒 App Store - **Umbrel как второй источник каталога** — каталог теперь мультиисточниковый: наряду с `runtipi/runtipi-appstore` можно включить `getumbrel/umbrel-apps` (~380 приложений). Источники настраиваются через `APPSTORE_SOURCES` (через запятую, по умолчанию `runtipi`); id приложений Umbrel неймспейсятся (`umbrel-`), чтобы каталоги не конфликтовали - **Compose-адаптер Umbrel** — установка понимает манифесты Umbrel: порт контейнера берётся из сервиса `app_proxy` (`APP_PORT`), runtime-сервисы Umbrel (`app_proxy`, `tor`) вырезаются, повисшие `depends_on` очищаются, а порт основного сервиса публикуется на хосте LXC, чтобы health-check прошёл; поведение Runtipi не меняется - **Иконки Umbrel** — иконки берутся из отдельного репозитория `getumbrel/umbrel-apps-gallery` (`/icon.svg`) при синке и кэшируются как логотипы Runtipi; сбой загрузки галереи никогда не роняет синк каталога - **Мультиисточниковый синк** — каждый источник синкается независимо (сетевой сбой одного не отменяет другие), а проход *исчез → недоступен* ограничен своим источником, так что синк Runtipi никогда не трогает строки Umbrel - **Фильтр источника и бейдж (UI)** — App Store получает фильтр по источнику и бейдж источника на карточке, показываемые только когда включено больше одного источника; метаданные каталога теперь отдают доступные `sources` - **Кастомный порт установки** — мастер установки принимает произвольный порт хоста (валидация 1..65535), переопределяющий дефолт каталога - **Мгновенная чистка инстанса** — удаление приложения сразу мягко удаляет связанный VM-инстанс для отзывчивости UI - **Модель данных и настройки** — столбец `catalog_apps.source` (миграция 34); новые env-настройки `APPSTORE_SOURCES`, `UMBREL_APPSTORE_REPO`, `UMBREL_APPSTORE_REF`, `UMBREL_APPSTORE_GALLERY_REPO` --- ## [v1.8.0] - 2026-07-07 ### 🛒 App Store - **Каталог self-hosted приложений с установкой в один клик** — новый модуль App Store: каждое приложение разворачивается в собственном **unprivileged LXC**-контейнере с **Docker Compose** (1 приложение = 1 LXC). Каталог импортируется из репозитория `runtipi/runtipi-appstore` (~265 приложений проходят фильтр) - **Catalog Service** — импорт метаданных, логотипов, описаний и compose-файлов в новую таблицу `catalog_apps`; идемпотентная синхронизация (кнопка *Обновить каталог* + автоматически раз в 24 ч через APScheduler); битый `config.json` пропускается, не роняя весь синк; флаг `update_available` вычисляется по `tipi_version` - **Пайплайн установки** — клон золотого LXC-шаблона → `pct push` compose/`.env` → `docker compose up -d` → HTTP health-check, с **живым журналом шагов по WebSocket**, динамическим рендером `form_fields` (text/password/email/number/boolean/fqdn), автогенерацией `random`-секретов и хранением env в зашифрованном виде (Fernet); сгенерированные учётные данные показываются один раз - **Управление жизненным циклом** — start / stop / restart / логи (`docker compose logs`) / удаление, плюс фоновая **реконсиляция состояния** каждые 60 с (контейнеры, удалённые мимо PVEmanager, помечаются `orphaned`) - **Обновление и откат** — при обновлении создаётся pre-update снапшот Proxmox, затем `docker compose pull && up -d` с health-check; откат восстанавливает снапшот (вместе с данными); хранится только последний pre-update снапшот - **UI** — сетка каталога (поиск, категории), страница приложения с дисклеймером об источнике и превью compose, мастер установки с расширенными параметрами LXC и живым прогрессом, экран управления **Мои приложения**; локали RU/EN; атрибуция *Powered by Runtipi appstore* - **Безопасность** — только unprivileged LXC; `pct exec` / `pct push` через SSH с доставкой файлов через base64 и экранированием значений `.env` (без shell-инъекций); новые права RBAC `app:view` / `app:install` / `app:manage` - **Модель данных и настройки** — таблицы `catalog_apps`, `installed_apps`, `app_operations` (миграции 31–32); новые env-настройки `APPSTORE_GOLDEN_TEMPLATE`, `RUNTIPI_APPSTORE_REF`, `APPSTORE_DATA_DIR`, `CATALOG_SYNC_INTERVAL_HOURS`, `APPSTORE_HOST_ARCH` - **Документация** — `docs/golden-template.md` (подготовка золотого LXC-шаблона) и `docs/appstore-poc.md` / `appstore-catalog.md` / `appstore-engine.md` --- ## [v1.7.0] - 2026-06-26 ### 🎯 Квоты - **Квоты ресурсов на пользователя** — ограничение количества инстансов и суммарных vCPU, RAM и диска по всем VM/LXC пользователя. Отсутствие записи квоты или значение `NULL` в столбце означает *безлимит* по этой метрике, поэтому администраторы и пользователи без ограничений никогда не блокируются - Бэкенд: новая модель `UserQuota` (таблица `user_quotas`) и `quota_service` (`get_user_usage` / `check_quota`); использование вычисляется из кэша `vm_instances` (`owner_id`) — учитываются только не удалённые и не шаблонные инстансы; при превышении лимита развёртывание VM/LXC прерывается с **HTTP 429** - Права: новые RBAC-разрешения `quota:view` и `quota:manage` (категория *Управление пользователями*, оба требуют `user:view`) - API: `GET/PUT /api/users/{id}/quota` (админ) возвращает лимиты вместе с текущим использованием; `GET /api/quota` (self-service) возвращает собственные лимиты и использование текущего пользователя - Фронтенд: диалог квот с полосами использования на странице Пользователей (админ); карточка собственных лимитов на странице Настроек; подсказка об остатке квоты на шаге конфигурации в мастере создания инстанса; хуки `useUserQuota` / `useSetUserQuota` / `useMyQuota`; локали RU/EN - Миграция: таблица `user_quotas` добавлена через `backend/migrations/migrations.py` --- ## [v1.6.0] - 2026-06-23 ### ✨ Images - **Каталог облачных образов** — просмотр и скачивание образов ОС из нескольких источников (стандартное зеркало Proxmox и кастомные зеркала); образы загружаются на хранилище Proxmox - **Автоматическая конвертация в шаблон VM** — опция автоматической конвертации загруженного `.qcow2` образа в шаблон VM Proxmox после завершения скачивания - **Кастомные зеркала для администраторов** — интерфейс, доступный только администраторам, для добавления, редактирования, просмотра и удаления источников-зеркал для поиска образов - **Фильтрация образов по архитектуре** — образы фильтруются по архитектуре платформы узла (x86-64, aarch64); дефолт-архитектура соответствует платформе выбранного узла - **Загрузка образов с прогрессом** — диалог загрузки с отслеживанием прогресса в реальном времени и опциональным переключателем конвертации в шаблон ### 🐛 Исправления - **Нормализация расширения файла при импорте образа** — расширение `.img` автоматически нормализуется в `.qcow2` при импорте - **Санитизация имени VM при импорте образа** — имена VM санитизируются при импорте образа для предотвращения ошибок создания; улучшенные сообщения об ошибках для прозрачной обратной связи с пользователем --- ## [v1.5.2-1] - 2026-06-20 ### 🖥️ Интерфейс - **Стилизованные диалоги подтверждения** — все нативные браузерные `confirm()` заменены единым тематическим модальным окном (`ConfirmDialog`). Добавлен глобальный `ConfirmDialogProvider` + хук `useConfirm` (Promise-based API). Затронуто: обновление панели, удаление шаблона/сервера/хранилища/SSH-ключа/HA-ресурса/SDN-зоны/VNet/подсети/IPAM-пула/аллокации, применение/откат сетевых изменений, очистка IPAM-сирот (16 мест в 11 файлах). --- ## [v1.5.2] - 2026-06-20 ### 📊 Метрики - **Реальное время: заполнение дисков VM, IOPS и сетевой I/O** — живые данные по каждому диску, скорости чтения/записи и сетевого ввода/вывода добавлены на вкладку Overview инстанса, в список инстансов и виджет топ-нагруженных на дашборде - Backend: `get_vm_fsinfo()` запрашивает данные файловых систем через QEMU guest agent; `metrics_broadcaster` вычисляет скорости I/O (байт/с) из накопленных счётчиков; цикл обновления списка инстансов теперь опрашивает каждую запущенную VM через `status/current` (гранулярность 1 с) вместо `cluster/resources` (10 с от pvestatd), с ограниченным параллелизмом и ритмом 1 с - Frontend: карточки по каждому диску, карточки Network I/O и I/O-rate на OverviewTab через WebSocket; колонки Net и Disk I/O в InstancesPage; Disk% отображается только для LXC; метрики в реальном времени на виджете топ-нагруженных на DashboardPage ### ⚙️ Настройки - **Язык интерфейса для каждого пользователя** — у каждого аккаунта теперь есть собственная колонка `language` (миграция 26); переключатель языка перенесён с вкладки «Панель» на вкладку «Профиль»; язык сохраняется в БД и применяется через `i18n.changeLanguage()` сразу при сохранении - **Улучшения вкладки «Панель»** — поле `panel_name` только для чтения (берётся из env `PANEL_NAME`); поле `log_retention_days` доступно в UI; API панели принимает `panel_name` в `PUT`, что позволяет переопределить значение через БД без правки env ### 🐛 Исправления - **Поля настроек SMTP/безопасности** — переименованы поля запроса/ответа SMTP (`host`, `port`, `username`, `password`, `from_email`, `tls`); хук настроек безопасности переведён на `/admin/api/security/settings` с типизированным `SecuritySettings`; добавлены i18n-ключи `minutes` / `security_saved` - **UX формы уведомлений** — добавлены тосты успеха/ошибки для кнопок сохранения SMTP и Telegram; переключатель языка в «Профиле» подключён; поля смены пароля очищаются только при успешном сохранении - **Telegram — раздел администратора** — убрано поле Chat ID из глобальных настроек Telegram (оно никогда не сохранялось в БД); проверка теперь выполняется через личный раздел «Мои уведомления → Отправить тест» - **Поле Webhook URL** — убрано нереализованное поле Webhook URL из настроек уведомлений, чтобы не вводить пользователей в заблуждение --- ## [v1.5.1] - 2026-06-04 ### 🐛 Исправления - **Сборка фронта: отсутствует компонент LogsPage** — в `src/router.tsx` есть ссылка на `./features/logs/LogsPage.tsx`, но сам файл был пропущен, из-за чего Vite 8.0.5 / rolldown не мог разрешить dynamic import. Добавлен `frontend/src/features/logs/LogsPage.tsx` со stat-карточками (всего за 24ч, ошибки, неудачные логины, записей на странице), фильтром по уровню, поиском, пагинацией и строками i18n. Использует уже существующие хуки `useLogs` / `useLogStats` / `useLogLevels`. - **Сборка фронта: коллизия в `.gitignore`** — в `frontend/.gitignore` правило `logs` без якоря матчило и корневой `logs/`, и `src/features/logs/`, скрывая новую страницу из VCS. Правило ограничено корнем — `/logs`. ### 📚 Документация - WIKI: версия поднята до v1.5.1, добавлен раздел **Logs & Audit** с описанием страницы, цветами уровней логов, ссылками на API (`/logs/api/logs`, `/logs/api/stats`, `/logs/api/levels`, `/logs/api/categories`), параметрами запросов, форматом ответа и заметками по правам доступа - README: обновлён бейдж версии на 1.5.1 --- ## [v1.5.0] - 2026-05-07 ### 🐧 LXC — развёртывание из CT-шаблонов - **Создание LXC из CT-шаблонов** — полный рабочий процесс создания LXC-контейнеров напрямую из CT-файлов Proxmox (`.tar.zst`, `.tar.gz`); выбор узла/хранилища, интеграция с IPAM, поддержка SSH-ключей - **Единый мастер создания инстансов** — переработанный мастер (`CreateInstanceWizard`) поддерживает как VM-шаблоны (QEMU), так и CT-шаблоны (LXC) в едином многошаговом потоке: выбор типа, браузер шаблонов, конфигурация, подтверждение - **Переустановка LXC из CT-шаблона** — поддержка переустановки контейнеров, созданных из CT-шаблонов; имя хоста, пароль, SSH-ключи и IP-адрес сохраняются при переустановке - **Сохранение учётных данных и IP при переустановке LXC** — пароль root, SSH-ключи, IP-конфигурация и шлюз переносятся автоматически при переустановке контейнера - **nesting=1 по умолчанию** — все новые LXC-контейнеры создаются с включённым `nesting=1` для обеспечения совместимости с systemd 255+ (cgroup v2) - **Исправлено: двойное URL-кодирование SSH-ключей** — SSH-ключи, передаваемые в API Proxmox при создании LXC, больше не кодируются дважды ### 🔑 Управление SSH-ключами - **API SSH-ключей** — полный CRUD для библиотеки SSH-ключей пользователя: `GET /api/ssh-keys`, `POST /api/ssh-keys`, `PUT /api/ssh-keys/{id}`, `DELETE /api/ssh-keys/{id}` - **Управление ключами администратором** — `GET /api/ssh-keys/user/{user_id}` — администраторы могут просматривать и управлять SSH-ключами любого пользователя - **Отпечаток ключа** — SHA-256 отпечаток вычисляется и сохраняется автоматически при создании/обновлении ключа - **Хранение приватного ключа** — опциональное зашифрованное хранение приватного ключа рядом с публичным - **UI управления SSH-ключами** — новая вкладка на странице настроек для добавления, редактирования и удаления SSH-ключей; отображает имя, отпечаток, комментарий и дату создания - **Выбор ключа в мастере** — при развёртывании VM или LXC можно выбрать SSH-ключи из личной библиотеки; администраторы, создающие инстанс от имени другого пользователя, могут выбирать из ключей этого пользователя - **Изоляция по пользователю** — обычные пользователи управляют только своими ключами; пользователи с разрешением `users.manage` могут управлять ключами любого аккаунта ### 🗑️ Операции с VM/LXC - **Автоматическая остановка перед удалением** — если VM или LXC-контейнер запущен в момент запроса удаления, он автоматически останавливается; предотвращает ошибку Proxmox `can't lock file` при уничтожении ### 🖥️ Улучшения фронтенда - **InstancesPage** — обновлённый макет, улучшенные бейджи статусов и меню действий - **NodesPage** — обновлённые карточки узлов с более чистым отображением метрик - **TemplatesPage** — улучшенный список шаблонов с лучшей фильтрацией и управлением группами - **BackupsPage** — исправлены граничные случаи в списке резервных копий, диалоге восстановления и UI планировщика заданий - **UsersPage** — улучшенная таблица пользователей с лучшим отображением ролей и индикаторами назначения серверов - **SettingsPage** — добавлен раздел SSH Keys Manager; общая полировка UX - **`api-client.ts`** — добавлены методы API SSH-ключей и эндпоинты CT-шаблонов - **`websocket.ts`** — улучшение стабильности соединения - **`types/index.ts`** — добавлены типы `SSHKey`, `LXCTemplate`, `LXCDeployRequest` ### 🛠️ Режим разработки - **Dev mode** — новый оверрайд `compose.dev.yml` для Vite HMR (горячая замена модулей); использовать `pve dev` или `docker compose -f compose.yml -f compose.dev.yml up -d frontend`; исходные файлы монтируются как тома, изменения применяются мгновенно без пересборки - **Маркер `.dev-mode`** — сигнализирует CLI `pve` о том, что фронтенд запущен в режиме разработки --- ## [v1.4.0] - 2026-04-06 ### 🌐 Сети — управление SDN и интерфейсы узлов - **Страница сетей** — новая объединённая страница (`/proxmox/networks`) для управления зонами SDN, VNet, подсетями и сетевыми интерфейсами на уровне узла; добавлена в боковую навигацию с специальной иконкой - **Редактирование зоны SDN** — `PUT /api/servers/{server_id}/sdn/zones/{zone}` — обновление свойств зоны (mtu, dns, reversedns, ipam и т.д.) - **Редактирование VNet SDN** — `PUT /api/servers/{server_id}/sdn/vnets/{vnet}` — обновление alias, VLAN tag, vlanaware и т.д. - **Удаление подсети SDN** — `DELETE /api/servers/{server_id}/sdn/vnets/{vnet}/subnets/{subnet_cidr}` — удаление подсети; опционально удаление связанной сети IPAM (`?delete_ipam_network=true`) - **Автоматическое создание сети IPAM при создании подсети** — `POST .../subnets` теперь поддерживает `create_ipam_network: true`; создаёт соответствующую `IPAMNetwork`, связанную с сервером и VNet, или возвращает существующую - **Сетевые интерфейсы узлов** — полный CRUD для интерфейсов на уровне узла (мосты, связки, VLAN, ethernet): список, получение, создание, обновление, удаление через `proxmox_client.py` - **Применение / Откат конфигурации сети узла** — `PUT` и `DELETE` на `/nodes/{node}/network` для активации или отката ожидающих изменений - **API получения списка узлов** — `GET /api/servers/{server_id}/nodes` — возвращает узлы для сервера Proxmox (используется селекторами страницы сетей) ### 🧹 Очистка кода - **Очистка импортов модуля SDN** — удалены неиспользуемые импорты (`ssl`, `asyncio`, `httpx`, `websockets`, `func`, `List` и т.д.) из `sdn.py` - **Маршрутизатор сетей** — новый модуль `networks.py` под `api/proxmox/` с маршрутом HTML страницы и API для узлов; зарегистрирован в `proxmox/__init__.py` ### 🌍 i18n - **49 новых ключей переводов** (EN + RU) для страницы сетей: типы интерфейсов, поля bridge/bond/VLAN, применение/откат конфигурации, метки интеграции IPAM, редактирование зоны/vnet, удаление подсети и многое другое --- ## [v1.3.1] - 2026-04-05 ### 🔍 Список ВМ — фильтрация по узлам и адаптивная панель инструментов - **Фильтр по серверу** — новое выпадающее меню для фильтрации списка ВМ по серверу/кластеру Proxmox; заполняется динамически из загруженных ВМ - **Фильтр по узлу** — новое выпадающее меню для фильтрации по узлу Proxmox; автоматически сужает список узлов, принадлежащих выбранному серверу - Оба фильтра сохраняются в параметры URL (`?server=...&node=...`) и восстанавливаются при перезагрузке страницы - **Панель инструментов переделана в 2 строки** — строка 1: все фильтры (тип / статус / сервер / узел / поиск с иконкой + статистика); строка 2: чекбокс выбрать все, пагинация, кнопки действий - **Адаптивные точки разрыва** — при ≤900px метки кнопок скрыты; при ≤768px фильтры переносятся 2 в строку; при ≤480px каждый фильтр во всю ширину; счётчик статистики скрыт на мобильных - Вспомогательные функции `populateServerFilter()` и `populateNodeFilter()` заполняют выпадающие меню из загруженных данных ВМ - Панель инструментов снимков мигрирована с устаревших классов `.vm-toolbar-left/.vm-toolbar-right` на inline flex, не затронута переделкой панели инструментов --- ## [v1.3.0] - 2026-03-27 ### 🖥️ Консоль — исправления VNC и терминала - **VNC «Connection closed» исправлено** — `RFBClass` (noVNC) теперь получает строку URL WebSocket непосредственно вместо предварительно открытого объекта `WebSocket`; хак `onFirstMessage`, нарушавший квитирование RFB перед первым фреймом, полностью удалён из `virtual_machines.html` и `instance_detail.html` - **VNCAuth исправлено для QEMU** — `vncproxy` теперь вызывается с `"generate-password": 1`; возвращаемый 8-символьный DES ключ передаётся в noVNC как пароль VNC; возвращается к `ticket` при отсутствии `password` (режим NoAuth Proxmox 9.x) - **LXC `vncproxy` 500 исправлено** — LXC API `vncproxy` не принимает `generate-password`; параметр пропускается для LXC, который использует `ticket` как пароль VNC - **Контекстное меню LXC открывает терминал xterm.js** — правый клик в списке ВМ теперь показывает **Терминал** для типа `lxc` (вызывает `openTerminalConsole()`) и **Консоль VNC** для типа `qemu`; ранее все типы использовали `openVNCConsole()` - **Модальное окно терминала добавлено на страницу списка ВМ** — `#terminalModal` с полным xterm.js (FitAddon, WebLinksAddon, тема Dracula) добавлено в `virtual_machines.html`; переиспользует существующие API endpoints `GET /api/{server_id}/container/{vmid}/terminal` и `WebSocket /proxmox/ws/terminal/{server_id}/{node}/{vmid}` --- ## [v1.2.0] - 2026-03-16 ### 🐛 Исправление ошибки — конфликт блокировки при изменении размера диска - **Основная причина исправлена** — `resize.put()` в API Proxmox асинхронна и возвращает задачу UPID; старый код не ждал завершения этой задачи перед запуском ВМ, что заставляло Proxmox сообщать `can't lock file '/var/lock/qemu-server/lock-xxx.conf' — got timeout` и `command '/usr/bin/qemu-img resize' failed: got timeout` - **`configure_vm` (создание ВМ из шаблона)** — теперь захватывает UPID изменения размера и вызывает `wait_for_task(120 s)` перед возвратом; ВМ может быть запущена только после полного изменения размера диска - **`resize_vm_disk`** — то же исправление применено; задача изменения размера завершается перед возвратом функции - **`resize_container_disk` (оба метода LXC)** — то же исправление; перезапуск контейнера выполняется только после подтверждения завершения задачи изменения размера - **Удалено ненужное перезагрузка ВМ после изменения размера** — изменение размера диска QEMU происходит на уровне хранилища и не требует перезагрузки ВМ; автоматический вызов `restart_vm()` после ручного изменения размера удалён, чтобы предотвратить второй конфликт блокировки --- ## [v1.1.8] - 2026-03-16 ### 👤 Назначение пользователю серверов - **Таблица `user_servers`** (миграция 20) — новая таблица связей `User ↔ ProxmoxServer`; позволяет напрямую назначать конкретные серверы пользователям - **API `GET /api/users/{id}/servers`** — список серверов, назначенных пользователю - **API `GET /api/users/{id}/server-assignments`** — расширенный список всех серверов с флагами `assigned` и `compatible` (совместимость по рабочим областям) - **API `PUT /api/users/{id}/servers`** — установка набора серверов для пользователя; проверяет пересечение рабочих областей — если сервер и пользователь не состоят ни в одной общей рабочей области, возвращает `409 workspace_conflict` - **Фильтрация серверов для обычных пользователей** — пользователь видит только серверы, которые ему назначены **и** входят в его рабочую область ### 🖥️ Владелец ВМ / LXC - **API `GET /api/{server_id}/vm/{vmid}/owner`** — получить текущего владельца ВМ/LXC и список доступных пользователей - **API `PUT /api/{server_id}/vm/{vmid}/owner`** — назначить или снять владельца (только для админ); действие логируется в аудит ### 🔐 RBAC и роли - **Миграция 21** — `dashboard:view` принудительно выставлен в `false` для роли `user` (новый формат ключей) - **Миграция 22** — ключ `proxmox.cluster.manage` → `cluster:manage` в роли `admin`; старый dot-формат удаляется, чтобы не сбрасывать весь карту разрешений - **`user_count`** в ответе `GET /api/roles` — для каждой роли возвращается количество активных пользователей ### 🚀 Умное перенаправление после входа - После успешного входа производится запрос `GET /api/auth/me` — пользователь автоматически перенаправляется на первую страницу, к которой у него есть доступ (`/dashboard` → `/virtual-machines` → `/vms` → `/backups` → `/ipam` → `/logs` → `/settings`) - Поддержка параметра `?returnUrl=` — возврат на запрошенную страницу после входа ### 🔧 Прочие улучшения - `GET /api/servers` для непривилегированного пользователя объединяет фильтры `assigned_servers` и `WorkspaceServer` — пользователь видит только серверы из своей рабочей области, которые ему назначены - `node_uptime` добавлен в ответ детального API сервера - Удалена лишняя проверка `PermissionChecker` на GET-маршруте страницы `/users` (HTML) --- *Для истории более ранних версий см. английскую версию [CHANGELOG.md](CHANGELOG.md)*