# Этап 7: серверы и мониторинг Подготовка 2026-09-20 по текущему коду после этапа 6. Блоки 7.1 и 7.2 реализованы 2026-09-21; далее права действий, блок 7.3. Основа: ReUI PRO, base-nova, Frame; переиспользовать установленные Filters/DataGrid, ServerFilters, PageHeader и Sheet. Не менять vendored-компоненты и правила сетевых операций. ## Инвентаризация | Область | Подтверждено в коде | Следующая доработка | | --- | --- | --- | | Серверы | `app/(main)/servers/page.tsx`: URL читает только `server`; search/typeFilter/advancedFilters — локальный useState | Восстановление фильтров из URL без сброса выбранного сервера | | Filters | `server-filter-fields.ts`: country/status/type; `apply-filter-query.ts` сохраняет AND/OR, вложенность, negated и черновики | Ограниченный валидируемый codec дерева, без уплощения | | Формы сервера | Уже есть сохранение формы при ошибке, блокировка повторов, загрузка деталей, разделение результатов опроса и обновления списка | Проверить UX шагов и доступность, сохранить существующие гарантии | | Мониторинг | `/uptime?probe=...` выбирает проверку; отдельные вкладки и фильтры пока не имеют полного URL-контракта | Отдельный блок URL после серверов; не распространять probe на несвязанные ресурсы/speed | | Телефон | Ping-пробы: фиксированная сетка из 11 колонок, FramePanel с overflow-hidden | Доступные имя/цель/состояние и действия на 320/390 px без обрезки | | Права | `lib/auth.ts`: can/hasPermission; страницы servers/uptime не используют их для разрешений действий | UI-доступность по фактической политике backend, с повторной обработкой 403 | ## Референсы и схема | Блок | Референс | Схема доработки | | --- | --- | --- | | Список серверов | [Data Grid Filtering 2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp) | Контекст → поиск/тип/Filters → результат → детали | | Детали и формы | [Sheet 8](https://reui.io/preview/base/sheet-8?ref=mcp) | Объект → доступное действие → форма → подтверждённый API-результат | | Проверки на телефоне | [List 9](https://reui.io/preview/base/list-9?ref=mcp) | Имя и цель → состояние → измерение → действия | ```text ПК: [Контекст сервера / проверки · снять выбор] [Поиск] [Тип] [Filters] [Доступные действия] [Таблица → детали → форма → результат] URL ↔ фильтры; Back/reload возвращают контекст Телефон: [Имя проверки Состояние] [Источник → цель] [RTT / потери] [Действия] [Раскрыть дополнительные сведения] ``` Это схема иерархии, а не разрешение переписать таблицы или блоки вручную. Конкретную композицию мобильного списка выбрать из установленных компонентов после проверки текущих действий строки. ## Блок 7.1 — URL серверов Реализованный контракт: | Параметр | Значение | Правило | | --- | --- | --- | | `server` | Точный ID из этапа 6 | Сохранять при изменении фильтров; отсутствие объекта не подменять другим | | `q` | Строка поиска | Пустое значение удалять; ввод обновлять сразу через native replaceState, без новых записей истории и повторных запросов API | | `type` | jump-host / exit-node / home-router | «Все» — отсутствие параметра; дискретный выбор добавляет запись истории | | `filters` | JSON `{v:1, query: FilterQuery}` | URLSearchParams кодирует значение; сохранить AND/OR и структуру групп | Сначала реализовать чистый codec в `lib/data-filters/server-url-state.ts` и профильные unit-тесты. Валидировать до передачи в Filters/evaluator: версию, тип узла, уникальные ID, поля из SERVER_FILTER_FIELDS, допустимые для select операторы/значения. Ограничить размер JSON 8 KiB, количество узлов 50, глубину 4. Эти числа — рабочие пределы нового контракта, не существующие ограничения ReUI. Окончательный список операторов сверить с установленной конфигурацией select. Черновик незавершённого условия оставить локальным; не публиковать частично собранное дерево и не превращать OR в AND. При восстановлении неверного filters/type показать понятное сообщение и действие сброса; до сброса не расширять результат до всех серверов молча. Не помещать в URL пароли, ключи и поля форм. URL — источник сохранённого состояния. Back/Forward/reload восстанавливают контролы и строки без циклов синхронизации, автозаписи и повторного открытия форм. При быстрых изменениях разных контролов читать актуальные параметры, чтобы поздняя запись поиска не затёрла type/filters/server. Сброс фильтров удаляет q/type/filters, сохраняя server и чужие параметры; «Все серверы» снимает только server. Приёмка: прямой URL; reload; Back/Forward; смена type после ввода поиска; AND/OR; черновик; повреждённый/слишком большой JSON; неизвестное поле/оператор; сброс с сохранением server; пустой результат; отсутствие POST/PATCH/DELETE от навигации. Прогнать codec unit-тесты, servers.spec.ts, профильные URL E2E, lint/TypeScript и production build. Затем журнал и локальный коммит без push. ## Блоки после 7.1 1. **7.2 — мобильные проверки (выполнено).** Устранить обрезку Ping-проб, сохранив выбор строк, раскрытие, запуск и меню. Проверить 320/390/1440 px, клавиатуру/Escape, отсутствие скрытых обязательных действий и горизонтального скролла всей страницы. 2. **7.3 — права действий.** Источник политики — `backend/src/lib/permissions.ts`, применение — `backend/src/plugins/auth.ts`. GET `/api/servers*` требует `mm:servers:read`, запись — `mm:servers:write`; GET `/api/uptime*` — `mm:uptime:read`, запись — `mm:uptime:write`. Учитывать наследование write/admin через существующий hasPermission и режим auth disabled. Проверить конкретные маршруты опроса/теста соединения, не считать их чтением только по названию. UI не заменяет backend-проверку: серверный 403 сохраняет форму и сообщает отказ. Не выдавать доступ только по is_admin без подтверждения текущей политики. 3. **7.4 — формы, детали и полный контекст мониторинга.** Восстановление вкладки/фильтров из URL, понятные единицы и подписи, возврат к списку после действия. Не дублировать сохранённые исправления этапа 1; проверить загрузку, отмену, 400/403/500, timeout и повторное нажатие. 4. **7.5 — приёмка этапа.** Сценарий «проблема → сервер/проверка → действие → возврат» с сохранением контекста; профильные E2E, права в HTTP-моках, TypeScript, lint и build. Реальные JWT/RouterOS отдельно в тестовом окружении. Локальная приёмка этапа 7 завершена 2026-09-23: 94 профильных E2E и 2 проверки смены backend. Полные границы и внешние ограничения — в docs/ux-ui-progress.md. Следующий этап — 8, трафик и статистика. ## Решение по синхронизации URL (7.1) Поиск использует native replaceState без debounce: установленный Next App Router синхронизирует useSearchParams, не запрашивая серверные данные. Браузерный тест подтвердил быстрый посимвольный ввод и неизменное количество GET /api/servers. Это устраняет отложенную запись, способную затереть последующий выбор type/filters. Дискретные изменения используют pushState, читая актуальный window.location.search. Черновик Filters привязан к сохранённому filters и сбрасывается при popstate. Неверные type/filters блокируют выдачу до исправления/сброса; server и чужие параметры сохраняются. ## Реализация адаптивных строк (7.2) Один DOM и прежние обработчики Ping-проб сохранены. Frame задаёт контейнер ширины; локальный CSS module перестраивает существующую строку в две колонки с подписями при ширине контейнера менее 1100 px. При достаточной ширине возвращается сетка 11 колонок. Имена, цель, интерфейс и фильтр переносятся; состояние подписано на узком экране. Переключатель получил доступное имя через label, кнопки — aria-label, серверный заголовок — aria-expanded. Используются прежние FormToggle/Button/Collapsible/Sparkline; ReUI и общая тема не изменены. 11 профильных E2E прошли, в том числе длинные подписи на 320/390/1440 px, видимость действий, Enter для раскрытия графика, редактирование/Escape, запрос звезды и включение пробы. Скриншоты 320/1440 просмотрены, обрезка строки устранена. Проверка не означает адаптивность всех вкладок uptime: Resources/Speed и их формы остаются отдельными частями плана.