460 KiB
UX/UI: журнал реализации
Общий план: UX/UI по этапам и пятичасовым окнам. План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения.
Правила продолжения
- План: 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 | Завершён в границах локальной приёмки 2026-09-30; блоки 9.1–9.64, ограничения в 9.64 |
| 10 | Маршрутизация, диагностика, карта и терминал | В работе: 10.1–10.45; оптимизатор принят локально, карта сети в работе |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Не начат |
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Не начат |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Не начат |
Блок 10.45 — согласованный снимок карты сети (2026-10-01)
- Servers/GRE/probes публикуются вместе после строгой проверки схем, уникальности и владельцев. Частичный каталог GRE и неизвестные ссылки отклоняются; первоначальный отказ не становится пустым успешным ответом. При фоновом сбое сохраняется последний полный снимок с явным предупреждением.
- Время ответа браузера отделено от измерений. Новый источник пересоздаёт контекст; epoch/alive запрещают позднему ответу и DNS изменять новую карту.
- 2 unit, 9 HTTP E2E и TypeScript прошли. ESLint карты содержит 5 исходных ошибок и 1 warning; сравнение с HEAD подтвердило отсутствие новых. Их исправление включено в дальнейшую приёмку карты. Next dev имеет собственный пустой alert, поэтому тест восстановления проверяет именно сообщение карты.
- Далее неизвестный статус, ресурсы и GRE без синтетических live значений; Flow/DNS, URL/доступность и приёмка карты ещё не завершены.
Блок 10.44 — локальная приёмка оптимизатора (2026-10-01)
- Схема расчёта использует общий WAN-аплинк, без утверждения о существующих WAN1/WAN2. Длинные имена/метаданные и badges переносятся; модельная категория/индекс имеют доступные подписи. Текст бейджей не сжимается/не переносится внутри них.
- 46 основных E2E + отдельный новый long-name 320 px = 47 разных; 8 source E2E, backend optimizer suite/live-maps и обе production сборки прошли в блоках 10.39–10.44; TS/lint без новых ошибок (backend два прежних warning). ReUI checklist проверен, vendor/theme не менялись. Девять снимков обновлены и просмотрены в окончательной композиции; форма и keyboard/disabled поведение проверены на 1440/390/320 px.
- Оптимизатор принят в локальных границах: Community live apply недоступен, demo receipt только симуляция; модельные chain/index/score явно отделены от измерений. Нет synthetic/mock WAN в live, чужих Community правил, неизвестных индексов как нулей. OSPF preview/apply full context/RBAC/receipt, optional observed контракт и Router ID ambiguity проверены на DI/HTTP фикстурах.
- Ограничения: настоящие RouterOS/JWT/БД/физические пробы/сетевые изменения не тестировались; dynamic Router ID/отсутствующие flags требуют фактической проверки; timestamp скорости probe отсутствует; алгоритм ранжирования прежний. Home tabs/черновые ECMP/RPF/VRF не восстанавливаются из URL. Прежний intermittent readonly fixture teardown ECONNREFUSED не считать реальной интеграцией.
- Следующий шаг: карта сети — согласованный snapshot servers/GRE/probes, сохранение last data, freshness/гонки/источник; затем Flow Map/DNS и unknown состояния графа. Терминал и этапы 11–12 ещё впереди.
Блок 10.43 — смысл настроек и scope Community (2026-10-01)
- Порог выигрыша — баллы, не проценты; счётчик обозначает рекомендации, не выполненные переключения. Интервал обновляет расчёт, не запускает измерения. Неиспользуемый гистерезис недоступен и явно пояснён; значения сохранённых настроек совместимы.
- Live правила Community фильтруются по sourceServerId домашнего устройства до limit/ranking; правила разных home/exit не смешиваются.
- 4 observed unit, 10 E2E layout/tables/trust, TS/lint и ReUI consumer audit прошли. Девять снимков обновлены/просмотрены; форма 320 px теперь снята с начала панели. При просмотре заметен риск обрезки header badges/длинных имён — исправить до приёмки.
- Далее окончательный layout header/схема цепочки, общая optimizer regression и локальная приёмка.
Блок 10.42 — WAN только из live каталога (2026-10-01)
- Live topology не ищет WAN по совпадению name/host/id в lib/data и не создаёт WAN1/1000 автоматически. Нет uplinks — нет цепочек/лучшего маршрута; пояснение ведёт к /servers?server=. Для существующих WAN формула ранжирования прежняя; лимит модели явно назван расчётным.
- 6 unit (включая совпадение с mock inventory), 16 E2E measured/unknown/empty WAN, read failures/races и simulation, TS/lint прошли.
- Далее уточнить единицы порога/инертный гистерезис, scope Community по домашнему серверу, затем обновить screenshots и принять оптимизатор локально.
Блок 10.41 — однозначное устройство OSPF (2026-10-01)
- Сопоставление Router ID больше не останавливается на первом совпадении. Проверяются все enabled устройства: нужен literal ID активного экземпляра, повтор на другом устройстве отклоняется; неизвестный disabled/ID либо отказ опроса сообщает ошибку до write. Повторы одного ID внутри одного устройства допустимы; known disabled исключены. Без соседских Router ID дополнительный сетевой опрос не нужен.
- Изменена достоверность контекста, формулы score/cost и порядок apply прежние. Для RouterOS с динамическим/symbolic Router ID или отсутствующими flags потребуется отдельная проверка фактического каталога; их не угадываем по host.
- Backend optimizer identity/metrics/parser/HTTP tests и production backend прошли. Lint без ошибок, два прежних unused warning в ospf.ts. Реальных RouterOS запросов не выполняли.
- Далее обновить 1440/390/320 screenshots и выполнить локальную приёмку оптимизатора; затем карта сети.
Блок 10.40 — происхождение метрик OSPF API (2026-10-01)
- Общий контракт @mmapp/contracts: value/source/sourceId/measuredAt для Ping/DL/UL. Источники speed-probe, interface-traffic, unknown; неизвестность не становится нулём. Задержка трафиком не измеряется. Backend добавляет observed данные до валидации ranked plan; некорректные данные отклоняются до write. Ranking/model defaults прежние.
- Исходные нули, дроби и давние даты сохраняются. Timestamp Ping пробы не используется как время speed; traffic snapshot даёт собственную дату и bps/1e6. Задержка серверных snapshot остаётся только модельным fallback, не измерением интерфейса.
- Preview показывает модель и исходный снимок раздельно. Старые ответы без optional observed совместимы, но их измерения отображаются неизвестными. UI не выдаёт model-only API поля за observed.
- Проверки: backend metric/parser/HTTP optimizer tests, test:live-maps, 30 E2E observed/preview/apply/tables, TS/lint, production frontend/backend прошли. ReUI consumer-композиция сохранена.
- Далее: убрать неоднозначность Router ID в backend optimizer (сейчас first-match при опросе), затем обновить screenshots и локальную приёмку оптимизатора. Настоящие RouterOS/БД запросы не выполнялись.
Блок 10.39 — исходные метрики цепочек оптимизатора (2026-10-01)
- Live WAN–JH/JH–Exit сохраняют observed record отдельно от model полей. Исходные 0, дроби, null и дата пробы не округляются/не ограничиваются WAN cap. Расчётные поля и ranking остаются прежними.
- Матрица показывает исходные измерения или «—»; без пробы не показывает вычисленный Ping/скорость как измерение. Дата Ping видима, время скорости неизвестно (API его не передаёт), давние пробы не названы текущими. Полные цепочки подписаны как модель, confidence — категория модели. Моки сохраняют отдельный демонстрационный режим.
- Проверки: 2 unit (нули/дроби/null/давняя дата/disabled/missing, сохранение model clamp/score), 9 E2E (2 новых measured/unknown плюс таблицы/симуляция), TS/lint прошли. ReUI audit consumer-композиции без vendor/theme изменений.
- Далее backend OSPF observed provenance и строгий контракт. Снимки 10.34 пока не обновлены; визуальную приёмку повторить после backend блока. RouterOS/БД операции по-прежнему не проверены.
Блок 10.38 — пояснение метрик OSPF preview (2026-09-30)
- Рядом с устройством preview явно сообщает: Ping/скорость могут включать расчётные значения и не подтверждают текущее качество соединения. Значения, ranking и write policy не менялись. Это обозначение ограничения, а не завершённая provenance-модель.
- Профильный lint, повторные 14 E2E preview и заключительные 17 E2E чтения/таблиц/симуляции после URL-оболочки прошли; production сборка из 10.36 (последняя правка только текста JSX). Снимки в плане отражают 10.34 до дополнительного пояснения.
- Точный следующий блок: добавить раздельное происхождение/observed значения для WAN–JH/JH–Exit и OSPF метрик, сохранив прежний ranking. Проверить measured 0, unknown/null, fallback и устаревшие пробы; не считать clamp Math.max(1, ...) наблюдаемым измерением. Точки: lib/route-optimizer-data.ts (454–494), backend/src/routes/ospf.ts (getLatestSnapshotLatencyMs/normalizeSpeedMbps/buildOptimizationPlan), контракт lib/ospf-response.ts. Затем обновить визуальные снимки и принять оптимизатор; карту/терминал пока не начинали.
- Известное ограничение: повторяющийся teardown catalog ECONNREFUSED в readonly fixture. Реальные RouterOS/БД операции остаются внешней приёмкой. Изменения skills/AGENTS/.codex другой задачи сохранены вне наших коммитов.
Блок 10.37 — изоляция источника оптимизатора (2026-09-30)
- Отдельный config с локально изменяемым backend проверяет поздний preview/apply success и failure после смены backend либо live → mock через настройки. Новый экран сохраняет свой snapshot, старый receipt/error не показывается, старое применение не запускает reread нового backend.
- 8 source E2E, TS/lint прошли; изменения только тестов/config, production frontend проверен в 10.36. HTTP interception, без реальных сетевых изменений.
- Дальше: происхождение модельных метрик/fallback и их отображение; затем карта/терминал. Этап 10 не завершён. Оставшийся пятичасовой лимит на проверке — 2%.
Блок 10.36 — URL устройства оптимизатора (2026-09-30)
- Параметр server восстанавливает OSPF устройство, select обновляет историю, другие параметры/fragment сохраняются. Suspense обеспечивает production render; URL меняет контекст без сброса локальной формы, источник по-прежнему изолирован key(mode, backendUrl).
- Unknown/disabled/malformed/empty explicit server не заменяется первым доступным: доступное имя отсутствует, alert предлагает выбор; preview/metadata запросы и применение заблокированы до явного выбора. Late preview проверен прежним race-тестом.
- 22 E2E preview/apply (6 новых URL сценариев), 3 unit, TS/lint и production frontend прошли. Новый unit fixture из 10.35 уточнён site/model/type после TypeScript проверки. Прежний teardown catalog ECONNREFUSED остаётся известным ограничением теста readonly.
- Далее: source isolation отдельным config, model provenance/fallback отдельно; затем карта/терминал. Вкладки Home/настройки пока не входят в URL. Реальные RouterOS/БД/JWT операции не проверены.
Блок 10.35 — неизвестные индексы Community (2026-09-30)
- Если полной цепочки нет, оба индекса показывают «—» с доступным названием; отсутствующая база не участвует в вычислении отображаемого выигрыша. Переключение не рекомендуется даже при нулевом пороге. Формула ранжирования полных цепочек не менялась.
- Проверки: 7 E2E (включая отсутствие ExitNode, полные таблицы и симуляцию), 3 unit (включая нулевой порог), TypeScript и профильный lint прошли. Production frontend был проверен в предыдущем блоке; общая основа не менялась.
- Далее: URL/source-контекст оптимизатора. Model fallback/clamp отдельно обозначить, затем карта/терминал; реальная RouterOS/БД приёмка внешняя.
Блок 10.34 — адаптивность и доступность оптимизатора (2026-09-30)
- KPI читаются на 320/390 px: одна колонка на телефоне, две/четыре при достаточной ширине контейнера. Визуальная проверка выявила скрытые KPI внутри native flex-fieldset; внутренний flex-контейнер восстановил layout без изменения общего KpiStatGrid.
- Настройки/вкладки — настоящие кнопки с keyboard/ARIA; числовые поля, устройство и ECMP названы, отключённый ECMP блокирует range и алгоритмы. Панели/toolbar переносятся, таблицы прокручиваются внутри своей оболочки. Убрана неподтверждённая команда ECMP; сценарий явно черновой. Семантические токены и декоративные иконки исправлены в четырёх grid consumers. Vendor/theme не менялись.
- Девять снимков 1440/390/320 px сохранены в плане и просмотрены. ReUI checklist выполнен в границах consumer-композиции. 35 E2E оптимизатора, TypeScript, профильный lint и production frontend прошли. В одном readonly E2E при teardown запрос catalog вышел из HTTP interception и получил ECONNREFUSED локального backend; тесты зелёные, реальный backend не участвовал.
- Оптимизатор целиком ещё не принят: model fallback/clamp и URL/source-контекст требуют отдельного блока; затем карта/терминал. Реальная RouterOS/БД проверка остаётся внешней. Следующий шаг: отсутствующий индекс Community не подменять нулём, затем восстановление контекста из URL.
Блок 10.33 — достоверность cost и плана OSPF (2026-09-30)
- Оптимизатор использует отдельный observed selector шаблонов: disabled/id/interface/currentCost должны быть достоверны. Cost не подставляется как 10, disabled не превращается в false. Missing/unsupported cost (включая 0 вне текущей write-policy 1–65535), дубликаты id и несколько активных шаблонов одного интерфейса отклоняются. Известные disabled и reference-интерфейсы сохраняют прежнее исключение из оптимизации.
- Весь ranked plan валидируется до первой записи; переполнение optimalCost, плохие метрики/идентификаторы не приводят к частичному apply. Отключённое устройство возвращает 409, неизвестное 404. Формула score, выбор проб и порядок сетевых изменений прежние.
- DI оптимизатора позволяет HTTP injection без БД/RouterOS. Проверены malformed plans до write, preview без write, success/empty, disabled/missing/bad weight и сетевой отказ. Unit selector проверяет unknown/default/duplicates и observed zero метрик.
- Проверки: test:ospf-optimizer, общий test:live-maps (включая OSPF/BGP/GRE/VXLAN compatibility), backend build прошли. Lint без ошибок; два прежних предупреждения unused and/measurePingByInterface остаются.
- Далее 10.34: адаптивность и keyboard/screen оптимизатора; затем URL/source context и различение observed/model метрик. Snapshot/traffic fallback и clamp значений в модели ещё сохранены и требуют отдельного отображения; весь раздел ещё не принят. Реальная RouterOS версия/DB не проверена. Последняя квота: 82% окна, 44% недели использовано. Локальный коммит без push.
Блок 10.32 — подтверждение применения OSPF и права (2026-09-30)
- Apply валидирует существующий ospfOptimizeSchema, serverId и вес запроса. Успех по count/name без списка applied больше не принимается. Последний receipt привязан к контексту и времени получения браузером; отсутствие применения отображается «—».
- Синхронный ref lock и disabled fieldset блокируют повтор/смену устройства/параметров до ответа. Проверяются network:write, enabled inventory и готовность preview. После любого результата перечитываются preview/catalog и исходный расчёт: ошибка может сопровождаться частичным применением RouterOS. Late unmounted контекст не публикует результат.
- RBAC конкретных server OSPF endpoints поставлен перед общим server matcher: GET/POST preview требуют network:read, изменения network:write. Общие server rights прежние. Изолированный HTTP тест с настоящими signed JWT проверяет reader/writer/servers-only/401 без БД и RouterOS.
- Проверки: 16 E2E apply/preview (success/HTTP/foreign/weight/count/missing/repeat/readonly), readonly повторно с завершением metadata, TS/lint, frontend/backend production build и backend auth regression прошли. Первичный readonly teardown оставлял metadata запрос; ожидание добавлено, повтор прошёл без proxy ошибки.
- Далее 10.33: происхождение cost и метрик backend OSPF планировщика; legacy defaults ещё не позволяют считать preview полностью наблюдаемым. Затем source/URL и visual acceptance. Реальный RouterOS/DB/JWT integration не проверен; signed JWT тест проверяет middleware со stub handlers. Последняя квота: 76% окна, 43% недели использовано. Локальный коммит без push.
Блок 10.31 — OSPF preview в оптимизаторе (2026-09-30)
- Preview требует точных serverId/pingWeight, идентификаторов интерфейсов, уникальности и согласованных interfaces/changes/counts. Старый или чужой контекст не публикуется и блокирует apply.
- Metadata переходит на строгий /ospf/catalog; ошибки выбранного устройства отображаются. Preview имеет явный повтор и обновляется после свежего расчёта. Pending/ошибка сохраняют последний preview того же контекста, с предупреждением; другой контекст его скрывает. Таблица использует реальные id.
- Optimistic обнуление changedCount после apply убрано: результат должен перечитываться. Сам receipt apply пока legacy — следующий отдельный блок. Backend алгоритм не менялся.
- Проверки: 12 E2E (шесть invalid/HTTP preview, повтор, cache, late device и четыре таблицы), TS/lint прошли; ранее 16 источников/доверия прошли после обновления контрактных fixtures. В сумме проверено 24 разных сценария этой группы.
- Далее 10.32: strict OSPF receipt, synchronous lock/права/контекст, ошибки частичного apply и reread. Затем backend provenance планировщика и visual acceptance; реальная RouterOS оптимизация не проверена. Последняя квота: 74% окна, 43% недели использовано. Локальный коммит без push.
Блок 10.30 — согласованное чтение оптимизатора (2026-09-30)
- Inventory/rules/probes читаются параллельно и валидируются до публикации полного расчёта. Неизвестные типы, дубликаты, stale правила, плохие измерения и чужие ссылки на устройства отклоняются; missing payload не заменяется пустым массивом. Stored rules с live:false/stale:false допустимы как конфигурация БД для модели.
- Частичный отказ оставляет предыдущий полный snapshot/topology/inventory, с явным предупреждением; начальная неизвестность отображается «—». OSPF apply блокируется при pending/ошибке исходного расчёта. Model fallback метрик пока сохранён и обозначен, сетевой алгоритм не изменён.
- Epoch и alive защищают от позднего расчёта/unmount. Успешное получение API и время построения модели разделены; время браузера не называется измерением устройства.
- Проверки: 16 E2E (начальные HTTP/invalid сбои трёх частей, повтор, partial cache, race, tables/preview/trust), два unit schema, TS/lint и production frontend (34 страницы) прошли. Race повторно прошёл после cleanup reader.
- Далее 10.31: OSPF preview/apply receipts, источник/устройство, права, synchronous lock и reread после ошибки. Legacy OSPF metadata читает старый endpoint; unknown/current model metrics ещё требуют профильной доработки. Последняя квота: 70% окна, 42% недели использовано. Локальный коммит без push.
Блок 10.29 — достоверность рекомендаций оптимизатора (2026-09-30)
- Live Community больше не показывает успех по таймеру: действия симуляции доступны только в демо. Переключение backend/mode размонтирует прежний контекст; таймеры симуляции отменяются, повтор синхронно заблокирован.
- Базовая цепочка подписана как расчётная; проценты вероятности заменены баллами индекса. Указано, что метрики могут включать модельные оценки, а ECMP/RPF/VRF служат локальному просмотру. Автоприменение Community отмечено недоступным; пересчёт настроек подписан явно. Алгоритм live ранжирования и сетевые операции не изменены.
- Демо-матрицы теперь сопоставлены с текущими mock server IDs: прежние jh/ex ID оставляли их пустыми. Проверена успешная симуляция с отдельной подписью. Настройки раскрываются настоящей кнопкой с aria-expanded.
- Проверки: шесть E2E (таблицы/preview, live без фиктивной записи, mock симуляция), TS/lint прошли. Первый прогон выявил div вместо кнопки и несовместимость демо-ID; исправлены.
- Далее 10.30: строгие ответы inventory/rules/probes, ошибки частей и последние данные, epoch/freshness. Затем OSPF preview/apply validation/права/контекст и visual acceptance. Раздел целиком ещё не принят; фактическая текущая Community цепочка и вероятности API отсутствуют. Последняя квота: 66% окна, 41% недели использовано. Локальный коммит без push.
Блок 10.28 — адаптивность и локальная приёмка маршрутов (2026-09-30)
- Раскрытие группы — отдельная кнопка с aria-expanded, Enter/Space; URL и клик строки сохранены. Форма имеет доступные имена полей и штатный finalFocus Base UI после Escape.
- Мобильный Sheet занимает полную ширину, header/footer сохраняются, fieldset владеет прокруткой. Убраны вложенные max-height списков стран/шлюзов; кнопки footer сохраняют высоту. Шапка устройства переносится, неизвестный тип больше не подменяется exit-node.
- Проверки: 48 основных E2E, восемь source, backend recursive HTTP/parser, lint и production frontend (34 страницы) прошли. Три layout сценария повторно прошли после audit: 1440/390/320 px, keyboard/focus trap/Escape/без page overflow. Первый layout-прогон выявил ширину ¾ и потерю фокуса; оба исправлены. Шесть снимков просмотрены и добавлены в план.
- ReUI checklist применён к consumer-композиции: Frame/DataGrid/Sheet переиспользованы, vendor/theme не изменены; семантические цвета, декоративные иконки и объявления обновления. API finalFocus проверен в установленном Base UI.
- Рекурсивные маршруты завершены в границах локальной приёмки 10.24–10.28. RouterOS/DB/JWT остаются внешними ограничениями; strict catalog может отклонять неполный ответ конкретной версии, это требует проверки на устройстве. Далее 10.29: достоверность результатов и чтения оптимизатора. Последняя квота: 60% окна, 40% недели использовано. Локальный коммит без push.
Блок 10.27 — строгий каталог рекурсивных маршрутов (2026-09-30)
- Новый /recursive-routes/catalog читает RouterOS напрямую и принимает только полный валидный managed-снимок. Неизвестные обязательные параметры или неподдерживаемая принадлежащая приложению запись дают 503, а не пустой список, который мог бы удалить маршруты при полном применении. Legacy GET сохранён для существующих потребителей Filters.
- Нули distance/scope/targetScope сохраняются; отсутствующие optional scope остаются null. Редактирование сохраняет disabled. Страна — только явная аннотация, без угадывания по имени шлюза.
- Gateway catalog сообщает использование шлюза в active/inactive маршрутах или неизвестность; это не проверка доступности шлюза. Основание полей: RouterOS IP route.
- Проверки: 42 основных E2E и повторные 18 data/values (три новых), восемь source E2E, backend parser/HTTP/config-sync/build, TS/lint прошли. Перехват нового вложенного catalog в source тесте исправлен; повторный прогон 8/8. Production frontend (34 страницы) прошёл.
- Далее 10.28: адаптивность, keyboard и снимки. Реальные RouterOS/DB/JWT и совместимость полного ответа конкретной версии устройства требуют внешней приёмки. Последняя квота: 55% окна, 40% недели использовано. Локальный коммит без push.
Блок 10.26 — URL и source/history рекурсивных маршрутов (2026-09-30)
- server/q/route/table сохранены в URL. Default устройство записывается через replace; выбор/раскрытие используют history, поиск replace. Чужие query-поля сохранены. Missing/invalid/repeated/oversized контекст блокирует срез; route требует table. Отсутствующая группа закрывается отдельно.
- ServerRail preserveSelection исключает автоматический переход с отсутствующего устройства на первый сервер. Предварительная проверка выявила этот fallback; исправление подтверждено.
- Общий lock живёт над device context и привязан к mode/backend. URL/history не снимает pending запись; завершение перечитывает текущий контекст соответствующего источника. Late read/write старого backend/режима не меняют новый снимок и не показывают старые toast/error.
- Путь recursive-routes использует mm:network:read, как backend. Readonly/disabled устройства по-прежнему не могут сохранять или восстанавливать.
- Проверки: 38 разных основных E2E в совокупности (первый прогон 37/38, после исправления missing-device прошли все 11 links), восемь source E2E, два unit, TS/lint и production frontend 34 страницы прошли. Source mock проверки используют фактическую заглушку раздела, без требования отсутствующей mode badge.
- Далее 10.27: строгие наблюдаемые поля маршрутов/шлюзов; затем layout/keyboard/screens и профильная приёмка. Legacy mapper ещё подставляет distance/default flags, реальный RouterOS/DB/JWT не проверен. Последняя квота: 46% окна, 38% недели использовано. Локальный коммит без push.
Блок 10.25 — backend-валидация рекурсивных операций (2026-09-30)
- PUT требует явные serverId/routes и валидные параметры каждого маршрута; отсутствие routes не превращается в удаление всех managed-маршрутов. Пустой массив остаётся допустимым намеренным действием. Нули distance/scope/targetScope сохраняются.
- Restore требует точного serverId, совпадения раздела/устройства и валидного payload. Null/object/неполный snapshot не подменяется пустым списком или default параметрами. Canonical версии без id совместимы; id формируется отдельно.
- Фабрика зависимостей позволяет через HTTP injection проверить отказ до поиска устройства и сетевого apply. Реальные БД/RouterOS не вызываются.
- Проверки: backend HTTP regression (15 malformed PUT, explicit empty/zero/copy/error, restore ownership/payload), auth smoke/permissions, config-sync, build и lint прошли. Алгоритм add/delete, managed markers и source apply/copy/rollback прежние.
- Далее 10.26: URL устройства/поиска/группы и source/history при незавершённой операции; затем strict observed parser и визуальная приёмка. Последняя квота: 38% окна, 37% недели использовано. Локальный коммит без push.
Блок 10.24 — подтверждённые операции рекурсивных маршрутов (2026-09-30)
- PUT и restore проверяют ok, serverId, полный список и pushedRoutes; backend добавляет serverId к чтению, шлюзам и receipts. Старые поля сохранены. Новый frontend требует совместимый обновлённый backend; старый ответ безопасно блокирует запись.
- Форма сохраняется при HTTP/неподтверждённом ответе; данные таблицы не заменяются черновиком. Синхронный lock объединяет save/delete/restore, блокирует повтор и обычную смену устройства; поля/закрытие недоступны при ожидании. Ошибка применения запускает повторное чтение, поскольку RouterOS мог применить часть запроса.
- Чтение валидирует snapshot и принадлежность устройству, сохраняет последний снимок при отказе; начальная неизвестность и stale empty не выдаются за «Нет маршрутов». Late read не заменяет другой срез. Mode/backend размонтируют прежний контекст; freshness чтения/записи раздельна. Gateway error показан явно.
- Группа определяется адресом и таблицей. Редактирование поиска берёт все endpoints группы из полного снимка, сохраняя скрытые поиском endpoints и другие таблицы. Действия подписаны/видимы с клавиатуры, write-права и enabled устройства проверяются; readonly история доступна.
- Проверки: 35 E2E (данные/операции/права/история/навигация/шапка), TS/lint, обе production-сборки и backend config-sync прошли. После разделения запрета restore и доступности чтения/отмены повторно прошли 11 общих history сценариев.
- Далее 10.25: валидация backend PUT/restore до сетевых действий; затем URL/source E2E, nullable наблюдаемые поля и визуальная приёмка. Legacy mapRosManagedRoutes ещё подставляет значения при недостоверных полях — раздел целиком не принят. Реальные RouterOS/DB/JWT не проверены. Последняя квота: 34% окна, 36% недели использовано.
Блок 10.23 — адаптивность и локальная приёмка OSPF (2026-09-30)
- Одна профильная сводка на вкладку вместо дублирования. Мобильные вкладки/таблицы прокручиваются внутри контейнеров; детали находятся под графом. Выбранный узел центрируется, легенда читабельна и включает согласование/неизвестность; семантические цвета текущей темы.
- Поиск, вкладки, кнопки таблицы и узлы доступны с клавиатуры. Enter/Space открывают детали; Escape закрывает и возвращает фокус. Reduced motion отключает SVG-анимацию, переключатель учитывает настройку устройства. Пульсация меняет прозрачность, сохраняя стабильную цель клика.
- Проверки: 43 профильных E2E, восемь source/history E2E, девять unit, TS/lint и production frontend (34 страницы) прошли. После последних коротких подписей повторно прошли три layout/motion сценария; восемь desktop/mobile снимков просмотрены. Первичный прогон: 44/45, нестабильная SVG-геометрия исправлена и identity click повторно прошёл без force.
- ReUI checklist применён в границах OSPF: Frame/Data Grid и общий KpiStatGrid переиспользованы, registry и общая тема не изменены. Backend regression/build прошли в 10.22; backend после него не менялся.
- OSPF завершён в границах локальной приёмки; реальные RouterOS/DB/JWT остаются внешней проверкой. Далее 10.24: рекурсивные маршруты — сохранение формы, строгий receipt, чтение/контекст/права. Последняя квота: 25% окна, 35% недели использовано; продолжать по поручению пользователя.
Блок 10.22 — метаданные и однозначные узлы OSPF (2026-09-30)
- Неизвестный subtype OSPF-маршрута показывается нейтрально, без intra-area fallback. Unknown multihop BFD не становится false. Legacy parsers совместимы; строгий каталог проверен raw fixtures.
- Router ID main/имя/null/несколько разных ID устройства не выдаются за один фактический IPv4 ID. Дубли между устройствами не связывают соседа с произвольным сервером. Однозначные наблюдаемые ID сопоставляют известные узлы; неизвестный удалённый узел остаётся отдельным, без угадывания.
- Проверки: 13 разных metadata/identity/links/states/values E2E, два identity unit, backend live-maps/build, TS/lint прошли. Сначала identity click попал на анимированный bbox группы; сценарий повторно прошёл с реальным hit target — неподвижным circle. Одна старая warning frontend, две backend; зависимость inventory labels useMemo исправлена.
- Далее desktop/mobile, keyboard/focus, reduced motion и профильная production-приёмка OSPF. Последнее чтение: 17% окна использовано; локальный коммит без push, реальные RouterOS/DB/JWT не проверены.
Блок 10.21 — поиск и выбранный узел OSPF (2026-09-30)
- Поиск текущего раздела и node сохраняются в URL, переживают reload/history. Устройство/таблица/топология используют текущий срез; invalid/repeated/oversized q/node блокируют контекст. Недоступный узел закрывается отдельным действием без сброса устройства.
- Пустой поиск отличается от отсутствия конфигурации. Подпись «N из M», сброс только поиска и доступное имя input добавлены через существующий DataPageToolbar. Область операции обозначена: все интерфейсы устройства, независимо от поиска; readiness проверяет полный каталог устройства.
- Проверки: 27 основных E2E плюс выбранный узел/reload/back (28 разных сценариев), три unit, TS/lint и production frontend (34 страницы) прошли. Новый тест нашёл безымянную кнопку закрытия; aria-label исправлен, сценарий повторно прошёл. Один прежний warning frontend. Компоненты ReUI/тема не изменены.
- Далее дополнительные неизвестные метаданные (тип маршрута, multihop, Router ID) и desktop/mobile/keyboard приёмка. Последнее чтение квоты: 14% окна использовано. Локальный коммит без push.
Блок 10.20 — URL-контекст и завершение OSPF-записи после history (2026-09-30)
- Устройство/вкладка контролируются URL; reload/back восстанавливают выбор, другие параметры сохранены. Повторные/невалидные параметры и отсутствующее устройство дают явный alert, не раскрывают общий каталог и не показывают нулевую сводку; reset исправляет только этот контекст.
- После history во время POST новая форма остаётся заблокированной до завершения прежней операции и повторного опроса. Завершение всегда освобождает lock живого родителя; после смены источника/unmount callback игнорируется. Поздний результат не выдаёт toast в новой форме, подтверждённый receipt привязан к исходному устройству.
- Проверки: 17 URL/operations/freshness/interface-values E2E, восемь source read/write E2E и два unit прошли. TS чистый, lint один старый warning; первый unit-запуск дал системный ENOMEM до теста, повторный прошёл. Next Suspense добавлен для URL-контекста; production проверить после следующего блока.
- Далее поиск/контекст выбранного объекта, затем desktop/mobile и клавиатура. Использовано 10% окна; локальный коммит без push.
Блок 10.19 — интерфейсы и метрики строгого OSPF-каталога (2026-09-30)
- Interface cost/priority/timers/type/disabled/inactive/useBfd и instance version/routerId/flags допускают null без legacy defaults. Оптимизация запрещена при неизвестных costs/состояниях выбранного устройства. DTO frontend выводятся из Zod, вместо дублирующих интерфейсов.
- Route cost читается только из ospf-metric; distance больше не выдаётся за cost. Наблюдаемые нули остаются нулями. По документации RouterOS interface cost допускает 0..65535: исправлена граница индекса соседей из 10.16. Чтение cost=0 корректно; существующая политика записи min=1 сохраняется, такая операция не предлагается.
- Проверки: 21 E2E (interface-values/values/states/operations/routing-tables), четыре cost/state unit, test:live-maps и обе production-сборки прошли. TypeScript чистый, lint без ошибок (три старых warning). Правила сетевых операций/legacy endpoints не изменены.
- Следующий объём: URL устройства/вкладки/поиска с back/reload и late-write, desktop/mobile приёмка. При аудите дополнительных метаданных не считать multihop=false/тип O маршрута доказанными только по прежним parser defaults. Использовано 6% окна; локальный коммит без push.
Блок 10.18 — неизвестные показатели BFD и приоритет соседей (2026-09-30)
- Строгие DTO каталога отделены от legacy: BFD multiplier/tx/rx/hold/counters и neighbor priority/stateChanges допускают null. Отсутствующие/некорректные значения не получают defaults; priority=0 и наблюдаемые нули сохраняются. Actual TX не подменяется desired TX; единицы us/ms/s и составные/clock durations проверяются без частичного parseInt.
- Таблицы показывают «—» для null, 0/0ms для измеренного нуля. Подпись TX факт / RX минимум соответствует источникам. Общий Rx неизвестен при неполном составе, подтверждённая сумма 0 видна. Старые endpoints и алгоритм оптимизатора совместимы.
- Проверки: 15 OSPF E2E (values/data/states/operations), test:live-maps с raw fixtures, frontend TypeScript и backend build прошли. Lint без ошибок; один старый warning frontend и два backend. MCP ReUI checklist получен; vendored компоненты/тема не изменены.
- Следующий блок: nullable interfaces/instances/route metric и readiness записи, затем URL/layout. Окно сбросилось; использовано 3%, недельного 31%. Локальный коммит без push, реальные RouterOS/DB/JWT не проверены.
Блок 10.17 — strict BFD и контрольная регрессия (2026-09-30)
- Strict-state режим BFD parser закреплён прямыми backend fixtures: missing/blank → Unknown, known up/down сохраняются; legacy missing → Down остаётся совместимым. Изменений сетевых правил нет.
- Восемь OSPF source E2E, один freshness E2E, весь test:live-maps, backend build и текущий production frontend (34 страницы) прошли. Первоначальный запуск backend регрессии дал системный ENOMEM в tsx до тестов; повторный запуск прошёл. Lint без ошибок, четыре прежних warning (два frontend, два backend).
- В карте этапа 10 сохранён точный порядок nullable parser/DTO/Zod/UI/readiness/tests и таблица подменённых значений. Приоритет следующего блока: не подменять missing счётчики/таймеры и route metric нулями/distance; затем URL и визуальная приёмка.
- Использовано 98% пятичасового окна. Этап 10 остаётся в работе, стадии 11–12 не начаты; реальные RouterOS/DB/JWT недоступны. Локальный коммит без push.
Блок 10.16 — cost в области OSPF (2026-09-30)
- Индекс cost учитывает устройство, интерфейс и areaId. Одинаковое имя в разных областях не подставляет чужую стоимость. Конфликтующие шаблоны одного ключа и cost вне диапазона 1..65535 дают null; одинаковые подтверждённые значения сохраняются.
- Четыре unit-теста (cost/state), семь E2E (области/конфликт плюс операции OSPF) и TypeScript прошли. Это только отображение соседей; оптимизатор и правила RouterOS не изменены. Далее backend nullable показатели, URL и визуальная приёмка. 97% окна использовано; локальный коммит без push.
Блок 10.15 — диапазон AS в клиенте BGP (2026-09-30)
- Клиентская схема согласована со строгим backend parser: localAs/remoteAs — null или целое 1..4294967295. Ноль и переполнение отклоняют ответ; предыдущий снимок сохраняется как неизвестный, повторный успешный опрос восстанавливает данные.
- 13 BGP data E2E и TypeScript прошли, включая обе AS × ноль/переполнение. На nullable показатели OSPF, URL и визуальную приёмку это не влияет; они остаются следующим основным объёмом. Локальный коммит без push.
Блок 10.14 — неизвестный cost соседа OSPF (2026-09-30)
- При отсутствии интерфейса в каталоге cost соседа остаётся null: таблица, линия топологии и панель узла показывают «—». Значение 10 больше не выдумывается; известные costs и сортировка сохранены.
- 11 E2E states/routing-tables и TypeScript прошли. Production-сборки проверены в 10.13; повторная полная регрессия не требовалась. Далее nullable показатели строгого backend-каталога, URL и layout; backend defaults ещё требуют проверки. 96% окна использовано; локальный коммит без push.
Блок 10.13 — подтверждённые состояния OSPF/BFD (2026-09-30)
- Восемь состояний соседства RouterOS распознаются независимо от регистра. Attempt, Init, ExStart, Exchange и Loading сохраняются как переходные состояния; неизвестные значения показываются нейтрально, без подмены Down. Топология различает Pending/Unknown и подтверждённый отказ. При неизвестном состоянии сводка не выдаёт полный подсчёт состояний.
- Строгий /ospf/catalog сохраняет Unknown при отсутствии BFD state; legacy endpoints оставлены совместимыми. Правила оптимизации и сетевых операций не менялись.
- Проверки: 14 E2E (states/data/operations), два unit-теста агрегации топологии, TypeScript, production frontend (34 страницы) и backend build прошли. Lint: два прежних warning stateClass/fmtMs.
- Следующий блок: неизвестные cost/счётчики/таймеры OSPF и BFD (сейчас некоторые backend defaults ещё подменяют отсутствующие значения), затем URL-контекст и desktop/mobile приёмка. Этап 10 не завершён; реальные RouterOS/DB/JWT не проверены. Локальный коммит без push.
Блок 10.12 — время чтения и подтверждения OSPF (2026-09-30)
- Отметки получения каталога, успешного опроса устройства и подтверждения оптимизации API разделены. Partial сохраняет время отказавшего устройства, общий отказ не обновляет успешные отметки. Удалённые/выключенные устройства исключаются из receipts; источник сбрасывает прежние времена.
- Подтверждение записи появляется только после проверки ответа правильного устройства; последующая ошибка чтения не выдаётся за отказ записи и не стирает её receipt. Времена обозначены как получение браузером, не измерение RouterOS.
- Семь E2E прошли: clocks/partial/global/recovery плюс шесть операций/read-права/receipt после ошибки poll. TypeScript чистый, lint — два старых warning. Далее — неизвестные состояния/показатели OSPF, URL и визуальная приёмка. Квота: 90% окна использовано; локальный коммит без push.
Блок 10.11 — защита оптимизации OSPF (2026-09-30)
- Синхронный lock исключает повторный POST. Во время операции заблокированы Refresh, смена устройства и вкладки; после API-ответа повторное чтение блокирует новую запись до подтверждённого каталога. Право UI — mm:servers:write, соответствующее существующему backend-маршруту /servers/:id/ospf/optimize; политика backend не изменена.
- Подтверждение проверяет serverId, параметры/диапазоны, уникальные интерфейсы и согласованность applied/optimizedCount. Ошибка/чужой/невалидный ответ не выдаёт success; сохраняет постоянный alert и запускает чтение, поскольку составная операция могла применить часть costs. Транзакционность не добавлена и не обещана.
- Mounted guards отклоняют поздний read/write после смены backend/live/mock: нет toast/ошибки/опроса в новом контексте. Уже отправленный RouterOS-запрос сменой страницы не отменяется.
- 21 OSPF E2E прошёл: семь данных, шесть operations/read-права и восемь source read/write. TypeScript чистый, lint — только два исходных warning stateClass/fmtMs; BackendInstance удалён. Далее — URL и временные отметки каждого устройства/подтверждения API, поля и layout. Квота: 88% окна использовано; локальный коммит без push.
Блок 10.10 — достоверность данных OSPF (2026-09-30)
- Экран использует /ospf/catalog и inventory, проверяет все пять списков/поля/ID/failures и включённый контекст. Partial сохраняет набор отказавшего устройства, successful empty очищает; общий/ошибочный ответ сохраняет кэш. Mode/backendUrl изолированы key/cleanup.
- Начальный отказ не выглядит как пустая настройка/нули. KPI неизвестны, строки neighbors/BFD/interfaces/routes явно отмечены при сбое. Топология не считается текущей при неполном опросе; сводка исправного выбранного устройства остаётся доступной. Rail включает включённые устройства без OSPF-строк.
- Постоянный alert/повтор и отметка браузерного получения; повтор Refresh блокируется во время чтения. Оптимизация пока доступна только после полного успешного каталога. Времена успешного опроса каждого устройства, права/lock/поздний write ещё требуют следующего блока.
- Удалён придуманный live optimal cost из порядка интерфейсов; opt показан только после ответа оптимизации. Убрано ложное mock «применены»: локальное изменение обозначено предпросмотром; кнопка сброса не выдаётся за серверный опрос.
- 17 E2E прошли (семь OSPF data + routing/BGP), TypeScript чистый, lint без ошибок с двумя исходными warning stateClass/fmtMs и неиспользуемым BackendInstance (удалён в 10.11). Далее — операции OSPF, URL/свежесть, unknown state/counters и layout. Квота: 84% окна использовано; локальный коммит без push.
Блок 10.9 — строгий каталог OSPF (2026-09-30)
- Добавлен /ospf/catalog с пятью списками и failures по устройствам. Строгий reader не скрывает отказ BFD или /ip/route за []; успешный пустой ответ остаётся пустым. Чужой serverId, пустые/повторяющиеся ID в разделе отклоняются.
- Снимок устройства консервативно атомарен: отказ любой зависимости делает весь его набор неподтверждённым, исправные устройства возвращаются. Это не обещает независимую доступность BFD/core при частичном сбое одного роутера. Legacy /ospf/all и старый reader сохранены до миграции consumers; правила optimize/apply не менялись.
- Unit проверил partial/empty/all-failed/context/duplicates и реальные ветки строгого reader при отказе BFD/routes; Fastify inject с production Zod проверил HTTP каталог. Backend build прошёл. Lint без ошибок; два исходных warning в ospf.ts (and, measurePingByInterface) сохранены.
- Далее — потребитель /ospf/catalog: валидация/inventory, кэш, неизвестные статусы/сводка, readiness оптимизации и source. Квота: 80% окна использовано; продолжаем по прямому поручению пользователя. Локальный коммит без push.
Блок 10.8 — визуальная и профильная приёмка BGP (2026-09-30)
- Два viewport 390×844/1440×1000, клавиатура и отсутствие общего переполнения проверены. Раскрытие сессии имеет явную кнопку с доступным именем/aria-expanded, Enter обновляет session URL. Выбранная сессия, скрытая фильтрами, имеет отдельное сообщение.
- Просмотрены шесть PNG BGP/деталей/аналитики. Визуальная проверка выявила обрезанные KPI и широкие детали на телефоне: подписи сокращены, детали ограничены viewport; таблица и state-фильтры сохраняют горизонтальную прокрутку. KpiStatGrid/Frame/Data Grid переиспользованы без изменений registry.
- 23 профильных E2E и четыре source-сценария прошли последовательно (27), четыре unit URL и server catalog/parser чистые. Frontend production build — 34 страницы, backend build, TypeScript/lint прошли.
- BGP завершён в границах локальных HTTP-фикстур и этих viewport. RouterOS/JWT/БД не проверены; общий accessibility/performance — 12. Старый неоднозначный BGP API/alert-engine остаётся для 11Б. Далее — OSPF: fetchServerOspf скрывает отдельные отказы BFD/routes; нужен строгий каталог и кэш с неизвестными состояниями. Квота на начале приёмки: 76% окна использовано. Локальный коммит без push.
Блок 10.7 — URL-фильтры BGP (2026-09-30)
- Поиск, тип, состояние и завершённый FilterQuery хранятся в URL. Draft не сериализуется как готовое условие; поиск использует replace, изменения фильтра — push. Back/reload восстанавливают срез и сохраняют устройство/сессию/сторонние параметры.
- Валидатор проверяет поля, operators/arity/значения, IDs, глубину/размер дерева и повторные URL-ключи. Некорректная ссылка явно блокирует расширение списка и предлагает сброс. AFI options получаются из текущих строк API/mock; сравнение точное, без подмены фактических семейств статическим IPv4.
- Доступны фильтры Unknown state/type, type-кнопки имеют aria-pressed. Поиск имён устройств учитывает регистр.
- 21 E2E прошёл, четыре unit URL проверили roundtrip/nesting/negation/draft/invalid/limits, TypeScript/lint чистые. Квота: 74% окна использовано, 27% недельного. Далее — desktop/mobile BGP, production build; затем каталог OSPF. Локальный коммит без push.
Блок 10.6 — неизвестные AS и тип BGP (2026-09-30)
- Новый catalog parser возвращает null для отсутствующей/некорректной AS, проверяет диапазон 1–4294967295; тип Unknown при недостаточном контексте. Legacy parser и его consumers сохранены.
- Экран/таблица показывают «AS неизвестна» и «Тип неизвестен» вместо AS0/eBGP. Неизвестный тип не добавляется к iBGP/eBGP; сводка типов и их сравнение не выдаёт неполный набор за полный.
- Unit проверил отсутствие/невалидные значения/верхнюю границу, равные и разные AS. 15 E2E BGP/OSPF прошли, frontend/backend TypeScript и lint чистые.
- Далее — URL фильтров/поиска, доступные состояния и desktop/mobile BGP, затем OSPF. AFI показывается фактической строкой API; варианты фильтра AFI требуют согласования с таким представлением. Реальный RouterOS не проверен; локальный коммит без push.
Блок 10.5 — URL, свежесть и источник BGP (2026-09-30)
- URL хранит server/session/tab, сохраняет сторонние параметры; раскрытие строки связано с session. Возврат и reload восстанавливают контекст. Недоступное устройство/сессия из ссылки показывают сообщение и явный переход, не подменяются всеми устройствами. Включён preserveSelection установленного rail: тест выявил сброс при пустом начальном inventory.
- Время получения каталога и последнего успешного опроса каждого включённого устройства разделены. Частичный/общий отказ сохраняет прежние отметки; эти времена не объявляются измерением RouterOS.
- 19 различных E2E прошли: 13 BGP/OSPF профиля, два URL/freshness и четыре backend/live/mock late GET в отдельной последовательной конфигурации. После исправления rail повтор URL/routing прошёл; async URL assertions ожидают навигацию. TypeScript/lint чистые.
- Далее — ASN/type unknown вместо fallback 0/eBGP, визуальная приёмка BGP и достоверность OSPF. Фильтры поиска/FilterQuery ещё локальные, их URL-перенос остаётся в этом этапе. Квота на проверках: 69% окна использовано, 26% недельного. Локальный коммит без push.
Блок 10.4 — неподтверждённые поля и экспорт BGP (2026-09-30)
- Новый каталог использует отдельный parser без defaults старого API: отсутствующие/некорректные таймеры, сообщения, prefix-count и AFI неизвестны. Наблюдаемый 0 сохранён, hold-time infinity отображается как 0. UPDATE-счётчики не объявляются числом префиксов; prefixesTx неизвестен, поскольку фактический каталог отправленных маршрутов не получен. Старый parser/API сохраняют прежнюю совместимость.
- API AFI отображается вместо придуманного IPv4, active prefixes не копируется из Rx. Неполная сумма неизвестна, сравнение пиров скрыто при пропуске Rx. Unknown не входит в число отказавших сессий. В карточках удалён hardcoded AS65001; AS берётся из сессий.
- Удалён RouterOS Export с выдуманными connection/filter/table параметрами; детали объясняют предел полученного API. Значения null и наблюдаемый ноль отображаются различно.
- Сверка: https://help.mikrotik.com/docs/spaces/ROS/pages/328220/BGP и /routing/bgp. 13 E2E, unit parser/Fastify, общий test:live-maps, TypeScript/lint/backend build прошли. Реальный RouterOS не проверен. Квота: 64% окна использовано на начале проверок.
- Далее — URL-контекст, свежесть каждого устройства, source/late-response и ПК/телефон. ASN/type fallback старого parser пока сохраняются и требуют отдельного уточнения. Локальный коммит без push.
Блок 10.3 — достоверность данных экрана BGP (2026-09-30)
- Экран использует /bgp/catalog и валидирует каталог/inventory, уникальные ID, failures и принадлежность включённым устройствам. Частичный отказ сохраняет строки отказавшего устройства, успешный пустой опрос удаляет их; общий сбой сохраняет последний снимок.
- Неизвестное начало не показывает пустой каталог/нули. Отказавшие строки имеют состояние «Неизвестно»; неполная сводка/аналитика не выдаёт старые значения за текущие. Исправный выбранный срез остаётся доступным. Null мониторинга не превращается в online. Смена mode/backendUrl перемонтирует источник; позднее чтение отклоняется cleanup.
- Постоянный alert с повтором, отметка получения браузером и блокировка повторного Refresh. Удалён пустой header Export; вкладки получили aria-pressed. Убран fallback выбранного устройства на все устройства.
- 12 E2E прошли: семь ошибок ответа/HTTP/inventory, частичный отказ и очистка, сортировка/раскрытие/Filters/пустые состояния BGP и OSPF. TypeScript/lint чистые.
- Далее — достоверность полей BGP (AFI, active prefixes, неизвестные RouterOS counters/state), URL/свежесть и приёмка источника/ПК/телефона. Эти поля ещё не исправлены; реальный RouterOS не проверен. Локальный коммит без push.
Блок 10.2 — серверный каталог BGP (2026-09-30)
- Добавлен /bgp/catalog: sessions и failures по устройствам. Poller различает успешный пустой ответ и отказ, отклоняет чужой serverId, пустые/повторяющиеся ID. Старый /bgp/sessions сохраняет массив для оповещений; его неоднозначность остаётся до 11Б.
- Выборный /servers/:id/bgp/sessions возвращает 503 при отказе вместо 200/[]; 404/валидация ID сохранены. Изолированные зависимости маршрута позволяют проверять HTTP без DB/RouterOS.
- Unit/Fastify проверили частичный/полный/пустой опрос, контекст/дубликаты, совместимый массив, 503/404/400 без лишнего опроса. TypeScript, lint и backend production build прошли; тест включён в test:live-maps.
- Далее — экран BGP: проверка нового каталога, кэш при частичных отказах, неизвестные статусы/сводка, источник и свежесть. Реальные устройства/JWT/БД не проверены. Локальный коммит без push.
Блок 10.1 — карта маршрутизации и диагностики (2026-09-30)
- План сохранён в ux-ui-stage-10.md: API, проблемы достоверности, порядок, референсы и схема. Переиспользуем Frame/Data Grid/панели ReUI; сетевые правила не меняем.
- BGP: новый /bgp/catalog с sessions/failures; старый /bgp/sessions сохраняется для оповещений до 11Б. Выборный опрос не должен скрывать отказ за []. Далее — серверный каталог и unit-проверки.
- Документация проверена; код не менялся. Квота: 58% пятичасового лимита использовано, 25% недельного. Продолжаем согласно поручению пользователя; локальный коммит без push.
Блок 9.64 — завершение локальной приёмки этапа 9 (2026-09-30)
- GET /gre/tunnels отклоняет явный невалидный serverId с HTTP 400 до БД/RouterOS вместо опроса всех устройств. Fastify inject проверил пять ID (включая пустой) для прямого GRE и общего Filters-каталога; TypeScript/backend build/lint прошли. Успешный и реальный выборный опрос требуют внешнего окружения.
- После 183 общей E2E регрессии прошли ещё 26 source-сценариев: Firewall 4, Filters 6, IPsec 6, GRE 6, VXLAN 4; отдельные Next-серверы запускались последовательно. Итого 209 сценариев последней приёмки этапа 9. Production frontend build — 34 страницы, backend build и unit каталогов/планов/экспортов чистые.
- Этап 9 завершён в границах локальной приёмки: операции показывают подтверждение API, ошибка сохраняет ввод/последние данные, повтор защищён, выбранное устройство не подменяется другим контекстом, unavailable API не выдаёт фиктивные действия/числа. ReUI Frame/base-nova и установленные компоненты сохранены; новые registry-компоненты не устанавливались.
- Ограничения: HTTP fixtures не проверяют RouterOS/JWT/БД, сетевое применение и транзакционность составных операций; VXLAN доступен только для чтения/экспорта, live-пулы GRE не представлены API. Эти ограничения явно отображаются/описаны. Общий GRE failures ещё надо использовать в карте сети (этап 10) и оповещениях (11Б). Адаптивность проверена на 390px/1440px, полный accessibility/performance аудит — этап 12.
- Следующий шаг — 10.1: карта API/референсы этапа 10, затем достоверный опрос BGP. Выявлено: /bgp/sessions возвращает [] при отказе устройства, /ospf/all скрывает частичные ошибки, карта/оптимизатор превращают отказ каталогов в пустые данные. Полные детали и порядок будут сохранены в docs/ux-ui-stage-10.md. Локальный коммит без push.
Блок 9.63 — приёмка GRE/VXLAN и мобильные панели (2026-09-30)
- GRE/VXLAN используют компактную сводку в две колонки на телефоне и краткие подписи. GRE KPI теперь относится к выбранному устройству/туннелю, а не глобальному списку. Неизвестная сводка учитывает выбранный срез. Для этого KpiStatGrid получил необязательный gridClassName; существующие потребители сохраняют прежнюю раскладку.
- Форма GRE и экспорт имеют ширину телефона; footer больше не обрезает «Копировать». На ПК панели ограничены шириной lg. GRE-поля получили доступные имена, optional IP не помечены обязательными; пустой site не выводит скобки. Убраны устаревшие справочные команды VXLAN arp-proxy/mac-learning и лишний баннер GRE; справка ведёт к MikroTik. VXLAN не обещает шифрование через обычный GRE.
- Просмотрены восемь PNG в docs/ux-ui/screens: GRE/VXLAN и формы/экспорт для ПК/телефона. Четыре сценария keyboard/layout проверили точный serverId/VNI, сохранение, отсутствие переполнения, полную мобильную ширину и границы кнопок footer. Общая регрессия этапа 9: 183 E2E прошли (source-конфигурации проверяются отдельно). Production frontend build — 34 страницы; TypeScript/lint/diff-check чистые. Backend test:live-maps, test:config-sync и unit экспортов прошли.
- Перегенерированные прежние Filters/IPsec PNG восстановлены к своим закоммиченным вариантам; новых продуктовых изменений там нет. Далее — отдельное исправление serverId GRE API и фиксация границ завершения этапа 9. Реальные RouterOS/JWT/БД не проверены. Локальный коммит без push.
Блок 9.62 — возможности API GRE-пулов (2026-09-30)
- Удалён фиктивный live-каталог из poolId интерфейсов: он не содержит CIDR/ёмкость, но раньше изображал полное заполнение и свободные блоки. Live KPI пулов теперь неизвестен с подписью «нет данных API», раздел объясняет отсутствие каталога/управления. Инвентаризация настоящих /ip/pool и её API не изобретены.
- Убраны кнопки создания пула, пустые меню изменения/удаления и selector пула, который не входил в GRE write-body. Mock-каталог остаётся только для просмотра с явной подписью; настройки локального IP остаются доступными. Кнопки разделов получили aria-pressed и имя группы.
- Семь E2E прошли: числовая сортировка/поиск 12 туннелей, отсутствие подмены неизвестных пулов пустыми, mock-каталог/no writes и три формы. TypeScript/lint чистые.
- Далее — desktop/mobile GRE/VXLAN и профильная регрессия. Расширение backend настоящим управлением адресными пулами — отдельный функциональный объём, текущий UX честно отражает доступные API. Локальный коммит без push.
Блок 9.61 — поддерживаемые параметры GRE/PSK и .rsc (2026-09-30)
- GRE .rsc вынесен в generateGreRsc: quoted RouterOS strings/PSK, нормализованные комментарии, локальный IP только при наличии, без придуманных удалённых IP/маршрутов и дополнительных manual IPsec peer/policy/proposal поверх автоматического ipsec-secret. Параметры сверены с https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE и правилами Scripting. FastPath в снимке не меняется автоматически; несовместимый IPsec/FastPath подписан в комментарии.
- Из формы удалены IKE/алгоритмы/DH/PFS/lifetime, которые API не принимает; доступный PSK и пределы формы объяснены. Отключение IPsec отправляет пустой ipsecSecret, иначе PATCH сохранял старый PSK. Переключатели и показ PSK получили доступные имена; FormToggle поддерживает необязательный ariaLabel. Подсказка FastPath больше не обещает аппаратное ускорение.
- Unit экспорта проверил строки/инъекцию новой команды/optional IP/no duplicate IPsec; шесть E2E PSK/create/edit/export прошли. TypeScript/lint чистые. RouterOS применение и реальное снятие PSK остаются внешней приёмкой.
- Далее — достоверное отображение live-пулов и возможности API, затем layout и профильная регрессия GRE/VXLAN. Локальный коммит без push.
Блок 9.60 — свежесть и снимок экспорта GRE (2026-09-30)
- Успешный ответ каталога и опрос каждого включённого устройства имеют отдельные отметки получения браузером. При failures отметка устройства сохраняется, при глобальной ошибке не обновляется. Подтверждение API записи/восстановления показано отдельно от опроса. Эти отметки не объявляются временем измерения RouterOS.
- Экспорт фиксирует туннель, имена устройств, время и актуальность при открытии. Фоновый опрос не меняет уже открытый код/контекст; устаревший статус — неизвестный, mock явно подписан. Source/URL смена закрывает прежний снимок.
- 11 E2E прошли: часы/частичный и полный отказ/восстановление/экспорт плюс readiness и данные. TypeScript и lint экрана чистые.
- Далее — корректность самого GRE .rsc и параметров формы, реальные возможности live-пулов и desktop/mobile. Локальный коммит без push.
Блок 9.59 — готовность и изоляция операций GRE (2026-09-30)
- Запись разрешена только после успешного чтения inventory/GRE на включённом устройстве без его failure. Частичный отказ не блокирует исправное устройство; меню и выбор сервера показывают недоступность отказавшего/выключенного. Проверка повторяется непосредственно перед запросом.
- Общий синхронный lock объединяет создание/редактирование, переключение, удаление и восстановление до последующего опроса. Ручное обновление заблокировано во время записи; после API-ошибки возможен повтор, после подтверждённого удаления и отказа чтения диалог закрывается, старые строки остаются неизвестными. Позднее завершение старого контекста не вызывает toast/опрос/ошибку в новом. Уже отправленная операция не отменяется сменой страницы.
- Проверено 25 различных E2E: 11 истории, три формы, пять readiness/delete/toggle и шесть поздних ответов в отдельной source-конфигурации. TypeScript и lint чистые. Проверки обнаружили и устранили незавершённое освобождение lock в delete/toggle; повтор прошёл.
- Далее — временные отметки и экспорт GRE, достоверность live-пулов, desktop/mobile приёмка. JWT/RouterOS остаются внешней приёмкой. Локальный коммит без push.
Блок 9.58 — достоверность чтения GRE (2026-09-30)
- Добавлена схема GRE с IPsec/PSK, уникальными составными serverId/id, уникальными failures и запретом одновременного успеха/отказа устройства. Inventory валидируется и принимает null мониторинга; rail показывает неизвестный статус. Ошибочный ответ не заменяет подтверждённые данные.
- Частичный отказ сохраняет строки отказавшего включённого устройства, успешный пустой опрос удаляет их. Постоянный alert содержит причину и повтор; начальный отказ не выглядит как отсутствие туннелей. Неполная сводка — неизвестная, отказавшие строки — «Неизвестно», фильтр активных исключает неподтверждённые статусы. Source/URL key и epoch исключают поздний результат чтения другого контекста.
- 22 E2E прошли: восемь сценариев данных плюс ссылки/формы/удаление/переключение. TypeScript и lint чистые. Удалены остатки неиспользуемых UI-хелперов; таблица использует стабильный составной ID.
- На время частичного отказа изменения пока блокируются для всего GRE. Следующий блок — readiness каждого устройства, общий lock записи и поздние результаты операций. Live-пулы/экспорт требуют дальнейшей проверки. Локальный коммит без push.
Блок 9.57 — устройства без снимка мониторинга (2026-09-30)
- IPsec/VXLAN принимают законный status: null из /servers до первого опроса, а также прежний ответ без status. В rail такой статус обозначен «Статус неизвестен»; он не выдаётся за online/offline и не делает успешный VPN-опрос ошибкой. Внутренний совместимый Server DTO сохраняет fallback, но отображение использует отдельный признак monitoringUnknown. Filters/Firewall уже принимают null.
- 14 E2E прошли, включая четыре новых HTTP-сценария null/missing и регрессию ошибок/частичных отказов IPsec/VXLAN. TypeScript и lint чистые. Реальные устройства не опрашивались.
- Далее — состояния данных GRE, затем readiness, изоляция операций и свежесть. Локальный коммит без push.
Блок 9.56 — ошибки общего GRE-каталога (2026-09-30)
- Общий GET /filters/gre-tunnels больше не превращает ошибку устройства в пустой успешный каталог: возвращает tunnels успешных устройств и failures с serverId/name/error. Опрос вынесен в тестируемый pollGreCatalog; чужой контекст строки считается отказом исходного устройства. Выборный успешный/503 путь сохранён.
- Явный невалидный serverId получает HTTP 400 до БД и не переключает запрос на все устройства. Нет изменений сетевого применения. Дополнительное поле failures совместимо с прежними потребителями, но карта сети/оповещения пока его игнорируют — их состояния входят в этапы 10/11 и не приняты этим блоком.
- Unit опроса проверил mixed/empty/all-failed/foreign/нет устройств; Fastify inject с production Zod compiler проверил четыре невалидных ID без запросов DB/RouterOS. TypeScript/backend build и lint новых файлов прошли. Тесты добавлены в test:live-maps. HTTP успех/503 с настоящей БД остаются внешней приёмкой.
- Далее — состояния/схемы/частичные отказы экрана GRE (он использует /gre/tunnels, уже имеющий failures), затем его readiness и контекст. Этап 9 открыт; локальный коммит без push.
Блок 9.55 — согласованность ответов IPsec/VXLAN (2026-09-30)
- IPsec дополнительно отклоняет чужой serverId вложенных peer/pool/shared-mode-config, повторные peer/сертификаты и отказ с пустым serverId. VXLAN отклоняет повторные failures, одновременные tunnel/failure одного устройства, несогласованные arpMode/arpProxy и повторные ID inventory. Прежние схемы payload и контекст выборного IPsec ответа сохранены.
- Противоречивый ответ целиком считается ошибкой чтения и не заменяет последние подтверждённые строки; вложенный объект не переносится под другой сервер. Старые ответы без arpMode совместимы.
- 24 E2E прошли: расширенные повреждённые/чужие payload IPsec и регрессия ссылок/сбоев/гонок VXLAN. TypeScript и lint четырёх файлов чистые. Backend в этом блоке не менялся; последний backend build — 9.54, frontend — 9.52.
- Далее — ошибки общего GRE-каталога и его потребители, затем экраны VXLAN/сводная регрессия этапа 9. Реальные RouterOS/JWT/БД не проверены. Локальный коммит без push.
Блок 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, строковые литералы RouterOS. Далее — согласованность ответа 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 | Клиенты | Клиенты |
| Sheet 8 | Форма клиента | Форма клиента |
| List 9 | Серверы | Сервер |
Блок 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 ПК, телефон | Устройство → свежесть → правила → действие |
| ReUI Sheet 8 | Форма ПК, телефон | 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 со схемой и референсами. Первичная инвентаризация 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: f8e7437210.
На старте уже изменены 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 в этом этапе.
- Сохранение: блокировать повторную отправку; закрывать форму и менять список только после успеха API. На 400/403/500/сетевой ошибке сохранять значения и показывать сообщение рядом с формой.
- Редактирование: загрузить полную модель до разрешения сохранения; защитить от ответа другого сервера и закрытой формы. Не выводить enabled из online/offline. Изменение подключения сбрасывает прежний результат проверки.
- Удаление: подтверждение конкретного объекта; не удалять строку при ошибке API; блокировать повтор.
- Включение: обновлять enabled через API, фактическую доступность не подменять локальным переключением.
- Опрос: результат по устройству; массово не более четырёх запросов одновременно, повтор только неуспешных. Ошибку перечитывания списка отличать от результата самого опроса.
- Добавить проверки по HTTP-пути frontend с контролируемыми ответами, а не только встроенный mock. Успех, 403, 500, таймаут, двойное нажатие и смена объекта во время запроса обязательны.
- Типизация, 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-table9.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 предупреждений; точный список. Это незакрытая часть этапа, правила не отключались |
Следующий запуск: продолжить этап 2, не переходить к этапу 3. Проверить лимит и HEAD; разобрать замечания установленного реестра, подготовить и проверить переход старых Filters в FilterQuery на эталоне серверов, выполнить визуальную и клавиатурную проверку эталона и итоговый ReUI audit. Затем завершить этап отдельным локальным коммитом. Текущее сохранение — промежуточный коммит, без push; ветку не выпускать.
Референсы: пример пагинации, PRO-таблица, Data Grid API, Filters API.
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 пропускает его оптимизацию; отчёт |
| Визуальная проверка | Просмотрены экраны 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. Это не полная приёмка доступности/производительности всего приложения.
Образец следующего переноса
- В выбранном доменном grid заменить
react-table-v8наreact-table, legacy-оболочку наDataGridShellи заголовки на новыйDataGridSortHeader. - Тип колонок —
ColumnDef<DataGridFeatures, T>, таблицы —Table<DataGridFeatures, T>. ИспользоватьuseTable({ features: dataGridFeatures, ... }); удалить старыеget*RowModel. Сверить переименованные sorting/pinning/resize props с установленным API. Сохранить стабильныйgetRowId. - Явно определить пагинацию: для полного списка без панели —
manualPagination: true; для серверной — передавать реальныйrowCount; для клиентской — подключить панель и контролируемую страницу. - Для Filters перенести поля
key → id, выбрать тип по данным, сохранить AND черезmigrateFilterQuery. Вычислитель сейчас поддерживает только операторы скалярных фильтров серверов и прежние текстовые contains; перед переносом дат, чисел или массивов расширить вычисление и тесты. Нельзя просто сплющить OR-дерево. - Проверить фильтрацию, сортировку, сброс/страницу, раскрытие и действия. Старую основу удалять только после последнего потребителя в этапе 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 | Поиск → страница таблицы → сортировка / выбор строки → детали |
| API Data Grid | Типизированные данные → 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, таблицы PRO, API Data Grid, API Filters.
Прямые потребители TanStack (47)
components/data-grids/asns-data-grid.tsxcomponents/data-grids/backups-data-grid.tsxcomponents/data-grids/bgp-sessions-data-grid.tsxcomponents/data-grids/certificates-data-grid.tsxcomponents/data-grids/communities-data-grid.tsxcomponents/data-grids/compact-data-grid.tsxcomponents/data-grids/data-collection-scheduler-data-grid.tsxcomponents/data-grids/domains-data-grid.tsxcomponents/data-grids/filters-data-grid.tsxcomponents/data-grids/firewall-rules-data-grid.tsxcomponents/data-grids/firewall-scenario-rules-data-grid.tsxcomponents/data-grids/gre-pools-data-grid.tsxcomponents/data-grids/gre-tunnels-data-grid.tsxcomponents/data-grids/ip-ranges-data-grid.tsxcomponents/data-grids/ospf-bfd-data-grid.tsxcomponents/data-grids/ospf-neighbors-data-grid.tsxcomponents/data-grids/ospf-routes-data-grid.tsxcomponents/data-grids/probes-schedule-data-grid.tsxcomponents/data-grids/probes-speed-probes-data-grid.tsxcomponents/data-grids/recursive-routes-data-grid.tsxcomponents/data-grids/route-optimizer-comm-recs-data-grid.tsxcomponents/data-grids/route-optimizer-full-routes-data-grid.tsxcomponents/data-grids/route-optimizer-ospf-preview-data-grid.tsxcomponents/data-grids/route-optimizer-wan-matrix-data-grid.tsxcomponents/data-grids/servers-data-grid.tsxcomponents/data-grids/shared/data-grid-shell.tsxcomponents/data-grids/shared/data-grid-sort-header.tsxcomponents/data-grids/subusers-data-grid.tsxcomponents/data-grids/traffic-flows-data-grid.tsxcomponents/data-grids/uptime-resources-data-grid.tsxcomponents/data-grids/uptime-speed-history-data-grid.tsxcomponents/data-grids/users-data-grid.tsxcomponents/data-grids/vxlan-data-grid.tsxcomponents/data-grids/wireguard-data-grid.tsxcomponents/data-grids/wireguard-peers-grid.tsxcomponents/data-table.tsxcomponents/ipsec/ipsec-users-grid.tsxcomponents/reui/data-grid/data-grid-column-filter.tsxcomponents/reui/data-grid/data-grid-column-header.tsxcomponents/reui/data-grid/data-grid-column-visibility.tsxcomponents/reui/data-grid/data-grid-table-dnd-rows.tsxcomponents/reui/data-grid/data-grid-table-dnd.tsxcomponents/reui/data-grid/data-grid-table-virtual.tsxcomponents/reui/data-grid/data-grid-table.tsxcomponents/reui/data-grid/data-grid.tsxcomponents/traffic/flow-analytics-panel.tsxcomponents/traffic/flow-traffic-map.tsx
Прямые потребители Filters (6)
app/(main)/backups/page.tsxapp/(main)/bgp/page.tsxapp/(main)/servers/page.tsxapp/(main)/statistics/page.tsxcomponents/backups/backups-history.tsxcomponents/data-page-toolbar.tsx