Commit Graph

399 Commits

Author SHA1 Message Date
markmorado
06b61dae65 fix(templates): show clear message after auto-import instead of "undefined"
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Frontend read res.count but the auto-import endpoint returns imported_count,
so the toast showed "Импортировано: undefined". Read imported_count and show
a distinct message when no new templates were imported.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 22:15:02 +05:00
markmorado
3502a72a13 docs(claude): require English commit messages
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
2026-07-23 21:59:31 +05:00
markmorado
d0824df0f5 docs: release notes and version bump for v1.10.0
Document the command palette, reorganized instance menu/tabs, global
minimized-operations tray, owner-scoped live Proxmox resources, and the
React Query cache clear on login/logout; bump VERSION and README badges.
2026-07-23 21:59:24 +05:00
markmorado
0b0b11c689 feat(scripts): run script executions in background and poll for completion
Community scripts (build.func) install packages like Java/OpenSearch and
can take minutes, well past the nginx/proxy HTTP timeout. execute_script
now returns immediately with status "running" and finishes the job on a
background thread with its own DB session; the frontend polls
/api/scripts/executions/{id} every 3s while running.

Also set TERM=xterm for script execution over SSH — community scripts
call `clear` and print colored output, which fails with "TERM
environment variable not set" when run without a PTY.
2026-07-23 21:59:18 +05:00
markmorado
761bd7bca8 fix(workspaces): grant server access via workspace membership alone
Non-privileged users previously needed a server to be both directly
assigned AND inside one of their workspaces (intersection) to see or use
it. Adding a user to a workspace should be sufficient on its own to let
them create instances on that workspace's servers, so the two access
paths are now unioned instead of intersected.
2026-07-23 21:59:09 +05:00
markmorado
203ae8bdd6 fix(workspaces): stop filtering server list by active workspace in assignment dialog
The workspace edit dialog reused useServers(), which always sends the
X-Active-Workspace header, so admins assigning servers to a workspace
only ever saw servers already in the currently active workspace instead
of the full list. apiClient now lets a caller override the header, and
useServers(allWorkspaces) requests '0' (admin "show all") for that dialog.
2026-07-23 21:59:02 +05:00
markmorado
ef5b40b2f7 fix(nodes): не давать пустым полям учётных данных затирать токен/пароль сервера
Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
При редактировании ноды (например, при смене имени) форма отправляла
пустые api_token_name/api_token_value, т.к. секреты не возвращаются
с бэкенда. Бэкенд принимал их как явно заданные и затирал реальные
credentials, из-за чего немедленная проверка подключения падала и
сервер помечался offline. Теперь пустые значения при редактировании
трактуются как «не менять» — и на фронтенде, и на бэкенде.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 21:57:27 +05:00
markmorado
d3b834cbe1 feat(auth): сбрасывать активную workspace при имперсонации и возврате
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
При смене токена (вход под пользователем / возврат к админу) сбрасываем
выбранную рабочую область через setActiveWorkspace(null): выбор
предыдущей личности передавался в хедере X-Active-Workspace и мог не
принадлежать новой. Дополняет уже существующий сброс кэша React Query.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:37:23 +05:00
markmorado
43336c02c7 feat(auth): имперсонация — вход админа под пользователем и возврат обратно
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Backend:
- POST /api/auth/impersonate/{user_id} — только для админа, выдаёт JWT
  с клеймом impersonator; запрещает вход под собой, отключённым,
  другим админом и вложенную имперсонацию
- POST /api/auth/stop-impersonate — по клейму impersonator завершает
  сессию имперсонации и перевыпускает токен исходного админа
- /api/auth/me отдаёт поле impersonator для баннера в SPA
- аудит-лог: impersonate_start / impersonate_stop

Frontend:
- auth-store: действия impersonate/stopImpersonate со сбросом кэша
  React Query при смене токена
- UsersPage: кнопка "войти под пользователем" (только админу,
  скрыта для себя/админов/неактивных и во время имперсонации)
