# План развития PVEmanager Документ описывает шесть направлений развития панели, согласованных 24.07.2026. Два из них уже реализованы, четыре — предстоят. Для каждого этапа указаны цель, затрагиваемые файлы, шаги и критерии готовности, чтобы задачу мог взять любой разработчик без дополнительного контекста. ## Статус | # | Направление | Статус | Приоритет | |---|---|---|---| | 1 | Автосоздание API-токена при подключении ноды | ✅ Сделано | — | | 2 | Графики метрик нод | ✅ Сделано (не проверено визуально) | — | | 3 | Одна команда установки (`curl \| bash`) | 🟡 Загрузчик готов (ветка B), не проверен на реальном PVE | 1 | | 4 | Интеграция с Proxmox Backup Server | ⬜ Запланировано | 2 | | 5 | Redis: вынос воркера задач и общий кэш | ⬜ Запланировано | 3 | | 6 | Внешний стек метрик и логов (опционально) | ⬜ Запланировано | 4 | Порядок выбран так: сначала дистрибуция (от неё зависит рост аудитории), затем крупная продуктовая фича, затем инфраструктурные улучшения. Этап 6 — самый дорогой и наименее обязательный, поэтому идёт последним. --- ## ✅ Этап 1. Автосоздание API-токена **Что сделано.** При добавлении сервера пользователь вводит логин и пароль, панель подключается ими один раз, создаёт на ноде собственный API-токен и дальше работает по нему. Токен отзывается из UI Proxmox, не даёт SSH- и веб-логина и виден в аудите PVE под своим именем. - `backend/app/proxmox/token_provisioning.py` — создание токена (`privsep=0`), выбор свободного имени (`pvemanager`, при коллизии `pvemanager-2`), откат через `revoke_api_token`. - `POST /api/servers` (`backend/app/api/proxmox/servers.py`) — поле `auto_create_token`; при сбое коммита созданный токен отзывается, чтобы на ноде не оставался сирота с потерянным секретом. - `POST /api/servers/{id}/provision-token` — перевод уже подключённого сервера с пароля на токен по сохранённому паролю. - `api_token_value` переведён на `EncryptedString` (`backend/app/models/proxmox.py`) — раньше токены лежали в БД открытым текстом, в отличие от паролей. - Фронтенд: выбор из трёх режимов подключения в `NodesPage.tsx`, кнопка «Перевести на API-токен» на карточке сервера. **Принятые решения.** Пароль после создания токена остаётся в БД (зашифрованным) — он нужен `ProxmoxClient._password` для SSH-фолбэков вроде `pvecm delnode`. Токен создаётся с `privsep=0`, то есть наследует права пользователя. ## ✅ Этап 2. Графики метрик нод **Что сделано.** Вкладка «Графики» в `NodeDetailPage`: CPU, IO delay, память, load average, сеть in/out, swap, корневая ФС. Пресеты `1h/24h/7d/30d/1y`. - `frontend/src/components/shared/MetricChart.tsx` — общий `ChartCard`, переиспользуется вкладкой инстансов. - `useNodeMetrics` в `frontend/src/hooks/use-nodes.ts` — нормализация сырого RRD (PVE отдаёт `cpu`/`iowait` долями 0..1). - `frontend/src/features/nodes/NodeGraphs.tsx`. Бэкенд не менялся — эндпоинт `/api/{server_id}/node/rrddata` существовал ранее. Дисковых I/O и IOPS в наборе нет: PVE их в node RRD не отдаёт. **Открытый хвост.** Рендер с реальными данными не проверялся визуально. --- ## 🟡 Этап 3. Установка одной командой **Что сделано.** `bootstrap.sh` в корне репозитория — единый загрузчик для обеих веток, определяет среду по наличию `/etc/pve`: - **Ветка A** (`install_branch_a`): ставит Docker (через `get.docker.com`, если его ещё нет) и git/curl/openssl/jq, клонирует репозиторий в `PVEMANAGER_DIR` (`/opt/pvemanager` по умолчанию) на выбранный `git`-реф (`PVEMANAGER_VERSION`, по умолчанию — последний тег репозитория, иначе `main`), передаёт управление `deploy.sh --standalone`. Docker ставится заранее нарочно: интерактивный запрос внутри `check_requirements()` в `deploy.sh` иначе заблокировал бы неинтерактивный запуск из LXC. - **Ветка B** (`install_branch_b`): создаёт LXC (Debian 12, DHCP на `vmbr0`, `nesting=1,keyctl=1` для Docker внутри), параметры (vmid, storage, bridge, ресурсы) настраиваются переменными `PVEMANAGER_LXC_*`; шаблон скачивается через `pveam`, если его ещё нет. Затем клонирует репозиторий во временную директорию **на хосте** только чтобы забрать актуальную версию самого `bootstrap.sh`, кладёт его в контейнер через `pct push` и выполняет там — внутри LXC `/etc/pve` не существует, поэтому скрипт сам уходит в ветку A. После того как панель поднялась (`GET /health`), хост создаёт токен `root@pam!pvemanager` локально через `pvesh create ... --privsep 0`, логинится в панель под `admin`/сгенерированным паролем и регистрирует сам себя (`POST /api/servers`) — пароль от Proxmox никуда не передаётся. **Принятые решения при реализации.** - Убран небезопасный дефолт `${POSTGRES_PASSWORD:-pvemanager_secure_password}` в `compose.yml` (заменён на `${POSTGRES_PASSWORD:?...}`) — раньше стек мог молча подняться с предсказуемым паролем БД при отсутствии `.env`. - Реф для клонирования (`resolve_ref()`) уже поддерживает пиннинг по последнему git-тегу через `git ls-remote --tags`, но в репозитории пока нет ни одного тега — до первого релиза загрузчик fallback'ится на `main`. **Не сделано / не проверено.** - Скрипт **не тестировался на живом Proxmox-хосте** — нет доступного стенда в этой сессии. Нужна проверка: создание LXC, установка Docker внутри unprivileged-контейнера, полный проход `deploy.sh --standalone`, логин и регистрация ноды. - Инфраструктура раздачи (домен `get.<домен>`, статика с нужными `Content-Type`/`Cache-Control`, публикация sha256, второй путь установки в README) — не делалась, требует внешних ресурсов (домен, хостинг). `bash bootstrap.sh` уже работает как локальный путь установки. - `pve --help` не проверялся в связке с этим потоком (устанавливается тем же `deploy.sh` через `install_pve_cli --auto`, логика не менялась). **Осталось до полного закрытия этапа** (инфраструктурная часть, не код): - Домен `get.<домен>` под контролем проекта + TLS, раздача статики (Cloudflare Pages/Worker или R2) с `Content-Type: text/plain` и коротким `Cache-Control`. - Публикация sha256 `bootstrap.sh` и второй путь установки в README («скачать → прочитать → запустить»). - Первый git-тег в репозитории, чтобы пиннинг версии в `resolve_ref()` начал реально на что-то указывать (сейчас fallback на `main`). - Живой прогон на Debian/Ubuntu-машине и на PVE-хосте — см. «Не сделано / не проверено» выше. **Готово, когда:** - на чистой Debian/Ubuntu-машине одна команда поднимает работающую панель; - на PVE-хосте та же команда создаёт LXC, ставит панель внутрь и регистрирует ноду без ввода пароля; - `pve --help` отвечает; - повторный запуск обновляет установку, не ломая её. ## ⬜ Этап 4. Интеграция с Proxmox Backup Server **Цель.** Управлять PBS напрямую, а не только через PVE. **Что уже есть.** PBS подключается к PVE как storage типа `pbs`, поэтому бэкап и восстановление уже работают через `backend/app/api/proxmox/backup.py` (storages, native jobs, restore, bulk restore). **Чего не хватает** (не видно через PVE API): использование datastore и дедупликация, задания verify/prune/GC, namespaces, sync- и tape-задания, браузер снапшотов с восстановлением отдельных файлов. **Шаги.** 1. Модель `PBSServer`: host, порт (по умолчанию 8007), `api_user`, токен (`user@pbs!tokenid`), fingerprint сертификата, `verify_ssl`. Секреты — через `EncryptedString`. 2. Клиент `backend/app/pbs/client.py` по образцу `ProxmoxClient` с миксинами: datastores, snapshots, verify/prune/GC, namespaces. 3. API-роутер `backend/app/api/pbs/` + права в `backend/app/rbac/permissions.py`. 4. Фронтенд: раздел PBS со списком серверов, datastore-обзором и браузером снапшотов. 5. Связать с существующим разделом бэкапов: если storage типа `pbs` соответствует зарегистрированному PBS-серверу — показывать расширенные данные. **Готово, когда** можно добавить PBS-сервер, увидеть занятость datastore и коэффициент дедупликации, запустить verify/prune и просмотреть содержимое снапшота. **Оценка.** Сопоставимо по объёму со всем текущим модулем бэкапов. ## ⬜ Этап 5. Redis: вынос воркера и общий кэш **Цель.** Вынести исполнение фоновых задач из процесса `app` в отдельный контейнер и убрать состояние, которое сейчас живёт только в памяти процесса. **Текущее состояние.** `TaskQueueService` хранит задачи в Postgres, а исполняются они внутри `app` через APScheduler при `UVICORN_WORKERS=1`. Последствия: воркеры не масштабируются, задача в статусе `running` зависает при рестарте контейнера, нет ретраев. **Важно:** очередь в Postgres сама по себе не проблема — для домашней нагрузки её достаточно. Выигрыш даёт именно вынос воркера; Redis нужен как брокер и попутно закрывает три места, которые сейчас ломаются при масштабировании: - `connection_cache` в `backend/app/proxmox/client.py` — словарь в памяти; - `_rrd_cache` в `backend/app/services/metrics_broadcaster.py` — то же; - `websocket_manager.py` — при более чем одном uvicorn-воркере рассылка не работает без pub/sub. **Шаги.** 1. Добавить сервис `redis` в `compose.yml` (alpine-образ, ограничение памяти). 2. Подключить **ARQ** как брокер (asyncio-native; Celery для этой задачи избыточен). Postgres остаётся источником правды по истории задач. 3. Вынести обработку `TaskQueue` в отдельный контейнер `worker`. 4. Перевести `connection_cache` и `_rrd_cache` на Redis. 5. Перевести WebSocket-рассылку на Redis pub/sub, после чего можно поднять `UVICORN_WORKERS`. 6. Добавить ретраи и переустановку статуса зависших задач при старте воркера. **Готово, когда** задачи исполняются в отдельном контейнере, переживают рестарт `app`, а панель корректно работает при `UVICORN_WORKERS > 1`. ## ⬜ Этап 6. Внешний стек метрик и логов **Цель.** Снять с панели хранение метрик и дать историю глубже, чем позволяет RRD, — но не навязывая всем пользователям тяжёлый стек мониторинга. **Ключевой факт.** Собирать метрики самим не нужно: у Proxmox есть встроенный external metric server (протоколы InfluxDB и Graphite) — нода push-ит метрики наружу без всякого кода в панели. Для pull-модели существует `prometheus-pve-exporter`. **Решения по составу.** - **VictoriaMetrics вместо Prometheus** и **VictoriaLogs вместо Loki** — заметно меньше RAM и диска при совместимом PromQL/LogsQL. - **Grafana необязательна.** Если панель сама ходит в PromQL, Grafana нужна только продвинутым пользователям — подключается опционально. - Весь стек включается через `docker compose --profile monitoring`, а **не** входит в поставку по умолчанию: для типовой домашней установки это дороже самой панели. **Шаги.** 1. Профиль `monitoring` в `compose.yml`. 2. В панели — переключаемый источник метрик: `native` (RRD через PVE API, как сейчас) либо `victoriametrics` (PromQL). Настройка в разделе Settings. 3. Абстрагировать слой доступа к данным на фронтенде, чтобы `GraphsTab` и `NodeGraphs` не переписывать при смене источника. 4. Инструкция по настройке external metric server на ноде. 5. Опциональная Grafana с преднастроенными дашбордами. **Готово, когда** при выключенном профиле всё работает как сейчас, а при включённом графики строятся из VictoriaMetrics с историей глубже RRD. **Зависимость.** Этап 2 намеренно сделан на RRD. При выполнении этого этапа слой доступа к данным нужно спрятать за один хук, а не переписывать компоненты. --- ## Технический долг, замеченный попутно - **Хардкод русских строк** в `frontend/src/features/instances/tabs/GraphsTab.tsx`: «IOPS чтение», «IOPS запись», «Заполненность диска», «Все», «Сбросить», «Нет данных» — не проходят через i18n. - **`graphify update .`** отказывается перезаписывать граф: AST-версия даёт 5938 узлов против 5959 в текущем `graph.json`. Нужно решить, форсить ли перестроение.