Files
Stend_mont/docs/PROJECT_CONTEXT.md
T

19 KiB
Raw Blame History

Project Context: Portal Stand Access

Этот файл нужен как быстрый технический контекст для нового разработчика/оператора.

1) Что это за проект

Веб-портал для выдачи пользователям доступа к стендам/сервисам через браузер.

Ключевая идея:

  • пользователь выбирает сервис;
  • портал открывает сервис в уже прогретом браузерном контейнере (WEB) или в RDP-слоте;
  • каждая пользовательская сессия имеет session_id (UUID) и свой URL /s/<session_id>/....

2) Текущий стек

  • API: FastAPI (app/main.py)
  • БД: PostgreSQL
  • Edge/router: Traefik (обязателен для динамических маршрутов runtime-контейнеров)
  • Runtime WEB: portal-kiosk (Chromium + x11vnc + websockify/noVNC)
  • Runtime RDP: portal-rdp-proxy (xfreerdp + x11vnc + websockify/noVNC)

3) Принятые продуктовые решения

  • Режим VNC как отдельный сервис больше не используется (deprecate).
  • Основной сценарий для пользователей: WEB и RDP.
  • Для WEB используется общий пул portal-webpool-* (и авторасширение при нагрузке).
  • Для RDP используется универсальный пул слотов (UNIVERSAL_POOL_SIZE).
  • Сессии пользователя имеют UUID-ссылки (/s/<uuid>/...).

4) Критичные маршруты

  • / — выбор сервисов
  • /go/<slug> — запуск пользовательской сессии
  • /s/<session_id>/ — страница ожидания старта
  • /s/<session_id>/view — сессионный view для WEB-пула
  • /svc/<slug>/ — роут к warm runtime конкретного сервиса
  • /w/<slot>/ — роут к WEB pool слоту
  • /u/<slot>/ — роут к universal pool слоту
  • /admin — админка

5) Что важно помнить по инфраструктуре

  1. Traefik удалять нельзя. Причина: динамические контейнеры создают labels во время работы, и именно Traefik маршрутизирует:
  • /s/<session_id>/...
  • /svc/<slug>/...
  • /w/<slot>/...
  • /u/<slot>/...
  1. При Nginx Proxy Manager (NPM):
  • внешний домен -> NPM -> внутренний Traefik.
  • в docker-compose.yml Traefik опубликован так:
    • 0.0.0.0:2288 -> 443
    • 0.0.0.0:8288 -> 80
  • в NPM обязательна опция Websockets Support.
  1. Кнопка «Домой» в runtime UI:
  • должна возвращать к выбору сервисов портала (/), а не вводить URL в удалённом сайте.

6) Диагностика типовых проблем

A) Черный экран в WEB

Проверять:

  • что у noVNC корректный WebSocket endpoint (.../websockify);
  • что сессия active в БД;
  • что контейнер WEB-пула running;
  • что в NPM включен websocket proxy.

Быстрая проверка:

  • логи portal-webpool-*
  • логи portal-api-1
  • содержимое /opt/portal/index.html внутри runtime-контейнера.

B) "Соединение со слотом потеряно" в RDP

Обычно не проблема портала, а проблема соединения xfreerdp до целевого host:port/cred/sec. Смотреть /tmp/session-app.log/xfreerdp.log в portal-universal-*.

C) Изменения не видны сразу

Если менялись runtime-скрипты, старые warm/pool контейнеры могут держать старую версию. Нужно пересобрать образ + пересоздать пул.

7) Где смотреть код

  • Backend и orchestration: app/main.py
  • Админка/UI: app/templates/admin.html, app/static/style.css
  • Пользовательский дашборд: app/templates/dashboard.html
  • WEB runtime: kiosk/entrypoint.sh, kiosk/manager.py
  • RDP runtime: rdp-proxy/entrypoint.sh
  • Universal runtime: universal-runtime/entrypoint.sh, universal-runtime/manager.py
  • Оркестрация: docker-compose.yml, traefik/traefik.yml

8) Операционные команды

Сборка runtime-образов:

docker compose --profile build-only build kiosk-image rdp-proxy-image universal-runtime-image

Поднять всё:

docker compose up -d --build

Перезапуск только API:

docker compose up -d api

Проверка состояния:

docker compose ps
docker compose logs -f api traefik

9) Что еще можно улучшить

  • вынести миграции в Alembic;
  • добавить отдельный health dashboard с websocket/rdp метриками;
  • централизованный сбор логов и алерты;
  • e2e smoke-тесты на сценарии /go -> /s/<uuid>/view.

10) Сервер и рабочие пути

  • SSH сервер: ruslan@10.17.39.3
  • Пароль sudo на сервере: utOgbZ09ruslanstand
  • Рабочий каталог проекта на сервере: /root/Stend_mont
  • Файл контекста на сервере: /root/Stend_mont/docs/PROJECT_CONTEXT.md

Базовый рабочий сценарий:

ssh ruslan@10.17.39.3
sudo -s
cd /root/Stend_mont

11) Git доступ и публикация