- AppLayout: баннер имперсонации с кнопкой "вернуться к администратору"
- локали ru/en

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:33:04 +05:00
markmorado
982522b8b5 fix(auth): очищать кэш React Query при login/logout
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
При входе под другим пользователем в той же вкладке React Query отдавал
закэшированные данные предыдущего пользователя (список инстансов и др.) до
жёсткой перезагрузки, из-за staleTime и отсутствия сброса кэша при смене сессии.

- queryClient вынесен из App.tsx в lib/query-client.ts (доступен вне React)
- auth-store вызывает queryClient.clear() при успешном login и при logout

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:22:14 +05:00
markmorado
42c6acd52e fix(instances): изоляция по владельцу для живых ресурсов Proxmox
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Список инстансов (/api/virtual-machines) уже фильтровался по owner_id, но
эндпоинты живых ресурсов Proxmox — /api/resources/all (дашборд) и
/api/{server_id}/resources (страница ноды/сервера) — отдавали все VM/LXC без
фильтра. Обычный пользователь (proxmox.view) через страницу ноды видел чужие
инстансы.

- _helpers: get_owned_vmids() — VMID, которыми владеет пользователь
- servers: get_server_resources / get_all_resources фильтруют VM/LXC по
  владельцу для не-привилегированных (сверка vmid с кэшем vm_instances);
  админы и роли с vm:manage видят всё
- assign_instances_owner.py: скрипт массового назначения владельца
  существующим инстансам (owner_id синхронизированных из Proxmox = NULL)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 04:56:17 +05:00
markmorado
25899866bc feat(appstore): глобальный трей свёрнутых операций, переживающий навигацию и перезагрузку
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 9s
Свёрнутые долгие операции (установка приложения, сборка золотого шаблона)
теперь живут в глобальном zustand-сторе (persist в localStorage) и
рендерятся треем MinimizedOpsTray в AppLayout, а не самим диалогом:

- плашка переживает навигацию между страницами и перезагрузку вкладки;
  прогресс опрашивает сам трей (REST, 3с) независимо от диалога
- клик по плашке возвращает на страницу операции и разворачивает диалог:
  установка — resume-режим InstallWizard (resumeInstall в navigation
  state), шаблон — openGolden с предвыбранным сервером
- «Свернуть» добавляет операцию в трей и закрывает диалог; крестик на
  плашке только убирает её (операция продолжается на сервере)
- плашки несуществующих операций (404 после перезагрузки) трей убирает сам

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 14:13:42 +05:00
markmorado
4621ffe88a fix(appstore): data files, надёжность установки/удаления и сворачиваемые диалоги
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 8s
Доставка файлов приложения из каталога (data_files) до compose up,
APP_PASSWORD/default_credentials для Umbrel, сворачивание диалогов
долгих операций (MinimizableDialog), фильтрация pull-шума в ошибках.

Исправления багов:
- teardown: отсутствующий в Proxmox CT считается удалённым — orphaned-приложение
  теперь можно удалить из БД
- install: сдвиг VMID мимо занятых записей (nextid не резервирует номер,
  retry мог подхватить чужой контейнер)
- retry: параметры установки сохраняются в installed_apps.install_params
  (cores/memory/disk/storage/bridge/ip_config/port_explicit, миграция JSONB)
  вместо жёстких дефолтов
