fix(netflow): проверять месяц и точные календарные границы
This commit is contained in:
1 parent
0c14da190b
commit
555bd31596
13 files changed
+291
-25
No files matched your search
@@ -20,7 +20,7 @@
|
||||
"test:auth": "tsx src/lib/permissions.test.ts && tsx src/plugins/auth.smoke.test.ts && tsx src/plugins/auth.ospf-optimizer.test.ts",
|
||||
"test:wireguard": "npx tsx src/services/wireguard-config.test.ts && npx tsx --test src/services/wireguard-import.test.ts src/services/wireguard-import-apply.test.ts src/services/wireguard-import-revision.test.ts && npx tsx src/routes/wireguard-import.test.ts",
|
||||
"test:traffic-rate": "tsx src/services/traffic-rate.test.ts",
|
||||
"test:traffic-flow": "tsx src/routes/traffic-flow-query.test.ts && tsx src/services/traffic-flow-parse.test.ts && tsx src/services/traffic-flow-ipv6-pipeline.test.ts && tsx src/services/traffic-flow-map-exporter.test.ts && tsx src/services/traffic-flow-ifaces.test.ts && tsx src/services/traffic-flow-ifindex.test.ts && tsx src/services/traffic-flow-dedup.test.ts && tsx src/services/traffic-flow-planes.test.ts && tsx src/services/traffic-flow-ip.test.ts && tsx src/services/traffic-flow-dest.test.ts && tsx src/services/traffic-flow-classify.test.ts && tsx src/services/traffic-flow-ripe.test.ts && tsx src/services/traffic-flow-brands.test.ts && tsx src/services/traffic-flow-ingest.test.ts && tsx src/services/traffic-flow-analytics.test.ts && tsx src/services/traffic-flow-map-hops.test.ts && tsx src/services/traffic-flow-purge.test.ts && tsx src/services/traffic-flow-geoip.test.ts && tsx src/services/traffic-flow-facts.test.ts && tsx src/services/traffic-flow-facts-filter.test.ts && tsx src/services/traffic-flow-facts-rebuild.test.ts && tsx src/services/statistics-aggregate.test.ts",
|
||||
"test:traffic-flow": "tsx src/routes/traffic-flow-query.test.ts && tsx src/services/traffic-flow-month.test.ts && tsx src/services/traffic-flow-parse.test.ts && tsx src/services/traffic-flow-ipv6-pipeline.test.ts && tsx src/services/traffic-flow-map-exporter.test.ts && tsx src/services/traffic-flow-ifaces.test.ts && tsx src/services/traffic-flow-ifindex.test.ts && tsx src/services/traffic-flow-dedup.test.ts && tsx src/services/traffic-flow-planes.test.ts && tsx src/services/traffic-flow-ip.test.ts && tsx src/services/traffic-flow-dest.test.ts && tsx src/services/traffic-flow-classify.test.ts && tsx src/services/traffic-flow-ripe.test.ts && tsx src/services/traffic-flow-brands.test.ts && tsx src/services/traffic-flow-ingest.test.ts && tsx src/services/traffic-flow-analytics.test.ts && tsx src/services/traffic-flow-map-hops.test.ts && tsx src/services/traffic-flow-purge.test.ts && tsx src/services/traffic-flow-geoip.test.ts && tsx src/services/traffic-flow-facts.test.ts && tsx src/services/traffic-flow-facts-filter.test.ts && tsx src/services/traffic-flow-facts-rebuild.test.ts && tsx src/services/statistics-aggregate.test.ts",
|
||||
"test:users": "tsx src/modules/users/iface-type.test.ts && tsx src/modules/users/bindings.test.ts && tsx src/modules/users/interface-inventory.test.ts && tsx src/routes/users-catalog.test.ts",
|
||||
"test:pg": "tsx src/db/sql-bind.test.ts && tsx src/db/sqlite-json.test.ts && tsx src/db/traffic-flags.test.ts && tsx src/db/pg-schema.test.ts && tsx src/services/config-revisions.test.ts",
|
||||
"test:recursive-routes": "tsx src/routes/recursive-routes.test.ts && tsx src/services/recursive-route-catalog.test.ts && tsx src/services/recursive-apply.test.ts",
|
||||
|
||||
@@ -21,6 +21,11 @@ try {
|
||||
for (let i = 0; i < 4; i++) assert.equal(tryAcquireFlowLiveSlot(), true)
|
||||
assert.equal(tryAcquireFlowLiveSlot(), false)
|
||||
for (let i = 0; i < 4; i++) releaseFlowLiveSlot()
|
||||
for (const month of ["bad", "2026-00", "2026-13", "0000-01", "2026-1", "2026-10junk"]) {
|
||||
const response = await app.inject({ method: "GET", url: `/api/traffic/flow/monthly?serverId=1&month=${encodeURIComponent(month)}` })
|
||||
assert.equal(response.statusCode, 400, month)
|
||||
assert.match(response.body, /Некорректный месяц отчёта/)
|
||||
}
|
||||
console.log("traffic-flow-query.test.ts: 21 invalid scoped requests rejected; SSE slots retained")
|
||||
} finally {
|
||||
resetFlowLiveSlotsForTests()
|
||||
|
||||
@@ -231,9 +231,9 @@ const trafficFlowRoutes: FastifyPluginAsyncZod = async (app) => {
|
||||
app.get("/traffic/flow/monthly", async (req, reply) => {
|
||||
const q = req.query as { month?: string; serverId?: string }
|
||||
const now = new Date()
|
||||
const month = /^\d{4}-\d{2}$/.test(q.month ?? "")
|
||||
? (q.month as string)
|
||||
: `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}`
|
||||
const month = q.month == null || q.month === ""
|
||||
? `${now.getUTCFullYear()}-${String(now.getUTCMonth() + 1).padStart(2, "0")}`
|
||||
: q.month
|
||||
return reply.send(await getFlowMonthly(month, parseId(q.serverId)))
|
||||
})
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import { appUsers, userInterfaceBindings } from "../db/schema.js"
|
||||
import type {
|
||||
FlowAnalyticsDto,
|
||||
FlowBreakdownRow,
|
||||
FlowClientsDto,
|
||||
FlowEntityCard,
|
||||
FlowExportersDto,
|
||||
FlowMapEdge,
|
||||
@@ -645,15 +644,16 @@ export async function safeBuildLiveFlowSample(q: Omit<FlowAnalyticsQuery, "minut
|
||||
})
|
||||
}
|
||||
|
||||
function monthBounds(month: string): { start: string; end: string } | null {
|
||||
if (!/^\d{4}-\d{2}$/.test(month)) return null
|
||||
export function flowMonthBounds(month: string): { start: string; end: string } | null {
|
||||
if (typeof month !== "string" || !/^(?!0000)\d{4}-(0[1-9]|1[0-2])$/.test(month)) return null
|
||||
const [yearRaw, monthRaw] = month.split("-")
|
||||
const year = Number(yearRaw)
|
||||
const monthIdx = Number(monthRaw)
|
||||
if (!Number.isFinite(year) || monthIdx < 1 || monthIdx > 12) return null
|
||||
const start = `${month}-01`
|
||||
const endDate = new Date(Date.UTC(year, monthIdx, 1))
|
||||
const end = endDate.toISOString().slice(0, 10)
|
||||
// Date.UTC treats years0..99 as1900..1999. Calendar arithmetic also preserves
|
||||
// the full ISO year at December9999 without truncating an extended date string.
|
||||
const end = `${String(year + (monthIdx === 12 ? 1 : 0)).padStart(4, "0")}-${String(monthIdx === 12 ? 1 : monthIdx + 1).padStart(2, "0")}-01`
|
||||
return { start, end }
|
||||
}
|
||||
|
||||
@@ -676,9 +676,9 @@ function toBreakdown(
|
||||
}
|
||||
|
||||
export async function getFlowMonthly(month: string, serverId?: number): Promise<FlowMonthlyDto> {
|
||||
const bounds = monthBounds(month)
|
||||
const bounds = flowMonthBounds(month)
|
||||
if (!bounds) {
|
||||
return { month, bytes: 0, countries: [], services: [], asns: [] }
|
||||
throw Object.assign(new Error("Некорректный месяц отчёта"), { statusCode: 400 })
|
||||
}
|
||||
const params: Array<string | number> = [bounds.start, bounds.end]
|
||||
let where = "day >= ? AND day < ? AND dim IN ('country', 'service', 'asn')"
|
||||
@@ -705,7 +705,9 @@ export async function getFlowMonthly(month: string, serverId?: number): Promise<
|
||||
} else if (row.dim === "service") services.push(rec)
|
||||
else if (row.dim === "asn") asns.push(rec)
|
||||
}
|
||||
const daysInMonth = Math.max(1, Math.round((Date.parse(`${bounds.end}T00:00:00Z`) - Date.parse(`${bounds.start}T00:00:00Z`)) / 86_400_000))
|
||||
const [year, monthIndex] = month.split("-").map(Number)
|
||||
const leap = year! % 4 === 0 && (year! % 100 !== 0 || year! % 400 === 0)
|
||||
const daysInMonth = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][monthIndex! - 1]!
|
||||
const windowSec = daysInMonth * 86_400
|
||||
const countryTotal = countries.reduce((a, r) => a + r.bytes, 0) || bytes || 1
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import assert from "node:assert/strict"
|
||||
import { flowMonthBounds, getFlowMonthly } from "./traffic-flow-analytics.js"
|
||||
import { pool, closePool } from "../db/index.js"
|
||||
import { initDatabase } from "../db/bootstrap.js"
|
||||
|
||||
for (const [month, end] of [
|
||||
["2026-10", "2026-11-01"], ["2026-12", "2027-01-01"],
|
||||
["0001-01", "0001-02-01"], ["0099-12", "0100-01-01"],
|
||||
["2024-02", "2024-03-01"], ["9999-12", "10000-01-01"],
|
||||
]) assert.deepEqual(flowMonthBounds(month!), { start: `${month}-01`, end })
|
||||
try {
|
||||
for (const month of ["bad", "2026-00", "2026-13", "0000-01", "2026-1", "2026-10junk", "2026-10-01", " 2026-10"]) {
|
||||
assert.equal(flowMonthBounds(month), null)
|
||||
await assert.rejects(getFlowMonthly(month), (error: unknown) => error instanceof Error && (error as Error & { statusCode: number }).statusCode === 400)
|
||||
}
|
||||
const ownDb = process.env.MMAPP_OWN_TEST_DB
|
||||
if (ownDb) {
|
||||
assert(/^mm_accept_149_\d+$/.test(ownDb))
|
||||
assert.equal((await pool.query("SELECT current_database() AS name")).rows[0].name, ownDb)
|
||||
await initDatabase()
|
||||
const serverId = Number((await pool.query("INSERT INTO servers (name,host) VALUES ('month-boundary-fixture','127.0.0.1') RETURNING id")).rows[0].id)
|
||||
const cases = [
|
||||
{ month: "0001-01", start: "0001-01-01", end: "0001-03-01", inside: "0001-01-15", outside: "0001-02-01", days: 31 },
|
||||
{ month: "0099-12", start: "0099-12-01", end: "0100-02-01", inside: "0099-12-15", outside: "0100-01-01", days: 31 },
|
||||
{ month: "1900-02", start: "1900-02-01", end: "1900-04-01", inside: "1900-02-28", outside: "1900-03-01", days: 28 },
|
||||
{ month: "2000-02", start: "2000-02-01", end: "2000-04-01", inside: "2000-02-29", outside: "2000-03-01", days: 29 },
|
||||
{ month: "9999-12", start: "9999-12-01", end: "10000-02-01", inside: "9999-12-15", outside: "10000-01-01", days: 31 },
|
||||
]
|
||||
for (const [i, item] of cases.entries()) {
|
||||
// Fixed fixture DDL only, guarded by an exact owned database before migrations.
|
||||
await pool.query(`CREATE TABLE flow_daily_dims_mm149_${i} PARTITION OF flow_daily_dims FOR VALUES FROM ('${item.start}') TO ('${item.end}')`)
|
||||
await pool.query("INSERT INTO flow_daily_dims (server_id,day,dim,key,bytes,packets) VALUES ($1,$2,'country','US',1200,12),($1,$3,'country','US',12000,120)", [serverId, item.inside, item.outside])
|
||||
const monthly = await getFlowMonthly(item.month, serverId)
|
||||
assert.equal(monthly.month, item.month)
|
||||
assert.equal(monthly.bytes, 1200, item.month)
|
||||
assert.equal(monthly.countries[0]?.bytes, 1200)
|
||||
assert.equal(monthly.countries[0]?.bps, 1200 * 8 / (item.days * 86400), item.month)
|
||||
}
|
||||
console.log("ISOLATED_MONTH_SQL_ACCEPTED: 5 exact intervals, outside rows excluded, leap-year rates verified")
|
||||
} else console.log("Monthly SQL: skip (requires an owned isolated database)")
|
||||
console.log("traffic-flow-month.test.ts: exact month bounds and invalid-before-SQL checks passed")
|
||||
} finally {
|
||||
await closePool()
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# UX/UI: протокол внешней приёмки 12.5
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.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.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.12.5 открыт.
|
||||
|
||||
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
|
||||
|
||||
@@ -1601,3 +1601,15 @@ Backend больше не извлекает numeric prefix из1suffix и не
|
||||
Backend/frontend ux-scope148 развёрнуты, health healthy. Real API9 malformed cases400 и2 valid scoped cases200; [receipt](ux-ui/acceptance/flow-scoped-query-2026-10-11.json), [PC/mobile readonly smoke](ux-ui/acceptance/traffic-flow-scope-smoke-2026-10-11.json). No native changes/password changes/schema/theme changes; rollback env/images сохранены. Populated native145 не повторялся без необходимости.
|
||||
|
||||
Следующий149 — строгий month input и calendar bounds: invalid month не должен подменяться текущим или выдаваться за подтверждённый zero report.12.5 открыт.
|
||||
|
||||
## 12.5.149 — календарный месяц без тихой подмены и ложных нулей (2026-10-11)
|
||||
|
||||
Supplied malformed month раньше подменялся current UTC month на route; impossible month мог вернуться из service как zero report. Теперь непустой параметр передаётся для strict YYYY-MM/month1..12/year!=0000 validation, invalid получает400 Некорректный месяц отчёта до SQL. Missing/empty optional month сохраняет прежний current UTC default. Runtime non-string тоже отклоняется.
|
||||
|
||||
Calendar bounds больше не используют Date.UTC дляyear1..99 (он превращает их в1901..1999) и не режут extended ISO date at year10000. Integer year/month arithmetic даёт exact next-month day1, average bps используют Gregorian month length/leap rule. Source tests проверяют нормальный month/year rollover,1/99/9999, invalid input rejection before SQL. Normalized labels/DB schema не менялись.
|
||||
|
||||
В candidate Docker5 SQL intervals прошли в own temporary PostgreSQL DB:0001 January,0099 December,1900 February28days,2000 February29days,9999 December/end10000. In-month1200B retained, next-month12000B excluded, average country bps matches exact month length. Fixture DDL выполняется только после exact own DB/current_database check, DB удалена с owner check; working DB/legacy SQLite не использовались fixtures. Both month and scoped-query tests добавлены в normal traffic-flow series. ESLint/backend build/984 output comparison и6 frontend scoped/context tests passed; frontend не пересобирался.
|
||||
|
||||
Backend ux-month149 развёрнут, frontend ux-scope148 сохранён, health healthy. Real API6 invalid months400 иcorrect2026-10→200/same month; initial smoke helper Fetch.status method typo исправлен только в harness, сохранён как setup error. [Full SQL/live receipt](ux-ui/acceptance/flow-month-calendar-2026-10-11.json), [PC/mobile smoke](ux-ui/acceptance/traffic-month-calendar-smoke-2026-10-11.json). Device/password changes нет, rollback retained. Это не расширяет UI на future month selection.
|
||||
|
||||
Следующий небольшой150 — понятные подписи Sessions columns вместо App/Proto/Iface/JH/EN, сохраняя ReUI grid/Frame/base-nova/data semantics.12.5 открыт.
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
# План реализации UX/UI по пятичасовым окнам
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.12.5 открыт.
|
||||
|
||||
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
|
||||
|
||||
## Актуальная точка продолжения — 2026-10-10
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.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.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.12.5 открыт.
|
||||
|
||||
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
|
||||
+14
-2
@@ -1,6 +1,6 @@
|
||||
# UX/UI: журнал реализации
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.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–148 и ограничения ниже. Runtime backend/frontend ux-scope148. |
|
||||
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–149 и ограничения ниже. Runtime backend ux-month149/frontend ux-scope148. |
|
||||
|
||||
## 12.5.149 — календарный месяц без тихой подмены и ложных нулей (2026-10-11)
|
||||
|
||||
Supplied malformed month раньше подменялся current UTC month на route; impossible month мог вернуться из service как zero report. Теперь непустой параметр передаётся для strict YYYY-MM/month1..12/year!=0000 validation, invalid получает400 Некорректный месяц отчёта до SQL. Missing/empty optional month сохраняет прежний current UTC default. Runtime non-string тоже отклоняется.
|
||||
|
||||
Calendar bounds больше не используют Date.UTC дляyear1..99 (он превращает их в1901..1999) и не режут extended ISO date at year10000. Integer year/month arithmetic даёт exact next-month day1, average bps используют Gregorian month length/leap rule. Source tests проверяют нормальный month/year rollover,1/99/9999, invalid input rejection before SQL. Normalized labels/DB schema не менялись.
|
||||
|
||||
В candidate Docker5 SQL intervals прошли в own temporary PostgreSQL DB:0001 January,0099 December,1900 February28days,2000 February29days,9999 December/end10000. In-month1200B retained, next-month12000B excluded, average country bps matches exact month length. Fixture DDL выполняется только после exact own DB/current_database check, DB удалена с owner check; working DB/legacy SQLite не использовались fixtures. Both month and scoped-query tests добавлены в normal traffic-flow series. ESLint/backend build/984 output comparison и6 frontend scoped/context tests passed; frontend не пересобирался.
|
||||
|
||||
Backend ux-month149 развёрнут, frontend ux-scope148 сохранён, health healthy. Real API6 invalid months400 иcorrect2026-10→200/same month; initial smoke helper Fetch.status method typo исправлен только в harness, сохранён как setup error. [Full SQL/live receipt](ux-ui/acceptance/flow-month-calendar-2026-10-11.json), [PC/mobile smoke](ux-ui/acceptance/traffic-month-calendar-smoke-2026-10-11.json). Device/password changes нет, rollback retained. Это не расширяет UI на future month selection.
|
||||
|
||||
Следующий небольшой150 — понятные подписи Sessions columns вместо App/Proto/Iface/JH/EN, сохраняя ReUI grid/Frame/base-nova/data semantics.12.5 открыт.
|
||||
|
||||
## 12.5.148 — подтверждённый срез потоков без агрегатной подмены (2026-10-11)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Оставшаяся внешняя приёмка — 2026-10-11
|
||||
|
||||
Это актуальная матрица после 12.5.148. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
Это актуальная матрица после 12.5.149. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
|
||||
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-scope148`, frontend `ux-scope148`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
|
||||
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-month149`, frontend `ux-scope148`; 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 validation passed147; scoped flow catalog/serverId guards passed148; strict monthly calendar149; последующие изменения проверять отдельно; 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 guards passed148; strict monthly calendar passed149; Sessions labels150; последующие изменения проверять отдельно; 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). Невыполненные пункты не являются все блокерами данного лабораторного сценария: для выпуска необходимо явно определить требуемые конфигурации и принять их либо согласовать ограничение.
|
||||
|
||||
@@ -516,3 +516,15 @@ Backend больше не извлекает numeric prefix из1suffix и не
|
||||
Backend/frontend ux-scope148 развёрнуты, health healthy. Real API9 malformed cases400 и2 valid scoped cases200; [receipt](ux-ui/acceptance/flow-scoped-query-2026-10-11.json), [PC/mobile readonly smoke](ux-ui/acceptance/traffic-flow-scope-smoke-2026-10-11.json). No native changes/password changes/schema/theme changes; rollback env/images сохранены. Populated native145 не повторялся без необходимости.
|
||||
|
||||
Следующий149 — строгий month input и calendar bounds: invalid month не должен подменяться текущим или выдаваться за подтверждённый zero report.12.5 открыт.
|
||||
|
||||
## 12.5.149 — календарный месяц без тихой подмены и ложных нулей (2026-10-11)
|
||||
|
||||
Supplied malformed month раньше подменялся current UTC month на route; impossible month мог вернуться из service как zero report. Теперь непустой параметр передаётся для strict YYYY-MM/month1..12/year!=0000 validation, invalid получает400 Некорректный месяц отчёта до SQL. Missing/empty optional month сохраняет прежний current UTC default. Runtime non-string тоже отклоняется.
|
||||
|
||||
Calendar bounds больше не используют Date.UTC дляyear1..99 (он превращает их в1901..1999) и не режут extended ISO date at year10000. Integer year/month arithmetic даёт exact next-month day1, average bps используют Gregorian month length/leap rule. Source tests проверяют нормальный month/year rollover,1/99/9999, invalid input rejection before SQL. Normalized labels/DB schema не менялись.
|
||||
|
||||
В candidate Docker5 SQL intervals прошли в own temporary PostgreSQL DB:0001 January,0099 December,1900 February28days,2000 February29days,9999 December/end10000. In-month1200B retained, next-month12000B excluded, average country bps matches exact month length. Fixture DDL выполняется только после exact own DB/current_database check, DB удалена с owner check; working DB/legacy SQLite не использовались fixtures. Both month and scoped-query tests добавлены в normal traffic-flow series. ESLint/backend build/984 output comparison и6 frontend scoped/context tests passed; frontend не пересобирался.
|
||||
|
||||
Backend ux-month149 развёрнут, frontend ux-scope148 сохранён, health healthy. Real API6 invalid months400 иcorrect2026-10→200/same month; initial smoke helper Fetch.status method typo исправлен только в harness, сохранён как setup error. [Full SQL/live receipt](ux-ui/acceptance/flow-month-calendar-2026-10-11.json), [PC/mobile smoke](ux-ui/acceptance/traffic-month-calendar-smoke-2026-10-11.json). Device/password changes нет, rollback retained. Это не расширяет UI на future month selection.
|
||||
|
||||
Следующий небольшой150 — понятные подписи Sessions columns вместо App/Proto/Iface/JH/EN, сохраняя ReUI grid/Frame/base-nova/data semantics.12.5 открыт.
|
||||
+13
-1
@@ -1,6 +1,6 @@
|
||||
# Этап 12: итоговая приёмка UX/UI
|
||||
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Актуальное продолжение 2026-10-11: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.12.5 открыт.
|
||||
|
||||
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
|
||||
|
||||
@@ -2906,3 +2906,15 @@ Backend больше не извлекает numeric prefix из1suffix и не
|
||||
Backend/frontend ux-scope148 развёрнуты, health healthy. Real API9 malformed cases400 и2 valid scoped cases200; [receipt](ux-ui/acceptance/flow-scoped-query-2026-10-11.json), [PC/mobile readonly smoke](ux-ui/acceptance/traffic-flow-scope-smoke-2026-10-11.json). No native changes/password changes/schema/theme changes; rollback env/images сохранены. Populated native145 не повторялся без необходимости.
|
||||
|
||||
Следующий149 — строгий month input и calendar bounds: invalid month не должен подменяться текущим или выдаваться за подтверждённый zero report.12.5 открыт.
|
||||
|
||||
## 12.5.149 — календарный месяц без тихой подмены и ложных нулей (2026-10-11)
|
||||
|
||||
Supplied malformed month раньше подменялся current UTC month на route; impossible month мог вернуться из service как zero report. Теперь непустой параметр передаётся для strict YYYY-MM/month1..12/year!=0000 validation, invalid получает400 Некорректный месяц отчёта до SQL. Missing/empty optional month сохраняет прежний current UTC default. Runtime non-string тоже отклоняется.
|
||||
|
||||
Calendar bounds больше не используют Date.UTC дляyear1..99 (он превращает их в1901..1999) и не режут extended ISO date at year10000. Integer year/month arithmetic даёт exact next-month day1, average bps используют Gregorian month length/leap rule. Source tests проверяют нормальный month/year rollover,1/99/9999, invalid input rejection before SQL. Normalized labels/DB schema не менялись.
|
||||
|
||||
В candidate Docker5 SQL intervals прошли в own temporary PostgreSQL DB:0001 January,0099 December,1900 February28days,2000 February29days,9999 December/end10000. In-month1200B retained, next-month12000B excluded, average country bps matches exact month length. Fixture DDL выполняется только после exact own DB/current_database check, DB удалена с owner check; working DB/legacy SQLite не использовались fixtures. Both month and scoped-query tests добавлены в normal traffic-flow series. ESLint/backend build/984 output comparison и6 frontend scoped/context tests passed; frontend не пересобирался.
|
||||
|
||||
Backend ux-month149 развёрнут, frontend ux-scope148 сохранён, health healthy. Real API6 invalid months400 иcorrect2026-10→200/same month; initial smoke helper Fetch.status method typo исправлен только в harness, сохранён как setup error. [Full SQL/live receipt](ux-ui/acceptance/flow-month-calendar-2026-10-11.json), [PC/mobile smoke](ux-ui/acceptance/traffic-month-calendar-smoke-2026-10-11.json). Device/password changes нет, rollback retained. Это не расширяет UI на future month selection.
|
||||
|
||||
Следующий небольшой150 — понятные подписи Sessions columns вместо App/Proto/Iface/JH/EN, сохраняя ReUI grid/Frame/base-nova/data semantics.12.5 открыт.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Тестовый сервер UX/UI — 2026-10-10
|
||||
|
||||
Сервер161.104.46.222: завершён12.5.148 — scoped flow HTTP/SSE ждут confirmed catalog; invalid serverId получает400 без aggregate fallback/SSE slot leak.36 E2E,21 backend checks/source+candidate,984 outputs/types/ESLint/both builds,live API+PC/mobile passed. Backend/frontend ux-scope148. Далее149 — strict monthly calendar input/bounds, без подмены invalid month текущим/нулевым отчётом.12.5 открыт.
|
||||
Сервер161.104.46.222: завершён12.5.149 — invalid month400 без current/zero fallback; calendar bounds исправлены для годов1–99/9999 и leap rates.5 SQL intervals в own DB/removed,984 outputs/build/ESLint,6 frontend checks и live400/200+PC/mobile passed. Backend ux-month149/frontend ux-scope148. Далее150 — ясные названия колонок Sessions вместо App/Proto/Iface/JH/EN, без изменения данных/темы.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-scope148 и mmapp-test/frontend:ux-scope148; запущены |
|
||||
| Образы приложения | mmapp-test/backend:ux-month149 и mmapp-test/frontend:ux-scope148; запущены |
|
||||
|
||||
Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example).
|
||||
|
||||
@@ -1332,3 +1332,15 @@ Backend больше не извлекает numeric prefix из1suffix и не
|
||||
Backend/frontend ux-scope148 развёрнуты, health healthy. Real API9 malformed cases400 и2 valid scoped cases200; [receipt](ux-ui/acceptance/flow-scoped-query-2026-10-11.json), [PC/mobile readonly smoke](ux-ui/acceptance/traffic-flow-scope-smoke-2026-10-11.json). No native changes/password changes/schema/theme changes; rollback env/images сохранены. Populated native145 не повторялся без необходимости.
|
||||
|
||||
Следующий149 — строгий month input и calendar bounds: invalid month не должен подменяться текущим или выдаваться за подтверждённый zero report.12.5 открыт.
|
||||
|
||||
## 12.5.149 — календарный месяц без тихой подмены и ложных нулей (2026-10-11)
|
||||
|
||||
Supplied malformed month раньше подменялся current UTC month на route; impossible month мог вернуться из service как zero report. Теперь непустой параметр передаётся для strict YYYY-MM/month1..12/year!=0000 validation, invalid получает400 Некорректный месяц отчёта до SQL. Missing/empty optional month сохраняет прежний current UTC default. Runtime non-string тоже отклоняется.
|
||||
|
||||
Calendar bounds больше не используют Date.UTC дляyear1..99 (он превращает их в1901..1999) и не режут extended ISO date at year10000. Integer year/month arithmetic даёт exact next-month day1, average bps используют Gregorian month length/leap rule. Source tests проверяют нормальный month/year rollover,1/99/9999, invalid input rejection before SQL. Normalized labels/DB schema не менялись.
|
||||
|
||||
В candidate Docker5 SQL intervals прошли в own temporary PostgreSQL DB:0001 January,0099 December,1900 February28days,2000 February29days,9999 December/end10000. In-month1200B retained, next-month12000B excluded, average country bps matches exact month length. Fixture DDL выполняется только после exact own DB/current_database check, DB удалена с owner check; working DB/legacy SQLite не использовались fixtures. Both month and scoped-query tests добавлены в normal traffic-flow series. ESLint/backend build/984 output comparison и6 frontend scoped/context tests passed; frontend не пересобирался.
|
||||
|
||||
Backend ux-month149 развёрнут, frontend ux-scope148 сохранён, health healthy. Real API6 invalid months400 иcorrect2026-10→200/same month; initial smoke helper Fetch.status method typo исправлен только в harness, сохранён как setup error. [Full SQL/live receipt](ux-ui/acceptance/flow-month-calendar-2026-10-11.json), [PC/mobile smoke](ux-ui/acceptance/traffic-month-calendar-smoke-2026-10-11.json). Device/password changes нет, rollback retained. Это не расширяет UI на future month selection.
|
||||
|
||||
Следующий небольшой150 — понятные подписи Sessions columns вместо App/Proto/Iface/JH/EN, сохраняя ReUI grid/Frame/base-nova/data semantics.12.5 открыт.
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"date": "2026-10-11",
|
||||
"block": "12.5.149",
|
||||
"runtime": {
|
||||
"backend": "ux-month149",
|
||||
"frontend": "ux-scope148",
|
||||
"backendHealthy": true
|
||||
},
|
||||
"checks": {
|
||||
"sourcePureBoundsAndInvalidBeforeSqlPassed": true,
|
||||
"sourceAndCandidateInvalidQueryChecksPassed": true,
|
||||
"ownedSqlCalendarIntervalsPassed": 5,
|
||||
"ownedDbRemoved": true,
|
||||
"eslintPassed": true,
|
||||
"backendProductionBuildPassed": true,
|
||||
"compiledBackendOutputsMatched": 984,
|
||||
"frontendScopedChecksPassed": 6,
|
||||
"liveMonthApi": [
|
||||
{
|
||||
"month": "bad",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"month": "2026-00",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"month": "2026-13",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"month": "0000-01",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"month": "2026-1",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"month": "2026-10junk",
|
||||
"status": 400
|
||||
},
|
||||
{
|
||||
"month": "2026-10",
|
||||
"status": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
"sql": {
|
||||
"date": "2026-10-11",
|
||||
"name": "mm_accept_149_1791717813194",
|
||||
"tests": [
|
||||
{
|
||||
"module": "traffic-flow-month",
|
||||
"passed": true,
|
||||
"output": "ISOLATED_MONTH_SQL_ACCEPTED: 5 exact intervals, outside rows excluded, leap-year rates verified\ntraffic-flow-month.test.ts: exact month bounds and invalid-before-SQL checks passed\n"
|
||||
}
|
||||
],
|
||||
"databaseRemoved": true
|
||||
},
|
||||
"bounds": [
|
||||
"Malformed supplied month now400, no fallback to current or fake zero report; omitted/empty month retains legacy current UTC default",
|
||||
"Year0000 rejected consistently with UI; full YYYY-MM/month1..12 required, runtime non-string rejected",
|
||||
"Integer calendar arithmetic fixes Date.UTC years1..99 offset and extended-year string truncation at December9999",
|
||||
"Explicit Gregorian leap/month lengths compute average rates without Date.parse limitations for year10000",
|
||||
"Five own SQL fixtures verify years0001/0099,1900 non-leap,2000 leap and9999 December; sibling next-month rows excluded",
|
||||
"Own fixture DDL only after exact database name/current_database checks; parent owner-checked removal; main DB/legacy SQLite untouched",
|
||||
"Initial live receipt helper incorrectly called Fetch response.status as a method; corrected harness only, product400/200 verified afterwards",
|
||||
"Frontend unchanged; no device/password/schema/theme change, no UI/capability expansion for future month selection"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"date": "2026-10-11",
|
||||
"block": "12.5.149",
|
||||
"runtime": {
|
||||
"backend": "ux-month149",
|
||||
"frontend": "ux-scope148"
|
||||
},
|
||||
"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/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
|
||||
}
|
||||
],
|
||||
"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"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user