docs: add development roadmap
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled

Records the six agreed directions with their status, the files each one
touches, the steps involved and the decisions already made, so the work can
be picked up without prior context.
This commit is contained in:
markmorado
2026-07-24 04:03:37 +05:00
parent 65c61e7886
commit db7411b1bf

206
docs/roadmap.md Normal file
View File

@@ -0,0 +1,206 @@
# План развития PVEmanager
Документ описывает шесть направлений развития панели, согласованных 24.07.2026.
Два из них уже реализованы, четыре — предстоят. Для каждого этапа указаны цель,
затрагиваемые файлы, шаги и критерии готовности, чтобы задачу мог взять любой
разработчик без дополнительного контекста.
## Статус
| # | Направление | Статус | Приоритет |
|---|---|---|---|
| 1 | Автосоздание API-токена при подключении ноды | ✅ Сделано | — |
| 2 | Графики метрик нод | ✅ Сделано (не проверено визуально) | — |
| 3 | Одна команда установки (`curl \| bash`) | ⬜ Запланировано | 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. Установка одной командой
**Цель.** Пользователь разворачивает панель на своём сервере одной командой,
вместе с ней устанавливается консольный хелпер `pve`.
**Что уже есть.** `deploy.sh` (36 КБ, основная логика развёртывания), `pve`
(CLI-хелпер), каталог `systemd/` с юнитами, `compose.yml`. Не хватает тонкой
обёртки-установщика и публикации.
**Шаги.**
1. Написать `install.sh` в корне репозитория:
- проверка ОС и наличия Docker + docker compose v2, понятная ошибка вместо
падения на середине;
- клонирование репозитория в `/opt/pvemanager` (путь настраиваемый);
- генерация `.env` со случайными секретами;
- `docker compose up -d`;
- установка `pve` в `/usr/local/bin`, установка systemd-юнита;
- идемпотентность: повторный запуск обновляет существующую установку, а не
ломает её.
2. Убрать дефолт `POSTGRES_PASSWORD: pvemanager_secure_password` из `compose.yml`
— в публичной поставке пароль должен генерироваться, а не иметь значение
по умолчанию.
3. Опубликовать скрипт (raw.githubusercontent или короткий домен), в README
дать два варианта: `curl … | bash` и «скачать → прочитать → запустить» с
публикацией sha256.
4. Документировать удаление и обновление.
**Готово, когда** на чистой Debian/Ubuntu-машине одна команда поднимает
работающую панель, `pve --help` отвечает, повторный запуск скрипта не ломает
установку.
**Риски.** `curl | bash` — потенциальный вектор атаки; обязательны контрольная
сумма и альтернативный путь установки.
## ⬜ Этап 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`. Нужно решить, форсить ли перестроение.