- reconcile: недоступный сервер больше не помечает все приложения orphaned
- update: реально опубликованный порт фиксируется в БД (url/health)
- .env: значения с '#' кавычатся (dotenv-парсер обрезал их как inline-комментарий)
- порт 80, выбранный явно в мастере, публикуется как есть
- useCatalog: available_only включён в queryKey (коллизия кэша)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 12:52:14 +05:00
markmorado
f22b24d86a fix(appstore): touch file bind-mounts instead of mkdir, breaking .env mounts
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
docker compose up failed for apps that bind-mount a single file (e.g.
AnythingLLM's .env) because _prepare_bind_mounts blindly mkdir -p'd every
bind-mount source, turning the file's path into a directory. Docker then
refused to mount a file onto that directory ("not a directory: ... mount
a directory onto a file"). File-looking sources (by name) now get touch'd
instead, with self-healing rm -rf for directories left over from prior
failed installs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 05:19:19 +05:00
markmorado
6a79dd2048 fix(appstore): DNS, per-server golden template, bind-mount perms, delete race
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m1s
Deploy to Production / Trigger production update (push) Successful in 8s
App Store install/update pipeline reliability fixes:
- explicit nameserver (APPSTORE_NAMESERVER) on App Store LXCs and the golden
  template build CT, instead of inheriting a node resolver that may be
  unreachable from the container network (e.g. Tailscale-only DNS)
- golden template storage/resolution moved from one global setting to
  per-server_id (migration 37: app_operations.server_id) — building it on one
  Proxmox server no longer overwrites the template configured for another
- golden template automated build fixed: vzdump export step no longer fails
  on "unable to parse directory volume name 'vztmpl/probe'"
- bind-mount host directories are pre-created with permissive ownership
  before `docker compose up`, fixing Permission denied for non-root
  containers (e.g. MariaDB) writing to Docker-auto-created root-owned dirs
- delete/teardown now waits for Proxmox to actually confirm the destroy task
  finished (was silently proceeding after a short timeout, letting a new
  install reuse the VMID while the node was still wiping the old disk)
- pct create retries a few times on transient "got lock" config errors
- failed pipeline steps now report the tail of command output (4000 chars)
  instead of the head, so the real error isn't buried under pull/progress noise
- install error box in the UI wraps long text and scrolls instead of
  stretching the dialog

Also carries forward in-progress script catalog / instances / RBAC changes
that were already uncommitted in the working tree before this session.

Bump to v1.9.1, update WIKI.md/docs/CHANGELOG accordingly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 04:49:40 +05:00
markmorado
b8536ac2e8 feat(instances): command palette, unified nav, расширенное меню инстанса и правки табов
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
- Командная палитра (Ctrl+K) с общим реестром nav-items и его store
- Новые общие UI-примитивы: alert, breadcrumb, checkbox, progress, switch, textarea
- Меню инстанса: добавлены «Параметры», «Мигрировать», «Изменить ресурсы»,
  «Создать резервную копию» (новый BackupDialog) и «Удалить»; исправлено
  закрытие меню при живом обновлении списка (стабильные columns + getRowId)
- Вкладки инстанса: «Вычислительные ресурсы», «Опции CPU», «Управление
  дисками» и «Изменение размера диска» перенесены с «Настройки» на
  «Оборудование» для VM (для LXC, у которых нет вкладки «Оборудование»,
  ресурсы и ресайз диска остаются в «Настройках»); общие карточки вынесены
  в ResourceCards.tsx
- Локализация: новые ключи ru/en для добавленных пунктов меню и бэкапа

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-17 00:58:45 +05:00
markmorado
8ca33681ca feat(scripts): каталог bash-скриптов для нод и гостей (VM/LXC)
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 59s
Deploy to Production / Trigger production update (push) Successful in 8s
Добавлена библиотека скриптов по образцу VMmanager: свои скрипты (CRUD в UI)
и синхронизация из git-репозитория, параметризация через env-переменные
(без конкатенации в shell), выполнение на нодах Proxmox (SSH), в LXC (pct
exec) и в VM (QEMU guest agent, переиспользует существующий execute_script).
Журнал запусков встроен в общий список задач /api/all-tasks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 04:35:43 +05:00
markmorado
f2ee09ab5a polish(ui): пульсация статус-точки для online, моно-цифры в бейджах, fade-up анимация
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-11 04:35:29 +05:00
markmorado
db2f408d57 fix(core): пункты 5-10 аудита — UPID-синк, порт, бэкап all, IPAM, креды
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 8s
5. UPID-синк: транзитная ошибка опроса статуса больше не помечает живую
   задачу failed — get_task_status(raise_on_error=True) + счётчик из 3
   последовательных неудач; в exit_status пишется реальная причина.
6. Дашборд и бэкапы для серверов на порту != 8006: metrics_broadcaster и
   backup_scheduler строят клиент через ProxmoxClient.from_server (учёт
   порта и token/password) вместо ручной сборки по ip_address.
7. Бэкап "все VM": create_backup при vmid in (None, 0, "all") передаёт
   vzdump параметр all=1 — раньше уходил vmid=0 и PVE отвергал задание.
8. IPAM: get_next_available_ip собирает занятые IP глобально (как проверяет
   allocate_ip), а не только по pool_id — авто-выдача больше не предлагает
   занятый адрес и не срывает создание инстанса.
9. IPAM: fallback в release_ip_by_vmid ищет только записи без
   proxmox_server_id — удаление VM не освобождает IP одноимённого vmid
   на другом сервере.
10. _get_proxmox_client: сервер без валидных кредов теперь возвращает
    понятную 503-ошибку вместо молчаливо пустых списков; перечисление
    серверов в метриках защищено per-server try/except.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 01:06:28 +05:00
markmorado
0efa5968ad fix(core): четыре критических бага — маршруты, очередь задач, логин, shutdown
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
1. vms.py: catch-all маршруты /vm/{vmid}/{action} и /container/{vmid}/{action}
   перенесены в конец файла — раньше они перехватывали POST /unlock,
   /cloud-init и /exec, и эти операции всегда падали с 400 "Invalid action".
2. task_queue_service: зависшие после рестарта running-задачи помечаются
   failed при старте — иначе очередь bulk-операций блокировалась навсегда.
3. api-client.ts: 401 от /api/auth/login больше не вызывает перезагрузку
   страницы — пользователь видит сообщение "неверный логин/пароль".
4. task_queue_service: bulk shutdown теперь вызывает shutdown_vm/
   shutdown_container (graceful) вместо жёсткого stop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 00:58:40 +05:00
markmorado
e62626c79b fix(nodes): детерминированная сортировка списка серверов
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m0s
Deploy to Production / Trigger production update (push) Successful in 7s
Список серверов терял порядок при фоновом рефетче (каждые 30с),
т.к. запрос с WHERE id IN (...) не гарантирует стабильный порядок строк.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 00:40:17 +05:00
markmorado
3424823793 feat(cluster): режим eject "только панель" для нод, не входящих в кластер
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
При провале join нода остаётся стейл-записью с cluster_name в панели, хотя
в Proxmox она standalone. Обычный eject пытается pvecm delnode через SSH и
падает ("SSH connection failed"), т.к. нода не член кластера и/или узел
недоступен по SSH.

- eject-эндпоинт: новый параметр panel_only — отвязывает панельную запись
  (cluster_name=None) без обращения к Proxmox/SSH.
- UI: чекбокс "Только отвязать запись в панели" в диалоге исключения,
  блокирует поле пароля при выборе.
- Локали ru/en.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 03:36:55 +05:00
markmorado
c88cdb4e26 fix(cluster): join по приватному адресу corosync + подтверждение членства
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 58s
Deploy to Production / Trigger production update (push) Successful in 7s
Проблема: присоединяемая нода подключалась к кластерной по её адресу из
панели (часто публичный FQDN), из-за чего join падал с
"Can't connect to <fqdn>:8006 (Connection timed out)" при выделенной
corosync-сети. Плюс панель помечала ноду как присоединённую сразу после
старта задачи, показывая ложное членство даже при провале join.

- join: новый опциональный параметр cluster_host — приватный IP кластерной
  ноды в corosync-сети; используется как hostname для API-подключения и
  для выбора fingerprint из nodelist. Фолбэк — ip_address из панели.
- join: cluster_name пишется в БД только после подтверждения, что нода
  реально появилась среди нод кластерной ноды (опрос до ~40с, укладываемся
  в nginx proxy_read_timeout 60с). Иначе — confirmed=false и предупреждение.
- UI: поле "Адрес кластерной ноды для подключения" в шаге 3 мастера,
  обработка неподтверждённого join (toast.warning, окно не закрывается).
- Локали ru/en.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 03:28:39 +05:00
markmorado
3b10e903a4 fix(cluster): корректное извлечение fingerprint из nodelist при join
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 8s
GET /cluster/config/join не возвращает fingerprint на верхнем уровне —
он лежит в nodelist[].pve_fp. Добавлен хелпер _extract_fingerprint,
который выбирает pve_fp целевой ноды (по IP), с фолбэком на
preferred_node и первую ноду. Устраняет ошибку 502
"Не удалось получить fingerprint кластера" при присоединении нод.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 03:07:53 +05:00
markmorado
0d056a89a5 feat(nodes): TLS-сертификаты ноды и массовая миграция инстансов
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 8s
- Сертификаты: методы клиента + endpoints GET/POST/DELETE
  /nodes/{node}/certificates, хуки и вкладка «Сертификаты» в
  NodeAdminManager (просмотр, загрузка PEM cert+key, удаление кастомного,
  бейдж срока действия)
- Bulk migrate: тип bulk_migrate в очереди задач с WS-прогрессом,
  target_node/online в BulkOperationItem, диалог выбора целевой ноды и
  кнопка в тулбаре инстансов (в пределах одного сервера/кластера)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 02:48:42 +05:00
markmorado
afde2bf569 feat(nodes): управление нодой как в Proxmox — питание, консоль, журнал/задачи/система
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 58s
Deploy to Production / Trigger production update (push) Successful in 7s
Ядро:
- Reboot/Shutdown ноды (POST /nodes/{node}/status) под новым правом node:power
  с подтверждением в UI; меню действий на карточке ноды + пункт «Консоль (Shell)».

Доп. вкладки в «Администрировании ноды»:
- Журнал (syslog ноды), История задач (tasks + лог задачи),
  Система (DNS / /etc/hosts / часовой пояс).

Бэкенд: методы node_power_action/get_node_syslog/get_node_tasks/get_node_task_log/
get_node_task_status/DNS/hosts/time в NodeAdminMixin + эндпоинты в node_admin.py.
RBAC: право node:power (admin + backfill server:manage).

Проверено: py_compile, tsc --noEmit, vite build; live — маршруты в openapi,
403 без токена, node:power засеян роли admin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 02:19:07 +05:00
markmorado
629357a0ee feat(appstore): автосборка золотого LXC-шаблона из UI (Workstream B)
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 8s
Автоматизирует ручную процедуру docs/golden-template.md: pveam download
базового Debian → pct create временного CT → установка Docker/Compose →
каталоги/сеть/logrotate → (опц.) проверка nginx → vzdump в vztmpl → удаление
временного CT. При сбое недособранный CT очищается.

- backend/app/appstore/golden_template.py — сборщик поверх SSH-инфраструктуры
  пайплайна (pct/pvesm/pveam/vzdump); идемпотентность по существующему vztmpl,
  версия базового шаблона берётся из pveam (не хардкодится)
- appstore_engine: prepare_golden_template/_run_golden_template (фон, журнал
  AppOperation + WS), golden_template_status; собранный volid сохраняется в
  PanelSettings и предпочитается env при установке (_resolve_golden_template)
- API: POST /api/appstore/golden-template, GET .../golden-template/status
  (app:manage / app:view)
- Frontend: GoldenTemplateDialog (выбор сервера/ноды/хранилищ, force, живой
  прогресс опросом статуса) + admin-кнопка «Золотой шаблон» на странице App
  Store; хуки useGoldenTemplateStatus/useBuildGoldenTemplate; локали RU/EN

Проверено: роуты зарегистрированы, golden_template_status и приоритет
_resolve_golden_template (override→saved→env) корректны, tsc 0 ошибок.
Полный e2e-прогон сборки на реальной ноде — по запросу.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:53:47 +05:00
markmorado
aebb726231 perf(appstore): быстрый синк Umbrel — иконки с CDN параллельно + стартовый синк
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
A1: иконки Umbrel тянутся пофайлово с GitHub Pages CDN в пуле из 16 потоков
(<app-id>/icon.svg) вместо тяжёлого tarball галереи со скриншотами. Синк
Umbrel: ~7.5 мин → ~13-17с, 379/379 иконок. Настройка UMBREL_APPSTORE_GALLERY_CDN
заменяет UMBREL_APPSTORE_GALLERY_REPO. 404/сетевой сбой отдельного запроса
просто пропускает иконку, не роняя синк.

A2: на свежем деплое каталог пуст, а IntervalTrigger впервые сработает лишь
через сутки. Теперь при пустом каталоге планировщик ставит разовый синк
немедленно (trigger=date) — каталог наполняется на старте без ручной кнопки.

Проверено на стенде: стартовый синк наполнил каталог 644 (runtipi 265 +
umbrel 379) за 16.5с; эндпоинт логотипа отдаёт 200 image/svg+xml.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:40:39 +05:00
markmorado
ebc1c8429e docs: релизы v1.8.1 (Umbrel в App Store) и v1.9.0 (IPAM-привязка, FQDN нод)
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
- VERSION → 1.9.0
- CHANGELOG: запись v1.8.1 (Umbrel как второй источник каталога, адаптер
  compose, иконки из галереи, мультиисточниковый синк, фильтр/бейдж источника,
  кастомный порт установки, мгновенная чистка инстанса) и v1.9.0 (привязка
  IPAM-сетей к серверу/ноде и области с автовыбором в визардах, приём FQDN в
  поле хоста ноды)
- README (en/ru): App Store — мультиисточниковый каталог (Runtipi + Umbrel)
- WIKI: источники, env-настройки Umbrel, иконки из галереи, фильтр/бейдж,
  параметр source в REST

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:32:44 +05:00
markmorado
4c164bec72 chore: убрать план из репозитория и игнорировать docs/plans/
Планы разработки не хранятся в репозитории — только пользовательская
документация. Файл сохранён у автора отдельно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:28:36 +05:00
markmorado
7e75dc7e28 docs(appstore): дорожная карта — плагин-каркас, золотой шаблон, оптимизация иконок
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Самодостаточный план для выполнения в отдельной сессии: контекст проекта и
конвенции, текущее состояние (Umbrel-мультиисточник), три workstream'а
(оптимизация каталога/иконок, автосоздание золотого LXC-шаблона, каркас
управляемых плагинов) с пошаговыми инструкциями и критериями приёмки.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:26:17 +05:00
markmorado
633f1a424c feat(appstore): кастомный порт при установке + мгновенная чистка инстанса
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 7s
App Store:
- поле кастомного порта в мастере установки (переопределяет порт каталога)
- валидация диапазона порта 1..65535 (Pydantic Field + EngineError)
- APP_PORT в окружении синхронизируется с выбранным портом
- при удалении приложения инстанс сразу помечается deleted в кэше
  vm_instances (soft_delete_vm_instance), не дожидаясь фонового воркера

Также включены правки IPAM (привязка сетей к рабочей области, UI
WorkspaceSelect) и синхронизации каталога App Store.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:20:28 +05:00
markmorado
bbaae7c2b1 fix(nodes): принимать доменное имя/FQDN в поле хоста сервера Proxmox
Some checks failed
Deploy to Production / Trigger production update (push) Has been cancelled
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Поле ip_address валидировалось строго как IP, из-за чего подключение ноды по домену (node1.tzim.cloud) падало с 'Invalid IP address format'. Добавлен хелпер validate_host: принимает IP (v4/v6) или корректный hostname/FQDN. IPAM-валидаторы по-прежнему требуют строгий IP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:20:06 +05:00
markmorado
a6eeae3dd7 feat(ipam): привязка сетей к серверу/ноде и автовыбор сети в визардах
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
- network-scope: scopedNetworks/autoPickNetworkId — фильтрация IPAM-сетей по
  выбранным серверу/ноде и детерминированный автовыбор сети для выдачи IP
- ServerNodeSelect: пара селектов «Сервер + Нода» для привязки сети
- Мастер установки App Store и CreateInstanceWizard: список сетей ограничен
  релевантными, при смене сервера/ноды сеть подбирается автоматически
- IPAM: страницы сетей учитывают привязку к ноде
- Исправлены типы обработчиков Select (onValueChange отдаёт string|null)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 20:09:17 +05:00
markmorado
23d3f95f54 fix(appstore): выбор хранилища в мастере установки + видимость реальной ошибки
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 8s
- Установка: поле «Хранилище» стало выпадающим списком доступных rootdir-хранилищ
  ноды (useLXCStorages) с автовыбором валидного вместо ручного ввода
- Диагностика сбоя: увеличен захват вывода упавшей команды (400 → 2000 символов)
  и добавлен 2>&1 к docker compose pull/up — реальная причина (напр. отсутствие
  тега образа) больше не обрезается за строками warning

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 19:28:39 +05:00
markmorado
6d5df8caa7 fix(appstore): устранить зависание/провал установки (compose network + SSH-таймаут)
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 8s
- pipeline: _normalize_compose() объявляет упомянутые в сервисах сети
  (tipi_main_network) как external в top-level — иначе docker compose up
  падал с "refers to undefined network: invalid compose project"
- pipeline: LOCAL_DOMAIN=tipi.local в .env (стандартная переменная Runtipi)
- pipeline: per-command таймауты (_CMD_TIMEOUT/_DOCKER_TIMEOUT), при таймауте
  установка падает с ошибкой, а не зависает на 75%
- ssh_client: execute() ждёт готовности exit-status с жёстким дедлайном
  вместо бесконечного recv_exit_status() (ловушка paramiko)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 01:15:33 +05:00
markmorado
c87a13953e feat(appstore): показывать рабочий порт приложения в каталоге и на карточке
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Порт (CatalogApp.port) уже был в API и типах, но не выводился в UI. Добавлен вывод в шапку страницы приложения и бейджем в карточке каталога (ключ appstore.port уже в локалях).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:52:08 +05:00
markmorado
e497ae541f fix(appstore): резервный REST-опрос прогресса установки (не зависать при потере WS)
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Мастер установки получал прогресс только по WebSocket; при потерянном
событии (или долгом docker compose up с тяжёлыми образами) UI замирал на
последнем шаге. Добавлен поллинг /operations раз в 3с как фолбэк.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:50:31 +05:00
markmorado
06c4ec8e94 fix(appstore): заменить нативные confirm() в «Мои приложения» на стилизованный ConfirmDialog
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Удаление/обновление/откат приложения использовали window.confirm() — не в стиле панели.
Переведено на общий useConfirm (Promise API), удаление — destructive-вариант.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:36:39 +05:00
markmorado
ab5b13a8b8 revert(auth): удалить неиспользуемый AuthPattern
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Декоративный SVG-паттерн так и не подключён к странице входа —
убираем висячий компонент.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:31:31 +05:00
markmorado
08d4396d2f feat(auth): декоративный SVG-паттерн для страницы входа
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 8s
Компонент AuthPattern — бесшовный геометрический паттерн (SVG <pattern>,
currentColor) для левой панели логина. Пока не подключён к LoginPage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:24:02 +05:00
markmorado
45e998cb3e fix(appstore): убрать реферер и прятать битые картинки в markdown
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 7s
Скриншоты из сторонних README на CDN с hotlink-защитой (cloudinary)
обрывали запрос по Referer (NS_BINDING_ABORTED) и резались браузером
(OpaqueResponseBlocking). Снимаем реферер, мягко скрываем не
загрузившиеся изображения.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:21:46 +05:00
markmorado
9bfb055f69 feat(appstore): показывать операции App Store в «Задачах» + IP из IPAM при установке
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 55s
Deploy to Production / Trigger production update (push) Successful in 8s
- AppOperation.to_task_dict(): операции install/update/delete/… приведены к
  общему формату и включены в /api/all-tasks, active-count и clear-completed
- Установка приложения: опциональный выбор сети/пула IPAM — статический IP
  вместо DHCP (net0 ip=<addr>/<mask>,gw=…), освобождение адреса при удалении
- Мастер установки: селекторы «Сеть IPAM»/«Пул IPAM» (ru/en), по умолчанию DHCP

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:20:33 +05:00
markmorado
e453f49a6a fix(appstore): удалять запись installed_apps при удалении инстанса со страницы инстансов
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 55s
Deploy to Production / Trigger production update (push) Successful in 7s
При удалении LXC/VM через delete_vm/delete_container чистим таблицу installed_apps
(по server_id+vmid), иначе приложение из каталога оставалось «хвостом» в «Мои приложения».
Шлём WS-эвент appstore_app_deleted для live-обновления списка у владельца.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:18:40 +05:00
markmorado
b2d90d2800 docs(appstore): golden template — брать имя шаблона из pveam available; env-пример
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
- docs/golden-template.md: шаг 1 разбит на 1a–1d, имя vztmpl берётся из
  `pveam available` в переменную и переиспользуется (фикс no such template /
  volume does not exist)
- backend/.env.example: добавлены APPSTORE_GOLDEN_TEMPLATE и APPSTORE_HOST_ARCH

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:43:25 +05:00
markmorado
799f18d88d fix(appstore): локализация названий категорий (фильтр и бейджи)
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 12s
Категории приложений (gaming, media, network, …) отображаются переведёнными
подписями через i18n (appstore.categories.*, ru+en) при сохранении сырого ключа
как значения фильтра. Неизвестные категории показываются как есть (fallback).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:42:59 +05:00
markmorado
635947eb15 fix(appstore): рендер markdown/скриншотов, фильтр категорий, локализация ошибки, ширина карточек
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 57s
Deploy to Production / Trigger production update (push) Successful in 8s
- Описания приложений: безопасный рендер markdown + HTML (react-markdown +
  remark-gfm + rehype-raw + rehype-sanitize), скриншоты отображаются как картинки
- Фильтр по категории: переведён на надёжную фильтрацию в Python (JSONB-оператор
  на generic JSON-колонке отрабатывал ненадёжно)
- Ошибка отсутствия золотого шаблона локализована (i18n appstore.golden_missing)
- Каталог: карточки шире (макс 3 колонки вместо 4), описание в 3 строки

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:28:19 +05:00
markmorado
490c4ad18d docs(appstore): актуализировать README/CHANGELOG/WIKI, версия 1.8.0
All checks were successful
Deploy to Production / Trigger production update (push) Successful in 12s
- VERSION → 1.8.0
- CHANGELOG (ru/en): запись v1.8.0 с разделом App Store
- README (ru/en): бейдж версии + категория App Store в возможностях
- WIKI: раздел «App Store» (предпосылки, env, install, My Apps, права, REST API) + оглавление

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:12:13 +05:00
markmorado
0606e8ac77 feat(appstore): модуль «App Store» — каталог self-hosted приложений (1 app = 1 LXC + Docker Compose)
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 1m4s
Deploy to Production / Trigger production update (push) Successful in 12s
Полный цикл M0–M5 по ТЗ:
- Catalog Service: импорт runtipi/runtipi-appstore → catalog_apps, идемпотентный
  синк, кэш логотипов, авто раз в 24ч (APScheduler), флаг update_available.
- App Engine: установка (клон золотого шаблона → pct push compose/.env →
  docker compose up → health-check) с журналом шагов, шифрованием env (Fernet),
  генерацией random-секретов и прогрессом по WebSocket.
- Lifecycle: start/stop/restart/logs/delete + реконсиляция состояния (orphaned).
- Update/Rollback через снапшоты Proxmox (pre-update, хранение последнего 1).
- UI: экраны App Store (сетка/поиск/категории), страница приложения, мастер
  установки (динамическая form_fields + advanced + прогресс + креденшелы),
  My Apps; i18n ru/en; атрибуция Runtipi.
- RBAC app:view/install/manage; только unprivileged LXC; pct exec/push без
  shell-инъекций (base64 + экранирование).
- Модели catalog_apps/installed_apps/app_operations (миграции 31–32).
- Docs: golden-template, appstore-poc/catalog/engine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 23:05:20 +05:00
markmorado
782524fff6 feat(hardware): проброс физических дисков ноды в VM (raw passthrough)
All checks were successful
Backend Tests / pytest (Python 3.12) (push) Successful in 56s
Deploy to Production / Trigger production update (push) Successful in 7s
Добавлена возможность пробросить физический диск ноды в VM по стабильному
пути /dev/disk/by-id/ (scsiN/virtioN/sataN) в карточке «Проброс устройств».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 23:37:13 +05:00