From 59938118bdf16e3ef899c45e04e5709de57eebcc Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sun, 11 Oct 2026 13:10:37 +0700 Subject: [PATCH] =?UTF-8?q?fix(traffic):=20=D0=B4=D0=BE=D0=B6=D0=B4=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=D1=81=D1=8F=20=D0=BA=D0=B0=D1=82=D0=B0=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B0=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=81=D0=B0=D0=BC=D0=B8=20=D0=B2=D1=8B=D0=B1?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=81=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(main)/traffic/page.tsx | 16 ++-- docs/ux-ui-external-acceptance.md | 12 ++- docs/ux-ui-plan.md | 6 +- docs/ux-ui-progress.md | 12 ++- docs/ux-ui-remaining-acceptance.md | 14 ++- docs/ux-ui-stage-12.md | 10 ++- docs/ux-ui-test-server.md | 12 ++- .../traffic-confirmed-catalog-2026-10-11.json | 85 +++++++++++++++++++ tests/e2e/traffic-catalog.spec.ts | 45 ++++++++++ 9 files changed, 194 insertions(+), 18 deletions(-) create mode 100644 docs/ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json create mode 100644 tests/e2e/traffic-catalog.spec.ts diff --git a/app/(main)/traffic/page.tsx b/app/(main)/traffic/page.tsx index 6cc4ac56..5ce2f46b 100644 --- a/app/(main)/traffic/page.tsx +++ b/app/(main)/traffic/page.tsx @@ -787,6 +787,11 @@ export default function TrafficPage() { const trafficLoading = trafficState?.key !== trafficKey const trafficError = trafficState?.key === trafficKey ? trafficState.error : undefined const [liveServers, setLiveServers] = useState([]) + const trafficSourceKey = JSON.stringify([isLive, backendUrl]) + const [liveServerOwner, setLiveServerOwner] = useState(null) + const confirmedLiveServer = isLive && liveServerOwner === trafficSourceKey + && /^[1-9]\d*$/.test(selectedId) && Number.isSafeInteger(Number(selectedId)) + && liveServers.some(server => server.id === selectedId) const [serverIfaces, setServerIfaces] = useState([]) const [selectedIface, setSelectedIface] = useState("__all__") const [hideDisabledIfaces, setHideDisabledIfaces] = useState(true) @@ -822,7 +827,7 @@ export default function TrafficPage() { const currentDetail = detailResult?.key === detailKey ? detailResult : null const detailBusy = isLive && effectiveMode === "servers" && Boolean(selectedId) && currentDetail === null const { sample: liveSample, error: liveStreamError, receivedAt: liveReceivedAt } = useTrafficLive({ - enabled: isLive && effectiveMode === "servers" && liveServers.some((s) => s.id === selectedId), + enabled: confirmedLiveServer && effectiveMode === "servers", backendUrl, serverId: selectedId, iface: selectedIface, @@ -860,6 +865,7 @@ export default function TrafficPage() { }) const mappedUsers = usersRes.users.map(toLiveUser) setLiveServers(mapped) + setLiveServerOwner(JSON.stringify([isLive, backendUrl])) setLiveUsers(mappedUsers) setLiveBoundIfaces(liveIfaces) setTrafficState({ key, status: "ready", receivedAt: Date.now() }) @@ -941,7 +947,7 @@ export default function TrafficPage() { ) useEffect(() => { - if (!isLive || effectiveMode !== "servers" || !selectedId) { + if (!confirmedLiveServer || effectiveMode !== "servers") { // eslint-disable-next-line react-hooks/set-state-in-effect setServerIfaces([]) setSelectedIface("__all__") @@ -954,10 +960,10 @@ export default function TrafficPage() { .then((res) => { if (!cancelled) setServerIfaces(res.interfaces) }) .catch(() => { if (!cancelled) setServerIfaces([]) }) return () => { cancelled = true } - }, [isLive, selectedId, effectiveMode, apiFetch]) + }, [confirmedLiveServer, selectedId, effectiveMode, apiFetch]) useEffect(() => { - if (!isLive || effectiveMode !== "servers" || !selectedId) { + if (!confirmedLiveServer || effectiveMode !== "servers") { return } let cancelled = false @@ -973,7 +979,7 @@ export default function TrafficPage() { if (!cancelled) setDetailResult({ key: detailKey, server: null, error: error instanceof Error ? error.message : "Не удалось загрузить детали трафика" }) }) return () => { cancelled = true } - }, [isLive, effectiveMode, selectedId, range, selectedIface, apiFetch, liveBoundIfaces, detailKey]) + }, [confirmedLiveServer, effectiveMode, selectedId, range, selectedIface, apiFetch, liveBoundIfaces, detailKey]) const handleModeChange = (next: GroupMode) => { setGroupMode(next) diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index d57fcecb..52fbc568 100644 --- a/docs/ux-ui-external-acceptance.md +++ b/docs/ux-ui-external-acceptance.md @@ -1,6 +1,6 @@ # UX/UI: протокол внешней приёмки 12.5 -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md). @@ -696,7 +696,7 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). @@ -1511,3 +1511,11 @@ Initial failures сохранены и исправлены в tests: analytics Changed-file ESLint, backend production build, RIPE/IP profile tests passed. Реальный production RIPE service снова обогатил два публичных IP; повторный public cache hit и special/private controls дают0 дополнительных requests. Действует backend ux-ripe140/frontend ux-log133; backend/PG healthy. Все984 emitted outputs совпали с candidate Docker, actual deployed IP service SHA256 совпал; private rollback env/old image сохранены. [Полные попытки/проверки/границы](ux-ui/acceptance/flow-special-ipv4-2026-10-11.json). Readonly live traffic/statistics smoke320: rendering200/no overflow/pageerror0. При этом traffic отправил initial requests /api/traffic/servers/srv1 и /interfaces, оба400/id is required; это existing mock-id hydration/catalog gate defect, не часть IPv4 fix и не скрытый success. [Smoke](ux-ui/acceptance/browser-flow-special-ip-2026-10-11.json). Следующий141 — gate live fetch до подтверждённого numeric server id/catalog. IPv6 special ranges — отдельно. Full UI1465 accepted139 до backend-only140; backend/SQL/live delta проверены отдельно, frontend не менялся.12.5 открыт. + +## 12.5.141 — подтверждённый каталог перед запросами трафика (2026-10-11) + +Исправлен обнаруженный140 initial live defect: details/interfaces requests отправлялись с demo ID srv1 до загрузки реального каталога и получали400. Теперь details, interfaces и SSE ждут positive safe numeric ID, присутствующий в подтверждённом каталоге текущего backend. Смена источника данных лишает старый каталог права запускать запросы; смена периода не сбрасывает выбранный интерфейс. Demo-режим и backend API не менялись. + +17 профильных E2E passed: два новых сценария удерживают запрос каталога и проверяют отсутствие любых individual requests до подтверждения, затем успех numeric ID или503 без запросов к серверу; остальные проверяют историю/ошибки/гонки периода/интерфейсов и SSE. Changed-file ESLint и source-only TypeScript passed; production Docker frontend build passed. Runtime frontend ux-traffic141, backend ux-ripe140 сохранён. Private rollback env и предыдущий образ оставлены. + +Readonly live /traffic1440 и320: каталог и numeric interfaces200, initial srv1/400 отсутствуют, pageerror0, horizontal overflow нет. [Протокол](ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json). Это приёмка начальной загрузки с реальным текущим каталогом, а не полной цепочки NetFlow ingestion/throughput. Сетевые объекты и пароли не менялись. Следующий отдельный блок — IPv6 special registry guard; оставшаяся внешняя приёмка перечислена в матрице.12.5 открыт. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 99a77629..bf287593 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-10 -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. Этапы0–11 завершены в локальных границах журнала. История выполненных внешних блоков и доказательства сохранены в [журнале](ux-ui-stage-12.md) и [протоколе](ux-ui-external-acceptance.md). Реальная Telegram доставка, Portal SSO, multi-instance и оставшиеся профильные сетевые ограничения открыты. @@ -371,6 +371,6 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 03ee1801..a44b8e5e 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -36,7 +36,15 @@ | 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 | | 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 | | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | -| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–140 и ограничения ниже. Runtime backend ux-ripe140/frontend ux-log133. | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–141 и ограничения ниже. Runtime backend ux-ripe140/frontend ux-traffic141. | + +## 12.5.141 — подтверждённый каталог перед запросами трафика (2026-10-11) + +Исправлен обнаруженный140 initial live defect: details/interfaces requests отправлялись с demo ID srv1 до загрузки реального каталога и получали400. Теперь details, interfaces и SSE ждут positive safe numeric ID, присутствующий в подтверждённом каталоге текущего backend. Смена источника данных лишает старый каталог права запускать запросы; смена периода не сбрасывает выбранный интерфейс. Demo-режим и backend API не менялись. + +17 профильных E2E passed: два новых сценария удерживают запрос каталога и проверяют отсутствие любых individual requests до подтверждения, затем успех numeric ID или503 без запросов к серверу; остальные проверяют историю/ошибки/гонки периода/интерфейсов и SSE. Changed-file ESLint и source-only TypeScript passed; production Docker frontend build passed. Runtime frontend ux-traffic141, backend ux-ripe140 сохранён. Private rollback env и предыдущий образ оставлены. + +Readonly live /traffic1440 и320: каталог и numeric interfaces200, initial srv1/400 отсутствуют, pageerror0, horizontal overflow нет. [Протокол](ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json). Это приёмка начальной загрузки с реальным текущим каталогом, а не полной цепочки NetFlow ingestion/throughput. Сетевые объекты и пароли не менялись. Следующий отдельный блок — IPv6 special registry guard; оставшаяся внешняя приёмка перечислена в матрице.12.5 открыт. ## 12.5.140 — специальные IPv4, RIPE и изолированная SQL-приёмка (2026-10-11) diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index 19571c8c..25955dbd 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,8 +1,8 @@ # Оставшаяся внешняя приёмка — 2026-10-11 -Это актуальная матрица после 12.5.140. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. +Это актуальная матрица после 12.5.141. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. -Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-ripe140`, frontend `ux-log133`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. +Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-ripe140`, frontend `ux-traffic141`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. | Раздел | Подтверждено | Осталось / условие завершения | | --- | --- | --- | @@ -18,7 +18,7 @@ | Recursive routes | Production PUT/change/own history restore88, disabled guards, partial/unknown/applied outcomes, live формы/контекст | Автоматический rollback/retry, durable receipts и несколько экземпляров отсутствуют; PUT не является idempotent noop. Полная произвольная legacy catalog миграция не принята | | Diagnostics/terminal | Allowlist/native reads, Ping/trace/route/MTU/DNS, actual avg-rtt, disabled guards, JWT/live PC/mobile89; real default memory tail/log limits/API/UI133 | DNS использует backend resolver; MTU — ограниченная оценка, не гарантированный максимум. Stop ожидания не доказывает остановку RouterOS команды; arbitrary CLI и physical disconnect не приняты | | Portal/интеграции | Локальные и isolated JWT guards; UI/API error states в границах журналов | Настоящий Portal issuer/login/отзыв прав; RIPE SDK two-IP/no-fetch passed140, полный flow pipeline/local licensed MaxMind/S3/container/certificate jobs и Gitea delivery требуют отдельных тестовых endpoints/аккаунтов. Не отправлять сообщения и не публиковать релиз без соответствующего поручения | -| Общая приёмка | Локальная12.3.83; UI1244/context221/compiled984 parity139; профильные build/E2E/live проверки последующих блоков | Traffic initial live mock-id gate141; IPv6 special ranges; последующие изменения проверять отдельно; scoped axe не означает полную WCAG сертификацию | +| Общая приёмка | Локальная12.3.83; UI1244/context221/compiled984 parity139; профильные build/E2E/live проверки последующих блоков | Traffic initial live mock-id gate passed141; IPv6 special ranges; последующие изменения проверять отдельно; scoped axe не означает полную WCAG сертификацию | Доказательства и точные ограничения: [полная история этапа12](ux-ui-stage-12.md), [внешний протокол](ux-ui-external-acceptance.md), [BGP93](ux-ui/acceptance/bgp-failover-2026-10-10.json), [паспорт стенда](ux-ui-test-server.md). Невыполненные пункты не являются все блокерами данного лабораторного сценария: для выпуска необходимо явно определить требуемые конфигурации и принять их либо согласовать ограничение. @@ -426,3 +426,11 @@ Initial failures сохранены и исправлены в tests: analytics Changed-file ESLint, backend production build, RIPE/IP profile tests passed. Реальный production RIPE service снова обогатил два публичных IP; повторный public cache hit и special/private controls дают0 дополнительных requests. Действует backend ux-ripe140/frontend ux-log133; backend/PG healthy. Все984 emitted outputs совпали с candidate Docker, actual deployed IP service SHA256 совпал; private rollback env/old image сохранены. [Полные попытки/проверки/границы](ux-ui/acceptance/flow-special-ipv4-2026-10-11.json). Readonly live traffic/statistics smoke320: rendering200/no overflow/pageerror0. При этом traffic отправил initial requests /api/traffic/servers/srv1 и /interfaces, оба400/id is required; это existing mock-id hydration/catalog gate defect, не часть IPv4 fix и не скрытый success. [Smoke](ux-ui/acceptance/browser-flow-special-ip-2026-10-11.json). Следующий141 — gate live fetch до подтверждённого numeric server id/catalog. IPv6 special ranges — отдельно. Full UI1465 accepted139 до backend-only140; backend/SQL/live delta проверены отдельно, frontend не менялся.12.5 открыт. + +## 12.5.141 — подтверждённый каталог перед запросами трафика (2026-10-11) + +Исправлен обнаруженный140 initial live defect: details/interfaces requests отправлялись с demo ID srv1 до загрузки реального каталога и получали400. Теперь details, interfaces и SSE ждут positive safe numeric ID, присутствующий в подтверждённом каталоге текущего backend. Смена источника данных лишает старый каталог права запускать запросы; смена периода не сбрасывает выбранный интерфейс. Demo-режим и backend API не менялись. + +17 профильных E2E passed: два новых сценария удерживают запрос каталога и проверяют отсутствие любых individual requests до подтверждения, затем успех numeric ID или503 без запросов к серверу; остальные проверяют историю/ошибки/гонки периода/интерфейсов и SSE. Changed-file ESLint и source-only TypeScript passed; production Docker frontend build passed. Runtime frontend ux-traffic141, backend ux-ripe140 сохранён. Private rollback env и предыдущий образ оставлены. + +Readonly live /traffic1440 и320: каталог и numeric interfaces200, initial srv1/400 отсутствуют, pageerror0, horizontal overflow нет. [Протокол](ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json). Это приёмка начальной загрузки с реальным текущим каталогом, а не полной цепочки NetFlow ingestion/throughput. Сетевые объекты и пароли не менялись. Следующий отдельный блок — IPv6 special registry guard; оставшаяся внешняя приёмка перечислена в матрице.12.5 открыт. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 87960749..75bff3ff 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-11: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Актуальное продолжение 2026-10-11: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -2816,3 +2816,11 @@ Initial failures сохранены и исправлены в tests: analytics Changed-file ESLint, backend production build, RIPE/IP profile tests passed. Реальный production RIPE service снова обогатил два публичных IP; повторный public cache hit и special/private controls дают0 дополнительных requests. Действует backend ux-ripe140/frontend ux-log133; backend/PG healthy. Все984 emitted outputs совпали с candidate Docker, actual deployed IP service SHA256 совпал; private rollback env/old image сохранены. [Полные попытки/проверки/границы](ux-ui/acceptance/flow-special-ipv4-2026-10-11.json). Readonly live traffic/statistics smoke320: rendering200/no overflow/pageerror0. При этом traffic отправил initial requests /api/traffic/servers/srv1 и /interfaces, оба400/id is required; это existing mock-id hydration/catalog gate defect, не часть IPv4 fix и не скрытый success. [Smoke](ux-ui/acceptance/browser-flow-special-ip-2026-10-11.json). Следующий141 — gate live fetch до подтверждённого numeric server id/catalog. IPv6 special ranges — отдельно. Full UI1465 accepted139 до backend-only140; backend/SQL/live delta проверены отдельно, frontend не менялся.12.5 открыт. + +## 12.5.141 — подтверждённый каталог перед запросами трафика (2026-10-11) + +Исправлен обнаруженный140 initial live defect: details/interfaces requests отправлялись с demo ID srv1 до загрузки реального каталога и получали400. Теперь details, interfaces и SSE ждут positive safe numeric ID, присутствующий в подтверждённом каталоге текущего backend. Смена источника данных лишает старый каталог права запускать запросы; смена периода не сбрасывает выбранный интерфейс. Demo-режим и backend API не менялись. + +17 профильных E2E passed: два новых сценария удерживают запрос каталога и проверяют отсутствие любых individual requests до подтверждения, затем успех numeric ID или503 без запросов к серверу; остальные проверяют историю/ошибки/гонки периода/интерфейсов и SSE. Changed-file ESLint и source-only TypeScript passed; production Docker frontend build passed. Runtime frontend ux-traffic141, backend ux-ripe140 сохранён. Private rollback env и предыдущий образ оставлены. + +Readonly live /traffic1440 и320: каталог и numeric interfaces200, initial srv1/400 отсутствуют, pageerror0, horizontal overflow нет. [Протокол](ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json). Это приёмка начальной загрузки с реальным текущим каталогом, а не полной цепочки NetFlow ingestion/throughput. Сетевые объекты и пароли не менялись. Следующий отдельный блок — IPv6 special registry guard; оставшаяся внешняя приёмка перечислена в матрице.12.5 открыт. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 37309d78..587025be 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -1,6 +1,6 @@ # Тестовый сервер UX/UI — 2026-10-10 -Сервер161.104.46.222: завершён12.5.140 — special IPv4 RIPE guard fixed,31 boundary cases/stale-cache/no-fetch checks;20 local flow scripts exit0 с честными PG skips,6 unique SQL modules passed в own DBs/removed4. Live RIPE passed,compiled984 parity; backend ux-ripe140/frontend ux-log133. Smoke выявил initial traffic srv1→400, не скрыт. Следующий141 — gate live traffic до numeric/catalog-confirmed ID; IPv6 registry отдельно.12.5 открыт. +Сервер161.104.46.222: завершён12.5.141 — live traffic ждёт подтверждённый numeric ID своего backend-каталога.17 профильных E2E, ESLint/types, production Docker build и live1440/320 passed; initial srv1/400 устранён. Backend ux-ripe140/frontend ux-traffic141. Следующий блок — IPv6 special ranges и оставшаяся внешняя приёмка;12.5 открыт. | Параметр | Проверенное состояние | | --- | --- | @@ -14,7 +14,7 @@ | PostgreSQL | postgres:18-alpine,18.6;mmapp-test-postgres healthy;SELECT version() passed | | Данные | Отдельный Compose project mmapp-test,том mmapp-test_mmapp-pgdata и каталог ./data | | Доступ | PostgreSQL не публикуется;frontend3000/backend8000 привязаны к127.0.0.1 после запуска | -| Образы приложения | mmapp-test/backend:ux-ripe140 и mmapp-test/frontend:ux-log133; запущены | +| Образы приложения | mmapp-test/backend:ux-ripe140 и mmapp-test/frontend:ux-traffic141; запущены | Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example). @@ -1242,3 +1242,11 @@ Initial failures сохранены и исправлены в tests: analytics Changed-file ESLint, backend production build, RIPE/IP profile tests passed. Реальный production RIPE service снова обогатил два публичных IP; повторный public cache hit и special/private controls дают0 дополнительных requests. Действует backend ux-ripe140/frontend ux-log133; backend/PG healthy. Все984 emitted outputs совпали с candidate Docker, actual deployed IP service SHA256 совпал; private rollback env/old image сохранены. [Полные попытки/проверки/границы](ux-ui/acceptance/flow-special-ipv4-2026-10-11.json). Readonly live traffic/statistics smoke320: rendering200/no overflow/pageerror0. При этом traffic отправил initial requests /api/traffic/servers/srv1 и /interfaces, оба400/id is required; это existing mock-id hydration/catalog gate defect, не часть IPv4 fix и не скрытый success. [Smoke](ux-ui/acceptance/browser-flow-special-ip-2026-10-11.json). Следующий141 — gate live fetch до подтверждённого numeric server id/catalog. IPv6 special ranges — отдельно. Full UI1465 accepted139 до backend-only140; backend/SQL/live delta проверены отдельно, frontend не менялся.12.5 открыт. + +## 12.5.141 — подтверждённый каталог перед запросами трафика (2026-10-11) + +Исправлен обнаруженный140 initial live defect: details/interfaces requests отправлялись с demo ID srv1 до загрузки реального каталога и получали400. Теперь details, interfaces и SSE ждут positive safe numeric ID, присутствующий в подтверждённом каталоге текущего backend. Смена источника данных лишает старый каталог права запускать запросы; смена периода не сбрасывает выбранный интерфейс. Demo-режим и backend API не менялись. + +17 профильных E2E passed: два новых сценария удерживают запрос каталога и проверяют отсутствие любых individual requests до подтверждения, затем успех numeric ID или503 без запросов к серверу; остальные проверяют историю/ошибки/гонки периода/интерфейсов и SSE. Changed-file ESLint и source-only TypeScript passed; production Docker frontend build passed. Runtime frontend ux-traffic141, backend ux-ripe140 сохранён. Private rollback env и предыдущий образ оставлены. + +Readonly live /traffic1440 и320: каталог и numeric interfaces200, initial srv1/400 отсутствуют, pageerror0, horizontal overflow нет. [Протокол](ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json). Это приёмка начальной загрузки с реальным текущим каталогом, а не полной цепочки NetFlow ingestion/throughput. Сетевые объекты и пароли не менялись. Следующий отдельный блок — IPv6 special registry guard; оставшаяся внешняя приёмка перечислена в матрице.12.5 открыт. diff --git a/docs/ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json b/docs/ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json new file mode 100644 index 00000000..8d014436 --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-confirmed-catalog-2026-10-11.json @@ -0,0 +1,85 @@ +{ + "date": "2026-10-11", + "block": "12.5.141", + "runtime": { + "backend": "ux-ripe140", + "frontend": "ux-traffic141" + }, + "checks": { + "e2ePassed": 17, + "eslintPassed": true, + "sourceTypesPassed": true, + "dockerProductionBuildPassed": true + }, + "cases": [ + { + "width": 1440, + "httpStatus": 200, + "api": [ + { + "path": "/api/traffic/users", + "status": 200 + }, + { + "path": "/api/traffic/bound-interfaces", + "status": 200 + }, + { + "path": "/api/traffic/servers", + "status": 200 + }, + { + "path": "/api/traffic/servers/1/live", + "status": 200 + }, + { + "path": "/api/traffic/servers/1/interfaces", + "status": 200 + }, + { + "path": "/api/traffic/servers/1", + "status": 200 + } + ], + "pageErrors": [], + "noOverflow": true + }, + { + "width": 320, + "httpStatus": 200, + "api": [ + { + "path": "/api/traffic/bound-interfaces", + "status": 200 + }, + { + "path": "/api/traffic/users", + "status": 200 + }, + { + "path": "/api/traffic/servers", + "status": 200 + }, + { + "path": "/api/traffic/servers/1/live", + "status": 200 + }, + { + "path": "/api/traffic/servers/1/interfaces", + "status": 200 + }, + { + "path": "/api/traffic/servers/1", + "status": 200 + } + ], + "pageErrors": [], + "noOverflow": true + } + ], + "bounds": [ + "Read-only initial loading with real current lab catalog; no full NetFlow ingestion or throughput claim", + "Catalog failure and pending loading checked by controlled E2E; numeric live server details/interfaces/SSE enabled only after confirmed catalog ownership", + "Interface filter remains selected on range changes; backend source switch invalidates prior catalog ownership" + ] +} diff --git a/tests/e2e/traffic-catalog.spec.ts b/tests/e2e/traffic-catalog.spec.ts new file mode 100644 index 00000000..6155cae3 --- /dev/null +++ b/tests/e2e/traffic-catalog.spec.ts @@ -0,0 +1,45 @@ +import { test, expect } from '@playwright/test' + +for (const outcome of ['success', 'error'] as const) { + test(`Трафик: каталог ${outcome} не отправляет запросы к неподтверждённому серверу`, async ({ page }) => { + let release!: () => void + const gate = new Promise(resolve => { release = resolve }) + const individual: string[] = [] + const server = { id: '1', name: 'Подтверждённый сервер', site: 'TEST', country: 'RU', status: 'online', rxNow: 2, txNow: 3, rxPeak: 5, txPeak: 6, rxTotal: 100, txTotal: 200, sessions: 1, rxSeries: [1, 2], txSeries: [2, 3] } + await page.route('**/health', route => route.fulfill({ json: { ok: true } })) + await page.route('**/api/**', async route => { + const path = new URL(route.request().url()).pathname + if (/^\/api\/traffic\/servers\/[^/]+/.test(path)) individual.push(path) + if (path === '/api/traffic/servers') { + await gate + if (outcome === 'error') return route.fulfill({ status: 503, json: { error: 'Каталог временно недоступен' } }) + return route.fulfill({ json: { servers: [server] } }) + } + if (path.endsWith('/live')) return route.fulfill({ status: 503, json: {} }) + const json = path === '/api/auth/config' ? { required: false } + : path === '/api/traffic/servers/1' ? { server } + : path === '/api/traffic/servers/1/interfaces' ? { interfaces: [] } + : path === '/api/traffic/users' ? { users: [] } + : path === '/api/traffic/bound-interfaces' ? { interfaces: [] } + : path === '/api/servers' ? [] : {} + return route.fulfill({ json }) + }) + const catalog = page.waitForRequest(r => new URL(r.url()).pathname === '/api/traffic/servers') + await page.goto('/traffic') + await catalog + await expect(page.getByRole('main')).toBeVisible() + // Allow initial effects to run while the catalog remains deliberately pending. + await page.waitForTimeout(500) + expect(individual).toEqual([]) + release() + if (outcome === 'success') { + await expect(page.getByRole('heading', { name: server.name, exact: true })).toBeVisible() + await expect.poll(() => individual.includes('/api/traffic/servers/1/interfaces')).toBe(true) + await expect.poll(() => individual.includes('/api/traffic/servers/1/live')).toBe(true) + expect(individual.every(path => /^\/api\/traffic\/servers\/1(?:\/|$)/.test(path))).toBe(true) + } else { + await expect(page.getByText('Каталог временно недоступен', { exact: false }).first()).toBeVisible() + expect(individual).toEqual([]) + } + }) +}