fix(netflow): проверять ответы аналитики и выбранный месяц
This commit is contained in:
1 parent
979dc3cfb0
commit
64df472202
10 files changed
+271
-16
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# UX/UI: протокол внешней приёмки 12.5
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.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.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.12.5 открыт.
|
||||
|
||||
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
|
||||
|
||||
@@ -1577,3 +1577,15 @@ Parser/interface/classifier profiles прошли локально и в product
|
||||
Backend/frontend ux-labels146 развёрнуты; backend/PG healthy, deployed traffic PC/mobile loading passed. [Label/check receipt](ux-ui/acceptance/ipv6-protocol-labels-2026-10-11.json), [readonly smoke](ux-ui/acceptance/traffic-labels-smoke-2026-10-11.json). Это live rendering/catalog smoke после label delta, а не повтор populated native145. Raw protocol integer сохранён в DB; talker/analytics response отображает его через новый protoName, schema/migration не требовались. Rollback env/images оставлены, device settings/passwords не менялись.
|
||||
|
||||
Следующий147 — применить существующие contract schemas к HTTP analytics/monthly, как уже сделано для SSE/settings, чтобы malformed200 response давал existing error/retry state без ложных нулей или page crash.12.5 открыт.
|
||||
|
||||
## 12.5.147 — подтверждённые HTTP данные аналитики и месяца (2026-10-11)
|
||||
|
||||
HTTP analytics/monthly раньше принимались как typed JSON без runtime schema check: malformed200 с отсутствующей conversationsList мог упасть при render. Теперь reused existing contract schemas и flowConfirmed error state, как в SSE/settings. Неверные required fields и negative RX/TX series отклоняются; monthly.month обязан совпадать с requested month. Existing Alert/Повторить аналитику показывает понятную ошибку, retry сохраняет server/range/month. Никаких false zero defaults для отсутствующих обязательных данных.
|
||||
|
||||
Необязательные overlay/wire measurements могут быть неизвестны отдельно от основных счётчиков. Invalid optional numbers (missing/null/string/negative/nonfinite) нормализуются в undefined, UI сохраняет Нет данных; legitimate numeric0 и valid core остаются. Это сохраняет partial-data UX и прежнюю проверку, вместо объявления всего DTO недоступным. Contract schemas/backend response shapes не менялись.
|
||||
|
||||
34 профильных E2E приняты across attempts:31 passed в первом запуске; strict optional metric rejection и два monthly fixtures без server catalog дали3 failures. Исправлены partial metric handling и fixtures, повторены только эти3, все passed. Covered incomplete analytics/monthly, negative series, different month, no pageerror/no false speed, retry with identical scope, existing flow races/SSE/metrics/month/table and IPv6 labels. ESLint/source-only TypeScript/frontend Docker build passed. [Receipt](ux-ui/acceptance/traffic-http-contracts-2026-10-11.json).
|
||||
|
||||
Frontend ux-http147 развёрнут, backend ux-labels146 сохранён. Настоящие analytics/monthly HTTP200 текущего backend прошли схемы; month2026-10 совпал с запросом. [Live PC/mobile smoke](ux-ui/acceptance/traffic-http-validation-smoke-2026-10-11.json). Это contract compatibility/read-only smoke с текущими lab data, не новый populated WAN test. Rollback image/env сохранены, device/password changes нет.
|
||||
|
||||
Следующий148 — не запускать scoped flow HTTP/SSE до подтверждённого выбранного элемента каталога и не превращать malformed serverId в aggregate request.12.5 открыт.
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
# План реализации UX/UI по пятичасовым окнам
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.12.5 открыт.
|
||||
|
||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-10
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.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.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.12.5 открыт.
|
||||
|
||||
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
# UX/UI: журнал реализации
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.12.5 открыт.
|
||||
|
||||
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
|
||||
|
||||
@@ -36,7 +36,19 @@
|
||||
| 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–146 и ограничения ниже. Runtime backend/frontend ux-labels146. |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–147 и ограничения ниже. Runtime backend ux-labels146/frontend ux-http147. |
|
||||
|
||||
## 12.5.147 — подтверждённые HTTP данные аналитики и месяца (2026-10-11)
|
||||
|
||||
HTTP analytics/monthly раньше принимались как typed JSON без runtime schema check: malformed200 с отсутствующей conversationsList мог упасть при render. Теперь reused existing contract schemas и flowConfirmed error state, как в SSE/settings. Неверные required fields и negative RX/TX series отклоняются; monthly.month обязан совпадать с requested month. Existing Alert/Повторить аналитику показывает понятную ошибку, retry сохраняет server/range/month. Никаких false zero defaults для отсутствующих обязательных данных.
|
||||
|
||||
Необязательные overlay/wire measurements могут быть неизвестны отдельно от основных счётчиков. Invalid optional numbers (missing/null/string/negative/nonfinite) нормализуются в undefined, UI сохраняет Нет данных; legitimate numeric0 и valid core остаются. Это сохраняет partial-data UX и прежнюю проверку, вместо объявления всего DTO недоступным. Contract schemas/backend response shapes не менялись.
|
||||
|
||||
34 профильных E2E приняты across attempts:31 passed в первом запуске; strict optional metric rejection и два monthly fixtures без server catalog дали3 failures. Исправлены partial metric handling и fixtures, повторены только эти3, все passed. Covered incomplete analytics/monthly, negative series, different month, no pageerror/no false speed, retry with identical scope, existing flow races/SSE/metrics/month/table and IPv6 labels. ESLint/source-only TypeScript/frontend Docker build passed. [Receipt](ux-ui/acceptance/traffic-http-contracts-2026-10-11.json).
|
||||
|
||||
Frontend ux-http147 развёрнут, backend ux-labels146 сохранён. Настоящие analytics/monthly HTTP200 текущего backend прошли схемы; month2026-10 совпал с запросом. [Live PC/mobile smoke](ux-ui/acceptance/traffic-http-validation-smoke-2026-10-11.json). Это contract compatibility/read-only smoke с текущими lab data, не новый populated WAN test. Rollback image/env сохранены, device/password changes нет.
|
||||
|
||||
Следующий148 — не запускать scoped flow HTTP/SSE до подтверждённого выбранного элемента каталога и не превращать malformed serverId в aggregate request.12.5 открыт.
|
||||
|
||||
## 12.5.146 — понятные подписи ICMPv6 и адресов IPv6 с портами (2026-10-11)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Оставшаяся внешняя приёмка — 2026-10-11
|
||||
|
||||
Это актуальная матрица после 12.5.146. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
Это актуальная матрица после 12.5.147. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-labels146`, frontend `ux-labels146`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-labels146`, frontend `ux-http147`; 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, native IPv6 ULA flow pipeline passed145 (IPv4 transport), public IPv6 WAN/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 gate passed141; IPv6 special ranges/cache passed142; unknown RIPE coordinates passed143; IPv6 synthetic UDP/worker/SQL passed144; native CHR ULA/IPFIX/API/UI passed145; ICMPv6/IPv6 endpoint labels passed146; HTTP DTO validation147; последующие изменения проверять отдельно; scoped axe не означает полную WCAG сертификацию |
|
||||
| Общая приёмка | Локальная12.3.83; UI1244/context221/compiled984 parity139; профильные build/E2E/live проверки последующих блоков | Traffic initial live mock-id gate passed141; IPv6 special ranges/cache passed142; unknown RIPE coordinates passed143; IPv6 synthetic UDP/worker/SQL passed144; native CHR ULA/IPFIX/API/UI passed145; ICMPv6/IPv6 endpoint labels passed146; HTTP DTO validation passed147; scoped flow catalog/serverId guards148; последующие изменения проверять отдельно; 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). Невыполненные пункты не являются все блокерами данного лабораторного сценария: для выпуска необходимо явно определить требуемые конфигурации и принять их либо согласовать ограничение.
|
||||
|
||||
@@ -492,3 +492,15 @@ Parser/interface/classifier profiles прошли локально и в product
|
||||
Backend/frontend ux-labels146 развёрнуты; backend/PG healthy, deployed traffic PC/mobile loading passed. [Label/check receipt](ux-ui/acceptance/ipv6-protocol-labels-2026-10-11.json), [readonly smoke](ux-ui/acceptance/traffic-labels-smoke-2026-10-11.json). Это live rendering/catalog smoke после label delta, а не повтор populated native145. Raw protocol integer сохранён в DB; talker/analytics response отображает его через новый protoName, schema/migration не требовались. Rollback env/images оставлены, device settings/passwords не менялись.
|
||||
|
||||
Следующий147 — применить существующие contract schemas к HTTP analytics/monthly, как уже сделано для SSE/settings, чтобы malformed200 response давал existing error/retry state без ложных нулей или page crash.12.5 открыт.
|
||||
|
||||
## 12.5.147 — подтверждённые HTTP данные аналитики и месяца (2026-10-11)
|
||||
|
||||
HTTP analytics/monthly раньше принимались как typed JSON без runtime schema check: malformed200 с отсутствующей conversationsList мог упасть при render. Теперь reused existing contract schemas и flowConfirmed error state, как в SSE/settings. Неверные required fields и negative RX/TX series отклоняются; monthly.month обязан совпадать с requested month. Existing Alert/Повторить аналитику показывает понятную ошибку, retry сохраняет server/range/month. Никаких false zero defaults для отсутствующих обязательных данных.
|
||||
|
||||
Необязательные overlay/wire measurements могут быть неизвестны отдельно от основных счётчиков. Invalid optional numbers (missing/null/string/negative/nonfinite) нормализуются в undefined, UI сохраняет Нет данных; legitimate numeric0 и valid core остаются. Это сохраняет partial-data UX и прежнюю проверку, вместо объявления всего DTO недоступным. Contract schemas/backend response shapes не менялись.
|
||||
|
||||
34 профильных E2E приняты across attempts:31 passed в первом запуске; strict optional metric rejection и два monthly fixtures без server catalog дали3 failures. Исправлены partial metric handling и fixtures, повторены только эти3, все passed. Covered incomplete analytics/monthly, negative series, different month, no pageerror/no false speed, retry with identical scope, existing flow races/SSE/metrics/month/table and IPv6 labels. ESLint/source-only TypeScript/frontend Docker build passed. [Receipt](ux-ui/acceptance/traffic-http-contracts-2026-10-11.json).
|
||||
|
||||
Frontend ux-http147 развёрнут, backend ux-labels146 сохранён. Настоящие analytics/monthly HTTP200 текущего backend прошли схемы; month2026-10 совпал с запросом. [Live PC/mobile smoke](ux-ui/acceptance/traffic-http-validation-smoke-2026-10-11.json). Это contract compatibility/read-only smoke с текущими lab data, не новый populated WAN test. Rollback image/env сохранены, device/password changes нет.
|
||||
|
||||
Следующий148 — не запускать scoped flow HTTP/SSE до подтверждённого выбранного элемента каталога и не превращать malformed serverId в aggregate request.12.5 открыт.
|
||||
+13
-1
@@ -1,6 +1,6 @@
|
||||
# Этап 12: итоговая приёмка UX/UI
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.12.5 открыт.
|
||||
|
||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||
|
||||
@@ -2882,3 +2882,15 @@ Parser/interface/classifier profiles прошли локально и в product
|
||||
Backend/frontend ux-labels146 развёрнуты; backend/PG healthy, deployed traffic PC/mobile loading passed. [Label/check receipt](ux-ui/acceptance/ipv6-protocol-labels-2026-10-11.json), [readonly smoke](ux-ui/acceptance/traffic-labels-smoke-2026-10-11.json). Это live rendering/catalog smoke после label delta, а не повтор populated native145. Raw protocol integer сохранён в DB; talker/analytics response отображает его через новый protoName, schema/migration не требовались. Rollback env/images оставлены, device settings/passwords не менялись.
|
||||
|
||||
Следующий147 — применить существующие contract schemas к HTTP analytics/monthly, как уже сделано для SSE/settings, чтобы malformed200 response давал existing error/retry state без ложных нулей или page crash.12.5 открыт.
|
||||
|
||||
## 12.5.147 — подтверждённые HTTP данные аналитики и месяца (2026-10-11)
|
||||
|
||||
HTTP analytics/monthly раньше принимались как typed JSON без runtime schema check: malformed200 с отсутствующей conversationsList мог упасть при render. Теперь reused existing contract schemas и flowConfirmed error state, как в SSE/settings. Неверные required fields и negative RX/TX series отклоняются; monthly.month обязан совпадать с requested month. Existing Alert/Повторить аналитику показывает понятную ошибку, retry сохраняет server/range/month. Никаких false zero defaults для отсутствующих обязательных данных.
|
||||
|
||||
Необязательные overlay/wire measurements могут быть неизвестны отдельно от основных счётчиков. Invalid optional numbers (missing/null/string/negative/nonfinite) нормализуются в undefined, UI сохраняет Нет данных; legitimate numeric0 и valid core остаются. Это сохраняет partial-data UX и прежнюю проверку, вместо объявления всего DTO недоступным. Contract schemas/backend response shapes не менялись.
|
||||
|
||||
34 профильных E2E приняты across attempts:31 passed в первом запуске; strict optional metric rejection и два monthly fixtures без server catalog дали3 failures. Исправлены partial metric handling и fixtures, повторены только эти3, все passed. Covered incomplete analytics/monthly, negative series, different month, no pageerror/no false speed, retry with identical scope, existing flow races/SSE/metrics/month/table and IPv6 labels. ESLint/source-only TypeScript/frontend Docker build passed. [Receipt](ux-ui/acceptance/traffic-http-contracts-2026-10-11.json).
|
||||
|
||||
Frontend ux-http147 развёрнут, backend ux-labels146 сохранён. Настоящие analytics/monthly HTTP200 текущего backend прошли схемы; month2026-10 совпал с запросом. [Live PC/mobile smoke](ux-ui/acceptance/traffic-http-validation-smoke-2026-10-11.json). Это contract compatibility/read-only smoke с текущими lab data, не новый populated WAN test. Rollback image/env сохранены, device/password changes нет.
|
||||
|
||||
Следующий148 — не запускать scoped flow HTTP/SSE до подтверждённого выбранного элемента каталога и не превращать malformed serverId в aggregate request.12.5 открыт.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Тестовый сервер UX/UI — 2026-10-10
|
||||
|
||||
Сервер161.104.46.222: завершён12.5.146 — ICMPv6 вместо58, IPv6 endpoint [IP]:port с сохранением IPv4/portless формата.3 backend profiles/source+candidate,30 E2E across attempts,984 outputs/types/ESLint и обе production builds passed; live PC/mobile loading passed. Runtime backend/frontend ux-labels146. Далее147 — schema validation HTTP analytics/monthly DTO, понятная ошибка вместо page crash.12.5 открыт.
|
||||
Сервер161.104.46.222: завершён12.5.147 — HTTP analytics/monthly проверяются existing contract schemas; malformed required DTO/negative series/wrong month дают error+retry, optional unknown metrics не прячут core и не становятся0.34 E2E across attempts/types/ESLint/build/live contracts+PC/mobile passed. Backend ux-labels146/frontend ux-http147. Далее148 — gate flow entity requests/SSE до confirmed catalog и reject invalid serverId без aggregate fallback.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-labels146 и mmapp-test/frontend:ux-labels146; запущены |
|
||||
| Образы приложения | mmapp-test/backend:ux-labels146 и mmapp-test/frontend:ux-http147; запущены |
|
||||
|
||||
Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example).
|
||||
|
||||
@@ -1308,3 +1308,15 @@ Parser/interface/classifier profiles прошли локально и в product
|
||||
Backend/frontend ux-labels146 развёрнуты; backend/PG healthy, deployed traffic PC/mobile loading passed. [Label/check receipt](ux-ui/acceptance/ipv6-protocol-labels-2026-10-11.json), [readonly smoke](ux-ui/acceptance/traffic-labels-smoke-2026-10-11.json). Это live rendering/catalog smoke после label delta, а не повтор populated native145. Raw protocol integer сохранён в DB; talker/analytics response отображает его через новый protoName, schema/migration не требовались. Rollback env/images оставлены, device settings/passwords не менялись.
|
||||
|
||||
Следующий147 — применить существующие contract schemas к HTTP analytics/monthly, как уже сделано для SSE/settings, чтобы malformed200 response давал existing error/retry state без ложных нулей или page crash.12.5 открыт.
|
||||
|
||||
## 12.5.147 — подтверждённые HTTP данные аналитики и месяца (2026-10-11)
|
||||
|
||||
HTTP analytics/monthly раньше принимались как typed JSON без runtime schema check: malformed200 с отсутствующей conversationsList мог упасть при render. Теперь reused existing contract schemas и flowConfirmed error state, как в SSE/settings. Неверные required fields и negative RX/TX series отклоняются; monthly.month обязан совпадать с requested month. Existing Alert/Повторить аналитику показывает понятную ошибку, retry сохраняет server/range/month. Никаких false zero defaults для отсутствующих обязательных данных.
|
||||
|
||||
Необязательные overlay/wire measurements могут быть неизвестны отдельно от основных счётчиков. Invalid optional numbers (missing/null/string/negative/nonfinite) нормализуются в undefined, UI сохраняет Нет данных; legitimate numeric0 и valid core остаются. Это сохраняет partial-data UX и прежнюю проверку, вместо объявления всего DTO недоступным. Contract schemas/backend response shapes не менялись.
|
||||
|
||||
34 профильных E2E приняты across attempts:31 passed в первом запуске; strict optional metric rejection и два monthly fixtures без server catalog дали3 failures. Исправлены partial metric handling и fixtures, повторены только эти3, все passed. Covered incomplete analytics/monthly, negative series, different month, no pageerror/no false speed, retry with identical scope, existing flow races/SSE/metrics/month/table and IPv6 labels. ESLint/source-only TypeScript/frontend Docker build passed. [Receipt](ux-ui/acceptance/traffic-http-contracts-2026-10-11.json).
|
||||
|
||||
Frontend ux-http147 развёрнут, backend ux-labels146 сохранён. Настоящие analytics/monthly HTTP200 текущего backend прошли схемы; month2026-10 совпал с запросом. [Live PC/mobile smoke](ux-ui/acceptance/traffic-http-validation-smoke-2026-10-11.json). Это contract compatibility/read-only smoke с текущими lab data, не новый populated WAN test. Rollback image/env сохранены, device/password changes нет.
|
||||
|
||||
Следующий148 — не запускать scoped flow HTTP/SSE до подтверждённого выбранного элемента каталога и не превращать malformed serverId в aggregate request.12.5 открыт.
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"date": "2026-10-11",
|
||||
"block": "12.5.147",
|
||||
"runtime": {
|
||||
"backend": "ux-labels146",
|
||||
"frontend": "ux-http147"
|
||||
},
|
||||
"checks": {
|
||||
"e2eAcceptedAcrossAttempts": 34,
|
||||
"sourceOnlyTypesPassed": true,
|
||||
"eslintPassed": true,
|
||||
"frontendProductionBuildPassed": true,
|
||||
"liveContracts": [
|
||||
{
|
||||
"path": "/api/traffic/flow/analytics?range=5m&serverId=1",
|
||||
"status": 200,
|
||||
"schemaPassed": true,
|
||||
"month": null
|
||||
},
|
||||
{
|
||||
"path": "/api/traffic/flow/monthly?month=2026-10&serverId=1",
|
||||
"status": 200,
|
||||
"schemaPassed": true,
|
||||
"month": "2026-10"
|
||||
}
|
||||
]
|
||||
},
|
||||
"initial": {
|
||||
"passed": 31,
|
||||
"failed": 3,
|
||||
"reasons": [
|
||||
"Strict optional overlay/wire rejection hid valid core data; corrected to preserve partial unknown metrics without zero substitution",
|
||||
"Two monthly fixtures had empty server catalog, so no actual monthly selection/request; fixed catalog to existing supported server shape"
|
||||
]
|
||||
},
|
||||
"retry": {
|
||||
"onlyFailedCasesRepeated": true,
|
||||
"passed": 3
|
||||
},
|
||||
"bounds": [
|
||||
"Existing authoritative schemas and error/retry UI reused; required HTTP analytics/monthly data validated before rendering",
|
||||
"Negative RX/TX series rejected consistently with SSE; incomplete payload does not crash page or create false zero counters",
|
||||
"Invalid optional overlay/wire numeric measurements become undefined/Нет данных; valid core and legitimate zero measurements retained",
|
||||
"Response month must equal requested month; retry preserves server/range/month filters",
|
||||
"No backend/schema/device/password change; real contract smoke reads current empty/history lab data, not newly populated WAN flow acceptance"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"date": "2026-10-11",
|
||||
"block": "12.5.147",
|
||||
"runtime": {
|
||||
"backend": "ux-labels146",
|
||||
"frontend": "ux-http147"
|
||||
},
|
||||
"checks": {
|
||||
"readOnlyFrontendUnchanged": true,
|
||||
"backendHealthy": true,
|
||||
"backendProductionBuildPassed": true
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"width": 1440,
|
||||
"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
|
||||
},
|
||||
{
|
||||
"width": 320,
|
||||
"httpStatus": 200,
|
||||
"api": [
|
||||
{
|
||||
"path": "/api/traffic/servers",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"path": "/api/traffic/bound-interfaces",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"path": "/api/traffic/users",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
@@ -12,13 +12,21 @@ import type {
|
||||
TrafficFlowSettingsPatch,
|
||||
} from "@mmapp/contracts/traffic-flow"
|
||||
import { z } from "zod"
|
||||
import { trafficFlowSettingsDtoSchema, trafficFlowSettingsPatchSchema, trafficFlowHostFileSchema, flowPurgeDtoSchema } from "@mmapp/contracts/traffic-flow"
|
||||
import { trafficFlowSettingsDtoSchema, trafficFlowSettingsPatchSchema, trafficFlowHostFileSchema, flowPurgeDtoSchema, flowAnalyticsDtoSchema, flowMonthlyDtoSchema } from "@mmapp/contracts/traffic-flow"
|
||||
import { requestJson } from "@/shared/api/http-client"
|
||||
|
||||
export type { TrafficFlowHostFile }
|
||||
|
||||
const flowSettingsSchema = trafficFlowSettingsDtoSchema.extend({ flowListenPort: z.number().int().min(1).max(65535), wgListenPort: z.number().int().min(1).max(65535) }).refine(data => (!data.hasHostPrivateKey || data.hostPublicKey.length > 0) && (!data.listenerBound || !!data.listenerAddress) && (data.lastDatagramAt === null || Number.isFinite(Date.parse(data.lastDatagramAt))) && new Set(data.peers.map(peer => peer.serverId)).size === data.peers.length, "Несогласованные настройки NetFlow")
|
||||
const flowPatchSchema = trafficFlowSettingsPatchSchema.strict()
|
||||
// Optional overlay/wire measurements may be unavailable independently of the
|
||||
// confirmed primary counters. Preserve that distinction instead of inventing zero.
|
||||
const optionalFlowMetric = z.preprocess(value => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined, z.number().nonnegative().optional())
|
||||
const flowAnalyticsSchema = flowAnalyticsDtoSchema.extend({
|
||||
bytesPayload: optionalFlowMetric, bytesOverlay: optionalFlowMetric,
|
||||
bytesMesh: optionalFlowMetric, bytesWire: optionalFlowMetric,
|
||||
bpsOverlay: optionalFlowMetric, bpsWire: optionalFlowMetric,
|
||||
}).refine(data => [...data.rxSeries, ...data.txSeries].every(value => Number.isFinite(value) && value >= 0), "Некорректные измерения трафика")
|
||||
function flowConfirmed<T>(schema: z.ZodType<T>, raw: unknown): T {
|
||||
const parsed = schema.safeParse(raw)
|
||||
if (!parsed.success) throw new Error("Данные NetFlow не подтверждены: получен некорректный ответ сервера")
|
||||
@@ -135,7 +143,7 @@ export async function getFlowAnalytics(
|
||||
excludeOverlay?: boolean
|
||||
},
|
||||
): Promise<FlowAnalyticsDto> {
|
||||
return requestJson<FlowAnalyticsDto>(baseUrl, `/api/traffic/flow/analytics${flowQuery(params)}`)
|
||||
return flowConfirmed(flowAnalyticsSchema, await requestJson<unknown>(baseUrl, `/api/traffic/flow/analytics${flowQuery(params)}`))
|
||||
}
|
||||
|
||||
export async function getFlowMonthly(
|
||||
@@ -145,7 +153,9 @@ export async function getFlowMonthly(
|
||||
const q = new URLSearchParams()
|
||||
q.set("month", params.month)
|
||||
if (params.serverId) q.set("serverId", params.serverId)
|
||||
return requestJson<FlowMonthlyDto>(baseUrl, `/api/traffic/flow/monthly?${q.toString()}`)
|
||||
const data = flowConfirmed(flowMonthlyDtoSchema, await requestJson<unknown>(baseUrl, `/api/traffic/flow/monthly?${q.toString()}`))
|
||||
if (data.month !== params.month) throw new Error("Сервер вернул данные другого месяца. Повторите загрузку.")
|
||||
return data
|
||||
}
|
||||
|
||||
export async function purgeTrafficFlowData(baseUrl: string, init?: RequestInit): Promise<FlowPurgeDto> {
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
for (const variant of ['missing-sessions', 'negative-series', 'monthly-missing', 'monthly-mismatch'] as const) {
|
||||
test(`Потоки: некорректный HTTP DTO ${variant} даёт ошибку и повтор без потери контекста`, async ({ page }) => {
|
||||
let bad = true
|
||||
const errors: string[] = []
|
||||
const queries: Array<{ range: string | null; month: string | null; serverId: string | null }> = []
|
||||
const monthlyCase = variant.startsWith('monthly')
|
||||
const stats = { bpsNow: 1000000, bytes: 200, packets: 2, conversations: 1, uniqueSrc: 1, uniqueDst: 1, topProto: 'TCP', topCategory: 'Восстановлено', rxSeries: [1], txSeries: [2], applications: [], protocols: [], sources: [], destinations: [], interfaces: [], conversationsList: [], ifaces: [], live: false }
|
||||
const card = { id: '1', name: 'Экспортёр DTO', subtitle: '', site: 'TEST', country: 'RU', status: 'online', rxNow: 2, txNow: 3, sessions: 1, bytes: 200, rxSeries: [1], txSeries: [2] }
|
||||
page.on('pageerror', error => errors.push(error.message))
|
||||
await page.route('**/health', route => route.fulfill({ json: { ok: true } }))
|
||||
await page.route('**/api/**', route => {
|
||||
const url = new URL(route.request().url()), path = url.pathname
|
||||
if (path === '/api/traffic/flow/analytics' || path === '/api/traffic/flow/monthly') {
|
||||
if (path.endsWith(monthlyCase ? '/monthly' : '/analytics')) queries.push({ range: url.searchParams.get('range'), month: url.searchParams.get('month'), serverId: url.searchParams.get('serverId') })
|
||||
if (path.endsWith('/monthly')) {
|
||||
const month = url.searchParams.get('month')!
|
||||
const data = bad && variant === 'monthly-missing' ? { month, bytes: 1500 }
|
||||
: { month: bad && variant === 'monthly-mismatch' ? (month === '2026-01' ? '2026-02' : '2026-01') : month, bytes: 1500, countries: [], services: [], asns: [] }
|
||||
return route.fulfill({ json: data })
|
||||
}
|
||||
const data = bad && variant === 'missing-sessions' ? { ...stats, conversationsList: undefined }
|
||||
: bad && variant === 'negative-series' ? { ...stats, rxSeries: [-1] } : stats
|
||||
return route.fulfill({ json: data })
|
||||
}
|
||||
if (path.endsWith('/live')) return route.fulfill({ status: 503, json: {} })
|
||||
const json = path === '/api/auth/config' ? { required: false }
|
||||
: path === '/api/traffic/flow/exporters' ? { exporters: [card] }
|
||||
: path === '/api/traffic/flows' ? { exportersOnline: 1, bytesPerMin: 200, uniqueSrc: 1, uniqueDst: 1, topProto: 'TCP', talkers: [], listenerBound: true }
|
||||
: path === '/api/traffic/servers' ? { servers: [] }
|
||||
: path === '/api/traffic/users' ? { users: [] }
|
||||
: path === '/api/traffic/flow/clients' ? { clients: [] }
|
||||
: path.endsWith('/interfaces') ? { interfaces: [] }
|
||||
: path === '/api/servers' ? [{ id: 1, name: card.name, host: '127.0.0.1', port: 80, useSsl: false, verifySsl: false, username: 'admin', password: '', type: 'jump-host', site: 'TEST', country: 'RU', asn: '', comment: '', enabled: true, lanSubnet: '', wanUplinks: [], createdAt: '', updatedAt: '', status: null, latency: null, os: null, model: null, uptime: null, cpuLoad: null, freeMemory: null, totalMemory: null, identityName: null, sessions: 0, polledAt: null }] : {}
|
||||
return route.fulfill({ json })
|
||||
})
|
||||
await page.goto('/traffic')
|
||||
await page.getByRole('group', { name: 'Разделы трафика' }).getByRole('button', { name: 'Потоки', exact: true }).click()
|
||||
if (monthlyCase) await page.getByRole('button', { name: 'Месяц', exact: true }).click()
|
||||
const alert = page.getByRole('alert').filter({ hasText: 'Аналитика недоступна' })
|
||||
await expect(alert).toBeVisible()
|
||||
await expect(alert).toContainText(variant === 'monthly-mismatch' ? 'данные другого месяца' : 'некорректный ответ сервера')
|
||||
await expect(page.getByLabel('Скорость потоков')).toHaveCount(0)
|
||||
const selected = queries.at(-1)!
|
||||
expect(selected.serverId).toBe('1')
|
||||
bad = false
|
||||
await page.getByRole('button', { name: 'Повторить аналитику', exact: true }).click()
|
||||
await expect(alert).toHaveCount(0)
|
||||
expect(queries.at(-1)).toEqual(selected)
|
||||
if (!monthlyCase) await expect(page.getByLabel('Скорость потоков')).toBeVisible()
|
||||
expect(errors).toEqual([])
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user