Репозиторий:

  • https://git.ruslan.xyz/ruslan/Stend_mont

Учетные данные HTTPS (текущие):

  • login: ruslan@ipcom.su
  • password/token: utOgbZ09ruslan

Пример push:

cd /root/Stend_mont
git add .
git commit -m "your message"
git push https://ruslan%40ipcom.su:utOgbZ09ruslan@git.ruslan.xyz/ruslan/Stend_mont main

12) Текущее runtime-состояние (на момент фиксации)

  • API запущен с uvicorn --workers 4 через docker-compose.yml.
  • Для WEB используется portal-webpool-*.
  • Для RDP используется portal-universal-*.

13) Последние изменения (2026-04-21)

  1. UI/брендинг:
  • Тексты в интерфейсе переведены на формулировку инфрастуктурный полигон.
  • На главной панели приветствие в блоке admin-intro: Добро пожаловать в инфрастуктурный полигон.
  • Кнопка выхода на дашборде: Выход (вместо Logout).
  1. WEB runtime (браузерные сервисы):
  • В панели управления runtime оставлены 2 кнопки:
    • Назад
    • Главная (ведет на главную панель портала /).
  • Кнопка Вперед удалена.
  • Изменения применены в kiosk/entrypoint.sh и universal-runtime/entrypoint.sh.
  1. Логин и просроченные пользователи:
  • Если пользователь найден и пароль верный, но аккаунт просрочен/неактивен, на экране входа показывается сообщение: Доступ к сервису приостоновлен, обратитесь к вашему менеджеру.
  • Сообщение рендерится в шаблоне app/templates/login.html через login_error.
  1. Категории сервисов:
  • Добавлены сущности и связи:
    • categories
    • service_categories
  • Категории можно создавать/удалять в админке.
  • При создании/редактировании WEB/RDP сервиса можно выбрать категории.
  • На главной панели добавлен стильный фильтр по категориям (chips) и бейджи категорий на карточке сервиса.
  1. Иконки сервисов:
  • Иконки на главной панели увеличены примерно в 6 раз.
  • Масштабирование иконок: object-fit: contain, чтобы картинка полностью влезала в рамку.
  • В админке загрузка иконки стала автоматической при выборе файла (без кнопки Upload).
  1. Многоворкерный API и startup:
  • API работает с uvicorn --workers 4.
  • Чтобы убрать гонку DDL на старте (при нескольких воркерах), добавлен file-lock на bootstrap схемы:
    • lock-файл: /tmp/portal-schema.lock
    • сериализуется выполнение Base.metadata.create_all(...) и ensure_schema_compatibility().
  1. Операционные заметки по применению runtime-изменений:
  • После изменения kiosk/universal-runtime нужно:
    1. пересобрать runtime-образы,
    2. пересоздать portal-webpool-*, portal-universal-*, portal-warm-* контейнеры,
    3. перезапустить api.

14) Обновление контекста (2026-04-21, вечер)

  1. Главная страница и 500:
  • Был зафиксирован Internal Server Error на /.
  • Причина: синтаксическая ошибка Jinja в app/templates/login.html (поврежденный endif).
  • Статус: исправлено, API перезапущен, / отвечает 200.
  1. Фон и визуальные эффекты:
  • Были тесты фонов main.jpg, main_general.jpg, 123.jpg и локального файла 71ba42f1d7d61e4313ad8fd086d3ed7f.jpg.
  • Текущее состояние по запросу: эффекты отключены.
  • Отключено: parallax, анимации облаков, hover-движения карточек/ссылок, blur карточек.
  • Главная панель оставлена со статичным светлым фоном без motion-эффектов.
  1. Файлы, затронутые в этой волне:
  • app/templates/dashboard.html: удален parallax/cloud слой из разметки.
  • app/static/style.css: добавлен override-блок для отключения эффектов.
  • app/templates/login.html: исправлена ошибка шаблона.
  1. Актуальный операционный контур:
  • Сервер: ruslan@10.17.39.3
  • Проект: /root/Stend_mont
  • Контекст: /root/Stend_mont/docs/PROJECT_CONTEXT.md
  • Применение UI-правок:
    1. ssh ruslan@10.17.39.3
    2. sudo -s
    3. cd /root/Stend_mont
    4. docker compose up -d --build api
  1. Git публикация:

15) Обновления (2026-04-21, таймаут и пулы)

  1. Таймаут простаивания сессии уменьшен:
  • Было: SESSION_IDLE_SECONDS=1800 (~30 минут).
  • Стало: SESSION_IDLE_SECONDS=300 (~5 минут).
  • Источник значения:
    • .env: SESSION_IDLE_SECONDS=300
    • docker-compose.yml: SESSION_IDLE_SECONDS: ${SESSION_IDLE_SECONDS:-300}
    • fallback в app/main.py: 300.
  1. Поведение при простое (heartbeat):
  • В runtime-страницах (kiosk, universal-runtime, rdp-proxy) heartbeat теперь проверяет HTTP-статус touch.
  • Если touch возвращает не 2xx (например, 410 Session expired), клиент делает редирект на: /?session_closed=idle
  • На / добавлено уведомление: Сессия была закрыта из-за простоя. Откройте сервис заново.
  • Уведомление показывается и на login-page, и на dashboard.
  1. Изменение API для touch:
  • POST /api/sessions/{id}/touch:
    • 404 если сессия не найдена/не принадлежит пользователю;
    • 410 если сессия найдена, но уже не ACTIVE.

