diff --git a/app/(main)/alerts/page.tsx b/app/(main)/alerts/page.tsx
index 8b28a758..f0f22ac1 100644
--- a/app/(main)/alerts/page.tsx
+++ b/app/(main)/alerts/page.tsx
@@ -2577,10 +2577,10 @@ function AlertsContent() {
- {/* ── main layout ── */}
-
-
- {/* ── rules card ── */}
+ >:null}
+
+
+ {known?<>
@@ -2629,14 +2629,20 @@ function AlertsContent() {
- {/* ── right sidebar ── */}
+ >:null}
+ {isLive?
:null}
+{isLive?:null}
+
+ {known?
{setTg(value);setTokenConfigured(configured)}}/>
+ :null}
+ {known?<>
{/* ── presets + groups (свёрнуто по умолчанию) ── */}
>:null}
- {isLive?:null}
- {isLive?:null}
diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md
index a3a9e503..83dd1cb2 100644
--- a/docs/ux-ui-plan.md
+++ b/docs/ux-ui-plan.md
@@ -4,7 +4,7 @@
## Актуальная точка продолжения — 2026-10-03
-Этап 11Б в работе; последний проверенный блок 11Б.6; Releases/probe schedule приняты локально. Следующий блок 11Б.7: сводная локальная регрессия оповещений, scheduler/integrations/settings/DB/releases/probe schedule, итоговый список внешних ограничений и production build; затем начать этап 12. Processing recovery без доказуемой остановки всех отправителей остаётся недоступен.
+Этап 11Б завершён в границах локальной приёмки (11Б.7); внешний выпуск не проверен. Следующий блок 12.1: общий shell — автоматический аудит доступности/клавиатура/фокус на ПК и320px в обеих темах, согласовать health popover с shared health; затем strict/partial источники dashboard, производительность и сквозная регрессия. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются.
Реальные pg_dump/pg_restore, PG rollback и остановка UDP worker требуют внешней приёмки. Датированные продолжения ниже — история; точный следующий шаг также указан в начале [журнала](ux-ui-progress.md).
diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md
index d1cb90e0..ccde2c70 100644
--- a/docs/ux-ui-progress.md
+++ b/docs/ux-ui-progress.md
@@ -28,7 +28,7 @@
| 9 | VPN, Firewall и Filters | Завершён в границах локальной приёмки 2026-09-30; блоки 9.1–9.64, ограничения в 9.64 |
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
-| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | В работе: 11Б.1–11Б.6; scheduler и GeoIP приняты локально; NetFlow принят локально; Evolution принят локально; далее общие Settings |
+| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
@@ -36,6 +36,14 @@
+## Блок 11Б.7 — сводная локальная приёмка администрирования (2026-10-03)
+
+- 189 browser, 68 context/source, 61 unit/contracts/API и7 named backend profiles прошли. После финальной композиции Alerts дополнительно16 reader/targets/queue и25 form/preview/layout,14 Alerts source прошли. Frontend/contracts production build и backend build прошли; финальная frontend build после композиции тоже прошла. Lint/typecheck профильных изменений прошли.
+- Очередь и каталоги теперь идут сразу под правилами в основной колонке, до Telegram на телефоне; перестройка не зависит от known основной загрузки. Новый delayed-primary тест доказывает один GET очереди при unknown→known без remount. Desktop/mobile screenshots просмотрены.
+- Добавлен единый administration-context профиль;39 снимков сохранены/обновлены в репозитории. Таблица результатов/референсы/схемы в docs/ux-ui-stage-11b.md; подготовлен план приёмки12. Установленные ReUI primitives/base-nova сохранены, checklist применён; полного WCAG соответствия не заявляем.
+- Локальная приёмка11Б завершена с явными исключениями: BGP-prefix evaluator/live GRE schedule/processing recovery не реализованы, UI не выдаёт их за работающие. CAS retry разрешён толькоunknown с принятием риска; processing удерживается. Реальные migrations0008/0009, PG isolation/rollback/CAS, restore/UDP workers, RouterOS/Telegram/MaxMind/Portal/Evolution/CI требуют внешней приёмки. Backend legacy speed DTO normalization не перепринята.
+- Следующий блок 12.1: общий shell — автоматический аудит доступности/клавиатура/фокус на ПК и320px в обеих темах, согласовать health popover с shared health; затем strict/partial источники dashboard, производительность и сквозная регрессия. См. docs/ux-ui-stage-12.md. Внешние ограничения 11Б сохраняются.
+
## Блок 11Б.6 — достоверное расписание проб скорости (2026-10-03)
- Live schedule reader выделен из диагностики, ждёт auth config и проверяет uptime:read до запроса/публикации. Strict required DTO/unique IDs/nullable finite metrics, no-store, 30s deadline, abort/lifetime/revision и source-key parent. Первоначальный сбой остаётся unknown, повтор явный; фоновая ошибка сохраняет подтверждённый список/время.
diff --git a/docs/ux-ui-stage-11b.md b/docs/ux-ui-stage-11b.md
index cb8c6e54..29c5307d 100644
--- a/docs/ux-ui-stage-11b.md
+++ b/docs/ux-ui-stage-11b.md
@@ -332,3 +332,24 @@ Releases strict metadata/unknown/local/безопасные ссылки и curr
### Продолжение 2026-10-03 — 11Б.6
Live probe schedule strict read/own permissions/last good/retry/deadline/source и unknown TX/RX принят локально; demo tunnel selection исправлен. Unit2/browser36+8/context8/typecheck/lint/ReUI audit прошли, screenshot320 просмотрен. Реальный collector/legacy backend normalization не переприняты. Следующий блок 11Б.7: сводная локальная регрессия оповещений, scheduler/integrations/settings/DB/releases/probe schedule, итоговый список внешних ограничений и production build; затем начать этап 12. Processing recovery без доказуемой остановки всех отправителей остаётся недоступен.
+
+## Сводная локальная приёмка — 11Б.7 (2026-10-03)
+
+| Группа | Локальный результат | Осталось вне этой проверки |
+| --- | --- | --- |
+| Scheduler / сбор данных | Независимые known/error/time, dirty/selective save, общий lock, receipt partial/fatal, source isolation | Реальное выполнение collectors, PG journal/rollback и UDP lifecycle |
+| GeoIP / NetFlow / Evolution | Reader/permissions, формы и секреты, unknown checkpoints, подтверждённый результат | MaxMind/RIPE, IPFIX/WireGuard export, Portal и upstream provider |
+| System DB | Выбор файла отделён от restore, backup bytes/metadata, один запрос, предупреждения и неизвестный результат | Реальные pg_dump/pg_restore, rollback и остановка всех workers |
+| Alerts | Rules/groups revision/If-Match, форма/права, независимые каталоги/очередь, Telegram API acceptance, CAS retry только unknown | PG migrations 0008/0009, isolation/CAS/rollback, реальные Telegram; processing recovery и BGP-prefix не реализованы |
+| Releases | Strict manifest, unknown/local/mismatch, безопасные ссылки, только current production announcement | Реальная публикация CI/Gitea |
+| Probe schedule | Strict read, uptime:read, retry/time/source, nullable TX/RX | Реальное выполнение uptime speed worker; backend legacy normalization не перепринята |
+
+Схема финального Alerts: сводка → правила → очередь → каталоги; справа Telegram/журнал, затем пресеты/подсказки. На телефоне очередь идёт перед Telegram; независимые readers остаются смонтированы при unknown → known основной загрузки.
+
+| Экран | ПК | Телефон | Референс |
+| --- | --- | --- | --- |
+| Alerts | [Экран](ux-ui/screens/alerts-overview-1440.png) | [Экран](ux-ui/screens/alerts-overview-320.png) | [List 9](https://reui.io/preview/base/list-9?ref=mcp), [Sheet 8](https://reui.io/preview/base/sheet-8?ref=mcp) |
+| Releases | [Экран](ux-ui/screens/releases-local-1440.png) | [Экран](ux-ui/screens/releases-local-320.png) | [List 9](https://reui.io/preview/base/list-9?ref=mcp) |
+| Probe schedule | [Экран](ux-ui/screens/probes-speed-schedule-1440.png) | [Экран](ux-ui/screens/probes-speed-schedule-320.png) | [Data Grid](https://reui.io/components/data-grid?ref=mcp) |
+
+Сводная регрессия: 189 browser, 68 source/context, 61 unit/contracts/API и 7 named backend profiles прошли. После заключительной компоновки Alerts дополнительные16 reader/targets/queue,25 forms/layout/preview,14 source и финальная production build прошли. Backend build тоже прошла.39 снимков сохранены в репозитории; итог фиксируется в начале журнала. Браузерные тесты подменяют HTTP; backend DI/HTTP используют тестовые зависимости. Это не доказательство работы внешних систем или полного соответствия WCAG. SQL миграции локально не применялись, push/deploy не выполнялись.
diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md
new file mode 100644
index 00000000..2d8f1105
--- /dev/null
+++ b/docs/ux-ui-stage-12.md
@@ -0,0 +1,17 @@
+# Этап 12: итоговая приёмка UX/UI
+
+План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
+
+| Блок | Проверка и результат | Критерий остановки |
+| --- | --- | --- |
+| 12.1 | Общая оболочка, автоматический аудит доступности, клавиатура/фокус, 320px/ПК и обе темы | Исправлены доказанные нарушения, непроверенные состояния перечислены |
+| 12.2 | Достоверность источников дашборда: неполный BGP, nullable counters/traffic, неверные DTO | Unknown/partial не становятся zero/down/empty; last good сохраняется |
+| 12.3 | Производительность больших списков и таблиц на фиксированных локальных данных | Записаны размер fixture, измерения и практические ограничения |
+| 12.4 | Сквозная регрессия интерфейса, права, context; production/contracts/backend builds и ReUI checklist | Итоговая матрица с результатами и точными исключениями |
+| 12.5 | Внешняя приёмка PG/RouterOS/Telegram/интеграций | Протокол тестового окружения; локальные моки не заменяют эту проверку |
+
+Сначала воспроизвести предполагаемые проблемы общей оболочки: health popover принимает только status:ok, тогда как shared health допускает подтверждённый legacy ok:true; проверить согласованность. Проверить реальные accessible names header triggers и skip link focus. Использовать установленный axe-core для автоматической части; отсутствие violations не означает полного соответствия или замену screen reader/manual проверки.
+
+Клавиатурный сценарий должен предоставлять эквивалент действий мышью ([W3C SC 2.1.1](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html)); программные имена/роли/состояния проверяются отдельно ([W3C SC 4.1.2](https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html)). Проверка reflow включает 320 CSS px; широкие таблицы проверяются как отдельные области прокрутки, а не как разрешение переполнения страницы ([W3C SC 1.4.10](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html)).
+
+Внешние ограничения 11Б сохраняются: migrations0008/0009, PG isolation/CAS/rollback, реальный restore/UDP workers, RouterOS, Telegram, MaxMind/RIPE, Portal/Evolution, CI/Gitea. Processing не разрешается повторять без доказуемой остановки всех отправителей; timeout или checkbox не являются таким доказательством. BGP-prefix evaluator отсутствует и честно обозначен UI; отдельного live GRE расписания нет. Производственный выпуск не разрешён одним успешным browser/DI прогоном.
diff --git a/docs/ux-ui/screens/alerts-overview-1440.png b/docs/ux-ui/screens/alerts-overview-1440.png
new file mode 100644
index 00000000..df3d579d
Binary files /dev/null and b/docs/ux-ui/screens/alerts-overview-1440.png differ
diff --git a/docs/ux-ui/screens/alerts-overview-320.png b/docs/ux-ui/screens/alerts-overview-320.png
new file mode 100644
index 00000000..463ee9c2
Binary files /dev/null and b/docs/ux-ui/screens/alerts-overview-320.png differ
diff --git a/docs/ux-ui/screens/data-collection-1440.png b/docs/ux-ui/screens/data-collection-1440.png
index 9680ac21..ec0b6aef 100644
Binary files a/docs/ux-ui/screens/data-collection-1440.png and b/docs/ux-ui/screens/data-collection-1440.png differ
diff --git a/docs/ux-ui/screens/data-collection-320.png b/docs/ux-ui/screens/data-collection-320.png
index e91a5fd5..e97e7985 100644
Binary files a/docs/ux-ui/screens/data-collection-320.png and b/docs/ux-ui/screens/data-collection-320.png differ
diff --git a/docs/ux-ui/screens/data-collection-390.png b/docs/ux-ui/screens/data-collection-390.png
index 042a7a5c..2651df2f 100644
Binary files a/docs/ux-ui/screens/data-collection-390.png and b/docs/ux-ui/screens/data-collection-390.png differ
diff --git a/docs/ux-ui/screens/data-collection-settings-1440.png b/docs/ux-ui/screens/data-collection-settings-1440.png
index 61cf5d4c..1c93047b 100644
Binary files a/docs/ux-ui/screens/data-collection-settings-1440.png and b/docs/ux-ui/screens/data-collection-settings-1440.png differ
diff --git a/docs/ux-ui/screens/data-collection-settings-320.png b/docs/ux-ui/screens/data-collection-settings-320.png
index 51f5cd3d..c9d0b48e 100644
Binary files a/docs/ux-ui/screens/data-collection-settings-320.png and b/docs/ux-ui/screens/data-collection-settings-320.png differ
diff --git a/docs/ux-ui/screens/data-collection-settings-390.png b/docs/ux-ui/screens/data-collection-settings-390.png
index e2a1fe5a..a6b6525d 100644
Binary files a/docs/ux-ui/screens/data-collection-settings-390.png and b/docs/ux-ui/screens/data-collection-settings-390.png differ
diff --git a/docs/ux-ui/screens/evolution-1440.png b/docs/ux-ui/screens/evolution-1440.png
index e2728bf6..198aaac8 100644
Binary files a/docs/ux-ui/screens/evolution-1440.png and b/docs/ux-ui/screens/evolution-1440.png differ
diff --git a/docs/ux-ui/screens/evolution-320.png b/docs/ux-ui/screens/evolution-320.png
index c3120188..7e7a9105 100644
Binary files a/docs/ux-ui/screens/evolution-320.png and b/docs/ux-ui/screens/evolution-320.png differ
diff --git a/docs/ux-ui/screens/evolution-390.png b/docs/ux-ui/screens/evolution-390.png
index 04ea7a6a..bfff5ead 100644
Binary files a/docs/ux-ui/screens/evolution-390.png and b/docs/ux-ui/screens/evolution-390.png differ
diff --git a/docs/ux-ui/screens/evolution-clear-1440.png b/docs/ux-ui/screens/evolution-clear-1440.png
index db1d6f02..30b49163 100644
Binary files a/docs/ux-ui/screens/evolution-clear-1440.png and b/docs/ux-ui/screens/evolution-clear-1440.png differ
diff --git a/docs/ux-ui/screens/evolution-clear-320.png b/docs/ux-ui/screens/evolution-clear-320.png
index 480e4bf8..0f784a2d 100644
Binary files a/docs/ux-ui/screens/evolution-clear-320.png and b/docs/ux-ui/screens/evolution-clear-320.png differ
diff --git a/docs/ux-ui/screens/evolution-clear-390.png b/docs/ux-ui/screens/evolution-clear-390.png
index 63fa1913..1b1b4341 100644
Binary files a/docs/ux-ui/screens/evolution-clear-390.png and b/docs/ux-ui/screens/evolution-clear-390.png differ
diff --git a/docs/ux-ui/screens/evolution-communities-1440.png b/docs/ux-ui/screens/evolution-communities-1440.png
index fd8c6530..a7147a99 100644
Binary files a/docs/ux-ui/screens/evolution-communities-1440.png and b/docs/ux-ui/screens/evolution-communities-1440.png differ
diff --git a/docs/ux-ui/screens/evolution-communities-320.png b/docs/ux-ui/screens/evolution-communities-320.png
index f1339847..44d7562d 100644
Binary files a/docs/ux-ui/screens/evolution-communities-320.png and b/docs/ux-ui/screens/evolution-communities-320.png differ
diff --git a/docs/ux-ui/screens/evolution-communities-390.png b/docs/ux-ui/screens/evolution-communities-390.png
index 71960fdb..32b34b17 100644
Binary files a/docs/ux-ui/screens/evolution-communities-390.png and b/docs/ux-ui/screens/evolution-communities-390.png differ
diff --git a/docs/ux-ui/screens/geoip-1440.png b/docs/ux-ui/screens/geoip-1440.png
index 44f5cecc..9e97a637 100644
Binary files a/docs/ux-ui/screens/geoip-1440.png and b/docs/ux-ui/screens/geoip-1440.png differ
diff --git a/docs/ux-ui/screens/geoip-320.png b/docs/ux-ui/screens/geoip-320.png
index fad9b984..27bfdeaf 100644
Binary files a/docs/ux-ui/screens/geoip-320.png and b/docs/ux-ui/screens/geoip-320.png differ
diff --git a/docs/ux-ui/screens/geoip-390.png b/docs/ux-ui/screens/geoip-390.png
index 0fc7d34f..eca0051e 100644
Binary files a/docs/ux-ui/screens/geoip-390.png and b/docs/ux-ui/screens/geoip-390.png differ
diff --git a/docs/ux-ui/screens/netflow-1440.png b/docs/ux-ui/screens/netflow-1440.png
index 1a5ffa3e..651e6170 100644
Binary files a/docs/ux-ui/screens/netflow-1440.png and b/docs/ux-ui/screens/netflow-1440.png differ
diff --git a/docs/ux-ui/screens/netflow-320.png b/docs/ux-ui/screens/netflow-320.png
index 00d7b7a4..67f0ae26 100644
Binary files a/docs/ux-ui/screens/netflow-320.png and b/docs/ux-ui/screens/netflow-320.png differ
diff --git a/docs/ux-ui/screens/netflow-390.png b/docs/ux-ui/screens/netflow-390.png
index 1a17b6c0..0f1a5565 100644
Binary files a/docs/ux-ui/screens/netflow-390.png and b/docs/ux-ui/screens/netflow-390.png differ
diff --git a/docs/ux-ui/screens/netflow-actions-1440.png b/docs/ux-ui/screens/netflow-actions-1440.png
index dadfecbd..f0e01645 100644
Binary files a/docs/ux-ui/screens/netflow-actions-1440.png and b/docs/ux-ui/screens/netflow-actions-1440.png differ
diff --git a/docs/ux-ui/screens/netflow-actions-320.png b/docs/ux-ui/screens/netflow-actions-320.png
index d67e3728..4491d846 100644
Binary files a/docs/ux-ui/screens/netflow-actions-320.png and b/docs/ux-ui/screens/netflow-actions-320.png differ
diff --git a/docs/ux-ui/screens/netflow-actions-390.png b/docs/ux-ui/screens/netflow-actions-390.png
index ea3d5bb3..33a38d12 100644
Binary files a/docs/ux-ui/screens/netflow-actions-390.png and b/docs/ux-ui/screens/netflow-actions-390.png differ
diff --git a/docs/ux-ui/screens/probes-speed-schedule-1440.png b/docs/ux-ui/screens/probes-speed-schedule-1440.png
new file mode 100644
index 00000000..88fc217b
Binary files /dev/null and b/docs/ux-ui/screens/probes-speed-schedule-1440.png differ
diff --git a/docs/ux-ui/screens/probes-speed-schedule-320.png b/docs/ux-ui/screens/probes-speed-schedule-320.png
new file mode 100644
index 00000000..e0a64fa2
Binary files /dev/null and b/docs/ux-ui/screens/probes-speed-schedule-320.png differ
diff --git a/docs/ux-ui/screens/releases-local-1440.png b/docs/ux-ui/screens/releases-local-1440.png
new file mode 100644
index 00000000..c7f1aeb4
Binary files /dev/null and b/docs/ux-ui/screens/releases-local-1440.png differ
diff --git a/docs/ux-ui/screens/releases-local-320.png b/docs/ux-ui/screens/releases-local-320.png
new file mode 100644
index 00000000..f40b23cd
Binary files /dev/null and b/docs/ux-ui/screens/releases-local-320.png differ
diff --git a/docs/ux-ui/screens/settings-general-1440.png b/docs/ux-ui/screens/settings-general-1440.png
index e751d0f9..897dbecb 100644
Binary files a/docs/ux-ui/screens/settings-general-1440.png and b/docs/ux-ui/screens/settings-general-1440.png differ
diff --git a/docs/ux-ui/screens/settings-general-320.png b/docs/ux-ui/screens/settings-general-320.png
index e9b48aec..d3a6ce5c 100644
Binary files a/docs/ux-ui/screens/settings-general-320.png and b/docs/ux-ui/screens/settings-general-320.png differ
diff --git a/docs/ux-ui/screens/settings-general-390.png b/docs/ux-ui/screens/settings-general-390.png
index 8610d956..f30e492a 100644
Binary files a/docs/ux-ui/screens/settings-general-390.png and b/docs/ux-ui/screens/settings-general-390.png differ
diff --git a/docs/ux-ui/screens/settings-security-1440.png b/docs/ux-ui/screens/settings-security-1440.png
index 5982e425..f2a28465 100644
Binary files a/docs/ux-ui/screens/settings-security-1440.png and b/docs/ux-ui/screens/settings-security-1440.png differ
diff --git a/docs/ux-ui/screens/settings-security-320.png b/docs/ux-ui/screens/settings-security-320.png
index af0fb2a1..d801fb7b 100644
Binary files a/docs/ux-ui/screens/settings-security-320.png and b/docs/ux-ui/screens/settings-security-320.png differ
diff --git a/docs/ux-ui/screens/settings-security-390.png b/docs/ux-ui/screens/settings-security-390.png
index f48aac54..5590904b 100644
Binary files a/docs/ux-ui/screens/settings-security-390.png and b/docs/ux-ui/screens/settings-security-390.png differ
diff --git a/docs/ux-ui/screens/system-database-confirm-1440.png b/docs/ux-ui/screens/system-database-confirm-1440.png
index 2ff71d00..4e6be03f 100644
Binary files a/docs/ux-ui/screens/system-database-confirm-1440.png and b/docs/ux-ui/screens/system-database-confirm-1440.png differ
diff --git a/docs/ux-ui/screens/system-database-confirm-320.png b/docs/ux-ui/screens/system-database-confirm-320.png
index 755aac7a..dbb304ab 100644
Binary files a/docs/ux-ui/screens/system-database-confirm-320.png and b/docs/ux-ui/screens/system-database-confirm-320.png differ
diff --git a/docs/ux-ui/screens/system-database-confirm-390.png b/docs/ux-ui/screens/system-database-confirm-390.png
index 7db57b38..20d2e31a 100644
Binary files a/docs/ux-ui/screens/system-database-confirm-390.png and b/docs/ux-ui/screens/system-database-confirm-390.png differ
diff --git a/playwright.administration-context.config.ts b/playwright.administration-context.config.ts
new file mode 100644
index 00000000..10654e00
--- /dev/null
+++ b/playwright.administration-context.config.ts
@@ -0,0 +1,5 @@
+import {defineConfig} from "@playwright/test"
+import base from "./playwright.config"
+const server=base.webServer
+if(!server||Array.isArray(server))throw new Error("Ожидается один локальный сервер")
+export default defineConfig({...base,use:{...base.use,baseURL:"http://127.0.0.1:3101"},testIgnore:[],testMatch:["alerts-context.spec.ts","data-collection-context.spec.ts","evobgp-context.spec.ts","geoip-context.spec.ts","netflow-context.spec.ts","settings-context.spec.ts","system-database-context.spec.ts","probes-context.spec.ts"],webServer:{...server,command:"node node_modules/next/dist/bin/next dev --hostname 127.0.0.1 --port 3101",url:"http://127.0.0.1:3101",env:{...server.env,NEXT_PUBLIC_BACKEND_URL:"local"}}})
diff --git a/tests/e2e/alerts-layout.spec.ts b/tests/e2e/alerts-layout.spec.ts
index b0139673..d7c4a7a3 100644
--- a/tests/e2e/alerts-layout.spec.ts
+++ b/tests/e2e/alerts-layout.spec.ts
@@ -15,7 +15,14 @@ for(const width of [320,1440])test("Alerts rules priority, accessible filters an
const name=page.getByText("Fixture rule",{exact:true});await expect(name).toBeVisible();expect((await name.boundingBox())!.width).toBeGreaterThan(100)
const position=await search.boundingBox();const catalogs=await page.getByText("Каталоги целей",{exact:true}).boundingBox();const queue=await page.getByRole("region",{name:"Очередь Telegram"}).boundingBox()
expect(position!.y).toBeLessThan(catalogs!.y);expect(position!.y).toBeLessThan(queue!.y)
+ if(width===320){const telegram=await page.getByRole("region",{name:"Параметры Telegram"}).boundingBox();expect(queue!.y).toBeLessThan(telegram!.y)}else expect(queue!.y).toBeLessThan(900)
await search.scrollIntoViewIfNeeded();await expect(search).toBeInViewport()
expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true)
- await page.screenshot({path:"test-results/alerts-layout-"+width+".png",fullPage:true})
+ await page.screenshot({path:"docs/ux-ui/screens/alerts-overview-"+width+".png",fullPage:true})
+})
+
+test("Alerts queue remains mounted when delayed primary snapshot becomes known",async({page})=>{
+ let started=false,calls=0,release!:()=>void;const gate=new Promise(resolve=>release=resolve)
+ await page.route("**/health",r=>r.fulfill({json:{status:"ok"}}));await page.route("**/api/**",async r=>{const path=new URL(r.request().url()).pathname;if(path==="/api/alerts"){started=true;await gate;return r.fulfill({json:alertsWithRule})}if(path==="/api/alerts/outbox")calls++;return r.fulfill({json:path==="/api/auth/config"?{required:false}:path==="/api/alerts/outbox"?emptyOutbox:path==="/api/filters/gre-tunnels"?{tunnels:[],failures:[]}:[]})})
+ try{await page.goto("/alerts");await expect.poll(()=>started).toBe(true);await expect(page.getByRole("region",{name:"Очередь Telegram"})).toBeVisible();await expect.poll(()=>calls).toBe(1);release();await expect(page.getByRole("textbox",{name:"Поиск правил",exact:true})).toBeVisible();expect(calls).toBe(1)}finally{release()}
})
diff --git a/tests/e2e/probes-schedule.spec.ts b/tests/e2e/probes-schedule.spec.ts
index 3a166a1c..bab6f20d 100644
--- a/tests/e2e/probes-schedule.spec.ts
+++ b/tests/e2e/probes-schedule.spec.ts
@@ -7,6 +7,6 @@ test("Probe schedule refresh preserves confirmed rows and missing RX does not be
test("Probe schedule timeout is retryable without automatic request",async({page})=>{await page.clock.install();await setup(page);let calls=0;await page.route("**/api/uptime/speed-probes",()=>{calls++});const panel=await open(page);await expect.poll(()=>calls).toBe(1);await page.clock.fastForward(30100);await expect(panel.getByRole("alert")).toContainText("Время ожидания");await expect(panel.getByRole("button",{name:"Обновить пробы скорости"})).toBeEnabled();expect(calls).toBe(1)})
test("Probe schedule respects its own uptime permission",async({page})=>{await setup(page);const claims={sub:"fixture",apps:["mm"],permissions:["mm:servers:read"],exp:Math.floor(Date.now()/1000)+3600};const token="e30."+Buffer.from(JSON.stringify(claims)).toString("base64url")+".fixture";await page.addInitScript(value=>localStorage.setItem("mmapp_token",value),token);await page.route("**/api/auth/config",r=>r.fulfill({json:{required:true}}));let calls=0;await page.route("**/api/uptime/speed-probes",r=>{calls++;return r.fulfill({json:{probes:[]}})});const panel=await open(page);await expect(panel.getByRole("alert")).toContainText("Нет права читать пробы скорости");expect(calls).toBe(0)})
-for(const width of [320,1440])test("Probe schedule known rows fit/"+width,async({page})=>{await setup(page);await page.setViewportSize({width,height:900});await page.route("**/api/uptime/speed-probes",r=>r.fulfill({json:{probes:[{...probe,lastRunAt:"2026-10-03T00:00:00Z"}]}}));const panel=await open(page);await expect(panel.getByText(/RX: неизвестно/)).toBeVisible();await panel.scrollIntoViewIfNeeded();await expect(panel.getByRole("button",{name:"Обновить пробы скорости"})).toBeInViewport();expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true);await panel.screenshot({path:"test-results/probes-schedule-"+width+".png"})})
+for(const width of [320,1440])test("Probe schedule known rows fit/"+width,async({page})=>{await setup(page);await page.setViewportSize({width,height:900});await page.route("**/api/uptime/speed-probes",r=>r.fulfill({json:{probes:[{...probe,lastRunAt:"2026-10-03T00:00:00Z"}]}}));const panel=await open(page);await expect(panel.getByText(/RX: неизвестно/)).toBeVisible();await panel.scrollIntoViewIfNeeded();await expect(panel.getByRole("button",{name:"Обновить пробы скорости"})).toBeInViewport();expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true);await panel.screenshot({path:"docs/ux-ui/screens/probes-speed-schedule-"+width+".png"})})
test("Demo schedule clears a tunnel from another device and selects a valid one",async({page})=>{await setup(page);await page.addInitScript(()=>localStorage.setItem("routerlists:data-source","mock"));await page.goto("/probes?server=srv1");await page.getByRole("button",{name:"Расписание",exact:true}).click();await page.getByRole("button",{name:"Добавить правило",exact:true}).click();const server=page.getByRole("combobox",{name:"Устройство расписания"}),tunnel=page.getByRole("combobox",{name:"Туннель расписания"});await expect(tunnel).toHaveValue("gre1");await server.selectOption("srv2");await expect(tunnel).toHaveValue("");await expect(page.getByRole("button",{name:"Добавить",exact:true})).toBeDisabled();await server.selectOption("srv7");await expect(tunnel).toHaveValue("gre5");await expect(page.getByRole("button",{name:"Добавить",exact:true})).toBeEnabled()})
diff --git a/tests/e2e/releases-layout.spec.ts b/tests/e2e/releases-layout.spec.ts
index d98899f5..bcce9212 100644
--- a/tests/e2e/releases-layout.spec.ts
+++ b/tests/e2e/releases-layout.spec.ts
@@ -9,7 +9,7 @@ for(const width of [320,1440])test("Releases local build is not presented as pub
await expect(page.getByText("Сводка коммитов",{exact:true})).toBeVisible()
await expect(page.getByRole("link",{name:"Открыть релиз",exact:true})).toHaveCount(0)
expect(await page.evaluate(()=>document.documentElement.scrollWidth<=window.innerWidth)).toBe(true)
- await page.screenshot({path:"test-results/releases-local-"+width+".png",fullPage:true})
+ await page.screenshot({path:"docs/ux-ui/screens/releases-local-"+width+".png",fullPage:true})
})
// Server component reads a local manifest. Restore the original bytes even on assertion failure.