1364 lines
364 KiB
Markdown
1364 lines
364 KiB
Markdown
# UX/UI: журнал реализации
|
||
|
||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения.
|
||
|
||
## Правила продолжения
|
||
|
||
- План: ReUI PRO, Frame, base-nova; KpiStatGrid, ServerTileRail и CodeExportSheet остаются источниками общих композиционных решений.
|
||
- Работа последовательно, без субагентов. После каждого завершённого этапа — локальный коммит на русском, без push.
|
||
- В начале этапа и после значимых проверок читать пятичасовой лимит. Базовый резерв 25%; по текущему прямому поручению пользователя продолжать до конца лимитов, сохраняя проверенные блоки локальными коммитами.
|
||
- Этапы 2–4 выполнять в отдельной ветке codex/reui-v9-migration; не выпускать её до завершения миграции всех потребителей.
|
||
- Локально доступны моки. Проверки операций должны идти по обычному API-пути с подменой HTTP-ответов в тестах: встроенный mock-режим обходит запросы и не доказывает корректность live-ветки.
|
||
- Реальное применение RouterOS, сетевой опрос и экспорт сертификатов требуют отдельной приёмки в тестовом окружении. Не считать их проверенными по мокам.
|
||
- Перед продолжением читать git status и новые коммиты; сохранять изменения других задач.
|
||
|
||
## Состояние этапов
|
||
|
||
| Этап | Результат | Статус |
|
||
| --- | --- | --- |
|
||
| 0 | Исходная база, карта миграции, проверки и обзор экранов | Завершён 2026-09-13 |
|
||
| 1 | Достоверность сохранения, удаления, включения и опроса серверов | Завершён 2026-09-13 |
|
||
| 2 | Общая оболочка Data Grid/TanStack v9, Filters и эталон серверов | Завершён 2026-09-13, с перечисленными ограничениями приёмки |
|
||
| 3 | Основные таблицы и справочники | Завершён 2026-09-13, границы проверок ниже |
|
||
| 4 | Остальные таблицы, удаление старых API, общая регрессия | Завершён 2026-09-20; границы приёмки ниже |
|
||
| 5 | Состояния данных, свежесть, частичные сбои, гонки polling | Завершён 2026-09-20 для дашборда; границы проверок ниже |
|
||
| 6 | Навигация и дашборд | Завершён 2026-09-20 в границах локальной приёмки; ограничения ниже |
|
||
| 7 | Серверы и мониторинг: детали, формы, URL-контекст, права | Завершён в границах локальной приёмки 2026-09-23; внешние ограничения ниже |
|
||
| 8 | Трафик и статистика | Завершён 2026-09-28 в границах локальной приёмки; ограничения в блоке 8.13 |
|
||
| 9 | VPN, Firewall и Filters | В работе: блоки 9.1–9.54 — IPsec/GRE/VXLAN, Firewall и операции Filters |
|
||
| 10 | Маршрутизация, диагностика, карта и терминал | Не начат |
|
||
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Не начат |
|
||
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат |
|
||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
|
||
|
||
## Блок 9.54 — корректный фрагмент .rsc VXLAN (2026-09-30)
|
||
|
||
- Генератор вынесен в lib/vxlan-export.ts. Строки RouterOS заключены в кавычки; кавычка/обратный слеш/dollar и управляющие символы экранируются. Заголовки не содержат переводов строки из имени/metadata. Числовые параметры идут из валидированной модели.
|
||
- По документации MikroTik используются port, learning, arp и доступный local-address. Удалены неподдерживаемые vtep-mac-address/arp-proxy/mac-learning, read-only l2mtu и выдуманная команда привязки к bridge. Это фрагмент интерфейса/статических VTEP; bridge/FDB/прочие параметры, которых нет в API, не включены. Импорт на RouterOS ещё не проверен.
|
||
- Backend возвращает точный arpMode, обычный arp=enabled больше не означает proxy ARP. Обрабатывается learning=no. Точный arp приоритетен над legacy arp-proxy. Новое поле optional на frontend для совместимости прежних ответов; при его отсутствии старый boolean может описать только proxy-arp/обычный enabled.
|
||
- Unit генератора проверяет сложные строки и отсутствие посторонних команд/недоступных параметров; backend unit проверяет все ARP modes и частичный опрос. TypeScript frontend/backend, frontend lint, 2 E2E экспорта/свежести и backend build прошли. Последний frontend build — 9.52.
|
||
- Источники: [VXLAN](https://help.mikrotik.com/docs/spaces/ROS/pages/100007937/VXLAN), [строковые литералы RouterOS](https://help.mikrotik.com/docs/spaces/ROS/pages/47579229/Scripting). Далее — согласованность ответа VXLAN, экраны и общая проверка, затем GRE-каталог. Локальный коммит без push.
|
||
|
||
## Блок 9.53 — достоверность VXLAN и режим просмотра (2026-09-30)
|
||
|
||
- Backend VXLAN предоставляет GET; удалены активные кнопки без обработчиков (создание/редактирование/включение/удаление). Экран явно отмечен «Только просмотр»; доступны опрос и экспорт .rsc. Новые сетевые write-операции в этом блоке не вводились.
|
||
- При полном отказе сохранённые строки получают неизвестный статус, KPI не выдают старый UP за актуальное значение. Первоначальная ошибка не показывает ложную пустую таблицу. Ошибка сохраняется до успешного повтора, время успешного чтения — по устройствам; частичный отказ не обновляет дату неответившего устройства. Даты клиентские, общий ответ не гарантирует успешный опрос каждого устройства.
|
||
- Экспорт фиксирует строку, metadata сервера, дату и признак неизвестной актуальности на момент открытия; обновление таблицы не меняет открытый код. Mock-экспорт подписан отдельно. Смена backend/mode отделяет состояние, панели и даты; URL-контекст сохранён.
|
||
- После последних изменений прошли 17 обычных E2E VXLAN и 4 отдельных E2E смены источника. TypeScript и lint чистые. Backend не менялся; последний frontend build — 9.52, backend — 9.44.
|
||
- Далее — точность/экранирование .rsc VXLAN и валидация согласованности ответа, затем ошибки общего GRE-каталога и общая регрессия этапа 9. Реальная RouterOS-приёмка/полные права/DB/JWT не выполнены. Локальный коммит без push.
|
||
|
||
## Блок 9.52 — клавиатура и экраны IPsec (2026-09-30)
|
||
|
||
- Два E2E проверили ПК 1440×1000 и телефон 390×844: выбор устройства на телефоне, открытие клиента клавиатурой, сохранение через Enter с единственным PATCH в правильный serverId, отсутствие горизонтального переполнения документа, границы формы и серверные действия. Шесть PNG сохранены и просмотрены. Имена клиентов получают title для обрезанного текста.
|
||
- Первые прогоны уточнили существующее имя поля и дождались штатной анимации Sheet; оба исправленных сценария прошли. Снимок сервера телефона показывает прокрученный контент с кнопками; таблица имеет внутреннюю горизонтальную прокрутку. Это профильная проверка PSK-редактирования, не вся приёмка screen reader/контраста/всех полей.
|
||
- Production build frontend прошёл (контракты/TypeScript, 34 страницы), lint изменённого компонента/теста чистый. Backend не менялся, последний build — 9.44. Снимки используют HTTP-фикстуры, реальные RouterOS/JWT/БД не проверены.
|
||
- Далее — оставшиеся ограничения VXLAN: достоверность после общего сбоя, свежесть, режим просмотра и источник; затем ошибки общего GRE-каталога. Этап 9 открыт. Локальный коммит без push.
|
||
|
||
| Референс | ПК | Телефон |
|
||
| --- | --- | --- |
|
||
| [Data Grid Filtering 2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp) | [Клиенты](ux-ui/screens/ipsec-desktop.png) | [Клиенты](ux-ui/screens/ipsec-mobile.png) |
|
||
| [Sheet 8](https://reui.io/preview/base/sheet-8?ref=mcp) | [Форма клиента](ux-ui/screens/ipsec-client-desktop.png) | [Форма клиента](ux-ui/screens/ipsec-client-mobile.png) |
|
||
| [List 9](https://reui.io/preview/base/list-9?ref=mcp) | [Серверы](ux-ui/screens/ipsec-servers-desktop.png) | [Сервер](ux-ui/screens/ipsec-servers-mobile.png) |
|
||
|
||
## Блок 9.51 — свежесть IPsec (2026-09-30)
|
||
|
||
- По выбранному устройству показано клиентское время получения успешного ответа; по всем устройствам — время последнего валидного ответа IPsec, которое не означает успешный опрос каждого роутера. Частичный отказ сохраняет прошлое время неответившего устройства, полный отказ не меняет ни одну дату. До первого успешного результата время неизвестно; время отмечается только для устройств, присутствующих в успешных сводках/клиентах.
|
||
- Подтверждённые изменения/восстановление показывают отдельный timestamp API с serverId. Он не заменяет последующий опрос. ISO доступен через time.dateTime, title поясняет клиентские часы; даты не сохраняются между перезагрузками, возраст не обновляется таймером.
|
||
- 8 E2E прошли: данные/схемы, новый тест управляемых часов с выбором устройства и расширенный замок удаления/ошибка опроса с подтверждением записи. TypeScript и lint чистые. Backend не менялся, build пока не повторялся.
|
||
- Далее — профильная клавиатурная и адаптивная приёмка IPsec, проверенные экраны в плане; затем оставшиеся VXLAN/GRE. Реальные RouterOS/JWT/БД не проверены. Локальный коммит без push.
|
||
|
||
## Блок 9.50 — замок и контекст операций IPsec (2026-09-30)
|
||
|
||
- Общий синхронный operationLock охватывает инициализацию, создание/редактирование клиентов/peer, удаление и восстановление до последующего чтения. Начало записи инвалидирует предыдущий опрос; внешний refresh при записи не отправляется. Восстановление и экспорт проверяют readiness устройства, ошибки остаются в своих панелях.
|
||
- Mounted-guard отсекает поздние успехи записи после смены источника: нет старого toast, повторного чтения или открытия сертификата. Ошибка удаления после размонтирования также игнорируется. Уже отправленная операция RouterOS не отменяется и может завершиться на прежнем backend — отмена UI не является отменой сетевой операции.
|
||
- Успешное удаление закрывает подтверждение даже при отказе последующего опроса; таблица сохраняет последние строки с явной ошибкой чтения и отключёнными действиями до повтора. Проверки не выдают это за неуспешное удаление.
|
||
- 30 E2E прошли: 6 отдельных тестов backend/mode контекста, 23 регрессии IPsec/истории (включая GRE smoke) и новый сценарий замка/ошибки чтения. TypeScript и lint чистые. Отдельная конфигурация ipsec-context исключена из обычной и использует порт 3101 последовательно.
|
||
- Далее — клиентская свежесть IPsec и профильные ПК/телефон экраны; затем оставшиеся VXLAN/GRE. Последние build frontend — 9.47, backend — 9.44. Реальные RouterOS/JWT/БД не проверены. Локальный коммит без push.
|
||
|
||
## Блок 9.49 — readiness действий IPsec (2026-09-30)
|
||
|
||
- Кнопки клиентов и серверов используют readiness конкретного serverId: требуется успешное чтение, доступный inventory, включённое устройство, отсутствие его failure и текущей загрузки/операции. Сохранённые строки не превращаются в разрешение редактировать/удалять. Успешное устройство остаётся доступным при частичном отказе другого.
|
||
- Формы создания получают только доступные устройства, уже выполняемый запрос сохраняет список. Submit и удаление дополнительно проверяют readiness перед API. Первоначальный/полный отказ блокирует создание. Refresh во время изменения/восстановления отключён. Серверные операции с неответившим устройством недоступны; просмотр истории не является разрешением восстановления.
|
||
- Новый E2E проверяет начальный отказ, частичный отказ двух устройств, общий отказ и восстановление с нулём write-запросов; вместе с прежними операциями/таблицами прошло 15 E2E. TypeScript и lint чистые. Табличная IPsec-фикстура теперь содержит реальный inventory устройства вместо пустого списка.
|
||
- Следующий блок: общий замок/контекст поздних операций, restore/export readiness и свежесть. Backend не менялся; последние build frontend — 9.47, backend — 9.44. Реальные RouterOS/JWT/БД не проверены. Локальный коммит без push.
|
||
|
||
## Блок 9.48 — состояния чтения IPsec (2026-09-30)
|
||
|
||
- listIpsec проверяет контракт, уникальность серверов/клиентов/отказов, конфликт успешного и неответившего устройства и контекст выборного ответа. Повреждённый ответ не меняет данные. IPsec и inventory загружаются независимо через allSettled; список устройств тоже проверяется схемой.
|
||
- Ошибка всего IPsec сохраняет последние строки; частичный отказ обновляет успешные устройства и сохраняет предыдущие строки/сводки неответивших. Новый подтверждённый пустой ответ удаляет прошлые строки. Постоянный alert даёт повтор; первоначальный отказ не изображает пустую таблицу, KPI неизвестного среза показаны «—»/«неизвестно».
|
||
- Поколение чтения игнорирует устаревшие ответы; смена mode/backend монтирует отдельное состояние. Поздние записи и доступность действий на сохранённых данных будут проверены следующим блоком, ещё не приняты.
|
||
- 17 E2E прошли: шесть новых сценариев чтения и 11 прежних операций. Ранее прошли три теста таблиц IPsec/GRE (два новых теста сперва требовали уточнения alert-локатора из-за Next route-announcer, исправлены). TypeScript и lint четырёх файлов чистые. Backend не менялся; последние build frontend — 9.47, backend — 9.44.
|
||
- Далее — readiness действий, свежесть и гонки IPsec; затем VXLAN/общий GRE. Реальные RouterOS/JWT/БД не проверены. Квота: 0% использования в начале, 4% пятичасовой/16% недельной после проверок. Локальный коммит без push.
|
||
|
||
## Блок 9.47 — общая регрессия Filters (2026-09-30)
|
||
|
||
- После блоков 9.35–9.46 последовательно прошли 27 E2E стандартной конфигурации и 6 E2E изоляции источника: данные/схемы, ошибки и повтор, каталоги, копирование и актуальная цель, удаление/порядок, история и общий замок, свежесть, гонки выбранного устройства, смена backend/mode, клавиатура и ПК/телефон.
|
||
- Production build frontend прошёл: контракты, TypeScript, 34 страницы. Последний backend build — 9.44, после него backend не менялся. Lint блока 9.46: 0 ошибок/13 прежних предупреждений. Исходный код в этом блоке не менялся.
|
||
- Это профильная локальная регрессия Filters по HTTP-фикстурам, не полная регрессия приложения и не приёмка RouterOS/JWT/БД. Этап 9 остаётся открыт; этапы 10–12 не начаты.
|
||
- Следующий шаг: проверить остаток квоты и последние файлы, разобрать первоначальные/частичные сбои IPsec; затем ограничения VXLAN и общего GRE-каталога. Пользователь разрешил продолжать до конца лимитов; после 33 E2E использовано 98% пятичасовой/15% недельной квоты. Результат сохраняется локальным коммитом без push.
|
||
|
||
## Блок 9.46 — клавиатура и экраны Filters (2026-09-30)
|
||
|
||
- Community использует установленный Base UI Combobox: фильтрация по коду/названию, выбор стрелками/Enter и свободный ввод. Поле связано с подписью, действие отмечено aria-pressed, ошибка объявляется alert; ввод блокируется при сохранении. Tab закрывает подсказки и возвращает доступ к остальным полям формы. При открытом popup Base UI временно ограничивает дерево доступности; тесты проверяют переход Tab, а не обходят его.
|
||
- Два новых E2E проверяют ПК 1440×1000 и телефон 390×844: отсутствие переполнения документа, выбор устройства на телефоне, валидацию, клавиатурный выбор/ручной ввод и единственный PUT в правильное устройство. Четыре PNG сохранены и просмотрены. Таблица на телефоне использует внутреннюю прокрутку; это не полная приёмка контраста, screen reader или всех форм шлюзов.
|
||
- 13 E2E прошли: layout/сохранение (4), копирование/актуальная цель/удаление/порядок/свежесть (9). TypeScript прошёл; lint 0 ошибок/13 прежних предупреждений страницы, тесты без замечаний. Build не повторялся, последние frontend/backend — 9.44. Моки HTTP проверяют live-путь; реальные RouterOS/JWT/БД не проверены.
|
||
- Далее — оставшиеся ограничения этапа 9: первоначальные/частичные сбои IPsec, свежесть VXLAN и ошибки общего GRE-каталога. Этап 9 открыт. Перед новым блоком проверить квоту и журнал; этапы 10–12 не начаты.
|
||
- Квота после профильных проверок: 96% пятичасовой/15% недельной. Пользователь разрешил работу до конца лимитов. Локальный коммит без push.
|
||
|
||
| Образец | Проверенный экран | Применённая композиция |
|
||
| --- | --- | --- |
|
||
| ReUI Data Grid Filtering 2 | [Filters ПК](ux-ui/screens/filters-desktop.png), [телефон](ux-ui/screens/filters-mobile.png) | Устройство → свежесть → правила → действие |
|
||
| ReUI Sheet 8 | [Форма ПК](ux-ui/screens/filters-rule-desktop.png), [телефон](ux-ui/screens/filters-rule-mobile.png) | Community → действие → пояснение → подтверждение API |
|
||
|
||
## Блок 9.45 — свежесть Filters (2026-09-30)
|
||
|
||
- Экран показывает время успешного получения правил, GRE и recursive каталогов выбранного устройства. До первого успеха время неизвестно; ошибочное/устаревшее чтение не обновляет время, успешный пустой каталог обновляет. Подтверждённая запись подписана отдельно «Применение подтверждено API», не выдаётся за опрос RouterOS. Read/write время сохраняется по serverId, сбрасывается вместе с изолированным источником.
|
||
- Это клиентские часы после ответа, не timestamp измерения RouterOS и не интервальная оценка возраста. ISO доступен в семантическом time, пояснение в title; между перезагрузками время не сохраняется. При чтении цели копирования отмечается полученный target набор, после PUT — подтверждение записи.
|
||
- Десять E2E прошли: новый тест с управляемыми часами проверяет все три времени, сохранение при HTTP-сбое, обновление после повтора/пустых каталогов и отдельное подтверждение удаления; прежние данные/каталоги/гонки. TypeScript прошёл. Новый тест lint-чистый, страница 0 ошибок/13 прежних предупреждений. Последние build — frontend/backend 9.44.
|
||
- Далее — профильная клавиатурная/адаптивная приёмка Filters, сохранить проверенные экраны в документации; затем оставшиеся ограничения сетевых разделов. Реальные RouterOS/JWT/БД не проверены; этап 9 открыт.
|
||
- Квота: 85% пятичасовой/13% недельной перед блоком, 87%/14% после проверок. Работа до конца лимитов разрешена пользователем. Локальный коммит без push.
|
||
|
||
## Блок 9.44 — достоверные каталоги шлюзов Filters (2026-09-30)
|
||
|
||
- GRE/recursive каталоги проверяются схемами и уникальностью ID; GRE должен принадлежать запрошенному serverId, recursive stale отклоняется. При HTTP/структурной ошибке сохраняется последний каталог, readiness остаётся false, виден alert с повтором. Поколения по устройству/типу каталога отсекают перекрывающиеся ответы; mounted-guard отменяет старый источник.
|
||
- Сохранение route требует подтверждённого каталога выбранного вида. Копирование route требует каталогов источника/цели и сопоставленного GRE/рекурсивного шлюза каждого правила; недостоверный либо отсутствующий маппинг блокирует кнопку, есть повтор. Blackhole не зависит от каталогов маршрутизации. Существующее сопоставление по remoteAddress либо dst/table/distance сохранено, сетевые правила не изменялись.
|
||
- Backend /filters/gre-tunnels?serverId=... возвращает 503 при отказе опроса вместо ложного успешного пустого списка. Общий GET без serverId пока сохраняет прежнюю частичную обработку и требует отдельного блока; реальные RouterOS/DB не проверены. Recursive backend уже сообщает stale=true, UI теперь его учитывает. GRE schema соответствует live API (ipsec=null), не предназначена для полного конфигурационного GRE-редактора.
|
||
- Прошли 12 E2E, два профильных сценария повторены после уточнения ожидания запросов. Проверены сохранение каталога при 503, отказ route-сохранения/копирования, повреждённый GRE либо stale recursive, пустой каталог без маппинга, повтор и успешное копирование. TypeScript frontend/backend и оба build прошли (frontend 34 страницы). Схема/новый тест lint-чистые; страница теперь 0 ошибок/13 прежних предупреждений (до блока 2/13), без отключения правил. Diff-check прошёл. Backend 503 проверен компиляцией/анализом контракта, без интеграционного теста с БД/RouterOS.
|
||
- Далее — свежесть полученных правил/каталогов Filters и подтверждения записи, затем профильная адаптивность/доступность и оставшиеся ограничения сетевых разделов. Этап 9 открыт.
|
||
- Квота: 81% пятичасовой/13% недельной перед блоком, 85%/13% после проверок. Пользователь разрешил продолжение до конца лимитов. Локальный коммит без push.
|
||
|
||
## Блок 9.43 — актуальная цель копирования Filters (2026-09-30)
|
||
|
||
- applyRules принимает подготовку правил под общим applyLock; копирование live читает целевой GET, требует корректный ruleset нужного устройства с live=true/без stale, затем объединяет актуальные правила с выбранными либо заменяет набор. Начальный кэш для append больше не используется. Валидное чтение обновляет сохранённый целевой набор; ошибка PUT не отменяет эти реальные прочитанные данные. В mock сохраняется прежняя локальная операция.
|
||
- Замок покрывает GET цели и PUT, блокируя повторы/отмену/конфликты. Ошибка чтения сохраняет выбранные цель/режим/правила и не отправляет PUT; размонтирование после GET останавливает продолжение старого источника.
|
||
- Десять E2E прошли: два новых append/replace (задержка GET, двойное нажатие, 503, чужой serverId, stale, повреждённые правила, отсутствие PUT при ошибках и использование нового целевого набора после успеха) и прежние сохранение/копирование/удаление/перемещение. TypeScript прошёл; новый тест lint-чистый, исходные 2 ошибки/13 предупреждений страницы сохранены. Последний frontend build — 9.40, backend — 9.32.
|
||
- Далее — каталоги GRE/recursive: схема ответов и явные ошибки вместо пустого списка при отказе, сохранение последнего успешного каталога и блокировка использования недостоверного маппинга. Затем свежесть/профильная приёмка. Реальные устройства не проверены; этап 9 открыт.
|
||
- Квота: 79% пятичасовой/12% недельной перед блоком, 81%/13% после проверок. Продолжение до конца лимитов разрешено пользователем. Локальный коммит без push.
|
||
|
||
## Блок 9.42 — изоляция источника Filters (2026-09-30)
|
||
|
||
- FiltersSource пересоздаёт состояние по ключу backend/режима. mounted-guard отменяет уведомления и продолжение старых мутаций; восстановление старого источника не запускает чтение правил/истории после ответа. Старые чтения уже отклоняются readEpoch/cleanup; загрузчики GRE/recursive также проверяют размонтирование перед применением результата.
|
||
- Контекстные проверки выполняются отдельно через playwright.filters-context.config.ts (порт 3101, NEXT_PUBLIC_BACKEND_URL=local); обычная конфигурация исключает filters-context.spec.ts. Это позволяет менять URL через настройки и проверять CORS HTTP-моки без реального backend.
|
||
- Прошли 26 E2E в двух финальных прогонах: шесть контекстных (поздний успех/ошибка чтения старого backend, поздний успех/403 применения после смены backend либо live/mock) и все 20 обычных Filters. Первый контекстный прогон остановлен после обнаружения неверного точного селектора ссылки с динамическим счётчиком; исправлен только селектор. Остановлено дерево только собственного Playwright-процесса, идентифицированного по точной командной строке. TypeScript прошёл, тесты/конфигурация lint-чистые; исходные 2 ошибки/13 предупреждений страницы сохранены. Diff-check прошёл. Последний frontend build — 9.40, backend — 9.32.
|
||
- Следующий шаг — актуальное чтение цели копирования перед append/replace; не использовать начальный кэш для объединения. Затем схемы/ошибки шлюзов и свежесть. Реальные RouterOS/JWT/БД не проверены; этап 9 открыт.
|
||
- Квота: 76% пятичасовой/12% недельной на старте, 79%/12% после проверок. Пользователь разрешил работу до конца лимитов, прежний резерв 25% для продолжения снят. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.41 — актуальное чтение выбранного устройства Filters (2026-09-30)
|
||
|
||
- Запись выбранного устройства доступна после успешного чтения его ruleset с live=true и без stale. readyServerId должен совпадать с выбранным ID, до ответа действия readonly; статус объясняет ожидание. Исходный GET без serverId отдаёт кэш и сам не разрешает запись. Восстановление с подтверждёнными rules либо успешным повторным чтением устанавливает готовность устройства.
|
||
- readEpoch отклоняет поздний успех/ошибку чтения. Поколение меняется при выборе устройства, первоначальной загрузке, начале применения/восстановления и cleanup контекста/размонтирования. Старое чтение не изменяет список, готовность, stale/статус и не показывает ошибку. Пока ручное обновление выполняется, общий applyLock блокирует записи; формы ожидают актуальное состояние.
|
||
- Все 20 E2E прошли: два новых сценария задержанного чтения первого устройства, readonly кэша, переключения на второе, подтверждённого удаления и позднего успеха/ошибки первого запроса; 18 прежних сценариев. После уточнения требования live=true повторены шесть профильных сценариев гонок/истории — passed. TypeScript прошёл; новый тест lint-чистый, исходные 2 ошибки/13 предупреждений страницы совпадают с HEAD. Diff-check прошёл. Последний frontend build — 9.40, backend — 9.32; в блоке не повторялись.
|
||
- Объём сознательно ограничен выбранным устройством. Следующий точный шаг: изолировать всё состояние Filters по backend/режиму и игнорировать завершения старых мутаций, затем перед копированием прочитать актуальный целевой ruleset и не объединять правила с первоначальным кэшем. Схемы/ошибки GRE/recursive, отключённые устройства, свежесть и реальные RouterOS/JWT/БД остаются открытыми; этап 9 не завершён.
|
||
- Квота: 73% пятичасовой/11% недельной на старте, 75%/12% после проверок. Достигнут резерв 25%: новый блок не начат, проверки/журнал завершены. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.40 — схемы и первоначальная загрузка Filters (2026-09-30)
|
||
|
||
- lib/filters-response.ts проверяет обязательные поля правила, action, уникальность ID в наборе и serverId в контейнере. Схемы используются в первоначальном GET, чтении устройства, PUT применения и POST восстановления. Ответ с ok=true, но повреждёнными rules отклоняется без замены таблицы/закрытия формы. Для каталога устройств переиспользуется общий существующий контракт firewallServersSchema; не добавлены новые зависимости.
|
||
- В live исходные rulesets пусты; ошибка загрузки больше не переключает каталог/правила/GRE на встроенные моки. Есть явный alert и повтор первоначальной загрузки; успешная пустая конфигурация отличается от ошибки. Повторный сбой чтения устройства сохраняет последние строки и блокирует изменения. Проверяется наличие ruleset каждого включённого устройства: backend начальный GET исключает отключённые устройства. Первоначальный запрос имеет cleanup от позднего завершения; общей защиты поколениями остальных чтений ещё нет.
|
||
- GRE из GET правил больше не применяется без схемы: используются отдельные существующие ensureGreTunnels/ensureRecursiveRoutes. Их payload/ошибки пока не валидируются и могут маскироваться пустыми списками; это оставшийся объём. GET без serverId возвращает backend-кэш (live=false), поэтому достоверность готовности к записи до чтения выбранного устройства требует следующего блока. Также остаются гонки смены backend/режима/устройства и старого чтения после мутации, неизвестные срезы отключённых устройств и свежесть.
|
||
- Все 18 профильных E2E прошли: пять новых сценариев повреждённого контейнера/правила/дублей/сервера с первоначальной ошибкой, повтором, последующим отказом/сохранением данных и повреждённым подтверждением сохранения; 13 прежних операций/замка/таблицы. TypeScript и production build прошли (34 страницы). Новые схема/тест lint-чистые; исходные 2 ошибки/13 предупреждений страницы совпадают с HEAD. Diff-check прошёл. Последний backend build — 9.32, backend не изменён.
|
||
- Следующий точный шаг: поколения загрузки Filters, инвалидировать старое чтение перед мутацией, изолировать backend/режим и устройство; не разрешать запись до подтверждённого актуального чтения selectedServerId. Проверить поздний успех/ошибку, смену устройства и первоначальный backend-кэш. Затем схемы/ошибки шлюзов и свежесть. Реальные RouterOS/JWT/БД не проверены; этап 9 открыт.
|
||
- Квота: 69% пятичасовой/11% недельной на старте, 72%/11% после профильных проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.39 — общий замок обновления и восстановления Filters (2026-09-30)
|
||
|
||
- refreshFromRouter и restoreRevision используют общий синхронный applyLock. Восстановление удерживает его до чтения правил (если ответ не содержит rules) и истории. Повторы/конфликты отклоняются, выбор устройства и действия таблицы удерживаются; finally освобождает замок после успеха/ошибки. Открытие/повтор загрузки истории также проверяют замок.
|
||
- loadLiveRules возвращает признак успешного чтения и требует ruleset выбранного serverId, без подстановки первого чужого набора; stale отклоняется. При отказе сохраняется последний список и readonly-состояние. Восстановление с ok=true без правил, но неудачным чтением, сохраняет подтверждение с сообщением «Версия применена, но актуальные правила не прочитаны» и не показывает уведомление полного успеха. После успешного чтения данные снова доступны для операций. При ошибке самой истории её существующий alert остаётся; подтверждение применения относится к ответу restore и данным, а не к доступности каталога ревизий.
|
||
- Прошли 15 разных E2E в нескольких прогонах: девять прежних операций/таблицы, два прежних сценария истории, три восстановления (403, HTTP/чужой ruleset/stale при повторном чтении, задержка чтения/истории, двойное нажатие, disabled конфликтов, освобождение замка) и двойное обновление с ошибкой/повтором. Первые прогоны новых тестов исправлены по селекторам: два alert в подтверждении и фоновые кнопки, скрытые модальным диалогом от accessibility tree. Финальные четыре профильных теста прошли. TypeScript и lint нового теста прошли; исходные 2 ошибки/13 предупреждений страницы совпадают с HEAD. Последние build: frontend — 9.31, backend — 9.32, не повторялись.
|
||
- Следующий точный шаг: схемы ответов Filters и достоверность первоначальной загрузки — убрать подмену live-ошибки встроенными моками, сохранять реальные последние данные, различать начальную ошибку и пустой список, дать повтор. Затем поколения чтения/смены backend/режима и свежесть; маппинг шлюзов/реальные RouterOS/JWT/БД ещё требуют приёмки. Структура payload rules пока не валидируется, поэтому malformed rules остаются риском. Этап 9 открыт.
|
||
- Квота: 66% пятичасовой/10% недельной на старте, 68%/11% на последней проверке перед журналированием. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.38 — перемещение Filters и порядок в поиске (2026-09-30)
|
||
|
||
- Перемещение работает по ID в полном наборе устройства, проверяет обе границы и ожидает applyRules. До ok=true порядок не меняется; отказ сохраняет порядок и показывает ошибку над таблицей. Синхронный moveLock исключает повторы, status сообщает ожидание; общий applyLock сохраняется.
|
||
- FiltersDataGrid принимает orderedRules и mutationsLocked: приоритет и границы перемещения вычисляются из полного списка даже при поиске/сортировке видимого среза. Во время записи/восстановления/недостоверных данных disabled перемещение, редактирование и удаление. Существующая композиция ReUI Data Grid сохранена, исходные обработчики индексов заменены одним обработчиком ID/направления.
|
||
- Девять E2E прошли: два новых направления из единственной найденной строки (полный приоритет, границы, задержка/двойное нажатие, 403, пустой ответ, ok=false, неизменный порядок, повтор с клавиатуры, успешный порядок после сброса поиска и блокировка конфликтующих действий), прежние операции и таблица. TypeScript прошёл; новый тест/таблица lint-чистые, исходные 2 ошибки/13 предупреждений страницы совпадают с HEAD. Diff-check прошёл. Последние build: frontend — 9.31, backend — 9.32; не повторялись.
|
||
- Следующий точный шаг: refreshFromRouter и restoreRevision подключить к общему синхронному замку; удерживать восстановление до чтения правил/истории, проверять отказ/повторы/конфликты и не считать ошибку чтения успешным восстановлением. Затем схемы и поколения загрузки Filters: первоначальная ошибка ещё подставляет моки, loadLiveRules может выбирать первый чужой ruleset и скрывает ошибку, смена backend/режима и ранее запущенные чтения ещё не защищены. Реальные RouterOS/JWT/БД не проверены; этап 9 открыт.
|
||
- Квота: 64% пятичасовой/10% недельной на старте, 65%/10% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.37 — подтверждённое удаление Filters (2026-09-30)
|
||
|
||
- Удаление открывает существующий AlertDialog с Community и устройством вместо подтверждения вторым нажатием на безымянную иконку. Цель операции хранит serverId и правило; перед отправкой проверяется наличие правила. Общий PUT /api/filters/rules сохраняет остальные правила в прежнем порядке. Строка удаляется только после ok=true через applyRules, ошибка сохраняет диалог и показывает alert.
|
||
- Синхронный deleteLock исключает повторы; отмена, действие удаления и Escape заблокированы до ответа, status сообщает ожидание. Повторное открытие очищает ошибку, смена устройства вне операции очищает подтверждение. Во время применения выбор устройства уже удерживается общим applyLock. Кнопка удаления получила доступное имя; ReUI Data Grid и существующие Base UI примитивы сохранены.
|
||
- Семь E2E прошли: удаление первого/последнего правила (отмена без запроса, двойное нажатие, задержка, 403, пустой ответ, ok=false, повтор, сохранение строки при ошибке и остальных правил после успеха), прежние сохранение/копирование и таблица. TypeScript прошёл. Таблица/новый тест lint-чистые; исходные 2 ошибки/13 предупреждений страницы совпадают с HEAD. Diff-check прошёл. Последние build: frontend — 9.31, backend — 9.32; не повторялись.
|
||
- Следующий точный шаг: перемещение Filters — проверить подтверждение и сохранение порядка при ошибках, границы, повторы и конфликты с другими операциями. Затем объединить замки восстановления/обновления, устранить гонки и подмену live-ошибки моками, добавить схемы. Реальные RouterOS/JWT/БД и загрузка актуального ruleset не приняты; этап 9 открыт.
|
||
- Квота: 62% пятичасовой/10% недельной на старте, 63%/10% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.36 — подтверждённое копирование Filters (2026-09-30)
|
||
|
||
- CopyRulesSheet ожидает applyRules через асинхронный onCopy. Преждевременные done и таймер закрытия удалены: форма закрывается после ok=true, при отказе сохраняет выбранные правила, целевой сервер и режим append/replace и показывает API-ошибку в alert. Общий applyRules продолжает обновлять целевой список только после подтверждения.
|
||
- Синхронный замок формы исключает двойную отправку. Fieldset и закрытие/отмена заблокированы во время запроса; Escape сохраняет открытую форму, status сообщает ожидание. Выбранные правила, цель и режим обозначены aria-pressed. Новый сеанс формы инициализируется ключом открытия/исходного устройства; обновление sourceRules больше не сбрасывает пользовательский выбор через effect. Существующие Sheet/Button и маппинг GRE/рекурсивных шлюзов сохранены.
|
||
- Пять E2E прошли: два сценария копирования append/replace (подмножество правил, сохранение/замена правил цели, новые ID, 403, пустой ответ, ok=false, повтор, двойное нажатие, блокировка/ошибка/повторное открытие и переход к целевой таблице), прежние два сохранения и таблица. Первый прогон копирования остановился только на ошибочном button-селекторе панели серверов; после замены на option весь прогон прошёл. TypeScript прошёл; новый тест lint-чистый, исходные 2 ошибки/13 предупреждений страницы совпадают с HEAD. Последние build: frontend — 9.31, backend — 9.32, в этом блоке не повторялись.
|
||
- Следующий точный шаг: Filters — удаление правил с сохранением подтверждения/ошибки и защитой повторов, затем перемещение и общий замок восстановления/обновления. Схемы ответов, гонки чтения/смены backend, первоначальная подмена live-ошибки моками и достоверность чтения целевого ruleset ещё открыты. Маппинг шлюзов и применение на настоящих RouterOS/JWT/БД этим блоком не приняты; этап 9 открыт.
|
||
- Квота: 59% пятичасовой/9% недельной на старте, 61%/10% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.35 — подтверждённое сохранение Filters (2026-09-30)
|
||
|
||
- Создание/редактирование правила ожидает результат PUT /api/filters/rules. applyRules возвращает результат, требует ok=true и обновляет live-список только после подтверждения; при ошибке прежний список остаётся. Подтверждённые rules из ответа имеют приоритет над отправленным списком. Общий путь применяется также к копированию/удалению/переносу, но их отдельный UX ещё не принят.
|
||
- Форма сохраняет введённые данные и показывает API-ошибку в alert. Во время запроса fieldset, кнопки отмены/закрытия/сохранения заблокированы, Escape не закрывает форму; status сообщает ожидание. Синхронные замки формы и applyRules предотвращают повторный PUT. Выбор устройства не переключается во время применения. Повторное открытие формы начинает новый сеанс с актуальными начальными значениями. Кнопка редактирования и поле описания получили доступные имена. Используются существующие Sheet/Button/Input и ReUI Data Grid, композиция base-nova сохранена.
|
||
- Проверки: пять E2E прошли — создание и редактирование (задержка, двойное нажатие, 403, пустой ответ, ok=false, повтор, подтверждённые сервером данные, повторное открытие), таблица Filters и два сценария истории. TypeScript прошёл. Новые тесты и таблица lint-чистые; исходные 2 ошибки/13 предупреждений страницы Filters совпадают с HEAD. Последние production build: frontend — 9.31, backend — 9.32; в этом блоке не повторялись.
|
||
- Следующий точный шаг: CopyRulesSheet и handleCopyRules — ожидать applyRules, сохранять выбранные цель/правила и показывать ошибку вместо преждевременного done. Затем подтверждение удаления/перемещения и общий замок обновления/восстановления. Открыты схемы ответа/правил, гонки чтения и смены backend/режима; первоначальная live-ошибка ещё подставляет встроенные моки, loadLiveRules может выбирать первый чужой ruleset и скрывает ошибку. Эти ограничения не считать исправленными данным блоком. Реальные RouterOS/JWT/БД не проверены; этап 9 открыт.
|
||
- Квота: 54% пятичасовой/8% недельной на старте, 58%/9% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.34 — свежесть данных Firewall (2026-09-30)
|
||
|
||
- Время успешного получения хранится для каждого включённого устройства × IP-семейства × таблицы/address-list. Успешный пустой срез тоже обновляет время, недоступный сохраняет прежнее либо null. Отключённые устройства исключаются из набора; смена источника очищает времена вместе с данными.
|
||
- Экран показывает диапазон времени выбранного устройства/семейства, количество ещё не полученных срезов и статус обновления. Предупреждение о сбое показывает время либо диапазон последних данных соответствующего среза/устройства. До первого успеха время неизвестно, при отсутствии включённых устройств сообщается отсутствие объектов для опроса.
|
||
- Метка «Получено в приложении» — клиентское время после валидации ответа, а не timestamp измерения RouterOS. Время берётся из часов браузера и не сохраняется между перезагрузками; это явно отражено в подписи/title. HTTP-ошибка, повреждённый или устаревший ответ не меняют время.
|
||
- Все 37 E2E Firewall прошли. Два новых сценария с управляемыми часами проверяют полный/частичный опрос, сохранение времени при HTTP/общем сбое, диапазон старых времён, неизвестный первоначальный срез и восстановление пустого среза. После уточнения диапазона общего сбоя два профильных теста повторно прошли. TypeScript прошёл; новые helper/тест lint-чистые, исходные 4 ошибки/2 предупреждения страницы не изменились. Diff-check проверен перед коммитом. Последние build: frontend — 9.31, backend — 9.32; повтор не выполнялся.
|
||
- Следующий шаг — Filters: проверить и исправить подтверждение API сохранения/применения/копирования/переключения/удаления, сохранение формы при ошибке и общий замок. Сначала прочитать текущие обработчики/контракт и выбрать один проверяемый блок. Ограничения RouterOS/БД и подтверждения после ошибки снимка из 9.32 сохраняются; этап 9 открыт.
|
||
- Квота: 50% пятичасовой/8% недельной на старте, 53%/8% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.33 — смена источника Firewall (2026-09-30)
|
||
|
||
- FirewallSource создаёт отдельное состояние по паре mode/backendUrl. Формы, ошибки и замки старого источника не переносятся в новый. Проверка mounted после ответа записи исключает поздние уведомления и повторное чтение старого API; чтение правил/истории также не запускается после unmount. Удаление проверяет mounted дополнительно после обновления списка.
|
||
- Четыре профильных E2E прошли: старое чтение с пустым успехом/ошибкой при смене backend; отложенное удаление после смены backend и Live → mock. Проверены данные нового API, отсутствие старого уведомления/диалога, отсутствие повторного чтения старого API и доступность нового действия. Использованы настройки и клиентская навигация с возвратом; реальные RouterOS/JWT не проверены.
|
||
- Профиль запускается отдельно: npx playwright test --config playwright.firewall-context.config.ts. Он использует local backend URL и порт 3101, обычный конфиг same-origin на 3100 исключает этот файл. Первые запуски профиля конфликтовали из-за слияния webServer при defineConfig(base, overrides); исправлено единственным объектом конфигурации, процесс пользователя не остановлен. Обнаружение четырёх тестов проверено после окончательной правки профиля.
|
||
- Все 39 E2E прошли в двух успешных прогонах: четыре профильных и 35 обычных Firewall. TypeScript прошёл. Новые тест/конфиги lint-чистые; исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check проверен перед коммитом. Build не повторялся: последний frontend — 9.31, backend — 9.32.
|
||
- Далее — свежесть данных Firewall: timestamp полного/частичного чтения, сохранение времени недоступного среза и понятная подпись последних данных. Затем Filters. Позднее завершение остальных типов мутаций покрыто общей проверкой mounted, но отдельные сценарии для каждого типа не запускались. Ограничения реальной БД/RouterOS и подтверждения после ошибки снимка из 9.32 сохраняются; этап 9 открыт.
|
||
- Квота: 43% пятичасовой/7% недельной на старте, 49%/8% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.32 — частичные сбои Firewall (2026-09-30)
|
||
|
||
- pollFirewallChunks опрашивает восемь таблиц правил и два address-list, сохраняет успешные срезы и возвращает failures с family/table/error. Повреждённый контейнер также считается сбоем. listFirewallAll добавляет устройство и сообщает общий сбой вместо маскировки успешным пустым списком.
|
||
- fetchFirewallState по умолчанию отклоняет неполное чтение: captureFirewallSnapshot и восстановление не используют неполный снимок. Для обзора явно разрешён partial; observed-ревизия записывается только при полном чтении. Ошибка записи ревизии возвращается как общий failure устройства. Реальная БД и RouterOS не проверены. Подтверждение применения после операции, если последующее чтение снимка не удалось, требует внешней приёмки: write-endpoints по-прежнему могут сообщить ошибку после фактического изменения устройства.
|
||
- UI валидирует failures, заменяет успешные срезы и сохраняет последние правила/address-list недоступных срезов включённых устройств. Сводка неполного выбранного IP-семейства неизвестна; предупреждение содержит устройство/срез/ошибку. Запись в этом срезе заблокирована до повторного успеха, восстановление — при любом failure выбранного устройства. Успешное пустое чтение удаляет старые строки; первоначальный сбой не выглядит успешным пустым списком.
|
||
- Серверный тест прошёл: mixed/empty/all-failed/malformed, strict snapshot rejection и сохранение семи успешных таблиц при одном сбое. Тест подключён к test:live-maps. Прошли 35 разных E2E в двух прогонах: 32 прежних и три новых частичных сценария. Первый прогон нового сценария остановился на проверке скрытого комментария; проверка заменена видимым портом, профильные три теста прошли. TypeScript frontend/backend и сборка backend прошли. Новые frontend-файлы/Grid lint-чистые; исходные 4 ошибки/2 предупреждения страницы сохранены. Diff-check проверен перед коммитом. Последний frontend production build — 9.31.
|
||
- Далее — timestamps свежести и дополнительные гонки Firewall при смене backend/режима и позднем завершении мутации; затем Filters. Полная валидация сырой записи RouterOS и интеграция записи observed-ревизий с реальной БД не проверены. Этап 9 открыт.
|
||
- Квота: 38% пятичасовой/6% недельной на старте, 42%/7% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.31 — проверка и загрузка данных Firewall (2026-09-30)
|
||
|
||
- Общие Zod-схемы проверяют контейнер, обязательные поля правил/address-list, IP-семейство, таблицу, boolean/числовые поля, ID устройств и дубли строк/серверов. Ответы обрабатываются как unknown до валидации; повреждённые данные не попадают в UI.
|
||
- Ошибка HTTP/валидации сохраняет последний успешный список устройств, правил и address-list; alert сообщает о последних данных. До первого успеха KPI неизвестны («—»), вместо таблицы показана загрузка/недоступность. Успешный пустой ответ остаётся допустимым и показывает нули.
|
||
- Поколение loadEpoch отменяет применение позднего ответа/ошибки и завершения старого чтения. Начало любой мутации инвалидирует ранее запущенное чтение. Смена backend/режима очищает данные и инвалидирует запросы; очистка при unmount также добавлена. Проверки смены backend/режима именно Firewall и позднего завершения самой мутации ещё не выполнены.
|
||
- Все 32 E2E Firewall прошли: восемь новых сценариев повреждённых контейнера/правила/address-list/серверов/дублей, первого сбоя/повтора/повторного сбоя и позднего успеха/ошибки чтения после переключения; прежние 24 сценария прошли. TypeScript и production build прошли (34 страницы). Новые схема/тест lint-чистые; исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check проверен перед коммитом.
|
||
- Следующий точный шаг: backend/src/services/firewall-live.ts — устранить маскировку сбоев через safeGet и catch в listFirewallAll, вернуть failures по устройству/семейству/таблице и сохранять последние данные этих срезов в UI. Текущий backend при сбое может вернуть валидный пустой массив; схема не отличает его от настоящей пустой конфигурации. Timestamp свежести, дополнительные гонки контекста и реальные RouterOS/JWT остаются открытыми. Затем Filters; этап 9 не завершён.
|
||
- Квота: 31% пятичасовой/5% недельной на старте, 37%/6% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.30 — общий замок истории Firewall (2026-09-30)
|
||
|
||
- Восстановление истории захватывает mutationLock до ответа API, обновления правил и повторного чтения истории. Ошибка освобождает замок; при занятой операции обработчик отклоняет восстановление с понятным сообщением, не выдавая успешное завершение. Отсутствие Live/устройства также сообщает ошибку.
|
||
- Кнопки «История» и «Обновить» disabled во время сохранения, удаления, переключения, переноса и восстановления. Их обработчики дополнительно проверяют синхронный замок. Уже запущенные запросы загрузки пока не отменяются и требуют защиты поколением запроса в следующем блоке.
|
||
- Прошли 26 разных E2E в двух прогонах: 23 сценария операций Firewall и три профильных сценария истории. Новый сценарий проверяет двойной запрос, 403, освобождение замка, задержку чтения правил/истории после успеха, недоступность конфликтов и последующее сохранение. Первая попытка нового теста остановилась на неоднозначном alert-селекторе; после уточнения селектора профильный прогон прошёл. TypeScript прошёл; изменённые тесты lint-чистые, исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check проверен перед коммитом. Последний production build — 9.21, повтор не выполнялся.
|
||
- Далее — схема ответа и гонки загрузки Firewall: сохранять последние данные при ошибке, неизвестные первоначальные KPI, поздние ответы/смена backend и конфликт ранее запущенного чтения с мутацией. Затем Filters. Реальные RouterOS/JWT не проверены; этап 9 открыт.
|
||
- Квота: 28% пятичасовой/4% недельной на старте, 31%/5% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.29 — перемещение Firewall (2026-09-30)
|
||
|
||
- POST перемещения требует ok=true. Оптимистический порядок откатывается при HTTP-ошибке, пустом ответе и ok=false. Status/alert содержат контекст правила; повторный запрос очищает ошибку.
|
||
- Перемещение использует общий mutationLock до ответа и завершения loadLive. Ручки переноса убираются, переключатели/меню переключения и удаления отключены; открытие формы и остальные обработчики записи блокируются. Перенос также отключён во время сохранения, удаления, переключения и восстановления истории.
|
||
- Все 23 E2E Firewall прошли: два новых сценария переноса вверх/вниз с проверкой payload, 403, пустого ответа, ok=false, отката, повторного успеха, блокировки конфликтов и задержанного чтения после успеха; прежние 21 сценарий прошли. TypeScript прошёл. Новый тест lint-чистый; исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check проверен перед коммитом. Последний production build — 9.21, повтор не выполнялся.
|
||
- Далее — согласовать восстановление истории с общим mutationLock, затем схема/гонки загрузки Firewall и Filters. Восстановление истории пока не захватывает замок, ручное обновление и поздние ответы могут конфликтовать с данными операции. loadLive сообщает ошибку отдельно: подтверждённое перемещение не гарантирует успешное последующее чтение. Реальные RouterOS/JWT не проверены; этап 9 открыт.
|
||
- Квота: 26% пятичасовой/4% недельной на старте, 28%/4% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.28 — формы Firewall (2026-09-30)
|
||
|
||
- Создание/редактирование правил и address-list требует ok=true в ответе POST/PUT. При 403, пустом ответе и ok=false форма сохраняет ввод, показывает alert и допускает повтор. Новое открытие сбрасывает ошибку; успешный ответ закрывает форму.
|
||
- Во время запроса fieldset и переключатели disabled, отмена и Escape блокируются, кнопка закрытия скрыта. Синхронный mutationLock общий для сохранения, удаления и переключения; открытие новой формы также учитывает занятость и восстановление истории.
|
||
- Все 21 E2E Firewall прошли: восемь новых сценариев rule/address × create/edit × IPv4/IPv6 проверяют метод/контекст/payload, двойное нажатие, задержку, сохранение ввода, 403, пустой ответ, ok=false и успех. Прежние 13 сценариев прошли. TypeScript прошёл. Новый тест lint-чистый; исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check проверен перед коммитом. Последний production build — 9.21, повтор не выполнялся.
|
||
- Далее — подтверждение и блокировка перемещения Firewall, затем Filters. Восстановление истории и перемещение пока не используют общий mutationLock, гонки загрузки не исправлены. После подтверждённой записи loadLive может сообщить отдельную ошибку чтения; реальные RouterOS/JWT не проверены. Этап 9 открыт.
|
||
- Квота: 23% пятичасовой/4% недельной на старте, 25%/4% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.27 — удаление Firewall (2026-09-30)
|
||
|
||
- Правила и address-list удаляются через общий AlertDialog существующей Base UI оболочки. Диалог показывает объект, устройство, IP-семейство, для правила — таблицу/цепочку; отмена до отправки не вызывает API.
|
||
- DELETE требует ok=true. При 403, пустом ответе и ok=false диалог сохраняет объект и ошибку. Повтор, отмена и Escape заблокированы до ответа и обновления списка; переключение и удаление используют общий синхронный замок. Переключатели/меню удаления и перенос строк отключены во время удаления. Новое открытие сбрасывает ошибку. Кнопка меню address-list получила доступное имя.
|
||
- Все 13 E2E Firewall прошли: четыре новых сценария rule/address для IPv4/IPv6 с проверкой точного payload, отмены, повторов, ошибок и успешного удаления; девять прежних сценариев. TypeScript прошёл. Grid/новый тест lint-чистые; исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check проверен перед коммитом. Последний production build — 9.21, повтор не выполнялся.
|
||
- Далее — сохранение форм и подтверждение перемещения Firewall, затем Filters. Замок остальных мутаций и гонки загрузки пока не исправлены. loadLive обрабатывает ошибку обновления отдельно; подтверждённое удаление не гарантирует успешное повторное чтение. Реальные RouterOS/JWT не проверены; этап 9 открыт.
|
||
- Квота: 21% пятичасовой/3% недельной на старте, 23%/4% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.26 — переключение address-list Firewall (2026-09-30)
|
||
|
||
- PATCH записи address-list требует ok=true. Переключатели и действие переключения в меню блокируются на время запроса/обновления, используется общий с правилами синхронный замок. Обработчик также учитывает занятость формы и восстановление истории.
|
||
- Status/alert содержат адрес и имя списка. При 403, пустом ответе и ok=false состояние записи сохраняется; успешный запрос обновляет список из API. Mock-режим сохраняет локальное переключение.
|
||
- Все 9 E2E Firewall прошли: два новых сценария включения/отключения address-list с двойным нажатием, задержкой, 403, пустым ответом, ok=false и успехом; прежние семь сценариев правил и таблицы. TypeScript прошёл. Новый тест lint-чистый, исходные 4 ошибки/2 предупреждения страницы не изменились относительно HEAD. Diff-check выполнен перед коммитом. Последний production build — 9.21, повтор не выполнялся.
|
||
- Далее — сохранение/удаление и подтверждение перемещения Firewall, затем Filters. Единая блокировка всех мутаций, гонки загрузки и реальная приёмка RouterOS/JWT остаются открытыми; этап 9 не завершён.
|
||
- Квота: 18% пятичасовой/3% недельной на старте, 20%/3% после проверок. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.25 — переключение правил Firewall (2026-09-30)
|
||
|
||
- PATCH правила требует ok=true. Синхронный замок блокирует повтор до ответа и обновления списка. Переключатели и действие переключения в меню disabled во время запроса; перенос строк отключён. Вызов также блокируется при занятости формы/восстановлении истории.
|
||
- Ожидание и ошибка отображаются через status/alert с комментарием либо RouterOS ID правила. При 403, пустом ответе и ok=false исходное состояние сохраняется; новый успешный запрос сбрасывает ошибку и обновляет таблицу из API. Mock-операция остаётся локальной.
|
||
- Все 7 E2E прошли: два новых сценария включения/отключения с задержкой, двойным нажатием, 403, пустым ответом, ok=false и успехом; пять прежних сценариев таблицы/перемещения/черновика. TypeScript прошёл. Grid и тест lint-чистые; исходные 4 ошибки/2 предупреждения страницы не изменились (сравнение с HEAD). Diff-check проверен перед коммитом. Build не повторялся, последний — 9.21.
|
||
- Далее — переключение address-list, затем сохранение/удаление и подтверждение перемещения Firewall. Защита остальных обработчиков и единая блокировка всех мутаций остаются открытыми; реальные RouterOS/JWT не проверены, этап 9 открыт.
|
||
- На старте использовано 15% пятичасовой и 2% недельной квоты. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.24 — схема ответа и гонки VXLAN (2026-09-30)
|
||
|
||
- Добавлены схемы туннелей, failures и записей серверов. Проверяются обязательные строки, булевы поля, статус, диапазоны VNI/портов, массив VTEP и уникальность пары serverId/id. Отсутствующий failures совместим со старым API (пустой список). Неверный ответ сохраняет последние данные и отображает ошибку.
|
||
- Все 16 E2E VXLAN прошли, включая новый сценарий пяти повреждённых payload и два сценария позднего ответа при смене server: успех/ошибка старого запроса не меняют ожидание и результат нового. Тест учитывает повторный mount Next.js development. Первоначальное ожидание ровно двух запросов уточнено до наличия нового запроса; проверки результата сохранены.
|
||
- TypeScript и lint изменённых файлов прошли; diff-check чистый. Build не повторялся, последний — 9.21. Синтаксическая проверка VTEP-адресов и криптографическая/сетевая достоверность RouterOS не проверены схемой. Серверы могут отсутствовать в каталоге: существующая таблица сохраняет строки с неизвестным сервером без подмены ID.
|
||
- Далее — Firewall: аудит записи/перемещения/удаления и ответы backend, сохранение формы при ошибке и защита повторов. Открытые ограничения VXLAN: countVxlanTunnels возвращает ноль при ошибке, timestamp свежести отсутствует, создание/изменение VXLAN не реализованы backend; этап 9 не завершён.
|
||
- Блок начат при 11% расхода пятичасовой и 2% недельной квоты. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.23 — частичные сбои VXLAN (2026-09-30)
|
||
|
||
- Общий API VXLAN возвращает tunnels/failures; неответившие устройства не маскируются пустыми списками. Сбой VTEP или повреждённый массив устройства также считается ошибкой опроса. Endpoint отдельного устройства возвращает 502 при ошибке вместо успешного пустого ответа.
|
||
- Существующая listVxlanTunnels остаётся совместимым списковым wrapper для счётчика. Сам countVxlanTunnels по-прежнему подменяет тайм-аут/ошибку нулём: исправление этой внешней сводки не включено в блок.
|
||
- UI заменяет данные успешно опрошенных устройств, сохраняет последние записи недоступных включённых серверов, показывает предупреждение и повтор. Недоступные строки имеют нейтральный статус «Неизвестно», KPI выбранного неполного среза — «—». Первичный частичный сбой не показывает успешное пустое состояние. Полная валидация записей и timestamp свежести пока не добавлены.
|
||
- Серверные проверки агрегации прошли: смешанный результат, успешный пустой список, сбой всех устройств. Прошли 13 разных E2E VXLAN (12 общих и 2 профильных во втором прогоне с одним повтором). TypeScript frontend/backend и lint изменённых frontend-файлов прошли. Diff-check проверен перед коммитом. Последний production build — 9.21; повторная сборка не выполнялась.
|
||
- Далее: общая валидация payload VXLAN и защита/проверка гонок загрузки; затем Firewall/Filters. Кнопка «Новый VXLAN» и запись конфигурации не реализованы существующим backend, не считать их выполненными. Реальные устройства/JWT не проверены; этап 9 открыт.
|
||
- Блок начат при 8% расхода пятичасовой и 1% недельной квоты. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.22 — состояния загрузки VXLAN (2026-09-30)
|
||
|
||
- Ответ без массивов tunnels/servers отклоняется вместо подмены пустым списком. Первоначальная ошибка показывает неизвестные KPI (—); успешный пустой список остаётся допустимым. При ошибке обновления сохраняются последние данные с пояснением об устаревании; загрузка объявляется через status.
|
||
- Поколение запроса блокирует устаревшие результат/ошибку/finally при новом запросе, смене backend/режима и размонтировании. Физическая отмена не добавлена. Существующий URL-контекст server/tunnel сохранён.
|
||
- Прошли 9 существующих E2E контекста/таблицы и 2 новых сценария повреждённого ответа (первоначальная ошибка и ошибка после успеха, сохранение данных и успешный повтор). Lint изменённых файлов и TypeScript чистые; diff-check прошёл. Build не повторялся, последний — 9.21. Гонки запросов отдельным новым E2E пока не проверялись.
|
||
- Далее: backend VXLAN — частичный сбой опроса устройств (сейчас API не сообщает failures), сохранение последних данных по устройству и понятное состояние недоступного сервера. Полная схема отдельных туннелей и работа с реальным RouterOS остаются открытыми. Затем Firewall/Filters. Этап 9 открыт.
|
||
- Блок начат при 5% расхода пятичасовой и 1% недельной квоты. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.21 — создание и редактирование GRE (2026-09-30)
|
||
|
||
- Создание принимает подтверждение ok=true/name либо объект с непустым ID и совпадением имени, serverId, удалённого адреса и enabled. Это проверка подтверждения операции, не полная схема GreTunnel. PATCH требует ok=true. Ответы соответствуют двум веткам backend; серверные правила не менялись.
|
||
- Ошибка отображается в панели, сохраняет ввод; замок блокирует повтор, закрытие и поля до ответа. Ожидание объявляется через status; основные поля получили доступные имена. Ошибка сбрасывается при открытии новой формы. Имена/устройство при редактировании остаются фиксированными по существующему контракту.
|
||
- Все 6 E2E GRE прошли: оба ответа создания, редактирование, удаление, включение и выключение. Проверены задержка, двойное нажатие, 403, пустой ответ, чужой serverId/ok=false, сохранение комментария и успешный повтор. TypeScript и production build (34/34 страницы) прошли. Новых замечаний lint нет: прежние 14 предупреждений GRE, тест чистый; diff-check прошёл. Первый прогон остановлен до тестов для исправления имени кнопки в новом тесте.
|
||
- Далее — VXLAN: загрузка/ошибка/повтор и контекст server/tunnel, затем Firewall/Filters. Остаются полная схема записей GRE, доступность остальных полей формы, реальные RouterOS/JWT и сквозная приёмка; этап 9 открыт.
|
||
- На старте использовано 1% пятичасовой и 0% недельной квоты после сброса. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.20 — переключение GRE (2026-09-30)
|
||
|
||
- Включение/выключение требует ok=true. Синхронный замок предотвращает повтор до PATCH и обновления списка; ожидание и ошибка с именем туннеля объявляются через status/alert. Ошибка не показывает успех и не меняет данные локально.
|
||
- Все 3 E2E прошли: включение, выключение и регрессия удаления. Проверены задержка, двойное нажатие, 403, пустой ответ, ok=false и успешный повтор. Lint: 0 ошибок, прежние 14 предупреждений GRE; новый тест чистый. TypeScript и diff-check проверены перед коммитом. Последний build — 9.16, повторная сборка не выполнялась.
|
||
- Далее — создание/редактирование GRE: два варианта ответа создания, подтверждение PATCH, сохранение формы и защита повторов/закрытия. Реальные RouterOS/JWT не проверены. Этап 9 открыт.
|
||
- На старте использовано 27% пятичасовой и 97% недельной квоты; выбран небольшой самостоятельный блок. Локальный коммит без push, чужие изменения сохранены.
|
||
|
||
## Блок 9.19 — удаление GRE (2026-09-30)
|
||
|
||
- Удаление требует ok=true; пустой ответ и ok=false сохраняют диалог и не показывают успех. Ошибка находится рядом с подтверждением выбранного туннеля. Синхронный замок блокирует повтор, Escape и отмену до ответа; ожидание объявляется через status. Существующие ограничения mutationsLocked проверяются также обработчиком.
|
||
- Добавлен E2E: точный serverId/RouterOS ID, двойное нажатие, задержка, 403, пустой ответ, ok=false, успех и повторное открытие без старой ошибки. Все 4 E2E (новое удаление и 3 проверки таблиц IPsec/GRE), TypeScript и diff-check прошли. Первый запуск завершился тайм-аутом запуска Next.js до тестов; повторный запуск с диагностикой успешен. Build не повторялся. Lint GRE: прежние 0 ошибок/14 предупреждений не изменились, новый тест чистый.
|
||
- Далее: создание/изменение и переключение GRE — контракты ответа, сохранение формы, защита повторов/закрытия; затем VXLAN/Firewall/Filters. Реальные RouterOS/JWT не проверены, этап 9 открыт. Последний build — 9.16.
|
||
- В начале блока пятичасовая квота сброшена (0% использовано), недельная — 93% использовано. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.18 — редактирование peer IPsec (2026-09-29)
|
||
|
||
- PATCH peer требует ok=true. Ошибка передаётся в форму, сохраняет введённые поля и не закрывает панель. Синхронный замок предотвращает повтор; поля, переключатели и закрытие заблокированы до ответа, ожидание объявляется через status. Начальные значения задаются один раз на открытие; добавлены доступные имена.
|
||
- Новый E2E прошёл: точный RouterOS ID, двойное нажатие, задержка, Escape/внешний клик, 403, пустой ответ, ok=false, успешный повтор и сброс ошибки при новом открытии. Lint изменённых файлов и TypeScript прошли; diff-check чистый. Build не повторялся, последний — 9.16.
|
||
- Далее: GRE — создание/изменение/удаление туннеля, проверка подтверждения API, сохранение формы и повторы; затем VXLAN/Firewall/Filters по карте. IPsec не объявляется полностью принятым: загрузка данных, реальные сертификаты/RouterOS/JWT и сквозная приёмка ещё требуют проверки.
|
||
- Блок начат при 88% расхода пятичасовой квоты по прямому продолжению пользователя и ранее разрешённой работе до конца лимита. Завершён самостоятельный небольшой блок; локальный коммит без push, чужие изменения сохранены.
|
||
|
||
## Блок 9.17 — удаление объектов IPsec (2026-09-29)
|
||
|
||
- Все четыре API удаления (клиент, сервер, peer, сертификат) требуют ok=true. Пустой ответ и ok=false не вызывают успех и не закрывают подтверждение.
|
||
- Общий диалог сохраняет объект и ошибку для повтора, объявляет ожидание; синхронный замок предотвращает повтор и закрытие до завершения. После успешного подтверждения диалог закрывается и список обновляется.
|
||
- При 409 для peer/сертификата принудительное удаление доступно отдельной кнопкой в том же диалоге вместо действия в toast. Оно использует тот же замок и проверку ответа, force=true отправляется только после явного нажатия; backend-правила не менялись.
|
||
- Все 4 новых E2E прошли: задержка, двойное нажатие, Escape, 403, пустой ответ, ok=false, успех; для peer/сертификата также 409 и принудительный повтор. Повторное открытие не сохраняет старую ошибку. Lint изменённых файлов, TypeScript и diff-check прошли. Build не повторялся, последний — 9.16.
|
||
- Далее: редактирование peer IPsec (handleEditPeer/IpsecPeerSheet/patchIpsecPeer) — подтверждение API, сохранение полей, блокировка повторов и закрытия. Затем оставшаяся карта этапа 9. Реальные RouterOS/JWT и последствия принудительного удаления не проверены моками.
|
||
- После E2E использовано 81% пятичасовой и 90% недельной квоты. Блок начат при 74%, завершён ниже резерва; новый блок не начат. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.16 — экспорт сертификатов IPsec (2026-09-29)
|
||
|
||
- Оба API экспорта проверяют схему бандла, непустые имя/файл/содержимое, синтаксис Base64 и наличие пароля архива. Это проверка транспортного ответа, не криптографическая проверка PKCS#12. Начальный пароль генерируется crypto.randomUUID вместо Math.random.
|
||
- Общий обработчик связывает результат/ошибку/finally с открытием панели; закрытие, новое открытие и размонтирование инвалидируют старый ответ. Повтор защищён синхронным замком. Ошибка остаётся в панели с повтором; первичная загрузка объявляется через status. Физическая отмена запросов не добавлена.
|
||
- Пароль загруженного архива доступен только для чтения: изменение требует нового экспорта. При ошибке повторного экспорта остаются прежний файл и его пароль; во время запроса скачивание заблокировано. Backend может вернуть эффективный пароль, поэтому показывается именно пароль из подтверждённого ответа.
|
||
- Все 6 E2E прошли: два новых сценария экспорта (identity и имя сертификата), инициализация и три сценария пользователей. Проверены поздний успех закрытой панели, 403, неверный Base64, повторное нажатие, 500 при повторном экспорте и успешная смена пары файл/пароль. Lint изменённых файлов, TypeScript и diff-check чистые. Production build прошёл: 34/34 страницы.
|
||
- Далее: удаление IPsec — confirmDelete и ответы удаления клиента/сервера/peer/сертификата, сохранение подтверждения при ошибке и повторные нажатия. Экспорт из формы создания получает бандл по прежней схеме создания; реальные сертификаты/RouterOS/JWT не проверены. Этап 9 открыт.
|
||
- После тестов использовано 67% пятичасовой и 88% недельной квоты. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.15 — создание и редактирование пользователей IPsec (2026-09-29)
|
||
|
||
- Создание проверяет ipsecUserCreatedSchema, принадлежность клиента серверу, имя и метод аутентификации. Пустой ответ, client=null и чужой сервер не считаются успехом; редактирование требует ok=true. Backend иногда возвращает client=null после применения: UI сообщает отсутствие подтверждения, а не утверждает откат операции.
|
||
- Ошибка остаётся в форме с введёнными значениями. Синхронный замок защищает повторное нажатие, поля/переключатель и закрытие блокируются до ответа; ожидание объявляется через status. Начальные значения задаются один раз на открытие. При смене сервера сбрасывается peer; короткий новый PSK при редактировании блокирует отправку. Поля получили доступные имена.
|
||
- Все 7 E2E прошли: три новых сценария пользователей (сертификат, PSK, редактирование) и четыре регрессионных проверки инициализации/таблиц. Проверены задержка, двойное нажатие, 403, повреждённый/неподтверждённый ответ, сохранение ввода и успех. Lint изменённых файлов, TypeScript и diff-check чистые. Build не повторялся, последний — 9.13.
|
||
- Далее: сертификаты IPsec — openCert/openCertByName/reexportCert, проверка бандла, сохранение контекста и защита поздних ответов/повторов. Получение настоящего сертификата, RouterOS/JWT и транзакционность операций не проверены. Этап 9 открыт. Локальный коммит без push; чужие изменения сохранены.
|
||
|
||
## Блок 9.14 — инициализация IPsec (2026-09-29)
|
||
|
||
- Успех требует валидной сводки по contracts, совпадения serverId и initialized=true. Пустой ответ, неинициализированный сервер и чужое устройство не закрывают форму и не показывают успех. Backend возвращает сводку после применения; правила сетевой операции не изменялись.
|
||
- Форма сохраняет ввод и показывает ошибку внутри панели. Синхронный замок предотвращает повтор; до ответа заблокированы поля, NAT, отмена, Escape и внешний клик. Ожидание объявляется через status. Инициализация полей выполняется один раз на открытие, чтобы обновление списка серверов не стирало ввод.
|
||
- Исправлен ввод IPv4 без CIDR вместо ошибочного требования маски; домены сохранены, IPv4 с октетом больше 255 отклоняется. Поля и переключатель получили доступные имена. Полная валидация подсети остаётся на backend.
|
||
- Прошли новый E2E и 3 регрессионных теста таблиц IPsec/GRE, lint всех изменённых файлов и TypeScript; diff-check чистый. Первоначальный тест исправлен: перед кнопкой инициализации требуется вкладка «Сервер». Build не повторялся; последний успешный — блок 9.13.
|
||
- Следующий шаг: создание/редактирование пользователя IPsec — проверка контракта результата, сохранение формы, защита повторов; затем сертификаты и остальные разделы карты. Реальные RouterOS/JWT и транзакционность составной инициализации не проверены. Этап 9 открыт.
|
||
- Использовано 41% пятичасовой и 84% недельной квоты. Локальный коммит без push; изменения пользователя в skill/config/AGENTS сохранены.
|
||
|
||
## Блок 9.13 — общая проверка и загрузка истории (2026-09-29)
|
||
|
||
- GRE, Firewall, Filters и рекурсивные маршруты подключены к ошибке/повтору общей панели. Ошибка не обнуляет сохранённые ревизии и не маскируется пустым списком. Поколение запроса защищает результат, ошибку и finally после закрытия, смены контекста и размонтирования; физическая отмена запросов не добавлялась.
|
||
- Общая parseConfigRevisions проверяет контейнер, поля записей, дату, количество, источник, раздел и принадлежность выбранному серверу во всех шести потребителях. Тип ConfigRevisionDto дополнен IPsec согласно backend; WireGuard использует ту же схему. Backend и правила применения не изменены.
|
||
- Все 36 E2E истории/WireGuard прошли. Пять сценариев истории проверяют 403, задержанный ответ закрытой панели, отсутствие контейнера, другой сервер/раздел, повреждённую дату и успешный пустой список. TypeScript прошёл. Общая схема, API и тест lint-чистые; 7 исходных ошибок и 31 предупреждение страниц не изменились (сравнение с HEAD). Production build прошёл: 34/34 страницы.
|
||
- Следующий шаг: IPsec — handleInit и форма инициализации: подтверждение API, сохранение ввода при ошибке, блокировка повторной отправки и закрытия до ответа; затем пользователи/сертификаты и остальные разделы карты. Полная проверка payload восстановления rules/routes, реальные RouterOS/JWT и весь этап 9 пока не завершены.
|
||
- После профильных проверок: использовано 21% пятичасовой и 81% недельной квоты. Локальный коммит без push; чужие изменения skill/config/AGENTS сохранены.
|
||
|
||
## Блок 9.12 — ошибка и повтор истории IPsec (2026-09-29)
|
||
|
||
- IPsec подключён к loadError/onRetry общего диалога. Ошибка не обнуляет историю и не показывает пустое состояние; прежние ревизии скрыты до успешного повтора. Ответ без массива revisions отклоняется.
|
||
- Поколение запроса и инвалидирование при закрытии, смене устройства/backend/режима или размонтировании блокируют устаревшие результат/ошибку/finally. Сетевые запросы физически не отменяются.
|
||
- Все 7 E2E истории прошли: прежние 6 сценариев восстановления и новый IPsec (403, повтор с задержкой, закрытие/открытие, повреждённый ответ, успешный пустой список, поздняя ошибка). Lint/TypeScript проверены перед коммитом; diff-check чистый. Build не повторялся; последний — 9.9.
|
||
- Ограничение: здесь проверен только контейнер revisions, полная схема отдельных ревизий и принадлежность серверу ещё не валидируются, в отличие от WireGuard. Реальные RouterOS/JWT не проверены. Далее — история GRE/Firewall/Filters/рекурсивных маршрутов и общая валидация ревизий. Этап 9 открыт. Блок начат при 87% расхода окна по прямому разрешению работать до конца лимита; локальный коммит без push.
|
||
|
||
## Блок 9.11 — подтверждение восстановления остальных разделов (2026-09-29)
|
||
|
||
- IPsec, GRE, Firewall, Filters и рекурсивные маршруты проверяют ok=true до изменения таблиц, обновления данных и сообщения успеха. Контракты всех пяти backend-маршрутов проверены по коду: они возвращают такое подтверждение. WireGuard уже использовал эту проверку.
|
||
- При ok=false, пустом/неподтверждённом ответе выбрасывается ошибка в общий диалог; выбранная ревизия сохраняется для повтора. Сетевые правила и композиция ReUI не изменены; получен audit checklist.
|
||
- Расширенные 6 E2E истории прошли: 403 с задержкой/двойным нажатием, ok=false, пустой ответ, затем успех. Lint теста, TypeScript и diff-check прошли. Диагностики пяти страниц сравнены с HEAD: прежние 7 ошибок и 31 предупреждение сохраняются, новых нет; единственное текстовое отличие Firewall — сдвиг строки прежнего set-state-in-effect с 2042 на 2043. Полный lint страниц остаётся красным по причинам блока 9.9.
|
||
- Полная регрессия/build не повторялись для этих условий; последний production build — 9.9. Проверка ok не является полной валидацией вложенных rules/routes; реальный RouterOS/JWT и транзакционность восстановления не проверены.
|
||
- Далее — состояния загрузки истории IPsec/GRE/Firewall/Filters/рекурсивных маршрутов: ошибка вместо пустого списка, повтор и поздние ответы. На контрольной точке использовано 80% пятичасового и 75% недельного лимита. Этап 9 открыт; локальный коммит без push.
|
||
|
||
## Блок 9.10 — состояния загрузки истории WireGuard (2026-09-29)
|
||
|
||
- Ошибка истории больше не подменяется пустым списком. ConfigHistorySheet получил необязательные loadError/onRetry; WireGuard показывает ошибку через role=alert с повтором. Пустое состояние доступно только после успешного пустого ответа. Во время ошибки прежние ревизии не предлагаются для отката; данные остаются в состоянии, но скрыты до успешной загрузки.
|
||
- listWireGuardRevisions проверяет поля ревизий, раздел wireguard и совпадение serverId. Повреждённый ответ и история другого сервера отклоняются. Новое поколение каждого запроса и инвалидирование при закрытии/размонтировании защищают результат, ошибку и finally от поздних ответов.
|
||
- Три новых E2E прошли: 403 → повреждённый ответ → чужой serverId → корректный пустой список; поздний успех и поздняя ошибка после переоткрытия не снимают новую загрузку. Итоговый набор из 33 E2E WireGuard и всех шести потребителей диалога истории прошёл. Lint изменённых файлов, TypeScript и diff-check прошли.
|
||
- Получен ReUI checklist; общий компонент сохраняет прежнее поведение для потребителей без новых props. Реальные RouterOS/JWT не проверены. Запросы после закрытия физически не отменяются, их ответы игнорируются. Production build не повторялся; последний успешный — 9.9. Исходные lint-ограничения остальных страниц из 9.9 сохраняются.
|
||
- Далее — подтвердить ok=true восстановления IPsec/GRE/Firewall/Filters/рекурсивных маршрутов; затем распространить обработку ошибок загрузки истории и продолжить профильный UX сетевых разделов. Этап 9 открыт; локальный коммит без push.
|
||
|
||
## Блок 9.9 — общий диалог восстановления (2026-09-29)
|
||
|
||
- ConfigHistorySheet закрывает подтверждение только после успешного завершения onRestore. Ошибка остаётся внутри через role=alert, выбранная ревизия сохраняется для повтора. Синхронный замок предотвращает двойной вызов; ожидание объявляется через role=status. Во время операции нельзя закрыть подтверждение или панель истории.
|
||
- Все шесть потребителей (WireGuard, IPsec, GRE, Firewall, Filters, рекурсивные маршруты) передают исключение в диалог вместо поглощения в toast. IPsec теперь возвращает Promise обработчика. Контракты API и сетевые правила не менялись; проверка ok=true остаётся добавленной ранее только у WireGuard, остальные требуют отдельного аудита ответов.
|
||
- Устранено недопустимое вложение Alert/div в AlertDialogDescription/p: предупреждение размещено рядом с описанием. Существующие Sheet/AlertDialog/Timeline/Frame и semantic tokens сохранены; получен ReUI checklist.
|
||
- Все 40 профильных E2E прошли, включая 6 новых сценариев общего диалога: точный POST, двойное нажатие, задержка, Escape, 403, сохранение подтверждения, повтор и очистка ошибки при новом выборе. Проверяются отсутствие pageerror и ошибок HTML в консоли (ожидаемый HTTP 403 исключён).
|
||
- Общий компонент, WireGuard/IPsec и тесты проходят lint. Сравнение ESLint текущих шести страниц с git show HEAD подтвердило неизменные 7 исходных ошибок и 31 предупреждение: Firewall — 4 set-state-in-effect; Filters — 2 set-state-in-effect; Recursive Routes — 1 no-empty-object-type; предупреждения также в GRE. Полный lint этих страниц остаётся красным; новых сообщений нет. Diff-check чистый; production build/TypeScript прошли (34 страницы).
|
||
- Далее — состояния загрузки истории WireGuard: ошибка не должна выглядеть пустой историей, поздние ответы не должны менять новый контекст. Затем валидация подтверждения восстановления остальных разделов и их профильный UX. Реальные RouterOS/JWT не проверены, этап 9 открыт. На контрольной точке использовано 31% пятичасового и 67% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 9.8 — подтверждение восстановления WireGuard (2026-09-29)
|
||
|
||
- Восстановление защищено синхронным замком до завершения операции и обновления данных. Успех требует ok=true; неподтверждённый HTTP 200 больше не объявляется применённой версией.
|
||
- Новый E2E прошёл: двойное нажатие отправляет один POST с точными ID ревизии/сервера, ok=false показывает ошибку без успеха, повтор с ok=true подтверждается. Итоговые lint, TypeScript и diff-check прошли. Полная регрессия/build не повторялись; реальные RouterOS/JWT не проверены.
|
||
- Найдено предупреждение браузера в общем ConfigHistorySheet: Alert с div вложен в AlertDialogDescription, который рендерит p. В этом ограниченном блоке общий компонент не изменён. Диалог подтверждения по-прежнему закрывается после ошибки; история остаётся доступной для повторного выбора.
|
||
- Следующий блок: исправить разметку общего диалога, сохранять подтверждение при ошибке и проверить потребителей; затем состояния загрузки истории и поздние ответы. Этап 9 открыт. Работа выполнена по разрешению продолжать сверх резерва; на старте использовано 90% пятичасового лимита. Локальный коммит без push.
|
||
|
||
## Блок 9.7 — точный выбор пира для экспорта (2026-09-29)
|
||
|
||
- Единая функция выбора используется локальным предпросмотром и запросом API. Явный ID ищется по id/rosId; если не найден, другой пир не подставляется. Первый пир выбирается только при отсутствии выбора, как в backend. Локальное пустое состояние объясняет необходимость обновить список; серверный запрос при отсутствующем пире не отправляется.
|
||
- API получает rosId выбранного пира, с id как запасным вариантом. Peer .conf сохраняет includePrivateKey=false. Схемы/сетевые правила backend не менялись.
|
||
- Прошли 4 профильных E2E экспорта (включая новый сценарий второго пира с отличающимися id/rosId), 2 unit-теста выбора, lint, TypeScript и diff-check. Неизвестный/пустой ID покрыты unit-тестом; полноценный браузерный сценарий устаревшего выбора не заявляется. Production build не повторялся; последний успешный — 9.4.
|
||
- Получен ReUI checklist, композиция CodeExportSheet сохранена. Реальные RouterOS/JWT/ключи не проверены. Далее — история/восстановление WireGuard, затем остальные разделы этапа 9. По разрешению пользователя работа продолжена сверх резерва; использовано 84% пятичасового и 60% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 9.6 — контекст ответа экспорта WireGuard (2026-09-29)
|
||
|
||
- Каждое открытие/закрытие панели меняет поколение запроса. Поздние результат, ошибка и finally старого экспорта не меняют новую панель и не снимают её busy. Размонтирование также инвалидирует ответ. Повторный запрос в текущей панели защищён синхронной блокировкой; закрытие доступно.
|
||
- Ответ проверяется схемой wgExportResponseSchema и совпадением формата с запросом. Повреждённый ответ/чужой формат не заменяет конфиг и не объявляется успешным экспортом. Локальное содержимое остаётся локальным; общая композиция CodeExportSheet не менялась.
|
||
- Три новых E2E прошли: поздний успех, поздняя ошибка после открытия другого сервера, повреждённый ответ/другой формат и успешный повтор. Проверяется двойное нажатие. Итоговый набор из 22 WireGuard E2E, lint, TypeScript и diff-check прошли. Первоначально исправлен селектор теста под существующий aria-label кнопки.
|
||
- Получен ReUI checklist. Production build не повторялся (последний — 9.4), реальные RouterOS/JWT/ключи не проверены. Запрос после закрытия не отменяется на сервере, только игнорируется в UI. Тесты используют фиктивное содержимое без секретов.
|
||
- Далее: точность выбора пира в экспорте (ID/rosId, отсутствие подстановки первого пира при неизвестном ID), затем история/восстановление WireGuard и остальные сетевые разделы. На контрольной точке использовано 69% пятичасового и 58% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 9.5 — подтверждение переключения WireGuard (2026-09-29)
|
||
|
||
- Переключение интерфейса защищено синхронным замком до ответа и обновления списка. Пункт меню недоступен во время операции; повторный вызов не отправляет второй PATCH. Никакого оптимистического изменения статуса нет.
|
||
- Успех требует ok=true. Ошибки API и неподтверждённый ответ остаются на странице через role=alert с именами интерфейса и сервера; ожидание объявляется через role=status. При следующей попытке прежняя ошибка очищается.
|
||
- Все 19 WireGuard E2E прошли. Новый сценарий проверяет точный сервер/RouterOS ID и тело PATCH, задержку, блокировку меню, 403, ok=false и успешный повтор. Итоговые lint, TypeScript и diff-check прошли. Production build не повторялся; последний успешный — блок 9.4.
|
||
- Получен ReUI checklist; существующие DataGrid/DropdownMenu и тема сохранены. Реальные RouterOS/JWT и физическое состояние туннеля локальными HTTP-моками не подтверждаются. Остальные типы операций не объединены в общий транзакционный замок.
|
||
- Далее — экспорт WireGuard: контекст выбранного интерфейса/пира, поздние ответы после закрытия/смены объекта, ошибки и валидация ответа. Затем остальные сетевые разделы по карте этапа 9. Локальный коммит без push.
|
||
|
||
## Блок 9.4 — создание интерфейса и пира WireGuard (2026-09-29)
|
||
|
||
- Создание интерфейса/пира и импорт используют общий синхронный замок формы. Повторный вызов не отправляет второй запрос; поля, переключатели, отмена и закрытие заблокированы до ответа. Ошибка остаётся внутри формы через role=alert, ожидание — role=status; значения сохраняются для повтора.
|
||
- Подтверждение интерфейса проверяется по реальному backend-контракту: DTO существующей схемы с совпадающими именем/сервером либо ok=true с совпадающим именем. Создание пира требует ok=true. Повреждённый HTTP 200 не объявляется успешным созданием. Правила RouterOS не менялись.
|
||
- Новое открытие формы пира сбрасывает прежний ввод; обе формы получили доступные имена полей, переключатели создания — aria-label. Сохранены установленные Sheet/Switch/Base UI и semantic tokens; область прокрутки использует min-h-0. Получен ReUI checklist.
|
||
- Все 18 WireGuard E2E прошли, включая три новых сценария создания (DTO интерфейса, короткое подтверждение интерфейса, пир). После изменения переключателей эти три сценария повторены: двойное нажатие, ожидание, Escape/внешний клик, 403, повреждённый ответ, сохранение ввода, успешный повтор и чистое повторное открытие. Итоговые lint, TypeScript и production build прошли (34 страницы), diff-check чистый.
|
||
- Ограничения: реальные RouterOS/JWT не проверены; 403 в HTTP-моке проверяет клиентскую реакцию. Многошаговое создание на RouterOS не стало транзакционным: частичный результат при серверной ошибке требует проверки устройства. Этап 9 открыт.
|
||
- Далее — переключение интерфейсов и экспорт WireGuard (повторы, подтверждение результата, контекст позднего ответа), затем остальные сетевые разделы. Локальный коммит без push.
|
||
|
||
## Блок 9.3 — ожидание результата импорта WireGuard (2026-09-29)
|
||
|
||
- Импорт защищён синхронной блокировкой повторного вызова. Во время запроса поля и кнопки недоступны, крестик скрыт, Escape и клик вне панели не закрывают форму и не очищают конфигурацию. После ответа блокировка снимается.
|
||
- Ошибка API сохраняется в форме через role=alert до повтора/нового открытия; ожидание объявляется через role=status. Поля сервера, формата и конфигурации получили доступные имена. Существующий Sheet/Base UI сохранён; прокрутка формы ограничена родительской высотой через min-h-0.
|
||
- Синхронизация исходного сервера перенесена из effect в условный сброс при смене контекста, без lint-исключений. Сетевые правила и контракт импорта не менялись.
|
||
- Все 15 WireGuard E2E прошли: прежние сценарии и новый тест двойного нажатия, блокировки полей/закрытия, ошибки 500 с сохранением данных, повтора и очистки сообщения при следующем открытии. Итоговые lint и TypeScript прошли; diff-check чистый. Production build и реальные RouterOS/JWT в этом блоке не проверялись.
|
||
- Получен ReUI checklist. Этап 9 остаётся открытым. Далее — создание интерфейса и добавление пира: защита повторов, сохранение формы при ошибке и подтверждение результата. Затем переключение/экспорт и остальные сетевые разделы по карте этапа 9.
|
||
|
||
## Блок 9.2 — подтверждение применения импорта WireGuard (2026-09-28)
|
||
|
||
- По прямому поручению пользователя продолжена работа сверх резерва 25%. Взята ограниченная проверка импорта без расширения форм и сетевых правил.
|
||
- Ответ импорта проверяется существующей схемой contracts; dryRun должен соответствовать запросу, применение требует applied. Повреждённый ответ, dry-run вместо применения и отсутствие applied больше не объявляются успешным импортом. Корректный dry-run в обработчике обозначен как проверка без применения и не закрывает форму; отдельной серверной кнопки dry-run сейчас нет, «Предпросмотр» разбирает конфигурацию локально.
|
||
- Новый E2E прошёл: 403, dry-run, отсутствие applied, пустой ответ и успешное применение; после ошибок сохраняются текст и выбранный сервер. Итоговые lint и TypeScript прошли. Общая регрессия/production build не повторялись; реальные RouterOS/JWT не проверены.
|
||
- Далее: создание/добавление пира, блокировка повторных операций и закрытия формы импорта во время запроса. Этот блок не закрывает весь UX импорта. На контрольной точке использовано 97% пятичасового и 46% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 9.1 — подтверждение удаления WireGuard (2026-09-28)
|
||
|
||
- Сохранена [карта этапа 9 со схемой и референсами](ux-ui-stage-9.md). Первичная инвентаризация API и контекста выполнена; полный аудит остальных операций впереди.
|
||
- Удаление интерфейса/пира WireGuard защищено синхронной блокировкой повторного запроса. До ответа недоступны кнопки и закрытие диалога. Ожидание и ошибка объявляются через status/alert. При ошибке объект сохраняется для повтора; успех требует ok=true.
|
||
- E2E выявил передачу ID строки пира вместо отличающегося RouterOS ID. Исправлено: при наличии используется rosId. Backend-контракт удаления и сетевые правила не менялись.
|
||
- Итоговые 13 WireGuard E2E прошли: ссылки/контекст, таблицы, оба удаления с задержкой, 403, ok=false и успешным повтором. Проверены точные сервер/ID DELETE, блокировка кнопок и Escape. Lint, TypeScript и diff-check прошли. Полная сборка не повторялась для локального изменения обработчика; последняя успешная сборка — 8.13.
|
||
- Получен ReUI checklist; используются установленные компоненты без изменения темы. Реальные RouterOS/JWT не проверены. HTTP-моки подтверждают клиентское поведение, а не сетевой результат. Этап 9 открыт.
|
||
- Следующий шаг: создание/импорт/добавление пира WireGuard — сохранение формы и контекста, защита повторов, различие dry-run и применения. На контрольной точке использовано 75% пятичасового и 43% недельного лимита; новые блоки в этом окне не начинать. Локальный коммит без push.
|
||
|
||
## Блок 8.13 — локальная приёмка трафика и статистики (2026-09-28)
|
||
|
||
- Добавлены доступные имена полей панели подключения jump-host и измерений статистики, aria-pressed общего SegmentedControl и role=alert ошибки flow. Сохранены установленные ReUI/base-nova, Frame и общие компоненты; зависимости и сетевые операции не менялись.
|
||
- Клавиатурные сценарии проверяют Enter, открытие списка стрелкой, Escape, удержание Tab внутри панели, возврат фокуса и сброс формы при повторном открытии без запросов записи. Устранён прежний lint-дефект синхронного сброса формы в effect; сброс теперь привязан к изменению контекста открытия/каталога.
|
||
- Обнаружена и исправлена ошибка обработки повреждённого ответа HTTP 200 статистики: основной и pivot-ответы проверяются существующими схемами contracts. Вместо падения страницы появляется ошибка с повтором, недостоверная сводка скрыта. Оба случая проверены E2E без pageerror.
|
||
- Полный профильный запуск: 63 E2E прошли. После добавления валидации повторены все 15 сценариев статистики (включая 2 новых); после изменения сброса формы повторён сценарий панели. Итого проверены 65 различных сценариев трафика/статистики. Отдельно прошли 3 backend-switch E2E и 10 unit-тестов периодов/контекста/фильтров. Итоговые production build/TypeScript (34 страницы), lint изменённых файлов и diff-check прошли.
|
||
- Этап 8 закрыт в границах локальной приёмки HTTP/SSE-моками. Реальные RouterOS/IPFIX/JWT не проверены. Удалённые из каталога серверы отсутствуют в месячном выборе; экспорт не реализован. SSE поддерживает LF/CRLF, без автоматического переподключения после закрытия; одиночный CR не поддержан. Времена получения не означают время измерения на устройстве. Полный аудит скринридером, контраста, производительности и сквозная регрессия остаются этапом 12.
|
||
- Следующий шаг: этап 9 — инвентаризация WireGuard/IPsec/GRE/VXLAN/Firewall/Filters, контекста устройства и подтверждений операций; сохранить схему и выбрать первый законченный блок. План и итоговая матрица этапа 8 обновлены. На контрольной точке использовано 52% пятичасового и 39% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 8.12 — доступные имена и выбранные состояния (2026-09-28)
|
||
|
||
- Получен актуальный ReUI get_audit_checklist. Поисковые поля трафика/потоков получили доступные имена. Карточки, разделы, источник flow, периоды и интерфейсы обозначают выбранное состояние через aria-pressed; затронутые native-кнопки получили type=button.
|
||
- Новый E2E проверяет выбор flow-сервера через Enter, сохранение его заголовка при поиске другой карточки, открытие месяца через Space и aria-pressed. Сценарий, lint, diff-check и production build/TypeScript прошли (34 страницы).
|
||
- Это профильный блок доступности, не полный аудит: ещё проверить общую Tab-навигацию/видимый фокус, слои/Escape, статусы загрузки и статистику, затем выполнить итоговый набор трафика/статистики и backend-switch. Этап 8 не закрыт. Реальные RouterOS/IPFIX/JWT не проверены; удалённые серверы и экспорт остаются ограничениями.
|
||
- Использовано 97% пятичасового и 31% недельного лимита. Следующий запуск начать с лимита и итоговой регрессии после оставшегося аудита. Локальный коммит без push.
|
||
|
||
## Блок 8.11 — каталог серверов месячного отчёта (2026-09-28)
|
||
|
||
- Для месячного режима список загружается через существующий listServers, независимо от активности IPFIX за 24 часа. Выбор доступен даже при полном отсутствии активных экспортёров. В списке только имена; скорости, графики и статус без подтверждения не подставляются. Сортировка по live-метрикам скрыта, поиск работает по имени.
|
||
- Ответ каталога привязан к flowKey и защищён флагом отмены; ошибка имеет повтор и скрывает недоступный отчёт. Выбор сохраняется при успешном повторе, если сервер остаётся в каталоге. Детали используют выбранный ID, а не первую карточку отфильтрованного поиска.
|
||
- Все 25 flow-E2E прошли. Новый сценарий проверяет сервер без потоков, правильный serverId, отсутствие мини-графиков, 403 каталога и повтор; после расширения отдельно проверен вход при полностью пустом списке экспортёров. Адаптивные 320/390/1440 входят в набор. Итоговые lint, diff-check и production build/TypeScript прошли (34 страницы).
|
||
- Граница: серверы, удалённые из каталога, не перечисляются; это явно указано в интерфейсе. API архивного каталога не добавлялся. Реальные RouterOS/IPFIX/JWT не проверены.
|
||
- Далее: ReUI/accessibility checklist для трафика/статистики и итоговая регрессия этапа 8; удалённые серверы и экспорт зафиксировать как оставшиеся ограничения. Использовано 77% пятичасового и 27% недельного лимита на контрольной точке. Локальный коммит без push.
|
||
|
||
## Блок 8.10 — выбор месяца flow-отчёта (2026-09-28)
|
||
|
||
- Месячный отчёт использует выбранный календарный месяц UTC через существующий GET /api/traffic/flow/monthly. Доступны текущий и прошлые месяцы; пустые, некорректные и будущие значения блокируют запрос и показывают связанную с полем ошибку. Текущий месяц остаётся начальным значением.
|
||
- Месяц входит в ключ аналитики, старый отчёт скрыт при смене/невалидном вводе; поздний ответ предыдущего месяца не применяется. API и правила сетевых операций не менялись. Кнопка периода переименована в «Месяц»; кнопки периодов получили aria-pressed, поле — Label/aria-invalid/aria-describedby через существующий Input.
|
||
- 23 прежних flow-E2E прошли, включая адаптивность 320/390/1440. Новый сценарий смены 2026-08→2026-07, позднего ответа, пустого/будущего месяца и восстановления прошёл после уточнения селектора alert (Next.js добавляет свой announcer). Проверены программный фокус и aria-pressed; это не полный клавиатурный аудит. Итоговые lint, diff-check и production build/TypeScript прошли (34 страницы).
|
||
- Следующий шаг: выбор серверов без активности в последние 24 часа для месячного отчёта; затем оставшийся ReUI/accessibility checklist и итоговая регрессия. Пока отчёт доступен только для серверов текущего списка экспортёров; исторические удалённые серверы отдельно не перечисляются. Реальный RouterOS/IPFIX/JWT не проверен. Использовано 52% пятичасового и 24% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 8.9 — ожидание первого SSE sample (2026-09-28)
|
||
|
||
- Управляемый ReadableStream умеет открываться без первого sample. Добавлены flow/серверные сценарии: до первого сообщения нет фиктивной live-метки или времени live-измерения; отображается подтверждённая REST-история.
|
||
- Heartbeat в ожидании не отменяет 15-секундный таймаут. После таймаута история и её отметка остаются; первый валидный sample восстанавливает live. Flow дополнительно проверяет изменение скорости 1→7 Мбит/с, источника API→live и времени получения. Сервер проверяет появление первого измерения 17 Мбит/с.
|
||
- Все 28 flow/серверных SSE-E2E прошли; lint, tsc --noEmit --incremental false и diff-check чистые. Production-код не менялся, production build не повторялся. Имитация начинается с открытого Response; отдельная задержка HTTP-заголовков в этом блоке не проверяется.
|
||
- Далее: зафиксировать итоговый объём месячного отчёта (архивные серверы/прошлые месяцы) и выполнить оставшийся ReUI/accessibility checklist перед завершением этапа 8. Реальные RouterOS/IPFIX/JWT не проверены. Использовано 32% пятичасового и 20% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 8.8 — одиночные точки основного графика (2026-09-28)
|
||
|
||
- Общий TrafficRxTxChart показывает маркер только для валидной точки без валидных соседей в том же направлении. Одиночный ноль и точки между пропусками видны; непрерывные серии сохраняют прежний вид без маркеров. RX/TX используют одинаковое правило и существующие цвета темы.
|
||
- До финального подключения TX прошли 38 E2E деталей/flow/дашборда. Новый тест выявил пропущенное подключение TX; после исправления все 10 тестов деталей прошли, включая нулевые RX/TX, три изолированные точки и порядок координат. Снимок изолированных RX осмотрен. Итоговые ESLint, diff-check и production build/TypeScript прошли (34 страницы).
|
||
- Граница: это отображение существующих точек, без изменения временной шкалы API или правил агрегации. Полная регрессия проекта не выполнялась; реальные RouterOS/IPFIX не проверены.
|
||
- Далее: ожидание первого SSE sample, решение по месячным ограничениям и ReUI/accessibility checklist. Этап 8 ещё открыт. Пятичасовой лимит обновился; на контрольной точке использовано 18%, недельного — 18%. Локальный коммит без push.
|
||
|
||
## Блок 8.7 — CRLF и heartbeat SSE (2026-09-28)
|
||
|
||
- В обоих hook разделители событий и строк принимают LF/CRLF, включая разделитель между двумя chunk. Комментарий перед event/data больше не отбрасывает весь блок: строки комментариев пропускаются парсером, sample сохраняется.
|
||
- Управляемый поток в двух сценариях отправляет CRLF-событие с начальным комментарием и разделённым delimiter. Heartbeat через 10 секунд не сбрасывает 15-секундный таймер валидного sample. Проверены сохранение данных, восстановление и уход из контекста.
|
||
- Все 26 flow/серверных SSE-E2E прошли; ESLint, diff-check и production build/TypeScript прошли (34 страницы). Это профильная проверка, не повтор полной регрессии этапа. Поддержка одиночного CR без LF не добавлена; реальный RouterOS/IPFIX не проверен.
|
||
- Следующий шаг: одиночная точка основного RX/TX-графика, затем ожидание первого sample, месячные ограничения и ReUI/accessibility checklist. Этап 8 остаётся открытым. Использовано 95% пятичасового и 15% недельного лимита; остаток сохранён для завершения и коммита. Локально, без push.
|
||
|
||
## Блок 8.6 — молчащий открытый SSE (2026-09-28)
|
||
|
||
- Оба live-hook запускают таймер ожидания валидного sample на 15 секунд. Основание: backend LIVE_TICK_MS равен 1500 мс для сервера и 2000 мс для flow, плюс время запроса. Порог допускает несколько пропущенных обновлений; это UI-признак отсутствия данных, не доказательство отказа устройства.
|
||
- По таймауту сохраняются последнее значение и время получения, снимается отметка live; новый валидный sample очищает ошибку и возобновляет ожидание. Heartbeat не обновляет свежесть. Таймер очищается при ошибке, завершении чтения и смене контекста. Подключение не разрывается только из-за таймаута, чтобы принять последующее сообщение.
|
||
- Прежние 24 SSE/flow-E2E прошли. Два новых сценария управляемого ReadableStream/часов проверили молчание, сохранение времени/значений, восстановление, смену периода flow и уход из серверного раздела. Первоначальные ожидания тестов уточнены (три live-отметки flow); оба новых сценария повторно прошли. ESLint, diff-check, production build/TypeScript прошли (34 страницы).
|
||
- Границы: тесты подменяют поток браузера, реальный транспорт/RouterOS не проверен. Нет автоматического переподключения закрытого SSE; отдельные проверки задержки до первого sample, heartbeat/CRLF и фонового throttling браузера остаются для аудита.
|
||
- Далее: оставшийся аудит парсинга SSE (CRLF/heartbeat), единичная точка основного графика, решение по месячным ограничениям и ReUI/accessibility checklist. Этап 8 ещё открыт. Использовано 84% пятичасового и 13% недельного лимита; новый блок в этом продолжении не начинаем. Локальный коммит без push.
|
||
|
||
## Блок 8.5 — промежуточная приёмка и достоверность сводки (2026-09-28)
|
||
|
||
- В flow-сводке устранена подмена выбранного среза общими метриками коллектора при недоступной аналитике. Удалён ошибочный пересчёт bytesPerMin в бит/с без деления на 60. Скорость/источники/протокол показывают «—» до подтверждения аналитики; доступное число экспортёров сохраняется. Ошибка и успешный повтор покрыты E2E.
|
||
- Убрана неработающая кнопка экспорта трафика; экспорт не объявлен реализованным. Подписи RX/TX не обещают «сейчас» для исторических/последних значений.
|
||
- Прошли 53 E2E трафика/статистики, 3 отдельных сценария смены backend, 10 модульных тестов периодов/контекста/фильтров статистики. ESLint изменённых файлов, diff-check и production build/TypeScript прошли (34 страницы). Это регрессия этапа 8, не всего проекта. Осмотрен flow-экран 390px; адаптивные сценарии 320/390/1440 прошли.
|
||
- Матрица приёмки и ограничения сохранены в ux-ui-stage-8.md, ближайший план обновлён. Этап не закрыт: следующий шаг — молчащий открытый SSE (снять live, сохранить данные/время, проверить восстановление и смену контекста). Далее — месячные ограничения и оставшийся ReUI/accessibility аудит. Реальный RouterOS/IPFIX/JWT не проверен. Использовано 71% пятичасового и 11% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 8.4П — временные отметки остальных видов трафика (2026-09-28)
|
||
|
||
- Общий REST-список серверов/клиентов/интерфейсов и история выбранного сервера показывают время успешного получения. При загрузке другого контекста или ошибке скрытые данные не оставляют прежнюю отметку.
|
||
- Серверный SSE хранит sample, receivedAt и ошибку вместе с ключом backend/сервера/интерфейса/режима. Удалён синхронный сброс через effect; hook проходит lint. Ошибка сохраняет время последнего валидного сообщения, смена интерфейса исключает чужое измерение.
|
||
- Поле at проверено в backend/src/services/traffic-rate.ts: parseMonitorTraffic создаёт его при обработке ответа. Поэтому подпись — «метка сервера», а не точное время измерения устройства. Время получения браузером отображается отдельно. Серверный контракт не изменён.
|
||
- Прошли 20 профильных E2E (детали, списки, SSE, мобильные клиенты/интерфейсы), затем 4 проверки SSE/flow после расширения сценария смены интерфейса. Финальная подпись проверена ещё 3 SSE-тестами и TypeScript. ESLint и diff-check чистые. Production build прошёл (34 страницы) до уточнения текста/имени prop; после уточнения выполнен tsc --noEmit --incremental false. Адаптивность 320/390 проверена тестами.
|
||
- Далее: сводная приёмка этапа 8 по журналу и stage-8: инвентаризация оставшихся проблем (неработающий экспорт, месячные ограничения, подписи текущих/исторических значений, молчащий SSE), затем согласованный набор регрессионных проверок. Таймаут SSE и достоверность времени устройства не реализованы этим блоком. Реальные RouterOS/IPFIX не проверены. На контрольной точке использовано 46% пятичасового и 7% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 8.4О — время получения flow-данных (2026-09-28)
|
||
|
||
- Список потоков и выбранная аналитика/месячный отчёт показывают отдельное время успешного получения. Источник обозначен как API или live-поток. Подпись явно сообщает, что время измерения не предоставлено: локальные часы браузера не выдаются за метку сетевой телеметрии.
|
||
- useFlowLive сохраняет receivedAt вместе с валидным sample и ключом среза. Ошибка/закрытие потока сохраняют эту отметку; невалидный sample не обновляет её. При смене среза, загрузке или ошибке без отображаемых данных прежняя отметка скрыта. Mock-режим не получает фиктивную метку API.
|
||
- 21 flow-E2E прошёл, включая управляемое время, задержку нового среза и ошибку после успешного sample. После уточнения скрытия отметок при ошибке списка повторно прошли 2 профильных E2E. ESLint, итоговый TypeScript и diff-check чистые. Production build прошёл (34 страницы); финальное условие скрытия дополнительно проверено TypeScript/E2E. Мобильный экран 390px осмотрен, проверки 320/390/1440 прошли.
|
||
- Следующий шаг: время получения REST-списков серверов/клиентов/интерфейсов и деталей сервера; отдельно использовать at серверного SSE как время измерения. Затем сводная приёмка этапа 8. Таймаут молчащего SSE этим блоком не реализован; наличие метки получения не доказывает свежесть измерения. Реальный IPFIX/RouterOS не проверен. Использовано 34% пятичасового и 5% недельного лимита на контрольной точке. Локальный коммит без push.
|
||
|
||
## Блок 8.4Н — поздний фрагмент открытого SSE (2026-09-28)
|
||
|
||
- Добавлен браузерный сценарий с управляемым ReadableStream: первый sample отображается, второй reader.read остаётся ожидающим, пользователь выбирает второй сервер. Проверены abort старой подписки, получение нового sample и завершение старого read после abort. Поздний фрагмент не заменяет данные второго сервера.
|
||
- Граница: fetch/ReadableStream подменены в браузере только для flow/live; поток намеренно игнорирует отмену, чтобы проверить защиту после await reader.read. Остальные HTTP-запросы используют прежние route-моки. Это не проверка реального сетевого транспорта или IPFIX/RouterOS.
|
||
- Все 20 flow-E2E прошли; ESLint теста, TypeScript (tsc --noEmit) и diff-check чистые. В первом прогоне исправлена ошибка тестового макета: Response должен создаваться до блокировки stream через getReader. Production-код не менялся, build не повторялся.
|
||
- Общий план синхронизирован. Следующий шаг: свежесть REST/SSE данных (разделять время получения и время измерения), затем сводная приёмка этапа 8. Этап остаётся открытым. На контрольной точке использовано 24% пятичасового и 4% недельного лимита; локальный коммит без push.
|
||
|
||
## Блок 8.4М — разрывы основного графика (2026-09-24)
|
||
|
||
- Существующий E2E пропусков дополнен проверкой SVG основного RX/TX: при [1, 2, null, 3, 4] каждая линия содержит два самостоятельных сегмента. Проверка прошла вместе со Sparkline; lint/diff-check чистые. Production-код не менялся.
|
||
- В этом продолжении также завершён блок 8.4Л (смена backend). На контрольной точке использовано 29% пятичасового и 97% недельного лимита. Следующий шаг: задержка внутри открытого SSE, свежесть данных и сводная приёмка этапа 8. Все результаты сохранены локально без push.
|
||
|
||
## Блок 8.4Л — смена backend трафика (2026-09-24)
|
||
|
||
- Добавлен E2E реального пользовательского пути через настройки: задержанное обновление списка старого backend, смена адреса, возврат к трафику, ответ старого источника, повторное обновление нового. Старый список не применяется, обновление отправляется только новому backend.
|
||
- Все 3 сценария playwright.backend.config.ts прошли (два прежних Ping 200/500 и новый трафик). Lint теста/diff-check чистые. Production-код не менялся, build не повторялся.
|
||
- Граница: переход через настройки размонтирует экран. Это не проверка смены provider без размонтирования и не отдельный flow-backend/SSE сценарий. Далее: задержка внутри открытого SSE, свежесть данных и общая приёмка этапа 8. Реальные IPFIX/RouterOS не проверены. Локальный коммит без push.
|
||
|
||
## Блок 8.4К — отмена SSE при смене сервера (2026-09-24)
|
||
|
||
- Добавлен браузерный сценарий: задержка SSE первого сервера до ответа, переход ко второму, подтверждение requestfailed для отменённой подписки, получение нового измерения и завершение старого обработчика. Старый sample не заменяет данные второго сервера.
|
||
- 3 профильных E2E прошли: закрытый SSE, поздний REST с интерфейсом первого сервера и новая проверка отмены SSE. Lint теста/diff-check чистые. Production-код не менялся; build не повторялся.
|
||
- Граница проверки: задержка перед получением ответа, не chunk внутри уже открытого ReadableStream. Далее: смена backend, задержка read внутри SSE, свежесть данных и приёмка этапа 8. Реальные IPFIX/RouterOS не проверены.
|
||
- Пятичасовое окно обновилось; использовано 10%, недельного — 94%. Локальный коммит без push.
|
||
|
||
## Блок 8.4И — интерфейс в контексте flow-сервера (2026-09-24)
|
||
|
||
- Выбор flow-интерфейса хранится вместе с контекстом backend, live/mock, раздела, источника и объекта. Чужой интерфейс не используется при первом рендере нового контекста. При выборе карточки фильтр сбрасывается; синхронный сброс через useEffect удалён.
|
||
- Страница traffic и изменённый тест теперь проходят lint без замечаний. 18 flow-E2E прошли; новый сценарий задерживает ответ ether1 первого сервера, выбирает второй, проверяет отсутствие iface во всех его запросах и сохранение аналитики после позднего ответа первого.
|
||
- diff-check, production build/TypeScript прошли (34 страницы). Использовано 89% пятичасового и 91% недельного лимита; локальный коммит без push.
|
||
- Далее: свежесть данных трафика, отдельные проверки смены backend и позднего SSE, общая приёмка этапа 8. Новый тест проверяет REST-смену сервера; backend/SSE этим сценарием не считаются проверенными. Реальный IPFIX/RouterOS не проверен.
|
||
|
||
## Блок 8.4З — разрывы общего Sparkline (2026-09-24)
|
||
|
||
- Sparkline принимает null/undefined и исключает нечисловые значения из расчётов, сохраняя исходную позицию каждой точки. Линия и заливка разделены на сегменты, пропуски не соединяются. Одиночная точка (включая ноль) отображается; пустая история имеет доступное имя. Масштаб для валидных значений сохранён.
|
||
- 16 E2E трафика/дашборда прошли, включая новый сценарий с null между сегментами, координатой следующего сегмента, одиночным нулём и пустой историей. Дополнительно прошли 4 профильных сценария мониторинга RTT/Resources URL. Это профильная, не полная регрессия мониторинга.
|
||
- Lint компонента/теста и diff-check чистые. Production build/TypeScript прошли (34 страницы). Использовано 62% пятичасового и 87% недельного лимита; локальный коммит без push.
|
||
- Далее: свежесть трафика, смена backend/сервера и поздний SSE, исправление оставшегося flowIface-effect и общая приёмка этапа 8. Реальные IPFIX/RouterOS не проверены; этап 8 не объявлен завершённым.
|
||
|
||
## Блок 8.4Ж — история в карточках трафика (2026-09-24)
|
||
|
||
- Две реализации MiniAreaChart заменены общим TrafficMiniChart. Пустые/полностью невалидные серии показывают «Нет истории трафика»; одна точка не создаёт NaN; нулевой TX не скрывается. Координаты RX/TX используют общую длину временной шкалы. Невалидные точки разделяют линии и заливку на сегменты.
|
||
- 31 E2E деталей/flow/мобильных экранов прошёл. Новый сценарий проверяет пустую историю, одну точку, нулевой TX, разрыв RX и отсутствие NaN/Infinity в SVG. Проверены существующие ширины 320/390/1440.
|
||
- Lint нового компонента, flow-панели и теста чистый; diff-check, production build/TypeScript прошли (34 страницы). На странице остаётся ранее известная ошибка lint flowIface. Использовано 42% пятичасового и 84% недельного лимита; локальный коммит без push.
|
||
- Далее: общий Sparkline в итогах (его обработка разрывов не изменена этим блоком), свежесть трафика, проверки смены backend/сервера и позднего SSE, приёмка этапа 8. Реальные IPFIX/RouterOS не проверены.
|
||
|
||
## Блок 8.4Е — отдельные отсутствующие направления RX/TX (2026-09-24)
|
||
|
||
- Общий график поясняет отсутствие RX или TX, если второе направление содержит измерения. Линия отсутствующего направления не создаётся; подсказка содержит только доступное направление.
|
||
- 7 E2E деталей прошли, включая два новых сценария: одна серия отсутствует, остаётся одна линия, при наведении нет отсутствующего значения и виден доступный показатель. Это проверка полностью отсутствующего направления; разрывы внутри ряда ещё не проверялись отдельным E2E.
|
||
- Дополнительно прошли 24 E2E дашборда/flow, покрывающие потребителей общего графика. Lint графика/теста и diff-check чистые. Production build/TypeScript прошли (34 страницы).
|
||
- Далее: мини-графики карточек, разрывы внутри исторического ряда и свежесть; смена backend/сервера и поздний SSE, затем приёмка этапа 8. Реальные IPFIX/RouterOS не проверены. Использовано 20% пятичасового и 81% недельного лимита; локальный коммит без push.
|
||
|
||
## Блок 8.4Д — пустая история RX/TX (2026-09-24)
|
||
|
||
- Live-преобразования серверов, клиентов и интерфейсов сохраняют пустые массивы истории вместо заполнения 60 нулями. Общий TrafficRxTxChart показывает «Нет исторических измерений за выбранный период», если обе серии не содержат валидных точек.
|
||
- Пропущенные, отрицательные и нечисловые точки графика преобразуются в null, а не в ноль. Подтверждённые нулевые ряды остаются данными и отображаются графиком.
|
||
- 22 E2E деталей/flow прошли, включая переход от пустой истории к [0, 0]. Lint графика/теста и diff-check чистые. Production build/TypeScript прошли (34 страницы). На странице остаётся ранее известная ошибка lint flowIface.
|
||
- Далее: проверка частично отсутствующих рядов/tooltip, мини-графиков карточек и свежести данных; смена backend/сервера и поздний SSE, итоговая приёмка этапа 8. Изменён общий график: остальные его потребители требуют общей регрессии в приёмке; полную регрессию проекта здесь не выполняли. Реальные IPFIX/RouterOS не проверены. Использовано 93% пятичасового и 77% недельного лимита. Локальный коммит без push.
|
||
|
||
## Блок 8.4Г — неизвестные дополнительные flow-метрики (2026-09-24)
|
||
|
||
- Overlay/Wire GRE/mesh больше не подставляют ноль при отсутствии измерения. Отсутствующие, отрицательные и нечисловые значения показывают «Нет данных». Подтверждённый ноль сохраняется как 0 Кбит/с или 0 Б; нулевой объём overlay теперь виден в подписи.
|
||
- 17 flow-E2E прошли: предыдущие 13 плюс четыре набора optional-метрик (отсутствующие, нулевые, положительные и некорректные REST). Проверены карточки и преобразование бит/с в Мбит/с. Lint изменённых файлов и diff-check чистые. Production build/TypeScript прошли (34 страницы).
|
||
- Далее: пустые исторические серии и их подстановка нулями; затем остальные проверки контекста/backend/SSE и итоговая приёмка этапа 8. Это точечная защита отображения optional-метрик, а не полная валидация REST. Реальные IPFIX/RouterOS не проверялись. На контрольной точке использовано 76% пятичасового и 74% недельного лимита; локальный коммит без push.
|
||
|
||
## Блок 8.4В — проверка live-контракта flow (2026-09-24)
|
||
|
||
- useFlowLive проверяет полный объект через существующую flowAnalyticsDtoSchema, дополнительно отклоняя отрицательные/нечисловые значения рядов RX/TX. Прежняя проверка только uniqueSrc/destinations удалена.
|
||
- Некорректный sample прекращает подписку и сохраняет последнее корректное измерение своего контекста с явной ошибкой. Ошибка не затирается последующим закрытием SSE; error-событие безопасно читает строку из неизвестного JSON.
|
||
- 13 flow-E2E прошли, включая пять повреждённых ответов: неполный объект, отрицательная скорость при остальных корректных полях, null, некорректная строка destinations и отрицательная серия. Каждый проверяет сохранение корректного измерения и отсутствие live-метки. Тесты явно создают новую подписку переходом 15m → 5m, так как вход в раздел уже выбирает 5m.
|
||
- Lint hook/тестов и diff-check чистые; production build/TypeScript прошли (34 страницы). Использовано 57% пятичасового и 71% недельного лимита. Локальный коммит без push.
|
||
- Далее: неизвестные optional-метрики (overlay/wire/mesh), пустые исторические серии и единицы; отдельные проверки смены backend/сервера и позднего SSE. REST-ответы этой проверкой не охвачены; реальный IPFIX/RouterOS не проверен. Этап 8 остаётся в работе.
|
||
|
||
## Блок 8.4Б — клиенты, интерфейсы и пустые списки (2026-09-24)
|
||
|
||
- Длинные идентификаторы переносятся в деталях и строках привязанных интерфейсов; строки адаптированы под телефон. Мини-графики итогов ограничены шириной ячейки: устранено переполнение на 320 px.
|
||
- Пустой успешный список показывает объяснение для серверов/клиентов/интерфейсов; поиск без совпадений имеет отдельную подпись. Сообщения не показываются вместо загрузки или ошибки API. Выбранные детали при поиске сохраняются.
|
||
- 10 E2E прошли: четыре сценария деталей плюс клиенты/интерфейсы с длинными значениями на 320/390 px, пустой список клиентов и очистка поиска. Тесты проверяют выход элементов за край экрана, исключая намеренно прокручиваемую навигацию. Скриншот клиентов 320 px просмотрен; снимки сохранены в игнорируемом test-results.
|
||
- Production build/TypeScript прошли (34 страницы). Lint нового теста чистый; на странице остаётся прежняя ошибка синхронного сброса flowIface. diff-check чистый. Использовано 25% пятичасового и 66% недельного лимита.
|
||
- Далее: единицы/неизвестные значения, пустые состояния деталей и flow; оставшиеся проверки backend/сервера/SSE и строгая валидация sample. Этап 8 остаётся в работе. API-тесты с моками не подтверждают реальную телеметрию RouterOS/IPFIX.
|
||
|
||
## Блок 8.4А2 — мобильный период серверного трафика (2026-09-24)
|
||
|
||
- Добавлены E2E ширин 320/390 px: кнопка 24ч помещается в экран, меняет период, показывает подтверждённые детали; документ не переполняется по горизонтали. Всего 4 теста деталей прошли, lint теста чистый. Изменений production-кода в этом блоке нет.
|
||
- Использовано 98% пятичасового и 62% недельного лимита; работа сохранена локальным коммитом без push. Следующий шаг: мобильные клиенты/интерфейсы, длинные значения и пустые состояния трафика, затем оставшиеся пункты 8.4. Общая приёмка этапа 8 ещё не завершена.
|
||
|
||
## Блок 8.4А — адаптивная оболочка трафика (2026-09-24)
|
||
|
||
- Общие списки/детали трафика и flow переходят в одну колонку на узких экранах; на широких — 300px + гибкая колонка. Отступы Frame адаптивны, заголовки и периоды переносятся, навигация разделов прокручивается по горизонтали.
|
||
- Flow-переключатели и периоды помещаются на телефоне. Подпись месячного отчёта больше не зависит от положения панели справа.
|
||
- 8 flow-E2E прошли: 5 сценариев данных и 3 ширины (320/390/1440) с обычной аналитикой и месячным отчётом, проверкой доступности кнопки периода и отсутствия горизонтального переполнения документа. Дополнительно прошли 7 прежних E2E обычного трафика. Lint панели/тестов и diff-check чистые. Скриншот 320 px просмотрен; снимки test-results/flow-monthly-{320,390,1440}.png не коммитятся. Этот блок меняет CSS-компоновку и подпись; отдельную production-сборку не повторяли после успешной сборки 8.3В.
|
||
- Этап 8.4 ещё не завершён: нужна профильная мобильная приёмка серверов/клиентов/интерфейсов, пустых состояний, единиц и длинных значений. Остались проверки смены backend/сервера и позднего SSE, валидация flow sample, месячный выбор архивного сервера. Не считать этап 8 принятым целиком.
|
||
- На контрольной точке использовано 94% пятичасового и 61% недельного лимита. Следующий шаг — мобильные сценарии обычного трафика на 320/390 px по этому журналу.
|
||
|
||
## Блок 8.3В — достоверный месячный отчёт (2026-09-24)
|
||
|
||
- «Текущий месяц» явно означает календарный месяц UTC. Удалён адаптер, заполнявший отсутствующие скорости, сессии и графики нулями. Месячный DTO отображается отдельно: объём, страны, сервисы и ASN; колонки скорости скрыты.
|
||
- Общая оперативная сводка скрыта в месячном режиме. Выбор экспортёров использует явный период 24h с пояснением; месячный отчёт справа запрашивает month/serverId. Фильтры дублей, overlay и mesh отключены с пояснением; интерфейсный фильтр не отображается.
|
||
- Месячный период доступен только для серверов: при переходе к клиентам выбран 1h. Иначе прежний API monthly возвращал глобальную сумму вместо клиентского среза. Группе переключения источника добавлено доступное имя.
|
||
- 5 flow-E2E прошли, включая контракт monthly, отсутствие неподтверждённых метрик, отключённые фильтры и переход к клиентам. Lint панели/тестов чистый, production build/TypeScript прошли (34 страницы). Реальная агрегация IPFIX не проверялась.
|
||
- Ограничение: выбор сервера пока зависит от списка активности 24h; архивный сервер без этой активности не появляется в списке. Выбор прошлых месяцев не добавлен. Следующий блок: 8.4 — адаптивность 320/390/1440, подписи единиц и пустые состояния; остаются отдельные проверки смены backend/сервера и позднего SSE, строгая валидация sample. На остановке использовано 84% пятичасового и 60% недельного лимита.
|
||
|
||
## Блок 8.3Б3 — контекст flow-аналитики (2026-09-24)
|
||
|
||
- Списки flow и аналитика привязаны к backend, режиму, периоду, объекту и фильтрам. Поздние ответы отменённого эффекта игнорируются. Ошибки списка/аналитики получили отдельные Alert и повтор без сброса контекста; ошибка списка не выдаётся за отсутствие экспортёров.
|
||
- При отсутствии подтверждённой аналитики график, метрики и таблицы деталей скрыты; прежняя подстановка общих показателей карточки удалена. Общая сводка может показывать подтверждённые агрегаты коллектора — дальнейшее уточнение подписей/области данных остаётся в 8.4.
|
||
- useFlowLive хранит данные с ключом контекста, проверяет abort после fetch/read, сообщает о завершении SSE. Последний sample сохраняется в своём контексте с отметкой недоступности live; одинаковая отметка используется в сводке и деталях.
|
||
- 7 прежних E2E трафика прошли; 4 новых flow-E2E прошли после исправления найденной тестом live-метки сводки: поздний период, ошибка аналитики/повтор, 403 списка/повтор и завершённый SSE. Production build/TypeScript — 34 страницы. Lint hook/панели/тестов чистый; на странице осталась 1 прежняя ошибка синхронного сброса flowIface (было 3).
|
||
- Далее: отдельные проверки смены сервера/клиента/backend и позднего SSE, строгая валидация sample, семантика месячного отчёта (30d сейчас запрашивает текущий календарный месяц; API monthly принимает только month/serverId и не применяет остальные фильтры). Затем 8.4: неизвестные значения, единицы и мобильная приёмка. Реальный IPFIX/RouterOS не проверен. Использовано 66% пятичасового и 57% недельного лимита.
|
||
|
||
## Блок 8.3Б2 — общие списки трафика (2026-09-24)
|
||
|
||
- Списки серверов, пользователей и интерфейсов и их сводка привязаны к backend, режиму, периоду и повтору загрузки. Ответ отменённого эффекта не меняет данные и выбранный объект. Flow-запросы больше не делят состояние загрузки/ошибки с этими списками.
|
||
- Во время запроса показаны загрузка списка и skeleton сводки. При ошибке прежние карточки и сводка скрыты; Alert содержит причину и повтор с сохранением контекста. Подтверждённые детали сервера остаются отдельным запросом.
|
||
- 7 E2E прошли: поздний список за старый период, ошибка обновления и повтор, предыдущие проверки деталей и SSE. ESLint нового теста чистый; traffic — 3 прежние ошибки flow-эффектов, прежнее предупреждение зависимостей устранено. Production build/TypeScript прошли, 34 страницы. HTTP-моки не подтверждают реальный сбор RouterOS/IPFIX.
|
||
- Следующий шаг: 8.3Б3 — ключи контекста, ошибки и поздние ответы flow-аналитики и useFlowLive. Затем неизвестные значения, пустые состояния и мобильная приёмка 8.4. Смена режима/backend именно для списка ещё не покрыта отдельным E2E. На контрольной точке использовано 46% пятичасового и 54% недельного лимита.
|
||
|
||
## Блок 8.3Б1 — контекст деталей трафика (2026-09-24)
|
||
|
||
- Детали привязаны к backend, режиму, серверу, периоду, интерфейсу и повтору запроса. При смене контекста прежние метрики/график скрыты, период остаётся доступен для выбора. Поздний ответ отменённого эффекта не применяется; список интерфейсов также игнорирует ответ прежнего сервера.
|
||
- Ошибка деталей показывает Alert и «Повторить загрузку деталей», сохраняя выбранный период/интерфейс. Общая сводка сервера больше не подставляется вместо неудавшегося запроса отдельного интерфейса.
|
||
- 5 E2E деталей/SSE прошли: задержанный период, ошибка интерфейса и повтор плюс предыдущие проверки потока. ESLint теста чистый; traffic — прежние 3 ошибки/1 предупреждение. Production build и TypeScript прошли: 34 страницы. Локальный коммит без push.
|
||
- Далее 8.3Б2: общие списки/сводка трафика и гонки при смене периода/режима; затем flow-аналитика. Проверка позднего списка интерфейсов отдельным E2E ещё не выполнена. На контрольной точке использовано 23% пятичасового и 50% недельного лимита.
|
||
|
||
## Блок 8.3А — достоверность live-подписей трафика (2026-09-24)
|
||
|
||
- useTrafficLive сообщает завершение SSE, проверяет отмену после fetch/read и не применяет некорректные sample (нечисловые/отрицательные RX/TX или неверное время). Последний корректный sample сохраняется при сбое, но подписан «Последнее live-измерение · поток недоступен»; история при отсутствии sample помечена отдельно, включая ожидание live.
|
||
- 3 E2E прошли: штатное завершение потока, повреждённое событие после корректного sample, HTTP 503. Неправильное событие не заменяет последнее корректное измерение. Lint теста чистый; сравнение с HEAD подтвердило прежние замечания traffic (3 ошибки/1 предупреждение), hook (1 ошибка). Production build с TypeScript прошёл, 34 страницы.
|
||
- Коммит отложился до продолжения после сброса квоты: в предыдущем окне она достигла 100%, сборка уже была запущена и завершилась успешно. На продолжении доступно 99% пятичасового окна. Локальный коммит без push.
|
||
- Далее 8.3Б: гонки чтения истории/деталей при смене сервера, интерфейса и периода; API-ошибка не должна оставлять данные другого контекста. Автоматическое переподключение SSE, парсер CRLF, useFlowLive и реальный IPFIX остаются непроверенными. Этап 8 целиком не завершён.
|
||
|
||
## Блок 8.2Б — URL-контекст статистики (2026-09-23)
|
||
|
||
- Проверяются дубли/пустые значения, dim/tab, view, planes, измерения pivot, ID сервера, ASN и длина кода страны. Неверный срез блокирует запрос, а не удаляется из API-query с расширением отчёта. Совпадающие dim/tab поддержаны; смена dim удаляет устаревший tab. Сброс удаляет параметры контекста, сохраняя from/to, чужие ключи и hash.
|
||
- Дискретный выбор периода, среза и режима использует native pushState, читая свежие параметры URL. Back/Forward/reload восстанавливают отчёт; черновик Filters по-прежнему применяется явно.
|
||
- 5 unit-тестов периода/контекста, 13 E2E статистики, ESLint и production build/TypeScript прошли (34 страницы). Проверены ошибочные ссылки без API, сброс, история периода/среза и отсутствие запросов записи при навигации. Совместимость значений следует текущему API: ASN — целое, country — два символа; справочники не используются как обязательный валидатор.
|
||
- Далее 8.3: live/история трафика, завершение SSE и гонки запросов; затем адаптивная приёмка и единицы. На контрольной точке использовано 73% пятичасовой / 42% недельной квоты. Локальный коммит без push.
|
||
|
||
## Блок 8.2А — строгий период статистики (2026-09-23)
|
||
|
||
- lib/statistics-range.ts проверяет существование календарной даты, ISO-время с зоной, порядок границ, дубли/неполную пару from/to. Сравнение по времени, date-only конец включён как UTC-день; конец ограничен текущим временем, как в backend parseStatisticsPeriod. Отсутствие обеих границ означает пресет 7 дней, повреждённая пара не заменяется им молча.
|
||
- Некорректный период блокирует запрос статистики, скрывает метрики и предлагает выбрать последние 7 дней. Восстановление сохраняет срез и чужие параметры. DateSelector использует строгую проверку вместо нормализации 30 февраля через Date. При изменении параметров читается текущий window.location.search.
|
||
- 3 unit-теста, 9 E2E статистики и lint прошли. Production build с TypeScript прошёл: 34 страницы. Проверены 403/500/повтор, гонка периодов, pivot, неверные прямые ссылки, сохранение country/keep при восстановлении.
|
||
- Это клиентская валидация; backend API напрямую всё ещё использует прежний парсер. Следующий блок 8.2Б: история URL и валидация остальных параметров, чтобы неверный срез не расширял отчёт молча. На проверке использовано 60% пятичасовой / 41% недельной квоты. Коммит локальный без push.
|
||
|
||
## Блок 8.1 — достоверность состояния статистики (2026-09-23)
|
||
|
||
- Новый план docs/ux-ui-stage-8.md с референсами и схемой. Результат статистики привязан к ключу backend/режим/период/срез/view/pivot/planes/повтор. Старый отчёт не выводится под новым контекстом; отменённый эффект не применяет поздний ответ.
|
||
- Ошибка API не показывает нулевые KPI, график и «Нет данных куба». Кнопка «Повторить загрузку» повторяет текущий запрос; подтверждённый пустой ответ по-прежнему показывает нули и пустое состояние. Данные и pivot публикуются после завершения всей цепочки запроса.
|
||
- Проверки: 4 новых E2E (403/500 + повтор с пустым ответом, задержка/гонка периодов, ошибка pivot) и существующий сценарий статистики из migrated-tables прошли. ESLint страницы/тестов чистый; production build с TypeScript прошёл, 34 страницы. Скриншот ошибки просмотрен. Использованы прежние Alert/Button/KpiStatGrid/DataGrid, без изменения темы/установленных примитивов.
|
||
- Ограничение: при сбое pivot сейчас скрыт весь отчёт, частично загруженный основной ответ отдельно не показывается. Последний успешный отчёт не сохраняется как отдельный доступный пользователю снимок. Следующий блок 8.2 — строгие периоды и URL, затем live/история трафика. На проверке использовано 44% пятичасовой / 38% недельной квоты. Коммит локальный без push.
|
||
|
||
## Завершение этапа 7 — локальная приёмка (2026-09-23)
|
||
|
||
- 94 профильных E2E dashboard-data/servers/uptime-links прошли. Включены сквозные сценарии сервера и Ping-проверки из очереди дашборда, права, ошибки/повторы операций, URL-контекст, формы и адаптивность. Сценарий Ping с действием и возвратом уже существует в uptime-links.spec.ts («очередь проверок…»); ранее он ошибочно оставался в списке следующих шагов журнала.
|
||
- Отдельная конфигурация playwright.backend.config.ts запускает только backend-switch.e2e.ts с NEXT_PUBLIC_BACKEND_URL=local. Оба теста прошли: задержанный Ping прежнего backend с 200/500, смена адреса через настройки, возврат к данным нового источника и следующий POST только новому адресу. Обычная конфигурация по-прежнему использует same-origin. Все HTTP-ответы подменены, реальные сетевые операции не выполнялись.
|
||
- ESLint новых тестов/конфигурации и TypeScript прошли. Последняя production-сборка приложения ca9474a успешна; после неё до завершения этапа 7 менялись только тесты/документы. Известный lint uptime (1 ошибка/6 предупреждений) остаётся.
|
||
- Границы: смена режима/backend проверена через настройки с размонтированием страницы, не через изменение контекста в смонтированной форме. Реальные JWT/RouterOS, длительные bandwidth-test, отмена выполняющейся сетевой операции, конкуренция разных пользователей/вкладок и полноценный экспорт серверов не подтверждены/не реализованы; ограничения из блоков 7.4 сохраняются. Общая приёмка доступности всех экранов — этап 12.
|
||
- Следующий этап 8: трафик и статистика, начиная с привязки данных к выбранному периоду/срезу и разделения ошибок и пустых ответов. Коммит этапа 7 локальный, без push.
|
||
|
||
## Приёмка 7.5Д — смена режима при незавершённом Ping (2026-09-23)
|
||
|
||
- Новый E2E удерживает POST collect-group, открывает настройки обычной ссылкой, переключает «Живые» на «Моковые», возвращается назад и получает поздний 500 старого запроса. Проверено отсутствие старой ошибки и доступность создания пробы в новом режиме. Тест прошёл; код приложения не менялся. Сценарий включает размонтирование страницы, не доказывает смену контекста без размонтирования.
|
||
- URL backend в текущем Playwright окружении заблокирован NEXT_PUBLIC_BACKEND_URL=same-origin. Смену адреса backend нужно проверять отдельной конфигурацией; этот сценарий остаётся открытым, как и сквозной переход к Ping-проверке из дашборда. Production build не повторялся для изменения теста; последняя успешная сборка ca9474a. Работа продолжена по просьбе пользователя при остатке 7% пятичасовой квоты. Локальный коммит без push.
|
||
|
||
## Приёмка 7.5Г — сквозной сценарий сервера (2026-09-23)
|
||
|
||
- Добавлен E2E «проблема на дашборде → выбранный сервер → опрос с 403 → успешный повтор → назад → вперёд». Проверены точный ID и одна строка, сохранение выбранного сервера при отказе, два явных POST только выбранному устройству и отсутствие операций записи от переходов истории.
|
||
- Новый тест прошёл, ESLint файла чистый. Код приложения не менялся, production build не повторялся: последняя успешная сборка ca9474a. HTTP-моки не доказывают реальное изменение состояния RouterOS; после возврата очередь отражает тот же фикстурный offline-статус.
|
||
- Следующий шаг 7.5: смена backend/mode при незавершённой операции мониторинга, затем свести границы приёмки этапа. Сквозной сценарий проверок мониторинга с действием из дашборда остаётся отдельно. На старте 18% пятичасовой квоты, после проверки 11%; выполнен небольшой блок по просьбе продолжить ниже резерва. Локальный коммит без push.
|
||
|
||
## Приёмка 7.5В — формы серверов и таблица Resources (2026-09-23)
|
||
|
||
- Форма сервера на телефоне занимает полную ширину; fieldset получил min-w-0, выбор типа узла и кнопки подвала допускают перенос. На 320 px прежде выходили за экран поля, страны и последний шаг. Проверены четыре шага редактирования, выбор Home Router, добавленный WAN, раскрытые дополнительные поля и Escape на 320/390/1440 px. Существующие проверки создания и ошибок сохранения также прошли.
|
||
- Resources: фильтры типов переносятся внутри панели. Таблица обёрнута установленным ReUI DataGridScrollArea с orientation=horizontal внутри DataGridContainer: правые колонки доступны при прокрутке, общая страница не расширяется. Общая оболочка DataGridShell, vendored ReUI и тема не изменены.
|
||
- Проверки: 55 профильных E2E серверов/мониторинга прошли; затем ещё 2 уточнённые проверки Resources на 320/390 px подтвердили доступ к значению последней колонки, поиск, пустой результат и восстановление строки. Скриншоты WAN, дополнительных полей и прокрученной таблицы просмотрены. Production build и TypeScript прошли: 34 статические страницы. Lint изменённых файлов чистый, кроме исходных 1 ошибки и 6 предупреждений uptime. ReUI API и audit checklist проверены.
|
||
- Границы: HTTP-моки, без реального RouterOS/JWT; сортировка в адаптивном тесте проверена на одной строке, порядок нескольких строк этим тестом не доказывается. Сквозной сценарий и смена backend/mode при незавершённой операции остаются следующими пунктами 7.5. Этап 7 целиком ещё не завершён. На контрольной точке осталось 23% пятичасовой и 72% недельной квоты. Локальный коммит без push.
|
||
|
||
## Приёмка 7.5Б — адаптивность мониторинга и форм (2026-09-23)
|
||
|
||
- Формы Ping/Speed используют всю ширину телефона; min-w-0 у fieldset устраняет выход полей за границы панели. Параметры Speed идут вертикально также на ПК: ширины боковой панели недостаточно для трёх колонок без перекрытия Direction и длительности.
|
||
- Вкладки мониторинга переносятся на новую строку. Ранее выбор «Скорость» прокручивал общий контейнер по горизонтали и обрезал левую часть экрана, хотя document.scrollWidth не превышал viewport. Добавлена отдельная проверка границ всех трёх вкладок. Длинное имя в заголовке Speed переносится внутри доступной ширины.
|
||
- 49 E2E uptime-links прошли после исправления форм; после найденного на скриншотах сдвига вкладок прошли 5 профильных проверок; после финального исправления перекрытия Speed повторно прошли 3 сценария на 320/390/1440 px. Проверены видимость сохранения/отмены, отсутствие выхода полей за экран, Escape, отсутствие перекрытия параметров Speed. Просмотрены скриншоты форм сверху/снизу, Resources и Speed. Production build с TypeScript прошёл: 34 статические страницы. Lint тестов чистый, uptime сохраняет исходные 1 ошибку react-hooks/set-state-in-effect и 6 предупреждений.
|
||
- ReUI checklist: установленные примитивы и тема не изменялись, исправлена локальная композиция страницы. Проверки используют HTTP-моки; реальный JWT/RouterOS не проверен. Resources проверен на наличие строки и ширину страницы, но взаимодействие с таблицей после прокрутки требует отдельной приёмки.
|
||
- Следующий блок 7.5: адаптивность форм серверов и таблицы Resources после прокрутки; сквозной сценарий дашборд → объект → действие → возврат; смена backend/mode при незавершённой операции. Этап 7 ещё не завершён. Квота после проверок: использовано 39% пятичасовой и 22% недельной. Локальный коммит без push.
|
||
|
||
## Приёмка 7.5А — неработающее действие экспорта серверов
|
||
|
||
- Удалена кнопка «Экспорт» серверов без обработчика и её неиспользуемый импорт. Полноценный экспорт не реализован: формат, поля и назначение требуют отдельного контракта. Пользователь больше не видит действие, которое ничего не делает.
|
||
- Проверки: ESLint страницы чистый, все 32 E2E servers.spec.ts прошли. Для удаления одного неработающего контрола production build повторно не запускался; предыдущая сборка 0734679 успешна.
|
||
- Этап 7 ещё не завершён. Далее: адаптивность форм и Resources/Speed, сквозная приёмка, документирование ограничений. Работа выполнена по просьбе продолжить ниже резерва (на старте оставалось 6% пятичасовой квоты). Локальный коммит без push.
|
||
|
||
## Блок 7.4В2 — URL-фильтры Resources (2026-09-23)
|
||
|
||
- Resources использует rq (поиск: replaceState) и rtype (jump-host/exit-node/home-router: pushState; отсутствие означает все). Фильтры сохраняются при смене вкладки, reload и Back/Forward. Значения Ping q/status/servers, probe, tab и чужие параметры не изменяются при сбросе Resources.
|
||
- Неизвестный rtype и дубли rq/rtype дают локальное предупреждение Resources; таблица не расширяется до всех строк. Кнопка сброса удаляет только rq/rtype. Использованы прежние DataPageToolbar, Grid, Alert и Button, без изменения общей темы.
|
||
- Проверки: 4 codec unit-теста и 9 URL E2E прошли (3 новых Resources, с реальными строками HTTP-мока). Проверены фильтрация, reload, история, независимость Ping и отсутствие запросов записи. Lint новых файлов/тестов чистый; uptime — прежние 1 ошибка/6 предупреждений. Production build и TypeScript прошли: 34 статические страницы.
|
||
- Следующий шаг: 7.5 — профильная приёмка серверов и мониторинга, сквозной сценарий из дашборда, адаптивность форм/Resources/Speed, список оставшихся ограничений (экспорт серверов без обработчика, длительный Speed, смена backend/mode во время операции). Этап 7 целиком ещё не объявлять завершённым. Реальные JWT/RouterOS доступны только во внешнем тестовом окружении.
|
||
- Квота после проверок: 81% пятичасовой / 13% недельной израсходовано. Локальный коммит без push, сторонние изменения не включать.
|
||
|
||
## Блок 7.4В1 — URL вкладки и фильтров Ping (2026-09-23)
|
||
|
||
- Новый codec lib/data-filters/uptime-url-state.ts и hook useUptimeUrlState делают URL источником вкладки и Ping-фильтров. tab=probes/resources/speed (по умолчанию probes), q=поиск, status=up/warn/down (отсутствует для всех), servers=JSON массива строковых ID. probe и посторонние параметры сохраняются.
|
||
- Поиск использует native replaceState, дискретные действия — pushState с чтением актуального window.location.search. Сброс Ping-фильтров атомарно удаляет q/status/servers, сохраняя tab/probe; восстановление ошибочной ссылки удаляет также tab. Back/Forward/reload восстанавливают контролы без POST/PUT/PATCH/DELETE.
|
||
- Проверяются допустимые tab/status, дубли одиночных параметров и формат servers (до 50 уникальных непустых ID длиной до 128, JSON до 8192 символов). Неизвестные ID не подменяются доступными. При ошибке показывается Alert и Ping-строки не выводятся до исправления/сброса. Фильтры Ping не применяются к Resources/Speed; их значения сохраняются при смене вкладки.
|
||
- Проверки: 3 unit-теста codec и все 43 E2E uptime-links прошли (6 новых URL-сценариев). TypeScript прошёл; новые файлы и тесты lint-clean, uptime — прежние 1 ошибка и 6 предупреждений. ReUI audit: композиция и установленные компоненты не менялись; выбранная вкладка/сервер имеют aria-pressed. Финальный production build прошёл: 34 страницы.
|
||
- Следующий шаг 7.4В2: отдельные параметры поиска и типа серверов Resources (сейчас локальный state), затем приёмка этапа 7. Состояние раскрытия графиков/групп и черновики форм в URL не помещались. Реальные JWT/RouterOS не проверялись.
|
||
- Квота после проверок: использовано 52% пятичасовой / 8% недельной. Коммит локальный, без push.
|
||
|
||
## Блок 7.4Б3б — ручной Ping и таймаут Speed-test (2026-09-23)
|
||
|
||
- collect-now и collect-group занимают общий savingRef до POST и удерживают его до обновления данных. Двойной запуск, CRUD и Speed-test не пересекаются в одном смонтированном экране. GET, запрошенный владельцем операции для обновления результатов, разрешён под блокировкой; фоновые GET пропускаются. saveContext отсекает ответы предыдущей операции/контекста, включая ошибки.
|
||
- Speed-test: клиентский timeout 120 секунд; ошибка ожидания использует serverOperationError и сообщает неизвестный результат. Проверена цепочка backend: два возможных GET адресов по 10 секунд, bandwidth-test 30 секунд, пауза 3 секунды и Ping 20 секунд, затем БД. 120 секунд — предел ожидания UI с запасом, а не гарантия завершения backend. Отмена fetch не останавливает RouterOS.
|
||
- Backend bandwidth-test по-прежнему имеет фиксированные 30 секунд при durationSec без верхней границы. Этот существующий конфликт для длительных измерений требует отдельного согласования сетевой операции; здесь backend-политика не менялась. Для общего/группового Ping отдельный клиентский timeout не вводился: длительность зависит от числа проб. Блокировки разных вкладок браузера/пользователей не обеспечиваются клиентским gate.
|
||
- Проверки: 35 E2E uptime-links прошли, затем 3 проверки Speed/поздней ошибки (2 новые) прошли; всего 37 уникальных сценариев. Проверены 200/403, повторное нажатие, блокировка CRUD/Speed, обновление данных под gate, поздняя ошибка после смены URL и timeout Speed. TypeScript прошёл; lint uptime — прежние 1 ошибка/6 предупреждений, тесты чистые. ReUI checklist: установленные компоненты/композиция не менялись. Финальный production build прошёл: 34 страницы.
|
||
- Следующий шаг: полный URL-контекст мониторинга (вкладка, поиск, статус, серверы), затем приёмка 7.5. В приёмке отдельно проверить смену backend/mode во время операции и задержку чтения после POST, успешный реальный Speed и его временные ограничения. Реальные JWT/RouterOS не проверялись.
|
||
- Квота после проверок: 23% пятичасовой / 4% недельной израсходовано. Локальный коммит без push; сторонние изменения сохранены.
|
||
|
||
## Блок 7.4Б3а — блокировка записи при Speed-test (2026-09-21)
|
||
|
||
- runSpeedTest занимает общий savingRef синхронно перед запросом: повторный запуск и CRUD проб блокируются, фоновые GET не перезаписывают измерение. В finally блокировка снимается при успехе/ошибке. Добавлена проверка saveContext перед применением позднего результата/ошибки после смены backend/mode или размонтирования.
|
||
- 6 профильных E2E прошли: блокировки форм, переключатели, звезда и новый сценарий одного Speed-test с запретом CRUD/Ping до ответа и освобождением после 500. Реальная смена backend/mode с отложенным Speed-ответом не проверялась отдельным E2E. Lint тестов чистый; uptime сохраняет 1 исходную ошибку и 6 предупреждений. ReUI checklist: композиция/компоненты не менялись. Production build и TypeScript прошли: 34 страницы.
|
||
- Следующий шаг 7.4Б3б: collect-now/collect-group должны занимать общую блокировку, исключать повторные запуски и поздние ответы. До этого уже запущенный Ping может пересекаться с записью/Speed. Также проверить ограничение времени ожидания Speed-test: сейчас общий gate удерживается до завершения fetch, отдельный timeout этой операции ещё не добавлен. Затем URL-контекст мониторинга и приёмка.
|
||
- На контрольной точке израсходовано 34% пятичасовой и 97% недельной квоты. Локальные HTTP-моки, без реального RouterOS/JWT. Коммит локальный без push.
|
||
|
||
## Блок 7.4Б2 — удаление и звезда (2026-09-21)
|
||
|
||
- После сброса пятичасовой квоты создан ранее отложенный коммит 4f23505. Предыдущий git add не выполнялся: auto-review не смог завершиться из-за лимита; повтор выполнен после восстановления квоты.
|
||
- Ping/Speed удаляются через существующий AlertDialog с названием/целью. Отмена не пишет данные; подтверждение выполняет PUT через общий gate. Во время запроса закрытие/повтор заблокированы; 403 оставляет диалог и строку, успех удаляет строку. Повторная проверка прав выполняется в обработчике.
|
||
- Звезда дашборда теперь применяет состояние после PATCH и сообщает ошибку, сохраняя прежнее значение. PATCH имеет timeout 30 секунд и использует тот же gate, что формы/переключатели/удаление; обновление mock-звёзд и событие дашборда отправляются после успеха.
|
||
- Проверки: все 30 E2E uptime-links прошли, включая 3 новых сценария удаления/звезды, прежние формы/права/mobile/ссылки. TypeScript прошёл; lint теста чистый, uptime — прежние 1 set-state-in-effect и 6 unused warnings. ReUI audit: переиспользован AlertDialog из серверного сценария, структура установленных компонентов и тема не изменены. Production build прошёл: 34 статические страницы.
|
||
- Осталось 7.4Б3: общий порядок записи и запущенных измерений (runSpeedTest, collect-now, collect-group), блокировка повторного запуска, поздние ответы после смены контекста. PUT/PATCH CRUD теперь сериализованы между собой, но запуск измерения пока не занимает общий gate. Далее URL-контекст мониторинга и приёмка 7.5.
|
||
- Проверки — HTTP-моки, реальные JWT/RouterOS не проверялись. Контроль квоты: 12% пятичасовой / 94% недельной израсходовано. Коммит локальный без push.
|
||
|
||
## Блок 7.4Б1 — подтверждённые переключатели (2026-09-21)
|
||
|
||
- По прямому поручению пользователя работа продолжена ниже резерва. Ping enabled и Speed update теперь используют общий saveProbeForm: синхронная блокировка, timeout, защита от устаревшего чтения, применение строки только после PUT. Ошибка видна вне Sheet и не сбрасывается фоновым GET.
|
||
- ID новой пробы создаётся при открытии формы и сохраняется при повторной отправке. Установленные компоненты ReUI и тема сохранены; checklist проверен.
|
||
- 14 профильных E2E прошли суммарно: 12 сценариев форм/прав, затем 2 сценария переключения (ожидание, 403, повтор). Первоначальные два сбоя были неоднозначным селектором alert из-за Next route-announcer; селектор уточнён. ESLint: прежние 1 ошибка/6 предупреждений uptime, тесты чистые. Финальный production build прошёл: 34 страницы, TypeScript без ошибок.
|
||
- Осталось: подтверждение удаления, применение удаления только после API, ошибка звезды и конкуренция ранее запущенных PATCH/Speed-test/PUT. Эти действия пока не переведены на общую блокировку. Локальные HTTP-моки не проверяют RouterOS/JWT.
|
||
- Квота на завершении блока: 96% пятичасовой и 92% недельной израсходовано. Следующий шаг — 7.4Б2 (удаление и звезда), затем URL мониторинга и приёмка. Коммит локальный, без push.
|
||
|
||
## Блок 7.3В/7.4А — подтверждённое сохранение форм (2026-09-21)
|
||
|
||
- Ping/Speed: формы ожидают PUT, обновляют локальный список и закрываются только после успешного ответа. При 400/403/500, сетевой ошибке или таймауте сохраняются поля и показывается ошибка в Sheet. Общий serverOperationError переиспользован для понятного 403 и неопределённого результата timeout.
|
||
- Синхронный ref блокирует повторное сохранение до React render; на время запроса заблокированы поля, действия, Отмена и Escape. PUT ограничен 30 секундами. Права повторно проверяются перед сохранением. API по-прежнему заменяет весь список; серверный контракт не менялся.
|
||
- GET overview/speed, начатые до сохранения, не применяются после него; чтение пропускается во время сохранения. Поздний ответ записи не применяется после смены mode/backend или размонтирования. Не утверждать полное устранение гонок ранее начатых PATCH/операций строк — это следующий блок.
|
||
- Проверки: 25 сценариев uptime-links прошли суммарно, включая 10 новых (400/403/500 и повтор для двух форм, двойное нажатие/Escape, таймаут). В первом прогоне 2 проверки ошибочно проверяли disabled у fieldset; заменены проверкой реального input, оба повторно прошли. TypeScript и production build прошли (34 страницы). ESLint теста чистый; у uptime прежние 1 ошибка set-state-in-effect и 6 предупреждений.
|
||
- ReUI audit: сохранены установленные Sheet/Alert, дизайн и тема; fieldset даёт нативную блокировку полей, aria-busy сообщает состояние. HTTP-моки не проверяют реальный JWT/RouterOS.
|
||
- Следующий шаг 7.4Б: подтверждение удаления, обновление строки только после API при переключении/удалении, обработка ошибки звезды и блокировка конкурирующих записей. Старые row-handlers пока оптимистичные; их PUT теперь сообщает ошибку вместо её поглощения, но rollback/подтверждение не реализованы. Затем полный URL-контекст мониторинга и приёмка 7.5.
|
||
- Контроль квоты: использовано 65% пятичасовой / 87% недельной; локальный коммит без push, сторонние файлы не включать.
|
||
|
||
## Блок 7.3Б — ограничения прав мониторинга (2026-09-21)
|
||
|
||
- Uptime использует can("mm:uptime:write") для Ping/Resources/Speed: создание, редактирование, удаление, переключение, звезда дашборда, групповой ping, collect-now и bandwidth-test. Дополнительное создание интерфейса из группы также ограничено. Backend-политика и auth disabled не изменены.
|
||
- Для читателя «Обновить данные» выполняет GET сохранённых результатов без POST collect-now. Фоновые GET, вкладки, фильтры, графики и CSV ресурсов доступны. Права servers:write и флаг is_admin не заменяют uptime:write; наследование uptime:admin сохранено.
|
||
- Обработчики повторно проверяют актуальные claims до изменения локального состояния/запроса. При локальном отзыве права форма Ping/Speed остаётся открытой, сообщение показано внутри неё. Кнопки пересчитываются на следующем render; подписка на изменения сессии не добавлена.
|
||
- Проверки: прежние 11 E2E прошли, новые 7 сценариев прав прошли; после проверки дополнительной кнопки повторно прошли 3 read-only сценария. TypeScript прошёл. ESLint теста чистый; uptime сохраняет исходные 1 set-state-in-effect (speedDraft) и 6 unused warnings. ReUI audit: установленные компоненты, композиция, тема сохранены; добавлены state/disabled и Alert. Финальный production build прошёл: 34 статические страницы.
|
||
- 7.3 ещё не принят целиком: persistProbes/persistSpeedProbes скрывают ошибки PUT, а формы оптимистично закрываются. Следующий блок 7.3В/7.4: подтверждённое сохранение Ping/Speed, сохранение формы на API 403/400/500, блокировка повторов, сообщения ошибок для переключения/звезды/удаления. Не считать локальный отзыв claims проверкой серверного 403.
|
||
- Реальный JWT/RouterOS не проверялся: использованы HTTP-моки и синтетические claims. На контрольной точке израсходовано 42% пятичасовой и 83% недельной квоты. Локальный коммит без push, исходные сторонние изменения не включать.
|
||
|
||
## Блок 7.3А — права действий серверов (2026-09-21)
|
||
|
||
- ServersPage использует существующий can("mm:servers:write") после AuthGuard. Backend относит создание/изменение/удаление, POST poll и test-connection к записи; политика API не изменена. Наследование write/admin и auth disabled сохранены, is_admin не даёт отдельного обхода.
|
||
- Режим «Только просмотр»: отключены добавление, редактирование, включение, удаление, опрос в заголовке/меню/деталях и повтор опроса. Детали, фильтры и WebFig доступны. Пустой список не предлагает читателю добавить сервер.
|
||
- Обработчики повторно проверяют актуальные claims перед действием; массовый опрос — перед каждым запросом. Отзыв права не закрывает форму и не отправляет запись. Проверка в UI не заменяет backend; неизвестный клиенту отзыв сервер возвращает как 403 с сохранением формы. Внешняя смена token отражается на следующем render/действии; подписка на изменения сессии не добавлена.
|
||
- Проверки: 32 E2E servers.spec.ts прошли (27 прежних и 5 прав), TypeScript и профильный ESLint прошли. Production build прошёл: 34 статические страницы. ReUI audit: композиция, установленный Data Grid и тема сохранены; добавлены только состояние прав, props прикладных компонентов и сообщение Alert.
|
||
- Границы: HTTP-моки и тестовые claims без реальной JWT-проверки; RouterOS не проверялся. Известная кнопка «Экспорт» серверов без обработчика остаётся задачей форм/действий 7.4.
|
||
- Следующий шаг: 7.3Б — инвентаризация write-действий uptime (Ping/Resources/Speed), сопоставление с backend и ограничения прав, затем профильные HTTP-мок тесты. 7.3 целиком пока не завершён.
|
||
- Лимит после основного блока: использовано 15% пятичасового, 79% недельного. Локальный коммит без push; исходные изменения навыков/AGENTS/.codex не включать.
|
||
|
||
## Этап 0 — исходная база
|
||
|
||
Исходный HEAD: f8e743721007e809b8b148bb6ddcf9e6adb3f52d.
|
||
На старте уже изменены 25 файлов навыков ReUI, AGENTS.md и создан .codex/config.toml. Они относятся к предыдущей настройке и не входят в коммит этого этапа. .codegraph/daemon.pid — служебный файл, не коммитить.
|
||
|
||
Изменение: в lib/format-service-path-label.test.ts убрано расширение .ts из локального импорта. Это устраняет TS5097 без ослабления tsconfig и без изменения UI или backend.
|
||
|
||
### Проверки
|
||
|
||
| Проверка | Результат |
|
||
| --- | --- |
|
||
| tsc --noEmit --incremental false | Успешно после исправления импорта |
|
||
| tsx lib/format-service-path-label.test.ts | Успешно |
|
||
| tsx backend/src/services/ipsec-config.test.ts | Успешно |
|
||
| tsx backend/src/services/ros-file-contents.test.ts | Успешно |
|
||
| npm run build | Успешно: контракты, Next.js, TypeScript, 34 статические страницы |
|
||
| eslint . | Не проходит: 494 ошибки, 11015 предупреждений; включает артефакты .ci/docker |
|
||
| Тот же lint-отчёт без файлов .ci/docker | 81 ошибка, 134 предупреждения; это фильтрация отчёта, не отдельный запуск |
|
||
|
||
Lint hotspots: components/reui/sortable.tsx (8 ошибок), app/(main)/probes/page.tsx (8), components/reui/filters.tsx (6), app/(main)/network-map/page.tsx (5), app/(main)/firewall/page.tsx (4), components/reui/date-selector.tsx (3). Не исправлять их массово в этапе 1. Изоляцию generated-каталогов в ESLint вынести в отдельный небольшой блок перед миграцией; правила проверок не отключать.
|
||
|
||
В песочнице сборка не могла записать существующие dist-файлы (EPERM), а tsx падал в uv_os_get_passwd. Повторные запуски вне песочницы прошли; это ограничения окружения, не ошибки приложения.
|
||
|
||
### Исходные экраны
|
||
|
||
Просмотрены /servers и /dashboard через локальную production-сборку на 127.0.0.1:3000, без backend, в mock-режиме. Скриншоты показаны в истории задачи; отдельные PNG в репозиторий не добавлены.
|
||
|
||
- Серверы: 9 записей, 7 онлайн; Frame/KPI, вкладки типов, фильтры и поиск работают как исходная композиция. На viewport 1280×720 KPI занимают две строки; часть правых колонок таблицы за пределами видимой области. Проверку прокрутки и мобильной компоновки выполнить на этапе 7.
|
||
- Дашборд: KPI с подписями «Флот», «Оверлей», «BGP Rx», «Здоровье»; ниже крупные быстрые переходы, затем график задержки и события. Очередь проблем не доминирует на первом экране — целевая перестройка этапа 6.
|
||
- Это исходный визуальный обзор, не сквозная проверка операций. Проверки консоли, клавиатуры, других размеров и тем остаются в профильных этапах.
|
||
|
||
### Сохраняемые исправления IPsec
|
||
|
||
Последние коммиты исправляют общий IKEv2-peer с отдельными сертификатами клиентов, декодирование .p12 из RouterOS /file/get, отсутствие неподдерживаемых proposal-ключей в .sswan и горизонтальное переполнение шторки сертификата. Эти сценарии включить в регрессию этапов 4, 9, 11А. Ограничение passphrase брать из @mmapp/contracts (IPSEC_MIN_PASSPHRASE), не дублировать.
|
||
Тест ipsec-config проходит отдельно, но отсутствует в общей npm test-цепочке backend; подключить его при следующей правке тестовой инфраструктуры.
|
||
|
||
## Задание этапа 1 (выполнено)
|
||
|
||
Начать с app/(main)/servers/page.tsx, components/data-grids/servers-data-grid.tsx, shared/api/servers.ts и моделей серверов. Не начинать миграцию ReUI в этом этапе.
|
||
|
||
1. Сохранение: блокировать повторную отправку; закрывать форму и менять список только после успеха API. На 400/403/500/сетевой ошибке сохранять значения и показывать сообщение рядом с формой.
|
||
2. Редактирование: загрузить полную модель до разрешения сохранения; защитить от ответа другого сервера и закрытой формы. Не выводить enabled из online/offline. Изменение подключения сбрасывает прежний результат проверки.
|
||
3. Удаление: подтверждение конкретного объекта; не удалять строку при ошибке API; блокировать повтор.
|
||
4. Включение: обновлять enabled через API, фактическую доступность не подменять локальным переключением.
|
||
5. Опрос: результат по устройству; массово не более четырёх запросов одновременно, повтор только неуспешных. Ошибку перечитывания списка отличать от результата самого опроса.
|
||
6. Добавить проверки по HTTP-пути frontend с контролируемыми ответами, а не только встроенный mock. Успех, 403, 500, таймаут, двойное нажатие и смена объекта во время запроса обязательны.
|
||
7. Типизация, lint изменённых файлов, профильные тесты и браузерная проверка; обновить журнал и сделать отдельный локальный коммит без push.
|
||
|
||
Остановка после этапа 0: на последней проверке осталось 15% пятичасовой квоты (было 35% на старте). Этап 1 не начат по согласованному правилу резерва. При продолжении сначала проверить свежие лимиты.
|
||
|
||
## Этап 1 — достоверность операций
|
||
|
||
Исходный HEAD: 88326d9. Изменения предыдущей настройки ReUI и служебные файлы не входят в коммит этапа.
|
||
|
||
- В `app/(main)/servers/page.tsx` сохранение закрывает форму только после подтверждения API. Ошибки остаются рядом с формой, повторные отправки блокируются синхронным замком. Пока загружаются детали, сохранение недоступно; ошибку загрузки можно повторить. Поздний ответ другого объекта игнорируется.
|
||
- Удаление требует подтверждения имени и адреса, при ошибке строка и диалог остаются. Включение изменяет `enabled` через API и не подменяет измеренный online/offline. Изменение параметров подключения сбрасывает прежний результат проверки.
|
||
- `lib/server-operations.ts` содержит замок операций, понятные сообщения ошибок и очередь опроса максимум по четыре запроса. Результат показан по каждому серверу, повторяются только неудачные запросы. Ошибка последующего обновления списка отделена от результата опроса, прежние строки сохраняются.
|
||
- В `shared/api/servers.ts` ожидание ограничено 30 секундами, для опроса — 60. Таймаут явно означает неизвестный результат: клиентское прерывание не отменяет действие на backend. Контракты и маршруты API не изменены.
|
||
- В `components/data-grids/servers-data-grid.tsx` действия блокируются на время операции; выключенный сервер помечается отдельно от доступности.
|
||
- Добавлены Playwright, `playwright.config.ts`, `tests/e2e/servers.spec.ts` и команда `npm run test:servers`. Используется установленный Microsoft Edge, свободный порт 3100 и отдельный Next dev процесс. Запросы API и health перехвачены тестами; встроенный mock-режим не используется. Отчёты исключены из Git.
|
||
|
||
### Проверки этапа 1
|
||
|
||
| Проверка | Результат |
|
||
| --- | --- |
|
||
| `npm run test:servers` | 14 браузерных тестов прошли: создание, сохранение 400/403/500 и повтор, двойное нажатие, удаление с повтором, enabled, загрузка деталей и смена объекта, массовый опрос и повтор, таймаут, отдельная ошибка обновления списка, запрет включения, сброс проверки подключения |
|
||
| TypeScript | Проверка без emit прошла; production build также проверяет типы |
|
||
| `npm run build` | Успешно: contracts, Next.js, TypeScript, 34 статические страницы |
|
||
| ESLint изменённых TS/TSX-файлов | 0 ошибок, 1 известное предупреждение React Compiler о TanStack v8 `useReactTable` |
|
||
| ReUI `get_audit_checklist` | Получен; сохранены установленные компоненты, Frame, семантические токены и типизированный API. Требование TanStack v9 остаётся этапам 2–4; полная доступность и адаптивность — профильным этапам и приёмке |
|
||
|
||
Моки достаточны для этих клиентских сценариев. Реальный backend, права реальных пользователей и применение RouterOS не проверены. Общие исходные ошибки lint перечислены в этапе 0; они не устранены этим этапом. Полную регрессию повторять после миграции общей основы.
|
||
|
||
### Следующий шаг — этап 2
|
||
|
||
В новом окне проверить лимиты, git status и последние коммиты. Создать ветку `codex/reui-v9-migration`, перепроверить актуальный совместимый API ReUI Data Grid/TanStack и Filters. Мигрировать общую оболочку и одну таблицу серверов, закрепить зависимости и описать образец переноса. Сохранить проверки операций из этапа 1. Ветку не выпускать до завершения этапа 4. После этапа — отдельный локальный коммит без push.
|
||
|
||
## Этап 2 — промежуточное сохранение 2026-09-13
|
||
|
||
Ветка `codex/reui-v9-migration`, исходный HEAD `c30f817`. Этап **не завершён**. На старте оставалось 51% пятичасового лимита, после основного блока — 24%; новые блоки остановлены по правилу резерва.
|
||
|
||
### Выполнено
|
||
|
||
- Проверены MCP API и dry-run официального реестра base-nova; установлен Data Grid, новый Filters с Cascader и учебный `components/examples/c-data-grid-1.tsx`. Пример не подключён к маршрутам приложения. 13 общих примитивов при установке не перезаписывались; итоговых изменений глобальной темы нет.
|
||
- Закреплён `@tanstack/react-table` 9.2.4. Для поэтапной совместимости старые таблицы используют alias `@tanstack/react-table-v8` (8.21.3), `components/reui/legacy-data-grid/` и `shared/legacy-data-grid-*`. Это временная изоляция, не эмуляция API v8 поверх v9. Все старые импорты изменены механически; семантика старых экранов сохраняется. Удалить alias и legacy-файлы после последнего потребителя в этапе 4.
|
||
- Канонические `shared/data-grid-shell.tsx`, `data-grid-sort-header.tsx`, `data-grid-layout.ts` типизированы через `DataGridFeatures`. `servers-data-grid.tsx` использует `ColumnDef<DataGridFeatures, Server>` и `useTable({ features: dataGridFeatures, ... })`. Отдельные `get*RowModel` удалены. `manualPagination: true` сохраняет прежний полный список: bundle включает пагинацию по умолчанию, а экран серверов её пока не показывает. Стабильный `getRowId` и раскрытие сохранены.
|
||
- Новый Filters установлен в `components/reui/filters/`; старый `components/reui/filters.tsx` и его шесть потребителей пока работают. При переносе импортировать новый API явно из `@/components/reui/filters/filters`: одноимённый старый файл имеет приоритет над каталогом. Сохранить AND-семантику старых условий; не применять `flattenFilterConditions` как вычислитель вложенных OR-групп.
|
||
|
||
### Проверки и остаток
|
||
|
||
| Проверка | Результат |
|
||
| --- | --- |
|
||
| `tsc --noEmit --incremental false` | Прошла для всего проекта |
|
||
| 14 браузерных тестов операций | Прошли после миграции |
|
||
| Дополнительный тест v9 | Прошёл: 12 строк без потерь, сортировка в обе стороны, раскрытие и закрытие деталей |
|
||
| Lint адаптированной таблицы, общей оболочки и тестов | Прошёл без замечаний |
|
||
| `npm run build` | Прошла: contracts, типы и 34 статические страницы |
|
||
| Lint новых официальных Data Grid / Filters / Cascader | 23 ошибки и 27 предупреждений; [точный список](reui-migration-lint.md). Это незакрытая часть этапа, правила не отключались |
|
||
|
||
Следующий запуск: **продолжить этап 2**, не переходить к этапу 3. Проверить лимит и HEAD; разобрать замечания установленного реестра, подготовить и проверить переход старых Filters в FilterQuery на эталоне серверов, выполнить визуальную и клавиатурную проверку эталона и итоговый ReUI audit. Затем завершить этап отдельным локальным коммитом. Текущее сохранение — промежуточный коммит, без push; ветку не выпускать.
|
||
|
||
Референсы: [пример пагинации](https://reui.io/preview/base/components/c-data-grid-1?ref=mcp), [PRO-таблица](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp), [Data Grid API](https://reui.io/docs/components/base/data-grid?ref=mcp), [Filters API](https://reui.io/docs/components/base/filters?ref=mcp).
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
A[Серверы: реальные API] --> B[DataGridShell]
|
||
B --> C[ReUI Data Grid + TanStack v9]
|
||
D[Остальные таблицы] --> E[Временная оболочка legacy]
|
||
E --> F[TanStack v8 alias]
|
||
G[Старые Filters] -. этапы 2–4 .-> H[FilterQuery: AND / OR]
|
||
```
|
||
|
||
### Малый блок после промежуточного сохранения
|
||
|
||
По отдельному поручению пользователя выполнить работу в пределах 10% квоты; на старте фактически оставалось 9%. В `data-grid.tsx` сериализация `tableLayout` и `tableClassNames` вынесена в именованные ключи зависимостей useMemo. Сравнение по содержимому сохранено, два замечания React Compiler устранены, правила не отключались.
|
||
|
||
Проверки: TypeScript всего проекта прошёл; браузерный тест v9 (12 строк, сортировка, раскрытие) прошёл. Повторный lint группы: **21 ошибка, 27 предупреждений**, актуальный компактный отчёт — `docs/reui-migration-lint.md`. Production build не повторялся после этой локальной правки; предыдущая сборка этапа прошла. Этап 2 остаётся в работе; следующий объём прежний.
|
||
|
||
## Этап 2 — завершение
|
||
|
||
Продолжение от `f9a4a07` в `codex/reui-v9-migration`. Записи о промежуточных остановках выше — история; текущий следующий шаг — **этап 3**.
|
||
|
||
### Результат
|
||
|
||
- Серверы используют ReUI Data Grid/TanStack 9.2.4 и новый `FilterQuery`; таблица сохраняет все строки, сортировку, детали и подтверждённые операции этапа 1. Для раскрытия есть отдельная кнопка с `aria-expanded`, работающая с клавиатуры. При пустом результате фильтрации показывается «Нет совпадений», а не предложение добавить первый сервер.
|
||
- `ServerFilters` повторяет контракт официального `c-filters-1`. Поля `country/status/type` имеют `type: select`, потому что данные скалярные. Варианты множественного выбора задаются операторами. Добавлены русские подписи Filters, вычислитель дерева `applyFilterQuery` и временный `migrateFilterQuery` для AND-массива старых условий. Неизвестное условие не расширяет выборку, незавершённые условия не превращают OR в истинное выражение.
|
||
- `DataPageToolbar.filterControl` позволяет переносить потребителей по одному; старые props сохранены только на период этапов 3–4. Новые импорты Filters обязательно указывают `/filters/filters`, пока существует старый одноимённый файл.
|
||
- Выполнены локальные исправления совместимости исходников ReUI с React Compiler. Контекст Data Grid передаёт актуальный снимок данных; императивный координатор ширины получает только закоммиченные React значения. Кэш подписей Cascader обновляется без мутации ref во время рендера; измерения запускаются через ResizeObserver/кадр браузера, отложенная навигация отменяется при смене контекста. Draft и автооткрытие Filters синхронизируются до рендера дочерних редакторов. Убраны неиспользуемые импорты и лишние вычисления. Правила lint не отключались, публичные API и композиция сохранены. При будущем обновлении реестра эти исправления сравнить с upstream, не перезаписывать автоматически.
|
||
|
||
### Приёмка
|
||
|
||
| Проверка | Результат |
|
||
| --- | --- |
|
||
| `npm run test:servers` | 17 браузерных тестов прошли, включая операции, сортировку 12 строк, фильтрацию AND, изменение/сброс, Escape и клавиатурное раскрытие |
|
||
| `npx tsx --test lib/data-filters/apply-filter-query.test.ts` | 6 тестов прошли: AND/OR, отрицание, черновики, пустые/неизвестные условия, эквивалентность поддерживаемых старых операторов |
|
||
| TypeScript и `npm run build` | Успешно, 34 статические страницы |
|
||
| Lint изменённых участков и новой группы ReUI | 0 ошибок, 1 предупреждение `react-hooks/incompatible-library` для виртуализатора. React Compiler пропускает его оптимизацию; [отчёт](reui-migration-lint.md) |
|
||
| Визуальная проверка | Просмотрены экраны 1440×1000 и 390×844. Page overflow отсутствует; широкая таблица сохраняет горизонтальный скролл внутри своего контейнера |
|
||
| ReUI audit | Checklist получен; проверены композиция Frame/base-nova, API, типизированные HTTP-данные, подписи, состояния и фокус эталона. Правки internals ограничены описанной совместимостью, без смены дизайна |
|
||
|
||
Границы приёмки: моки HTTP не подтверждают реальные права или применение RouterOS. Общая мобильная шапка обрезает часть действий, KPI занимают много высоты — исходные задачи этапов 6–7. Некоторые служебные объявления вложенного Cascader ещё английские — завершить локализацию на этапе 7. Все режимы DnD/виртуализации/автоподбора ширины не были проверены браузером на этом этапе; их проверять при переносе использующих их экранов. Изменённый способ публикации контекста Data Grid требует профилирования больших таблиц на этапе 12. Это не полная приёмка доступности/производительности всего приложения.
|
||
|
||
### Образец следующего переноса
|
||
|
||
1. В выбранном доменном grid заменить `react-table-v8` на `react-table`, legacy-оболочку на `DataGridShell` и заголовки на новый `DataGridSortHeader`.
|
||
2. Тип колонок — `ColumnDef<DataGridFeatures, T>`, таблицы — `Table<DataGridFeatures, T>`. Использовать `useTable({ features: dataGridFeatures, ... })`; удалить старые `get*RowModel`. Сверить переименованные sorting/pinning/resize props с установленным API. Сохранить стабильный `getRowId`.
|
||
3. Явно определить пагинацию: для полного списка без панели — `manualPagination: true`; для серверной — передавать реальный `rowCount`; для клиентской — подключить панель и контролируемую страницу.
|
||
4. Для Filters перенести поля `key → id`, выбрать тип по данным, сохранить AND через `migrateFilterQuery`. Вычислитель сейчас поддерживает только операторы скалярных фильтров серверов и прежние текстовые contains; перед переносом дат, чисел или массивов расширить вычисление и тесты. Нельзя просто сплющить OR-дерево.
|
||
5. Проверить фильтрацию, сортировку, сброс/страницу, раскрытие и действия. Старую основу удалять только после последнего потребителя в этапе 4.
|
||
|
||
Следующий шаг: проверить квоту и состояние файлов; выполнить только этап 3 (обзор, мониторинг, трафик, статистика и справочники) в этой ветке, перечислить оставшихся legacy-потребителей и сделать локальный коммит без push. Перед миграцией виртуализированных таблиц добавить профильные проверки указанного выше риска контекста. Этапы 2–4 не выпускать до общей регрессии этапа 4.
|
||
|
||
## Этап 3 — основные таблицы и справочники
|
||
|
||
Перенесены десять прямых потребителей: `asns-data-grid`, `domains-data-grid`, `ip-ranges-data-grid`, `communities-data-grid`, `compact-data-grid`, `uptime-resources-data-grid`, `uptime-speed-history-data-grid`, `traffic-flows-data-grid`, `traffic/flow-analytics-panel`, `traffic/flow-traffic-map`. Через CompactDataGrid новую основу получили таблицы дашборда, статистики и снимков состояния. Серверы уже перенесены на этапе 2.
|
||
|
||
Используются `useTable`, `dataGridFeatures` и типы v9. Сохранены доменные props, стабильные идентификаторы, раскрытие и обработчики действий. Для списков без панели явно отключена клиентская пагинация; для каталогов EvoBGP она сохранена. Таблицы потоков сохраняют исходный порядок данных. Состояние выбора Communities приведено к типу v9. Общая оболочка получила русские служебные подписи через документированный `i18n`, без изменения установленных примитивов ReUI.
|
||
|
||
| Референс | Схема сохранённого сценария |
|
||
| --- | --- |
|
||
| [Data Grid Filtering 2](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp) | Поиск → страница таблицы → сортировка / выбор строки → детали |
|
||
| [API Data Grid](https://reui.io/docs/components/base/data-grid?ref=mcp) | Типизированные данные → useTable v9 → DataGridShell → таблица и опциональная пагинация |
|
||
|
||
Проверки: TypeScript и целевой ESLint — без ошибок и предупреждений. 17 браузерных тестов серверов прошли. Добавлены 6 сценариев `tests/e2e/migrated-tables.spec.ts`: пагинация и поиск с последней страницы в трёх справочниках, числовая сортировка через границу страницы, выбор одной из 12 Communities, все 12 строк статистики и переход в URL-срез. Первый старт Next.js превысил 120 секунд; повторный старт успешен. Два теста сначала упали из-за неточных селекторов, исправлены и повторно прошли. Все запросы перехватывались HTTP-моками.
|
||
|
||
ReUI audit checklist получен. Сохранены Frame/base-nova, композиция и типизированные источники; новые props сверены с установленными файлами. Просмотрен экран Communities: таблица и выбранная строка отображаются, но правая панель деталей обрезается при ширине 1440 px. Исправить размещение таблицы/деталей при профильной переработке экранов; общую доступность и адаптивность не считать принятой. Существующие неработающие действия справочников также не входят в приёмку миграции. Браузерные проверки всех комбинаций мониторинга, traffic-map и snapshot-деталей остаются для общей регрессии этапа 4 и профильных этапов 7–10. Виртуализатор эти десять компонентов не используют; нагрузочный профиль общей основы остаётся этапу 12.
|
||
|
||
Production build прошёл: `npm run build`, 34 статические страницы. Последняя проверка квоты перед завершением блока: использовано 37% пятичасового окна и 50% недельного; это общий расход аккаунта, не оценка стоимости этапа.
|
||
|
||
### Остаток для этапа 4
|
||
|
||
- Доменные legacy-таблицы: backups, bgp-sessions, certificates, data-collection-scheduler, filters, firewall-rules, firewall-scenario-rules, gre-pools, gre-tunnels, ospf-bfd, ospf-neighbors, ospf-routes, probes-schedule, probes-speed-probes, recursive-routes, route-optimizer-comm-recs, route-optimizer-full-routes, route-optimizer-ospf-preview, route-optimizer-wan-matrix, subusers, users, vxlan, wireguard, wireguard-peers, ipsec-users-grid.
|
||
- Общая основа: `components/data-table.tsx`, `components/data-grids/shared/legacy-*`, `components/reui/legacy-data-grid/*`; ссылки на legacy layout в DataPageCard и DataPageToolbar. Проверить отсутствие потребителей перед удалением.
|
||
- Старые Filters: статистика, BGP, backups, backups-history и fallback DataPageToolbar; старые определения полей/вычислитель. Статистика передаёт в API только равенство скалярных срезов: при переносе нельзя принимать OR/отрицание и молча превращать их в равенство. Сохранять незавершённый черновик отдельно от URL.
|
||
|
||
Следующий шаг: проверить квоту и git status; начать этап 4 в `codex/reui-v9-migration`, переносить оставшихся потребителей ограниченными группами, затем удалить v8/старые Filters и выполнить общую регрессию. Ветку до этой проверки не выпускать. Коммит этапа 3 — только локальный, без push; настройки skills/AGENTS/.codex других работ не включать.
|
||
|
||
## Этап 4 — блок 1: BGP и OSPF
|
||
|
||
Перенесены `bgp-sessions-data-grid`, `ospf-neighbors-data-grid`, `ospf-routes-data-grid`, `ospf-bfd-data-grid`. Использована установленная основа ReUI v9 (`useTable`, `dataGridFeatures`, современная оболочка и заголовки); `manualPagination: true` сохраняет полный список. Стабильные row ID, сортировка, раскрытие BGP и управляемый выбор OSPF сохранены. Убрано неиспользуемое извлечение `onHighlight` из props, сам внешний контракт не менялся.
|
||
|
||
Проверки: `npx tsc --noEmit --incremental false` и целевой ESLint успешны. Три сценария `tests/e2e/routing-tables.spec.ts` подтвердили 12 строк во всех четырёх таблицах, числовую сортировку, выбор OSPF-соседа, раскрытие/сворачивание BGP после сортировки и пустые ответы API. Один тест сначала ожидал сокращённый текст пустого BFD; после уточнения селектора прошёл. Это HTTP-моки, не подтверждение реальной работы сетевых протоколов. Общая основа не менялась, повторная полная сборка/регрессия отложены до завершения этапа 4.
|
||
|
||
ReUI checklist получен: сохранены композиция, props установленного API, источники данных и оформление. Полная клавиатурная доступность действий строк, мобильная компоновка и сценарии графа остаются профильному этапу 10 и итоговой приёмке; текущие тесты их не подтверждают.
|
||
|
||
Квота: на старте использовано 49%, после блока 58% пятичасового окна (общий расход аккаунта). Этап 4 не завершён. BGP и три OSPF-таблицы исключить из списка оставшихся выше; остальные legacy-таблицы и все перечисленные старые Filters ещё остаются.
|
||
|
||
Точный следующий шаг: проверить git status и квоту, перенести VPN-группу (`wireguard-data-grid`, `wireguard-peers-grid`, `ipsec-users-grid`, `gre-pools-data-grid`, `gre-tunnels-data-grid`, `vxlan-data-grid`) с профильными проверками. Затем перейти к оставшимся таблицам управления/диагностики и миграции Filters. Старые зависимости удалять только после последнего потребителя. Этот блок сохранить отдельным локальным коммитом без push; ветку не выпускать.
|
||
|
||
## Этап 4 — блок 2: WireGuard
|
||
|
||
Перенесены `wireguard-data-grid` и `wireguard-peers-grid` на установленную основу ReUI v9. Сохранены внешние props, идентификаторы, обработчики операций и раскрытие интерфейса. Явное `manualPagination: true` сохраняет все строки без скрытого ограничения в десять записей. Общие примитивы и сетевые операции не менялись.
|
||
|
||
Проверки: TypeScript (`--incremental false`) и целевой ESLint прошли без замечаний. Два браузерных сценария `tests/e2e/wireguard-tables.spec.ts` прошли: 12 интерфейсов, сортировка по порту, раскрытие/сворачивание пиров выбранного интерфейса, 12 строк отдельной вкладки пиров, сортировка и пустые состояния обеих вкладок. Фикстура проверяется схемой `wgListResponseSchema`, ответы подменяются на HTTP-уровне. Реальные операции RouterOS и права этими тестами не проверены; их приёмка остаётся этапу 9. Применён уже полученный ReUI checklist: сохранены композиция, публичный API и оформление; полная доступность и адаптивность ещё не приняты.
|
||
|
||
Квота на старте: использовано 67% пятичасового окна; после браузерных проверок — 74% (остаток 26%). Новый блок не начинать на границе резерва. Полная сборка и общая регрессия остаются завершению этапа 4, общая основа в этом блоке не менялась.
|
||
|
||
Следующий шаг после проверки квоты: перенести оставшиеся четыре VPN-таблицы `ipsec-users-grid`, `gre-pools-data-grid`, `gre-tunnels-data-grid`, `vxlan-data-grid`. WireGuard, BGP и три OSPF-таблицы уже исключены из остатка. Остальные таблицы управления/диагностики и старые Filters ещё не перенесены; этап 4 не завершён, ветку не выпускать. Блок WireGuard сохранить локальным коммитом без push.
|
||
|
||
## Этап 4 — блок 3: VXLAN
|
||
|
||
По явному поручению пользователя продолжить ниже резервного порога выполнен один небольшой блок: `vxlan-data-grid` перенесён на установленную ReUI v9-оболочку. Использованы `useTable`, `dataGridFeatures`, типы v9 и `manualPagination: true`; сохранены идентификаторы, сортировка и обработчик экспорта. Общая основа не менялась.
|
||
|
||
TypeScript (`--incremental false`), целевой ESLint и браузерный сценарий `tests/e2e/vxlan-table.spec.ts` прошли. Проверены 12 строк, числовая сортировка VNI, открытие экспорта выбранного туннеля после сортировки, поиск, пустой результат и сброс. Использованы типизированные HTTP-моки; скачивание файла, применение RouterOS и существующие пункты редактирования/включения/удаления этим тестом не проверены. По ранее полученному ReUI checklist сохранены композиция, публичный API и оформление; профильная доступность и адаптивность остаются этапу 9. Полная регрессия остаётся завершению этапа 4.
|
||
|
||
После проверок осталось 8% пятичасового лимита (общая квота аккаунта). Блок сохранить локальным коммитом без push. Следующий шаг после сброса: `ipsec-users-grid`, `gre-pools-data-grid`, `gre-tunnels-data-grid`; затем оставшиеся таблицы управления/диагностики и старые Filters. VXLAN исключить из предыдущего списка остатка. Этап 4 не завершён, ветку не выпускать.
|
||
|
||
## Этап 4 — блок 4: IPsec и GRE (2026-09-14)
|
||
|
||
Перенесены `ipsec-users-grid`, `gre-tunnels-data-grid`, `gre-pools-data-grid`: `useTable`, `dataGridFeatures`, типы и общая оболочка ReUI v9. Явное `manualPagination: true` сохраняет полный список. Сохранены существующие идентификаторы и обработчики; ID GRE по-прежнему включает индекс исходных данных, его стабильность при переупорядочивании ответа API не улучшалась в этом блоке. Установленные примитивы и сетевые правила не менялись.
|
||
|
||
Проверки: TypeScript (`--incremental false`), целевой ESLint и три браузерных сценария `tests/e2e/ipsec-gre-tables.spec.ts` прошли. Проверены 12 клиентов IPsec, сортировка и подтверждение удаления выбранного клиента с отменой; 12 GRE-туннелей и производных пулов, числовая сортировка MTU, поиск, сортировка пулов и пустые ответы API. Селектор заголовка «Клиент» уточнён после совпадения с кнопкой панели. IPsec-фикстура валидируется контрактной схемой; GRE типизирован через доменную модель. Используются HTTP-моки: применение RouterOS, удаление клиента и экспорт сертификата этим прогоном не проверены.
|
||
|
||
ReUI checklist получен; сохранены публичный API, композиция и оформление. Полная доступность, адаптивность, работа операций и существующие декоративные действия GRE-пулов остаются профильному этапу 9 и итоговой приёмке. Общая основа не менялась; полная сборка и регрессия остаются завершению этапа 4.
|
||
|
||
Квота: в начале использовано 1%, после проверок 18% пятичасового окна (общий расход аккаунта). VPN-группа миграции завершена, этап 4 в целом ещё открыт. Следующий конкретный блок — `users-data-grid`, `subusers-data-grid`, `certificates-data-grid`, `backups-data-grid`; затем оставшиеся таблицы диагностики/управления и Filters. Только после последнего потребителя удалить legacy-основу и v8 и выполнить общую регрессию. Блок IPsec/GRE сохранить локальным коммитом без push; ветку до завершения этапа 4 не выпускать.
|
||
|
||
## Этап 4 — блок 5: таблицы администрирования (2026-09-14)
|
||
|
||
Перенесены `users-data-grid`, `subusers-data-grid`, `certificates-data-grid`, `backups-data-grid` на установленный API ReUI v9 с явным `manualPagination: true`. Сохранены идентификаторы, обработчики и раскрытие. `SubusersDataGrid` сейчас не имеет потребителей в app/components; для него выполнена статическая проверка, браузерная приёмка не заявляется.
|
||
|
||
Браузерная проверка выявила сортировку размера бэкапа по форматированной строке. В `Backup` добавлено необязательное `sizeBytes`; страница сохраняет число байтов из API, таблица сортирует по нему. Отображение размера не менялось. При отсутствии исходного числа запись считается неизвестной и располагается в конце (`sortUndefined: "last"`), строка не превращается в выдуманное число. Старые демонстрационные объекты без sizeBytes не дают числовой сортировки; текущая страница загружает бэкапы через API.
|
||
|
||
Три сценария `tests/e2e/admin-tables.spec.ts` прошли: 12 пользователей и сертификатов с сортировкой/раскрытием, SAN выбранного сертификата, 12 бэкапов с числовой сортировкой и правильным файлом в подтверждении удаления с отменой. Исправлены неполные HTTP-фикстуры настроек сертификатов, вызывавшие предупреждения controlled/uncontrolled. Реальные права, удаление, восстановление и операции сертификатов этим прогоном не проверены. Общая сборка/регрессия остаётся завершению этапа 4.
|
||
|
||
Применён полученный ReUI checklist: сохранены композиция и установленный API; полная доступность и адаптивность остаются профильной приёмке. Квота: использовано 26% на старте, 50% после браузерных проверок (общий расход аккаунта). Блок сохранить локальным коммитом без push.
|
||
|
||
Следующий блок: `filters-data-grid`, `firewall-rules-data-grid`, `firewall-scenario-rules-data-grid`. Затем `data-collection-scheduler-data-grid`, `probes-schedule-data-grid`, `probes-speed-probes-data-grid`, `recursive-routes-data-grid` и четыре `route-optimizer-*-data-grid`. Также остаются общая legacy-основа, `components/data-table.tsx`, старые Filters и зависимость v8. Этап 4 не завершён, ветку не выпускать.
|
||
|
||
Статические проверки блока 5: TypeScript прошёл; lint четырёх таблиц, фикстур и доменной модели — без замечаний. Расширенный lint `app/(main)/backups/page.tsx` обнаружил исходную ошибку `react-hooks/set-state-in-effect` на `void loadLive()` в эффекте (подтверждено в HEAD до правок). Эта ошибка не исправлялась в миграции; устранить при работе над состояниями данных на этапе 5. Не считать lint всей страницы успешным.
|
||
|
||
## Этап 4 — блок 6: таблица сетевых Filters (2026-09-14)
|
||
|
||
`filters-data-grid` перенесён на установленную ReUI v9-основу с полным списком (`manualPagination: true`). Сохранены props, ID, обработчики и действующее отключение сортировки в live-режиме. Кнопки поднятия/опускания правила получили доступные подписи с community. Это миграция таблицы сетевых правил; старый компонент построения Filters/FilterQuery этим блоком не затронут.
|
||
|
||
TypeScript и целевой ESLint прошли. Браузерный сценарий `tests/e2e/network-filters-table.spec.ts` подтвердил 12 строк, исходный порядок и отсутствие кнопки сортировки в live-режиме, блокировку перемещения за границы, поиск/пустой результат/сброс. Первый вариант теста ошибочно ожидал доступную сортировку; ожидание исправлено под существующий контракт страницы. HTTP-моки не подтверждают перестановку и применение правил к RouterOS. Применён ранее полученный ReUI checklist; профильная приёмка операций и доступности остаётся этапу 9.
|
||
|
||
Квота: на старте использовано 64%, после статических проверок — 78% (остаток 22%). Новые блоки не начинать в резерве. Firewall не переносился: `firewall-rules-data-grid` использует DnD и требует чтения нового API и профильного браузерного теста перетаскивания с проверкой порядка. Следующий блок после проверки квоты — обе Firewall-таблицы; далее восемь таблиц диагностики/сборщика, общие legacy-потребители, старые Filters и удаление v8. Этап 4 остаётся открытым, ветку не выпускать. Сохранить локальный коммит без push.
|
||
|
||
## Этап 4 — блок 7: Firewall и DnD
|
||
|
||
Перенесены `firewall-rules-data-grid` и `firewall-scenario-rules-data-grid`. Общая основа — установленный ReUI v9; полный список сохранён через `manualPagination: true`. В режиме DnD применён `manualSorting: reorderable`, в локальном сценарии — `manualSorting: true`. Сохранены row ID, обработчики, формат запросов и правила допустимости перемещения. Props `DataGridTableDndRows` сверены с установленным исходником: `dataIds`, `handleDragEnd`. Примитивы ReUI не менялись. Действия сценария получили подписи поднятия/опускания/удаления и видимость при фокусе.
|
||
|
||
Пять браузерных сценариев `tests/e2e/firewall-tables.spec.ts` прошли: клавиатурное и мышиное перемещение среди 12 правил, правильные rosId/destinationRosId в API, откат при ошибке 500, Escape без запроса, 12 правил локального сценария с перестановкой и удалением выбранной строки. Начальные падения объяснялись преждевременным завершением переноса в тесте; добавлено ожидание фактической смены цели DnD через live-region. Тесты используют HTTP-моки, не подтверждают применение RouterOS. Перенос между серверами/таблицами, touch, сортируемый режим общего списка и поведение на больших наборах остаются профильной и общей регрессии.
|
||
|
||
TypeScript и целевой ESLint прошли. ReUI checklist получен: сохранены композиция и публичный API; проверены мышь/клавиатура и отмена переноса. Служебные объявления DnD пока английские — локализовать при профильной доступности, не считать её полностью принятой. Остальные ограничения предыдущих блоков сохраняются.
|
||
|
||
Квота: использовано 0% на старте обновлённого окна, 34% после профильных тестов (общая квота аккаунта). Следующий блок — `data-collection-scheduler-data-grid`, `probes-schedule-data-grid`, `probes-speed-probes-data-grid`; затем `recursive-routes-data-grid` и четыре `route-optimizer-*-data-grid`. После них остаются общая legacy-основа/`data-table`, старые Filters и удаление v8 с полной регрессией. Этап 4 ещё не завершён; локальный коммит без push, ветку не выпускать.
|
||
|
||
Production build блока 7: `npm run build` прошёл, 34 статические страницы. Это проверка сборки, не замена общей регрессии этапа 4.
|
||
|
||
## Этап 4 — блок 8: сборщик и расписания проб (2026-09-14)
|
||
|
||
Перенесены `data-collection-scheduler-data-grid`, `probes-schedule-data-grid`, `probes-speed-probes-data-grid` на установленный ReUI Data Grid/TanStack v9: `useTable`, `dataGridFeatures`, общая современная оболочка и заголовки. Сохранены идентификаторы строк, обработчики и порядок задач сборщика; автоматическая пагинация отключена. Кнопка запуска задачи получила доступное имя с названием задачи.
|
||
|
||
Проверки: TypeScript без incremental и ESLint изменённых файлов; три сценария Playwright — 12 speed-probes и сортировка источника, все 11 задач сборщика и POST выбранного `alert_engine/run-now`, сортировка и удаление выбранного правила демонстрационного расписания. Финальный браузерный прогон: 3 passed. Исправлены неполные фоновые HTTP-фикстуры EvoBGP, GeoIP и Traffic Flow; повторный прогон без предупреждений controlled/uncontrolled. Live-ветки проверены с подменой HTTP, обычное расписание — отдельно во встроенном mock-режиме. Реальное исполнение задач и RouterOS не проверялись.
|
||
|
||
Первичная проверка TypeScript до браузерного запуска прошла. Финальная повторная проверка после Playwright заблокирована двумя TS2304 в сгенерированном `.next/dev/types/validator.ts` (строки 379 и 388: отсутствует `RouteHandlerConfig`). `next typegen` успешно обновил типы, но ошибку dev-кэша не устранил. Исходники и конфигурация TypeScript ради обхода ошибки не менялись. При продолжении проверить dev-кэш и повторить tsc; финальный TypeScript не считать пройденным. ESLint изменённых файлов прошёл.
|
||
|
||
Применены правила установленного ReUI и ранее полученный checklist: публичный API и существующая композиция сохранены, полная визуальная/адаптивная приёмка остаётся последующим этапам. Общая основа не менялась; полная регрессия — после завершения миграции.
|
||
|
||
Квота: использовано 46% на старте, 81% перед финальными проверками. Остаток ниже резерва 25%, новые блоки не начинать. Следующий шаг — `recursive-routes-data-grid` и четыре `route-optimizer-*-data-grid`; далее `data-table`, общие legacy-потребители, старые Filters и удаление v8 с общей регрессией. Этап 4 остаётся открытым; сохранить блок локальным коммитом без push, ветку не выпускать.
|
||
|
||
## Этап 4 — блок 9: рекурсивные маршруты (2026-09-14)
|
||
|
||
По прямому указанию пользователя продолжена работа ниже резерва квоты (89% использовано на старте). `recursive-routes-data-grid` переведён на установленную общую оболочку ReUI/TanStack v9, сохранены управляемое раскрытие по ключу группы, сортировка, обработчики редактирования/удаления и отсутствие пагинации.
|
||
|
||
Проверки: Playwright `recursive-routes-table.spec.ts` — 1 passed (12 групп через HTTP-мок, сортировка в обе стороны, раскрытие и закрытие деталей после сортировки, отсутствие pageerror); ESLint компонента и теста — успешно. TypeScript до и после браузерного прогона — успешно. Реальные сетевые изменения не проверялись.
|
||
|
||
Уточнение блока 8: в `.next/types/validator.ts` присутствовала полноценная декларация `RouteHandlerConfig` и проверки обоих API-маршрутов. Удалён только ошибочный сгенерированный `.next/dev/types/validator.ts`; исходники, tsconfig и production-validator сохранены. После этого tsc прошёл, в том числе после нового запуска Playwright. Ошибка предыдущей финальной проверки снята; правка кеша не входит в Git.
|
||
|
||
После блока использовано 95% пятичасовой квоты. Следующий блок — четыре `route-optimizer-*-data-grid`, затем общие legacy-потребители/`data-table`, старые Filters и удаление v8 с полной регрессией. Этап 4 не завершён. Этот блок сохранить локальным коммитом без push.
|
||
|
||
## Этап 4 — блок 10: оптимизатор маршрутов (2026-09-14)
|
||
|
||
Четыре `route-optimizer-*-data-grid` перенесены на установленный ReUI/TanStack v9. Сохранены динамические колонки WAN × JH, отсутствие сортировки матрицы, раскрытие списка комбинаций (5 → все), сортировка и ключи Community, состояния загрузки/ошибки/пустого OSPF preview. Удалены два неиспользуемых импорта.
|
||
|
||
Проверки: TypeScript до и после Playwright — успешно; ESLint всех четырёх компонентов и нового теста — без замечаний. `route-optimizer-tables.spec.ts`: 4 passed, включая 12 WAN, 12 комбинаций, сортировку и закрепление выбранной Community, 12 интерфейсов OSPF и числовую сортировку, пустой ответ и HTTP 500 preview. Первый прогон имел запрос при завершении теста к отключённому backend; добавлено ожидание загрузки основной таблицы, повторный прогон без этого сообщения. Проверки используют live-ветку с HTTP-моками; применение RouterOS не выполнялось.
|
||
|
||
Обнаруженный исходный долг для этапов 5/10: `applyRec` страницы имитирует успех через таймер даже в live-режиме; `buildLiveOptimizerData` рассчитывает вероятности Community из длины строки и использует оценочные ping/bandwidth при отсутствии замеров. Тест закрепления не подтверждает реальность применения или достоверность этих оценок. Алгоритмы в блоке миграции не менялись.
|
||
|
||
Квота: новое окно 0% на старте, 13% использовано после проверок, недельная — 91%. Остаток Data Grid: `components/data-table.tsx`, layout-импорты `DataPageCard`/`DataPageToolbar` и затем удаление общей legacy-основы/v8. Старые Filters остаются у BGP, statistics, backups, backups-history и в fallback DataPageToolbar. Этап 4 не завершён; сохранить блок локальным коммитом без push.
|
||
|
||
## Этап 4 — блок 11: удаление старого Data Grid (2026-09-14)
|
||
|
||
Мигрирована общая `DataTable` с сохранением опциональной клиентской пагинации (`manualPagination: !pagination`). `DataPageCard` и `DataPageToolbar` используют современный layout; значения CSS-классов совпадают с прежними. Удалены 14 файлов неиспользуемой legacy-копии и обёрток, а также alias `@tanstack/react-table-v8` и его вложенная зависимость из package.json/lockfile. Версия v9 остаётся 9.2.4. Поиск по app/components/lib/package.json/package-lock.json больше не находит импортов legacy Data Grid/v8.
|
||
|
||
Проверки после удаления общей основы: TypeScript и ESLint изменённых обёрток — успешно; вся браузерная регрессия — **49 passed**; production build — успешно, 34 статические страницы. У `DataTable` сейчас нет потребителей, её generic API проверен компилятором; пагинация рабочих таблиц покрыта регрессией справочников. Next.js сообщил о восстановлении SWC lockfile, итоговый diff lockfile содержит только удаление v8 и вложенного table-core. Старый Filters ещё не удалён: этап 4 остаётся открытым, ветку не выпускать.
|
||
|
||
Следующий блок — BGP и backups/backups-history на FilterQuery, затем statistics с явным ограничением на поддерживаемые API-срезы (AND равенств) и удаление старого Filters/fallback. Сохранить текущий блок отдельным локальным коммитом без push.
|
||
|
||
## Этап 4 — блок 12: Filters BGP и резервных копий (2026-09-14)
|
||
|
||
BGP, backups и BackupsHistory используют FilterQuery и современный `QueryFilters` через `filterControl`. Поля переведены на FilterField; scalar-поля с несколькими вариантами используют select и операторы выбора. Фильтрация выполняется общим рекурсивным evaluator с сохранением AND/OR и черновиков. Для текстового поля «Сервер» добавлены поддерживаемые ReUI операции starts_with/ends_with, включая отрицание и сравнение без учёта регистра.
|
||
|
||
Проверки: TypeScript — успешно; 8 профильных браузерных тестов BGP/OSPF/администрирования — passed, включая фильтрацию, изменение значения, AND и сброс; 7 unit-тестов evaluator — passed. Первый запуск tsx в sandbox завершился системной ошибкой uv_os_get_passwd ENOMEM; повтор вне sandbox прошёл. ESLint без ошибок в проверенных файлах, в BGP остаются 7 исходных предупреждений неиспользуемых импортов/StateBadge; известная исходная ошибка effect в backups/page не исправлялась этим блоком, lint всей этой страницы не заявляется чистым.
|
||
|
||
После блока использовано 42% пятичасовой и 96% недельной квоты. Остались statistics, старый fallback DataPageToolbar и старые Filters/helper; после их удаления повторить общие проверки. Сохранить блок локальным коммитом без push. Этап 4 остаётся открытым.
|
||
|
||
## Этап 4 — подготовка блока 13: адаптер статистики (2026-09-14)
|
||
|
||
Добавлен независимый `statistics-filter-query.ts`: преобразование URL-срезов в FilterQuery и строгий обратный адаптер с результатами valid/draft/invalid. Поддерживается только AND равенств скалярным строкам; OR, отрицание, массивы, неизвестные поля и конфликтующие значения не преобразуются молча. Незавершённый черновик не возвращает частичный набор срезов. Страна нормализуется в двухбуквенный код, ASN/serverId проверяются как положительные безопасные целые; недопустимые значения не обрезаются и не очищаются до другого числа.
|
||
|
||
Проверки: 5 unit-тестов адаптера, ESLint и TypeScript — успешно. Адаптер пока не подключён к экрану: это подготовительный checkpoint, а не завершение миграции statistics.
|
||
|
||
Точный следующий шаг: создать StatisticsFilters с отдельным локальным черновиком FilterQuery и отображением ошибки адаптера; обновлять URL/запрос только при valid, сохранять прежние срезы при draft/invalid; синхронизировать внешний переход/сброс URL с черновиком. Полям дать только оператор is, остальные неподдерживаемые выражения всё равно проверять адаптером. Затем удалить старые slicesToFilters/filtersToSlices страницы, fallback DataPageToolbar, `components/reui/filters.tsx` и неиспользуемый старый evaluator после проверки всех импортов. Unit-тест совместимости со старым evaluator заменить самостоятельными ожидаемыми результатами. Завершить браузерными тестами URL/черновика/ошибки и общей регрессией, только затем закрывать этап 4.
|
||
|
||
Квота после подготовки: 49% пятичасовой и 97% недельной использовано. Сохранить подготовку локальным коммитом без push. Чужие изменения skill/AGENTS/.codex не включать.
|
||
|
||
## Этап 4 — блок 13: подключение Filters статистики (2026-09-14)
|
||
|
||
StatisticsFilters подключён вместо старого массива Filter. Поля предлагают только is, адаптер дополнительно отклоняет неподдерживаемые выражения. Локальный черновик не изменяет URL до явного «Применить срез»; invalid/draft блокируют применение и сохраняют действующие срезы. Ключ редактора зависит от URL-срезов, поэтому внешний переход сбрасывает черновик. Старые функции slicesToFilters/filtersToSlices страницы удалены.
|
||
|
||
TypeScript до и после первого браузерного прогона и scoped ESLint прошли. Расширенный браузерный сценарий статистики прошёл: сортировка/переход в срез, восстановление фильтра из URL, редактирование без изменения URL, применение, сброс, отклонение RUS без обрезания до RU и внешняя смена страны на DE. В первом расширенном прогоне исправлен неоднозначный локатор alert; повтор — 1 passed. Проверки через HTTP-моки.
|
||
|
||
На последнем чтении использовано 62% пятичасовой и 99% недельной квоты. Старые Filters/fallback/helper ещё физически остаются, поэтому этап 4 НЕ завершён. Следующий шаг — удалить неиспользуемый fallback DataPageToolbar и старые Filters/evaluator после проверки импортов, обновить тест совместимости, затем выполнить полную регрессию и production build. Сохранить этот блок локальным коммитом без push.
|
||
|
||
## Этап 4 — завершение: удаление старого Filters (2026-09-20)
|
||
|
||
Удалены `components/reui/filters.tsx`, `apply-reui-filters.ts` и временный `migrate-filter-query.ts`. У DataPageToolbar удалены устаревшие props filters/onFiltersChange/filterFields и их fallback; все четыре действующих потребителя используют filterControl и FilterQuery. Props filters/onFiltersChange у BackupsHistory остаются внутренним контрактом нового FilterQuery, а не старого Filters. Unit-тест сравнения двух реализаций заменён независимыми ожидаемыми результатами для шести операторов с AND.
|
||
|
||
| Финальная проверка миграции | Результат |
|
||
| --- | --- |
|
||
| Поиск старых FilterFieldConfig/applyReuiFilters/migrateFilterQuery, legacy-data-grid и react-table-v8 в app/components/lib/tests/package.json/package-lock.json | Совпадений нет |
|
||
| Unit-тесты дерева FilterQuery | 7 passed |
|
||
| Unit-тесты адаптера статистики | 5 passed |
|
||
| TypeScript без incremental | Успешно |
|
||
| ESLint изменённых файлов | Успешно |
|
||
| Полная браузерная регрессия | 51 passed, 2.4 минуты |
|
||
| Production build | Успешно, 34 статические страницы |
|
||
| git diff --check изменённых файлов | Успешно |
|
||
|
||
Получен актуальный ReUI MCP `get_audit_checklist`: в этом блоке сохранены установленная композиция, публичный API и тема, новых данных/интерактивных элементов/секретов не добавлено. Миграция Data Grid/TanStack v9 и Filters завершена; старые временные API больше не нужны. Это завершение технической миграции, а не полной UX/UI-приёмки: остаются ранее записанные ограничения адаптивности/доступности, исходные lint-долги страниц, имитация Community apply и оценки в оптимизаторе. Реальные RouterOS, права на сетевые операции и все состояния backend по мокам не подтверждены. Полный repository lint не заявляется чистым; профильные проверки изменённых участков и production build прошли.
|
||
|
||
Квота: 2% пятичасовой/0% недельной использовано на старте; после регрессии — 32%/5%. Этап 4 сохранить локальным коммитом без push. Изменения skills/AGENTS/.codex другой работы не включать. Общую регрессию этапа 4 считать выполненной; автоматический merge, push или релиз не выполнялись.
|
||
|
||
**Следующий этап 5:** `hooks/use-dashboard-live.ts` и `app/(main)/dashboard/page.tsx`. Подтверждено чтением: fetchSnapshot уже использует Promise.allSettled, но при ошибках очищает probes/servers/BGP/traffic/overlay, а fetchRecentEvents очищает события; обновления запускаются из нескольких effects и таймеров без защиты результатов запросов. Ввести состояния/свежесть по источникам и сохранение последних успешных данных; отличать начальную ошибку от частичного сбоя и фонового обновления. Защитить смену backend/mode и перекрывающиеся запросы от поздних результатов, включая дополнительные запросы Internet Path. Проверить HTTP-моками первоначальную ошибку, частичный сбой, повторное восстановление и гонки; профильный UX показывать без подмены неизвестных данных нулями. Зафиксировать отдельным коммитом этапа 5.
|
||
|
||
## Этап 5 — состояния данных дашборда (2026-09-20)
|
||
|
||
`use-dashboard-live` сохраняет последние успешные servers/probes/BGP/traffic/events и отдельные GRE/WireGuard/VXLAN при сбоях. Состояние и время успешного получения ведутся по девяти источникам; Internet Path дополнительно показывает серверный sampledAt. Новый DashboardDataStatus использует существующие Alert/Button, сообщает частичный сбой, раскрывает время/ошибки источников и позволяет повторить загрузку. Неизвестные KPI отображаются как «—», пустые очереди проблем при недоступных источниках больше не утверждают «всё исправно». При фоновом обновлении сохранённые данные остаются видимыми.
|
||
|
||
Для snapshot и событий введены независимые счётчики запросов: применяются только результаты последнего запроса, включая дополнительные await Internet Path; cleanup инвалидирует незавершённые ответы при смене контекста или размонтировании. Убран дублирующий первоначальную загрузку effect по pathname. Смена backend/mode очищает данные предыдущего контекста. Это защита состояния, а не отмена уже отправленных HTTP-запросов.
|
||
|
||
Internet Path использует успешный серверный снимок независимо от сбоя списка серверов. Ошибка snapshot или обязательных данных fallback сохраняет старую модель; ошибки дополнительных lookup/wan-runtime/speed-probes не маскируются новым пустым снимком. Сами сетевые команды и правила выбора маршрутов не менялись.
|
||
|
||
Проверки: TypeScript и scoped ESLint — успешно; **5 браузерных сценариев passed**: начальная ошибка и восстановление, частичный сбой с сохранением данных/событий/времени, поздний основной ответ, ошибка дополнительной загрузки Internet Path, поздний дополнительный ответ. Для проверки поздних ответов тест дожидается завершения HTTP и двух кадров отрисовки. Сценарий частичного сбоя дополнительно повторён на ширине 390; скриншоты 1440/390 просмотрены, новый блок не обрезан, восстановление доступно. Получен ReUI checklist; используются существующая композиция, семантические цвета, role=status/alert и подписанная кнопка type=button. Общая основа ReUI не менялась, полная регрессия/production build не повторялись после успешной приёмки этапа 4 в этом окне.
|
||
|
||
Границы: браузерные проверки идут через HTTP-моки; реальная свежесть RouterOS не подтверждена. Время «Получено» обозначает успешный ответ API, не новый замер устройства; sampledAt показан отдельно, где доступен. Смена backend/mode защищена cleanup, но отдельный браузерный сценарий смены backend не запускался (в e2e backend фиксирован конфигурацией). Существующие доменные допущения вроде null server.status → offline и оценочных метрик оптимизатора относятся к следующим профильным этапам.
|
||
|
||
Квота: 41% пятичасовой на старте, 73% после профильных проверок (недельная 11%). Следующий этап 6 — общая оболочка и дашборд: показать одну схему ПК/телефона по App Shell 12/Stats 12, затем улучшать навигацию, контекст и очередь проблем с переходами к объектам. Этот этап сохранить отдельным локальным коммитом без push; настройки skills/AGENTS/.codex не включать.
|
||
|
||
## Этап 6 — блок 1: схема и адаптивная шапка (2026-09-20)
|
||
|
||
Схема ПК/телефона и таблица референсов сохранены в `docs/ux-ui-stage-6.md`. PageHeader сохраняет установленные SidebarTrigger/Breadcrumb/AppsMenu/SystemMonitorPopover: текущая страница видна на телефоне, действия переносятся, фиксированная высота снята. У Breadcrumb корректные прямые li внутри ol и русское доступное имя. Примитивы ReUI, зависимости и backend не менялись.
|
||
|
||
Проверки: TypeScript и scoped ESLint успешны. Четыре браузерных сценария шапки (320/390/1024/1440 px) прошли: геометрия заголовка/кнопок, меню с клавиатуры, Escape и возврат фокуса. Дополнительно прошли таблица рекурсивных маршрутов и мобильный сценарий серверов. Просмотрены скриншоты 320/1440. Первый запуск теста ошибочно искал banner: header внутри main этой роли не имеет; локатор исправлен без изменения семантики приложения. ReUI validate_usage/checklist получены ранее, используются установленные API и семантические цвета.
|
||
|
||
Предыдущая попытка запуска была остановлена ошибкой автоматической проверки разрешений из-за исчерпанной квоты; после сброса проверка запуска прошла. На старте этого продолжения использовано 2% пятичасовой и 16% недельной квоты. Этап 6 остаётся открытым. Следующий блок — единый список Sidebar/CommandPalette и стандартное управление фокусом поиска, затем дашборд и ссылки очереди. Локальный коммит без push; файлы настройки другой работы не включать.
|
||
|
||
## Этап 6 — блок 2: навигация и поиск (2026-09-20)
|
||
|
||
`lib/navigation.ts` — общий каталог 30 страниц, групп, иконок и поисковых синонимов. AppSidebar и CommandPalette используют его вместо двух независимых списков. Названия «Мониторинг» и «Communities» согласованы; поисковые синонимы uptime/BGP сохранены. NavMain получил именованный nav и aria-current; мобильная шторка закрывается при клиентском переходе, включая выбор текущей страницы.
|
||
|
||
CommandPalette использует установленные Command/cmdk и Base UI Dialog вместо самописного затемнённого окна и ручной навигации. Фокус при открытии переходит в поиск, Tab удерживается внутри, Escape возвращает фокус; ввод сбрасывается при новом открытии. Поддержаны поиск по синонимам, стрелки/Enter, объявление пустой выдачи, светлая/тёмная тема. Высота списка ограничена высотой диалога и viewport. Новые зависимости и примитивы не устанавливались; данные/API и схема прав не менялись.
|
||
|
||
Профильные проверки: 4 сценария navigation passed (один проверяет каталог по реальным файлам страниц), 4 сценария шапки passed. Проверены переход на серверы и возврат браузером, пустой поиск, фокус, мобильный выбор текущей страницы, размеры 390×600 в двух темах; скриншоты просмотрены. TypeScript успешен; ESLint новых navigation/CommandPalette/NavMain/test успешен. В AppSidebar сохранилась исходная ошибка react-hooks/set-state-in-effect на сбросе liveCounts при смене режима; её наличие подтверждено чтением HEAD до изменений, логика счётчиков не менялась. Не заявлять чистый lint всего проекта.
|
||
|
||
Блок готов для локального коммита без push. Этап 6 продолжается: иерархия дашборда, затем переходы из очереди к конкретным объектам.
|
||
|
||
## Этап 6 — блок 3: сводка и приоритет проблем (2026-09-20)
|
||
|
||
Дашборд сохраняет KpiStatGrid, AttentionQueue и Frame, но очередь «Требует внимания» теперь идёт сразу после сводки, до измерений. Быстрые переходы перенесены вниз. Подписи заменены на «Серверы онлайн», «Туннели работают», «Префиксы BGP», «Проверки с проблемами»; состояния в очереди названы по-русски. Длинные имена проблем переносятся вместо обрезки. Состояния пустого каталога серверов, отсутствия туннелей и активных проверок отделены от отсутствия ошибок.
|
||
|
||
useDashboardLive больше не обрезает массивы проблем до пяти до подсчёта. Счётчики учитывают все элементы; UI сначала показывает пять и раскрывает остальные через «Ещё N» с клавиатуры. Загрузка/частичные сбои/свежесть/защита от поздних ответов этапа 5 сохранены. Запросы и сетевые операции не менялись.
|
||
|
||
Приёмка текущей общей основы: **65 Playwright-тестов passed**, включая 6 сценариев дашборда, 4 навигации и 4 шапки; отдельные профильные запуски также успешны. Новый сценарий проверяет 7 проблем при 5 видимых строках, раскрытие клавиатурой, порядок очереди перед измерениями, пустые активные проверки и ширину 390. Просмотрены скриншоты дашборда 1440/390 и поиска в двух темах. **Production build успешен: контракты, TypeScript, 34 страницы.** Scoped ESLint нового кода успешен; исходная ошибка AppSidebar описана в блоке 2. ReUI checklist получен; vendored-примитивы, зависимости и тема не менялись. Проверки используют HTTP-моки, реальный RouterOS не проверен.
|
||
|
||
**Этап 6 ещё не завершён.** Ссылки AttentionRow пока открывают профильный раздел (/servers, /uptime, /gre, /wireguard, /vxlan), без выбора конкретного объекта. Следующий точный шаг: спроектировать единый URL-контракт идентификатора объекта и сервера, подключить принимающие страницы и только после этого заменить href очереди. Начать с сервера и проверить «дашборд → конкретный сервер → назад», прямое открытие URL, удалённый/недоступный объект, затем адаптировать мониторинг и туннели. Не считать query-параметр рабочим, пока целевая страница его не обрабатывает. Полные формы/права/фильтры URL этапа 7 остаются следующим этапом.
|
||
|
||
Границы: текущий mapper дашборда по-прежнему трактует null server.status как offline; неизвестные состояния устройств требуют отдельного исправления и проверки. Квота при завершении общей регрессии и запуске build: использовано 65% пятичасовой и 26% недельной. Сохранить блок локальным коммитом без push; изменения skills/AGENTS/.codex не включать.
|
||
|
||
## Этап 6 — блок 4: переход к серверу (2026-09-20)
|
||
|
||
Очередь серверов дашборда формирует `/servers?server=<encoded id>`. Страница серверов читает параметр в Suspense, ограничивает таблицу точным ID и показывает контекст перед общей сводкой. «Все серверы» снимает только параметр server, сохраняя остальные query-параметры; «К дашборду» и браузерный возврат доступны. Прямой URL и перезагрузка сохраняют выбор. При отсутствующем ID или 403/500 другой сервер не подставляется. Состояния загрузки, ошибки получения и отсутствующего объекта разделены.
|
||
|
||
При выбранном сервере верхняя кнопка «Проверить сервер» опрашивает только его через существующую очередь операций. Без параметра сохраняется прежний массовый опрос. API, права и правила мутаций не менялись. Контекст использует установленный ReUI Alert; состав общей сводки явно указан. Полная синхронизация поиска/Filters/форм с URL остаётся этапу 7.
|
||
|
||
Проверки: 27 профильных сценариев servers/dashboard passed; после переноса контекста над сводкой повторно пройден сценарий выбора/опроса/возврата и просмотрен мобильный экран 390. ESLint изменённых файлов успешен. Production build прошёл: контракты, TypeScript, 34 страницы. HTTP-фикстура дашборда дополнена и проверяется serverReadSchema: переход на сервер использует строгий API-контракт. Реальный RouterOS не проверялся.
|
||
|
||
Окружение: предыдущий запуск остановился из-за исчерпанной квоты автоматической проверки разрешений. После сброса обнаружен dev-кеш Next.js, возвращавший 404 для существующего маршрута; .next/dev сохранён как .next/dev-before-server-links, чистый кеш устранил ошибку, пять URL-сценариев и вся профильная регрессия прошли. Это игнорируемые сборочные артефакты, не исходники.
|
||
|
||
Квота нового окна: 1% использовано на старте, 26% при запуске итоговой сборки. Блок сохранить отдельным локальным коммитом без push. Этап 6 открыт: далее `/uptime?probe=<id>` и обработка выбранной проверки, затем туннели с идентификатором устройства и объекта.
|
||
|
||
## Этап 6 — блок 5: переход к проверке мониторинга (2026-09-20)
|
||
|
||
Очередь проверок формирует `/uptime?probe=<encoded id>`. UptimeRoute читает параметр в Suspense и сбрасывает локальный контекст страницы при выборе другого ID или полного списка. Фильтрация использует точный ID, поэтому одинаковые имена/назначения не смешиваются. Контекст показывает источник, назначение, состояния загрузки/ошибки/отсутствия; «Все проверки» удаляет только probe, остальные query-параметры сохраняются. Прямой URL, перезагрузка, браузерный возврат и ссылка на дашборд работают.
|
||
|
||
Ссылка и верхнее «Обновить данные» выполняют чтение, без collect-now. Ручной ping существующей кнопкой группы отправляет только ID выбранной проверки; формат API и механизм мутаций не менялись. При сбое фонового обновления прежние данные остаются, а контекст предупреждает об их возможном устаревании. В режиме полного списка верхнее обновление сохраняет прежнее поведение. Выбор не распространяется на отдельные вкладки ресурсов/speed; общий URL-контракт вкладок и фильтров относится к этапу 7.
|
||
|
||
Проверки: пять новых сценариев uptime-links passed, затем **18 связанных сценариев passed** (uptime-links/dashboard-data/collector-probes-tables/navigation). Проверены совпадающие имена, кодирование ID со слешем, отсутствие POST при переходе/чтении, payload ручного ping, сброс/возврат/reload, отсутствующий объект, 403/500, сохранение строки при 503 и восстановление. Мобильный блок контекста 390 просмотрен и не обрезан. У существующей широкой сетки строк Ping-проб на телефоне по-прежнему обрезается правая часть; исправление сетки и доступности её действий включить в этап 7, не считать весь экран мониторинга принятым по этой проверке.
|
||
|
||
Production build успешен: контракты, TypeScript, 34 страницы. Lint нового теста и изменённого hook успешен. У uptime/page.tsx исходные одна ошибка react-hooks/set-state-in-effect в эффекте speedDraft и шесть предупреждений unused-vars — тот же набор подтверждён запуском ESLint на содержимом HEAD до изменений. Новых lint-ошибок нет; не заявлять чистый lint проекта. ReUI checklist получен в этом продолжении, используются установленный Alert и существующая композиция. Проверки на HTTP-моках, реальная сеть не проверена.
|
||
|
||
Квота перед итоговой сборкой: использовано 55% пятичасовой и 40% недельной. Сохранить отдельный локальный коммит без push. **Следующий шаг этапа 6 — туннели GRE/WireGuard/VXLAN:** добавить сервер и ID объекта в href overlay, обработать оба значения на принимающих страницах, исключить подстановку другого устройства при отсутствующем ID. Проверить прямую ссылку, возврат, одинаковые имена/RouterOS ID на разных устройствах и отсутствие мутаций при открытии. Этап 6 остаётся открытым до этих переходов и приёмки.
|
||
|
||
## Этап 6 — блок 6: переход к GRE-туннелю (2026-09-20)
|
||
|
||
Очередь проблем открывает `/gre?server=<serverId>&tunnel=<id>`; оба значения кодируются. Ключ GRE в очереди включает сервер и ID, поэтому одинаковые RouterOS ID на разных устройствах не конфликтуют. Принимающая страница выбирает точную пару, показывает контекст через установленный ReUI Alert и сохраняет остальные query-параметры при снятии выбора. Ссылка «Все туннели сервера» оставляет сервер; ручная смена устройства снимает выбор туннеля и отражается в URL. Back/reload восстанавливают контекст. Открытие ссылки не отправляет POST.
|
||
|
||
Отдельно обработаны отсутствующая пара, ошибки 403/500, неуспешное обновление с сохранением последних данных и частичный сбой выбранного сервера. Такой сбой не выдаётся за отсутствие туннеля; действия таблицы блокируются. Полная достоверность сводки GRE при частичном опросе и сетевые формы остаются этапом 9.
|
||
|
||
Тесты обнаружили автоматический сброс URL-выбора серверной панелью до завершения загрузки. Добавлен opt-in `preserveSelection` в ServerRailLayout/ServerTileRail, включён для GRE; существующие потребители сохраняют прежнее поведение. При отсутствующем сервере панель не выбирает другой автоматически.
|
||
|
||
Проверки: 20 связанных E2E (GRE, IPsec, дашборд, навигация) passed, затем отдельный дополнительный сценарий ручной смены устройства passed — всего 21. Production build и TypeScript успешны, 34 статические страницы. Скриншот контекста ошибки просмотрен на 390 px. ESLint новых замечаний не добавил: у GRE прежние 14 unused warnings, у ServerRailLayout прежняя ошибка set-state-in-effect (оба baseline сверены с HEAD); остальные изменённые TS-файлы чистые. Проверки выполнены с HTTP-моками, реальный RouterOS не проверен.
|
||
|
||
Квота: на старте использовано 69% пятичасовой, перед заключительными проверками 86% (недельной 45%). Следующий блок в этом окне не начинать. Сохранить локальным коммитом без push. **Следующий шаг: WireGuard, затем VXLAN** — URL с сервером и точным ID, запрет fallback на другой сервер, переиспользовать preserveSelection; проверить одинаковые имена/ID, прямой URL, Back, ошибки и отсутствие автоматических мутаций. Этап 6 остаётся открытым до завершения этих переходов и приёмки.
|
||
|
||
## Этап 6 — блок 7: переход к интерфейсу WireGuard (2026-09-20)
|
||
|
||
Готов `/wireguard?server=<serverId>&interface=<id>` из очереди проблем, включая встроенные моки. Выбирается точная пара; таблица, пиры и сводка ограничены интерфейсом. Alert показывает сервер и адрес, ошибки и отсутствие объекта. Снятие выбора сохраняет сервер и остальные query; смена сервера снимает interface, Back/reload восстанавливают выбор. Используется preserveSelection без подстановки другого сервера.
|
||
|
||
При ошибке HTTP последние данные сохраняются с предупреждением; изменяющие действия для устаревших интерфейсов/пиров блокируются. Частичные failures выбранного сервера показаны отдельно. Полная достоверность KPI при частичных сбоях и UX форм остаются этапом 9. Ключи строк интерфейсов включают сервер, пиров — сервер/интерфейс; раскрытие строк и поиск интерфейса для действий пира используют тот же контекст.
|
||
|
||
Проверки: 9 новых сценариев wireguard-links и 2 прежних wireguard-tables passed; 6 сценариев dashboard-data passed. Проверены одинаковые ID/имена, отдельные строки и раскрытие, вкладка пиров, URL/Back/reload, 403/500/503, частичный сбой, восстановление и отсутствие запросов записи. Мобильный контекст 390 px просмотрен. ESLint всех изменённых TS-файлов успешен; production build/TypeScript, 34 страницы — успешно. Реальный RouterOS не проверен, используются HTTP-моки по схеме контрактов.
|
||
|
||
Квота: 0% использовано на старте нового окна, 25% перед сборкой (недельной 51%). Блок сохранить локальным коммитом без push. Следующий шаг — VXLAN и итоговая приёмка переходов этапа 6.
|
||
|
||
## Этап 6 — блок 8: VXLAN и итоговая приёмка (2026-09-20)
|
||
|
||
Готов переход `/vxlan?server=<serverId>&tunnel=<id>`. Выбор точной пары ограничивает список и сводку, сохраняется после reload/Back, снимается при ручной смене сервера. Остальные query сохраняются. Использованы установленный ReUI Alert, ServerRail preserveSelection и существующая Frame-композиция. Ключи очереди и строк таблицы учитывают сервер. Проверен экспорт .rsc выбранного объекта, без автоматических запросов записи при навигации.
|
||
|
||
Ошибка HTTP сохраняет последние данные и показывает предупреждение. Backend VXLAN сейчас возвращает пустой список при неуспешном опросе устройства: listVxlanTunnels и listVxlanTunnelsForServer подавляют исключения. Поэтому сообщение по ссылке говорит «туннель не получен» и перечисляет возможные причины, не утверждая, что объект удалён. Исправление этого API, полной достоверности сетевых KPI, форм и существующих незавершённых действий VXLAN — этап 9; сетевые алгоритмы в этом блоке не менялись.
|
||
|
||
Проверки блока: 8 новых vxlan-links, прежний vxlan-table и 6 dashboard-data — 15 passed. Итоговая приёмка этапа 6: **68 E2E passed** (page-header, navigation, dashboard-data, servers, uptime-links, gre-links, wireguard-links, vxlan-links, wireguard-tables, vxlan-table). Покрыты клавиатура/Escape, темы навигации, шапка 320/390/1024/1440 px, все пять типов объектов очереди, точный контекст, совпадающие ID, возврат, HTTP-ошибки и повтор операций. Контекст VXLAN просмотрен на 390 и 1440 px, WireGuard — на 390 px. Все изменённые TS-файлы WireGuard/VXLAN проходят ESLint. Финальные production build, TypeScript и генерация 34 страниц успешны; для сборки уточнён локальный тип существующего serverId в ответе VXLAN. ReUI audit checklist сверён: компоненты переиспользованы, ссылки настоящие, состояния объявляются role=status, vendored-компоненты/тема/зависимости не менялись.
|
||
|
||
**Этап 6 завершён в границах UI и HTTP-моков.** Реальные устройства, серверная авторизация и сетевые операции требуют отдельной приёмки. Это не итоговая приёмка всего продукта: известная обрезка мобильных строк Ping-проб остаётся этапом 7, прежние lint-ошибки общих компонентов перечислены выше. Квота перед фиксацией: использовано 70% пятичасовой и 58% недельной. Сохранить локальным коммитом без push; следующий крупный этап начать отдельным блоком.
|
||
|
||
**Следующий точный шаг — этап 7:** составить схему серверов/мониторинга по Data Grid Filtering 2 и Sheet 8, инвентаризировать права действий и текущие формы. Первый ограниченный блок — URL-контекст поиска/типа/Filters на /servers (с сохранением server), проверка прямого URL/Back/reload и возврата к списку. Затем мобильные строки Ping-проб и формы/права по журналу. Не менять сетевые правила в рамках визуальной унификации.
|
||
|
||
## Этап 7 — подготовка (2026-09-20)
|
||
|
||
На старте продолжения использовано 80% пятичасовой квоты (остаток 20%, ниже резерва). Код приложения не менялся: выполнена ограниченная подготовка по текущим файлам. Создан `docs/ux-ui-stage-7.md` с таблицей референсов, схемами ПК/телефона, инвентаризацией форм/прав и разбивкой 7.1–7.5.
|
||
|
||
Подтверждено: серверы сохраняют в URL только server; поиск/тип/Filters локальные. Ping-пробы используют фиксированную сетку внутри overflow-hidden. В lib/auth.ts уже есть can/hasPermission, а на двух страницах проверки прав действий не подключены; backend-политика разделяет servers/uptime read/write. В плане записан конкретный контракт q/type/filters, ограничения parser и сценарии проверки Back/reload/черновиков/ошибочного URL.
|
||
|
||
Проверка подготовки — сверка путей, типов, обработчиков и правил backend по исходникам, git diff --check. Тесты приложения повторно не запускались: изменения только документационные. Сохранить локальным коммитом без push. **Следующий шаг: блок 7.1 по ux-ui-stage-7.md — codec URL серверов с unit-тестами, затем подключение к странице и профильные E2E.** Этап 7 не считать реализованным.
|
||
|
||
## Этап 7 — блок 7.1: URL-фильтры серверов (2026-09-21)
|
||
|
||
Реализован codec `lib/data-filters/server-url-state.ts`, hook `hooks/use-server-url-state.ts` и подключение к ServersPageContent. Параметры q/type/filters восстанавливают поиск, тип и дерево Filters; server остаётся точным контекстом из этапа 6. JSON имеет версию v=1, сохраняет AND/OR, вложенность и negated. Проверяются поля/значения текущих SERVER_FILTER_FIELDS, операторы select, уникальные ID, размер 8 KiB, глубина 4, число узлов 50. Неизвестный тип, повторные параметры или повреждённые фильтры показывают предупреждение и не расширяют выдачу до всех серверов.
|
||
|
||
Черновик условия не сериализуется. Сброс q/type/filters сохраняет server и чужие query-параметры. Дискретные изменения используют native pushState; поиск — replaceState без debounce. Это уточнение плана обосновано текущим Next App Router: useSearchParams обновляется без навигационного запроса, быстрый ввод не создаёт записи на каждый символ и не имеет отложенного обновления, затирающего соседние параметры. Тест проверяет неизменное число GET списка при вводе. Back/Forward очищают локальный черновик и восстанавливают URL-состояние; формы и API операций не менялись.
|
||
|
||
Проверки: 4 unit-теста codec passed; 21 прежний сценарий servers passed; 6 новых URL E2E passed после уточнения селектора alert (в странице также есть Next route announcer). Отдельно повторён сценарий с мобильной проверкой на 390 px, скриншот просмотрен. Проверены прямой URL, Back/Forward/reload, OR/negated, завершение условия, быстрый ввод, отсутствие запросов записи, сброс с server/keep, повреждённый/слишком большой JSON. TypeScript, ESLint всех изменённых TS-файлов и production build (34 страницы) успешны. HTTP-моки, реальные устройства не проверены.
|
||
|
||
Квота: использовано 1% на старте, 30% перед заключительной сборкой (недельной 66%). Сохранить локальным коммитом без push. **Следующий шаг — 7.2:** мобильные строки Ping-проб в uptime/page.tsx, доступность имени/цели/состояния и меню без обрезки на 320/390 px с сохранением действий, выбора и раскрытия; затем права по блоку 7.3. Этап 7 в целом остаётся открытым.
|
||
|
||
## Этап 7 — блок 7.2: мобильные строки Ping-проб (2026-09-21)
|
||
|
||
Устранена отмеченная на этапе 6 обрезка правой части строк Ping-проб. В uptime/page.tsx сохранён один набор контролов и прежние обработчики. Frame-контейнер и локальный probe-rows.module.css переключают строку между двумя колонками с подписями и широкой сеткой при доступной ширине от 1100 px. Длинные имя, фильтр и цель переносятся, серверный заголовок и действия группы тоже допускают перенос. FormToggle получил label, кнопки звезды/редактирования/удаления — aria-label, заголовок группы сервера — aria-expanded. Вендорные ReUI-компоненты, тема, данные и сетевые правила не менялись.
|
||
|
||
Проверки: **11 E2E passed** (uptime-links и collector-probes-tables). Новые сценарии 320/390/1440 px проверяют длинные подписи, доступность кнопок в пределах экрана, отсутствие горизонтального переполнения страницы, широкую/узкую композицию, переключатель, раскрытие графика Enter, редактирование/Escape, PATCH звезды и PUT включения. Скриншоты 320/1440 просмотрены после исправлений переноса. TypeScript и production build успешны, 34 страницы. Новый тест проходит lint; у uptime/page.tsx прежние 1 ошибка set-state-in-effect и 6 предупреждений, тот же baseline подтверждён на HEAD. Не заявлять чистый lint всего проекта.
|
||
|
||
Ограничения: проверены HTTP-моки. Общая адаптивность вкладок Resources/Speed, подтверждение удаления и обработка ошибок существующего persistProbes не входили в этот блок; относятся к дальнейшей работе с формами и операциями. Этап 7 остаётся открытым. Квота: использовано 47% на старте, 81% перед фиксацией (недельной 74%). Новые блоки в этом окне не начинать; сохранить локальным коммитом без push.
|
||
|
||
**Следующий шаг — 7.3:** подключить разрешения действий серверов и мониторинга по can/hasPermission и действующим backend-маршрутам; проверить read-only, write/admin, auth disabled и серверный 403 без потери формы. Начать с серверов, затем мониторинг; UI-проверки не заменяют backend.
|
||
|
||
## Карта миграции (исходная инвентаризация этапа 0)
|
||
|
||
Исходная связка на этапе 0: @tanstack/react-table ^8.21.3, @tanstack/react-virtual ^3.14.4, base-nova. По итогам этапа 4 используется @tanstack/react-table 9.2.4 с useTable/dataGridFeatures и дерево FilterQuery вместо старого filters/onChange. Список ниже сохранён как историческая инвентаризация.
|
||
|
||
Источники: [контракт UI](ui-design-contract.md), [таблицы PRO](https://reui.io/preview/base/data-grid-filtering-2?ref=mcp), [API Data Grid](https://reui.io/docs/components/base/data-grid?ref=mcp), [API Filters](https://reui.io/docs/components/base/filters?ref=mcp).
|
||
|
||
### Прямые потребители TanStack (47)
|
||
|
||
- `components/data-grids/asns-data-grid.tsx`
|
||
- `components/data-grids/backups-data-grid.tsx`
|
||
- `components/data-grids/bgp-sessions-data-grid.tsx`
|
||
- `components/data-grids/certificates-data-grid.tsx`
|
||
- `components/data-grids/communities-data-grid.tsx`
|
||
- `components/data-grids/compact-data-grid.tsx`
|
||
- `components/data-grids/data-collection-scheduler-data-grid.tsx`
|
||
- `components/data-grids/domains-data-grid.tsx`
|
||
- `components/data-grids/filters-data-grid.tsx`
|
||
- `components/data-grids/firewall-rules-data-grid.tsx`
|
||
- `components/data-grids/firewall-scenario-rules-data-grid.tsx`
|
||
- `components/data-grids/gre-pools-data-grid.tsx`
|
||
- `components/data-grids/gre-tunnels-data-grid.tsx`
|
||
- `components/data-grids/ip-ranges-data-grid.tsx`
|
||
- `components/data-grids/ospf-bfd-data-grid.tsx`
|
||
- `components/data-grids/ospf-neighbors-data-grid.tsx`
|
||
- `components/data-grids/ospf-routes-data-grid.tsx`
|
||
- `components/data-grids/probes-schedule-data-grid.tsx`
|
||
- `components/data-grids/probes-speed-probes-data-grid.tsx`
|
||
- `components/data-grids/recursive-routes-data-grid.tsx`
|
||
- `components/data-grids/route-optimizer-comm-recs-data-grid.tsx`
|
||
- `components/data-grids/route-optimizer-full-routes-data-grid.tsx`
|
||
- `components/data-grids/route-optimizer-ospf-preview-data-grid.tsx`
|
||
- `components/data-grids/route-optimizer-wan-matrix-data-grid.tsx`
|
||
- `components/data-grids/servers-data-grid.tsx`
|
||
- `components/data-grids/shared/data-grid-shell.tsx`
|
||
- `components/data-grids/shared/data-grid-sort-header.tsx`
|
||
- `components/data-grids/subusers-data-grid.tsx`
|
||
- `components/data-grids/traffic-flows-data-grid.tsx`
|
||
- `components/data-grids/uptime-resources-data-grid.tsx`
|
||
- `components/data-grids/uptime-speed-history-data-grid.tsx`
|
||
- `components/data-grids/users-data-grid.tsx`
|
||
- `components/data-grids/vxlan-data-grid.tsx`
|
||
- `components/data-grids/wireguard-data-grid.tsx`
|
||
- `components/data-grids/wireguard-peers-grid.tsx`
|
||
- `components/data-table.tsx`
|
||
- `components/ipsec/ipsec-users-grid.tsx`
|
||
- `components/reui/data-grid/data-grid-column-filter.tsx`
|
||
- `components/reui/data-grid/data-grid-column-header.tsx`
|
||
- `components/reui/data-grid/data-grid-column-visibility.tsx`
|
||
- `components/reui/data-grid/data-grid-table-dnd-rows.tsx`
|
||
- `components/reui/data-grid/data-grid-table-dnd.tsx`
|
||
- `components/reui/data-grid/data-grid-table-virtual.tsx`
|
||
- `components/reui/data-grid/data-grid-table.tsx`
|
||
- `components/reui/data-grid/data-grid.tsx`
|
||
- `components/traffic/flow-analytics-panel.tsx`
|
||
- `components/traffic/flow-traffic-map.tsx`
|
||
|
||
### Прямые потребители Filters (6)
|
||
|
||
- `app/(main)/backups/page.tsx`
|
||
- `app/(main)/bgp/page.tsx`
|
||
- `app/(main)/servers/page.tsx`
|
||
- `app/(main)/statistics/page.tsx`
|
||
- `components/backups/backups-history.tsx`
|
||
- `components/data-page-toolbar.tsx`
|