16) Обновления (2026-04-21, ночь)

  1. Ограничение активных сервисов пользователя:
  • Лимит оставлен MAX_ACTIVE_SERVICES_PER_USER=4.
  • Поведение изменено на FIFO-ротацию:
    • при открытии 5-го сервиса автоматически закрывается самый старый активный;
    • при открытии 6-го — следующий по старшинству и т.д.
  • Жесткий редирект с ошибкой теперь используется только как аварийный fallback.
  1. Время простоя:
  • Для обычного простоя подтверждено SESSION_IDLE_SECONDS=300 (5 минут).
  • Значения синхронизированы в .env, docker-compose.yml, app/main.py.
  1. Runtime-навигация в сервисах:
  • Кнопки оставлены символьные:
    • (назад)
    • (главная)
  • Позиция обновлена: слева вверху, но чуть ниже прежнего:
    • kiosk: top:34px
    • universal-runtime: top:64px (ниже статусного блока)
  1. UI карточек на главной:
  • В описании карточки добавлена прокрутка (max-height + overflow:auto), если текст не влезает.
  • Поддержаны переносы строк.
  • Поддержано отображение жирного текста из:
    • **markdown**
    • простых HTML-тегов (<b>, <strong>, <i>, <em>, <u>, <br>), с безопасным экранированием остального.
  1. Авторизация:
  • При неверном логине/пароле теперь отображается явное сообщение на странице входа: Неверный логин или пароль (вместо немого 401 без человекочитаемого текста).
  1. Производительность API:
  • Увеличено число воркеров Uvicorn:
    • было: --workers 4
    • стало: --workers 6
  • Изменение внесено в docker-compose.yml.
  1. WEB pool (устойчивость при пике):
  • Добавлен recovery на конфликты Docker имен/удаления (already in use, marked for removal).
  • Для ensure_web_pool добавлены повторные попытки и принудительное удаление конфликтного контейнера перед повтором.
  • Это закрывает сценарий, когда буфер (WEB_POOL_BUFFER) должен расширять пул, но упирается в конфликт имени контейнера.
  1. RDP режим приведен к on-demand модели:
  • UNIVERSAL_POOL_SIZE=0 в .env.
  • default в docker-compose.yml: ${UNIVERSAL_POOL_SIZE:-0}.
  • Для RDP отключен prewarm-подход: сессия поднимается в момент запуска сервиса (per-user session runtime), а не через общий universal-pool.
  • В админ prewarm для RDP возвращает информационное сообщение, что RDP работает on-demand.
  1. Важный операционный урок:
  • При работе с docker compose обязательно сохранять .env заполненным; пустой .env приводит к запуску со значениями по умолчанию (пустые креды/хост), что ломает подключение API к БД.

17) Версионность (введено 2026-04-22)

Принята базовая схема SemVer:

  • MAJOR — несовместимые изменения API/поведения;
  • MINOR — новая функциональность без поломки совместимости;
  • PATCH — исправления багов и операционные правки.

Текущая версия проекта:

  • 0.6.0 (см. файл VERSION в корне репозитория).

Правило релиза:

  • при любом релизном изменении обновлять VERSION и добавлять краткую запись в PROJECT_CONTEXT.md.

18) Обновления (2026-04-22)

  1. Причина закрытия сессии (idle vs limit):
  • Добавлен статус сессии ROTATED в API;
  • Для POST /api/sessions/{id}/touch при закрытой сессии возвращается 410 с JSON:
    • ok: false
    • reason: idle|limit
    • status: <SessionStatus>
  • В рантаймах (kiosk, universal-runtime) редирект на главную теперь учитывает причину:
    • /?session_closed=idle
    • /?session_closed=limit
  • На главной странице добавлено отдельное сообщение о закрытии из-за лимита активных сервисов.
  1. API воркеры:
  • Значение в docker-compose.yml увеличено до uvicorn --workers 18.
  1. Логирование API усилено (structured logging):
  • Добавлены структурированные JSON-события с event и req_id;
  • Расширен middleware логирования запросов: метод, путь, query, статус, длительность, client_ip, user_agent;
  • Добавлен порог медленных запросов через LOG_SLOW_REQUEST_MS (по умолчанию 2000 мс);
  • Добавлены ключевые события жизненного цикла сессий:
    • session_open_requested
    • session_created
    • session_rotated
    • session_closed
    • session_touch_rejected
    • session_closed_by_user
  1. Операционная польза:
  • Быстрее диагностируются причины 504/обрывов/закрытий;
  • Проще фильтровать инциденты по req_id и session_id в docker compose logs api.