From 7b884164156594b5c495eefa11b80a6ff0d49c06 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Tue, 13 Oct 2026 13:58:56 +0700 Subject: [PATCH] =?UTF-8?q?fix(traffic):=20=D1=81=D1=87=D0=B8=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B9=20=D0=BF=D0=B8?= =?UTF-8?q?=D0=BA=20=D0=BF=D0=BE=20=D1=81=D0=BE=D0=B2=D0=BF=D0=B0=D0=B4?= =?UTF-8?q?=D0=B0=D1=8E=D1=89=D0=B8=D0=BC=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package.json | 2 +- .../services/traffic-aggregate-peak.test.ts | 31 + backend/src/services/traffic-rate.ts | 49 +- .../src/services/traffic-volume-sql.test.ts | 13 + docs/ux-ui-external-acceptance.md | 22 +- docs/ux-ui-plan.md | 6 +- docs/ux-ui-progress.md | 22 +- docs/ux-ui-remaining-acceptance.md | 22 +- docs/ux-ui-stage-12.md | 20 +- docs/ux-ui-test-server.md | 22 +- .../traffic-peak-deployed-2026-10-13.json | 6 +- .../traffic-peak-e2e-2026-10-13.json | 16 + .../traffic-peak-interop-2026-10-13.json | 10 + .../traffic-peak191-compiled191-result.json | 1050 +++++++++++++++++ .../traffic-peak191-peak191-api-result.json | 26 + .../traffic-peak191-runtime191-result.json | 25 + .../traffic-peak191-source191-result.json | 10 + .../traffic-peak191-sql191-result.json | 31 + lib/traffic-observations.test.ts | 4 + lib/traffic-observations.ts | 5 +- tests/e2e/traffic-peak-confidence.spec.ts | 25 + 21 files changed, 1390 insertions(+), 27 deletions(-) create mode 100644 backend/src/services/traffic-aggregate-peak.test.ts create mode 100644 docs/ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json create mode 100644 docs/ux-ui/acceptance/traffic-peak-interop-2026-10-13.json create mode 100644 docs/ux-ui/acceptance/traffic-peak191-compiled191-result.json create mode 100644 docs/ux-ui/acceptance/traffic-peak191-peak191-api-result.json create mode 100644 docs/ux-ui/acceptance/traffic-peak191-runtime191-result.json create mode 100644 docs/ux-ui/acceptance/traffic-peak191-source191-result.json create mode 100644 docs/ux-ui/acceptance/traffic-peak191-sql191-result.json create mode 100644 tests/e2e/traffic-peak-confidence.spec.ts diff --git a/backend/package.json b/backend/package.json index 0c37a6a9..5403e1f8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,7 +19,7 @@ "test:exec": "tsx src/services/mikrotik-logs.test.ts && tsx src/routes/exec.test.ts && tsx src/plugins/auth.exec.test.ts", "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 src/services/wireguard-ipv6.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 src/services/wireguard-delete.test.ts && npx tsx src/routes/wireguard-import.test.ts", - "test:traffic-rate": "tsx src/services/traffic-rate.test.ts && tsx src/services/traffic-observation.test.ts && tsx src/services/traffic-freshness.test.ts && tsx src/services/traffic-live.test.ts && tsx src/services/traffic-observation-sql.test.ts && tsx src/services/traffic-history-sql.test.ts && tsx src/services/traffic-live-sql.test.ts && tsx src/services/traffic-volume-sql.test.ts && tsx src/services/traffic-binding-status.test.ts && tsx src/services/traffic-status-sql.test.ts && tsx src/services/traffic-gap.test.ts && tsx src/services/traffic-identity.test.ts && tsx src/services/traffic-membership.test.ts", + "test:traffic-rate": "tsx src/services/traffic-rate.test.ts && tsx src/services/traffic-observation.test.ts && tsx src/services/traffic-freshness.test.ts && tsx src/services/traffic-live.test.ts && tsx src/services/traffic-observation-sql.test.ts && tsx src/services/traffic-history-sql.test.ts && tsx src/services/traffic-live-sql.test.ts && tsx src/services/traffic-volume-sql.test.ts && tsx src/services/traffic-binding-status.test.ts && tsx src/services/traffic-status-sql.test.ts && tsx src/services/traffic-gap.test.ts && tsx src/services/traffic-identity.test.ts && tsx src/services/traffic-membership.test.ts && tsx src/services/traffic-aggregate-peak.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/pg-pool.test.ts && 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", diff --git a/backend/src/services/traffic-aggregate-peak.test.ts b/backend/src/services/traffic-aggregate-peak.test.ts new file mode 100644 index 00000000..0e50c641 --- /dev/null +++ b/backend/src/services/traffic-aggregate-peak.test.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert/strict' +import {buildTrafficFromSamples, mergeBuiltTraffic} from './traffic-rate.js' + +const at = Date.parse('2026-10-13T00:00:00Z') +const rows = (name:string, bytes:number[], times=[0,30_000,60_000], known=[false,true,true]) => bytes.map((value,i)=>({ + interfaceName:name,sampledAt:new Date(at+times[i]).toISOString(),rxBytes:value,txBytes:value/2, + rxBps:0,txBps:0,running:true,disabled:false,countersKnown:true,continuityKnown:known[i],nativeCounterIdentity:name, +})) +const build = (r:ReturnType) => buildTrafficFromSamples(r,at,at+60_000,undefined,undefined,true) +const a=build(rows('a',[0,375_000_000,375_000_000])) +const b=build(rows('b',[0,0,375_000_000])) +const separate=mergeBuiltTraffic([a,b]) +assert.equal(separate.rxPeak,100);assert.equal(separate.txPeak,50) +assert.equal(separate.observations!.rxPeak,true) +assert.equal(separate.rxTotalGiB,a.rxTotalGiB+b.rxTotalGiB) +assert.equal(mergeBuiltTraffic([a,a]).rxPeak,200) +assert.equal(mergeBuiltTraffic([separate,separate]).rxPeak,200,'nested merge preserves raw intervals') +assert.equal(mergeBuiltTraffic([build(rows('z',[0,0,0])),build(rows('z2',[0,0,0]))]).observations!.rxPeak,true,'measured zero is known') +const missing=build(rows('missing',[0,0,375_000_000],[0,30_000,60_000],[false,false,false])) +assert.equal(mergeBuiltTraffic([a,missing]).observations!.rxPeak,false) +const jitter=build(rows('jitter',[0,0,375_000_000],[1,30_001,59_999])) +assert.equal(mergeBuiltTraffic([a,jitter]).observations!.rxPeak,false,'sharing a chart bucket does not establish a matching wave') +const differentStart=build(rows('start',[0,375_000_000],[15_000,30_000])) +assert.equal(mergeBuiltTraffic([a,differentStart]).observations!.rxPeak,false,'same end with different interval is not simultaneous') +const recovery=build(rows('recovery',[0,0,375_000_000],[0,30_000,60_000],[false,false,true])) +assert.equal(mergeBuiltTraffic([a,recovery]).rxPeak,100) +assert.equal(mergeBuiltTraffic([a,recovery]).observations!.rxPeak,true) +assert.equal(mergeBuiltTraffic([a,build([])]).observations!.rxPeak,false) +assert.equal(mergeBuiltTraffic([a,{...a}]).observations!.rxPeak,false,'serialized legacy parts have no raw interval proof') +assert(!JSON.stringify(separate).includes('rxKnown'),'internal points are not DTO fields') +console.log('aggregate peak: separate/coincident/nested/zero/missing/jitter/interval/recovery/empty/legacy/serialization passed') diff --git a/backend/src/services/traffic-rate.ts b/backend/src/services/traffic-rate.ts index 699b4943..73a8478d 100644 --- a/backend/src/services/traffic-rate.ts +++ b/backend/src/services/traffic-rate.ts @@ -25,6 +25,7 @@ export interface RatePoint { } export interface TrafficObservations {rxNow:boolean;txNow:boolean;rxSeries:boolean[];txSeries:boolean[];sampledAt:string|null;expiresAt?:string|null;measurementIntervalMs?:number|null; + rxPeak?:boolean;txPeak?:boolean; currentState?: import("./traffic-freshness.js").TrafficCurrentState;lastAttemptAt?:string|null;lastSucceededAt?:string|null;error?:string|null} export interface BuiltTrafficSeries { @@ -40,6 +41,14 @@ export interface BuiltTrafficSeries { txSeries: number[] } +type PeakWave = { start: number; rx: number; tx: number; rxKnown: boolean; txKnown: boolean } +// Raw intervals stay internal: DTO serialization must not expose or round these points. +const peakWaves = new WeakMap>() +function retainPeakWaves(built: BuiltTrafficSeries, waves: Map): BuiltTrafficSeries { + peakWaves.set(built, waves) + return built +} + export interface MonitorLiveSample { rxMbps: number txMbps: number @@ -129,7 +138,7 @@ export function buildTrafficFromSamples( txSeries: Array.from({ length: SERIES_POINTS }, () => 0), } const noObservations:TrafficObservations={rxNow:false,txNow:false,rxSeries:Array(SERIES_POINTS).fill(false),txSeries:Array(SERIES_POINTS).fill(false),sampledAt:null} - if (rows.length === 0) return includeObservations?{...empty,observations:noObservations}:empty + if (rows.length === 0) return retainPeakWaves(includeObservations?{...empty,observations:{...noObservations,rxPeak:false,txPeak:false}}:empty,new Map()) const bySeries = new Map() for (const r of rows) { @@ -145,7 +154,7 @@ export function buildTrafficFromSamples( const rxPoints: Array<{ t: number; v: number }> = [] const txPoints: Array<{ t: number; v: number }> = [] - const byTs = new Map() + const byTs = new Map() let includedSeries=0,lastAttemptAt:number|null=null const membership = new Map() let latestMembershipAt = -Infinity @@ -205,7 +214,8 @@ export function buildTrafficFromSamples( if (rxBps == null && txBps == null) continue const rxMbps = bpsToMbps(rxBps ?? 0) const txMbps = bpsToMbps(txBps ?? 0) - const acc = byTs.get(t1) ?? { rx: 0, tx: 0,rxObserved:true,txObserved:true,count:0,intervalMs:0 } + const acc = byTs.get(t1) ?? { rx: 0, tx: 0,rxObserved:true,txObserved:true,count:0,intervalMs:0,start:t0,sameStart:true } + acc.sameStart &&= acc.start === t0 acc.intervalMs = Math.max(acc.intervalMs, t1 - t0) acc.count++;acc.rxObserved&&=rxBps!==null;acc.txObserved&&=txBps!==null acc.rx += rxMbps @@ -228,12 +238,18 @@ export function buildTrafficFromSamples( const last = lastTs != null ? byTs.get(lastTs) : undefined const peak = (points: Array<{t:number;v:number}>, side: "rxObserved"|"txObserved") => points.reduce((m,p) => { const wave = byTs.get(p.t)! - return p.t >= rangeStartMs && p.t <= rangeEndMs && wave[side] && wave.count === expectedAt(p.t) ? Math.max(m,p.v) : m + return p.t >= rangeStartMs && p.t <= rangeEndMs && wave.sameStart && wave[side] && wave.count === expectedAt(p.t) ? Math.max(m,p.v) : m },0) const rxPeak = peak(rxPoints,"rxObserved") const txPeak = peak(txPoints,"txObserved") - return { + const waves = new Map() + for (const [t, wave] of byTs) { + if (t < rangeStartMs || t > rangeEndMs) continue + const complete = wave.sameStart && wave.count === expectedAt(t) + waves.set(t,{start:wave.start,rx:wave.rx,tx:wave.tx,rxKnown:complete&&wave.rxObserved,txKnown:complete&&wave.txObserved}) + } + return retainPeakWaves({ rxNow: last?.rx ?? 0, txNow: last?.tx ?? 0, rxPeak, @@ -250,8 +266,10 @@ export function buildTrafficFromSamples( txSeries:bucketAvg([...byTs].map(([t,v])=>({t,v:Number(v.txObserved&&v.count===expectedAt(t)&&t>=rangeStartMs&&t<=rangeEndMs)})),rangeStartMs,rangeEndMs).map(v=>v===1), sampledAt:lastAttemptAt===null?null:new Date(lastAttemptAt).toISOString(), measurementIntervalMs:lastTs===lastAttemptAt?last?.intervalMs??null:null, + rxPeak:[...waves.values()].some(w=>w.rxKnown), + txPeak:[...waves.values()].some(w=>w.txKnown), }}:{}), - } + },waves) } export function mergeBuiltTraffic(parts: BuiltTrafficSeries[]): BuiltTrafficSeries { @@ -281,8 +299,6 @@ export function mergeBuiltTraffic(parts: BuiltTrafficSeries[]): BuiltTrafficSeri for (const p of parts) { acc.rxNow += p.rxNow acc.txNow += p.txNow - acc.rxPeak += p.rxPeak - acc.txPeak += p.txPeak acc.rxTotalGiB += p.rxTotalGiB acc.txTotalGiB += p.txTotalGiB acc.sessions += p.sessions @@ -291,7 +307,22 @@ export function mergeBuiltTraffic(parts: BuiltTrafficSeries[]): BuiltTrafficSeri acc.txSeries[i] += p.txSeries[i] ?? 0 } } - return parts.every(p => p.observations) ? { ...acc, observations: mergeTrafficObservations(parts.map(p => p.observations!)) } : acc + const waves = new Map() + const first = peakWaves.get(parts[0]) + for (const [t, wave] of first ?? []) { + const matching = parts.map(p => peakWaves.get(p)?.get(t)) + if (!matching.every(w => w && w.start === wave.start)) continue + const rows = matching as PeakWave[] + const combined = {start:wave.start,rx:rows.reduce((n,w)=>n+w.rx,0),tx:rows.reduce((n,w)=>n+w.tx,0), + rxKnown:rows.every(w=>w.rxKnown),txKnown:rows.every(w=>w.txKnown)} + waves.set(t,combined) + if (combined.rxKnown) acc.rxPeak = Math.max(acc.rxPeak,combined.rx) + if (combined.txKnown) acc.txPeak = Math.max(acc.txPeak,combined.tx) + } + return retainPeakWaves(parts.every(p => p.observations) ? { ...acc, observations: { + ...mergeTrafficObservations(parts.map(p => p.observations!)), + rxPeak:[...waves.values()].some(w=>w.rxKnown),txPeak:[...waves.values()].some(w=>w.txKnown), + } } : acc,waves) } export function parseMonitorTraffic( diff --git a/backend/src/services/traffic-volume-sql.test.ts b/backend/src/services/traffic-volume-sql.test.ts index fbcbee17..ab986f8f 100644 --- a/backend/src/services/traffic-volume-sql.test.ts +++ b/backend/src/services/traffic-volume-sql.test.ts @@ -59,6 +59,19 @@ else { for(const[name,offset,bytes]of[["ether1",-90_000,0],["ether1",-60_000,0],["ether1",-30_000,1024**2],["new",-30_000,0],["ether1",0,1024**2],["new",0,0]] as const)await put(name,offset,bytes); await pool.query("UPDATE traffic_samples SET flags=61,native_counter_identity=interface_name WHERE server_id=$1",[serverId]);await pool.query("UPDATE traffic_samples SET flags=45 WHERE server_id=$1 AND interface_name='new' AND sampled_at=$2",[serverId,new Date(Date.parse(at)-30_000).toISOString()]); s=(await get(`/traffic/servers/${serverId}?range=1h`)).server;assert.equal(s.observations.rxNow,true);assert.equal(s.rxPeak,0);assert.equal(s.txPeak,0);assert.equal(s.rxTotal,1/1024);assert(s.observations.rxSeries.some(Boolean));cases++; + await pool.query("DELETE FROM user_interface_bindings WHERE user_id=$1",[userId]) + for(const name of ['peakA','peakB'])await pool.query("INSERT INTO user_interface_bindings(id,user_id,server_id,interface_name,interface_type) VALUES($1,$2,$3,$4,'ether')",[prefix+name,userId,serverId,name]) + for(const mode of ['separate','coincident','jitter']){ + await pool.query("DELETE FROM traffic_samples WHERE server_id=$1",[serverId]) + for(const [name,offset,bytes] of [['peakA',-60_000,0],['peakA',-30_000,375_000_000],['peakA',0,375_000_000], + ['peakB',-60_000,0],['peakB',-30_000,mode==='coincident'?375_000_000:0],['peakB',0,375_000_000]] as const) + await put(name,offset+(mode==='jitter'&&name==='peakB'?-1:0),bytes) + const aggregate=(await get('/traffic/users?range=1h')).users.find((u:{id:string})=>u.id===userId) + assert.equal(aggregate.rxPeak,mode==='jitter'?0:mode==='coincident'?200:100) + assert.equal(aggregate.observations.rxPeak,mode!=='jitter');assert.equal(aggregate.observations.txPeak,mode!=='jitter') + assert.equal(aggregate.rxTotal,750_000_000/1024**3);assert(aggregate.observations.rxSeries.some(Boolean)) + assert.equal(aggregate.interfaces.length,2);assert(aggregate.interfaces.every((i:{rxPeak:number})=>i.rxPeak===100));cases++ + } console.log(`traffic volume owned SQL: ${cases} cases; exact bytes/binary unit/server/user/binding/100-part aggregate/reset passed`) }finally{await app.close();await pool.query("DELETE FROM app_users WHERE id=$1",[userId]);if(serverId!==undefined){await pool.query("DELETE FROM traffic_samples WHERE server_id=$1",[serverId]);await pool.query("DELETE FROM servers WHERE id=$1",[serverId])}await closePool()} } diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index 425a3976..18080b66 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-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.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-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). @@ -2296,3 +2296,21 @@ Unit проверил partial high point → последующая complete0 wa Точный следующий шаг: общий peak вычислять из подтверждённых совпадающих временных срезов, сохраняя исходные timestamp/confidence внутренних parts; не складывать индивидуальные maxima. При отсутствии совместимого времени показывать неизвестное значение, сохраняя volumes/history/current metadata. Проверить разные времена peaks, совпадающий peak, missing contributor, jitter/неполные bins и recovery. Не подменять raw point peak максимумом bucket average без явной семантики. Нужны meaningful own SQL/API/UI cases перед production rollout. Стенд остаётся backend ux-peak190/frontend ux-warning183. Source/runtime190 и real CHR/config/passwords unchanged; messages0. После191 — scoped control затронутых разделов и одна согласованная общая регрессия; внешние Portal/Telegram/client OS/multi-WAN/scale требуют доступов/сценариев из матрицы.12.5 открыта. Локальный commit без push сохраняет точное продолжение. + +## 12.5.191 — подтверждённый общий пик привязок: реализация и приёмка (2026-10-13) + +Исправлен baseline ниже: индивидуальные максимумы в разные моменты больше не складываются. A=100Mbps на первой волне и B=100Mbps на следующей дают общий пик100, совпадающие интервалы —200. Сумма byte deltas/учтённый объём сохранена. Пик является максимумом подтверждённых средних скоростей соседних счётчиков за совпадающие интервалы, а не мгновенным максимумом линии или максимумом chart bucket average. + +Исходные интервалы и confidence parts хранятся во внутреннем WeakMap и не попадают в DTO/JSON. Merge, включая вложенный, требует совпадения начала и конца интервала и подтверждённых вкладов всех выбранных привязок для каждого направления. Jitter, отсутствие part, несовместимые интервалы или сериализованные parts без исходных точек не доказывают общий пик: observations.rxPeak/txPeak=false, UI показывает «—», а не ложный ноль. Подтверждённый ноль остаётся0. Для старого backend новый reader сохраняет прежнюю совместимость при отсутствии новых optional flags; interop проверен до переключения backend. История, объём и freshness metadata сохраняются. Данные разных серверов не интерполируются и не сдвигаются ради создания искусственного общего пика. + +Изменены traffic-rate.ts, lib/traffic-observations.ts и профильные тесты. ReUI PRO/base-nova/Frame/KpiStatGrid переиспользуются, vendor/theme/layout не менялись. Проверены different/coincident peaks, nested merge, measured zero, missing/empty/legacy parts, jitter внутри одинаковых chart bins, одинаковый конец с разным началом и recovery. Реальный PostgreSQL/API fixture добавляет3 сценария пользователя с двумя привязками, включая неизменный объём750000000bytes. Все71 профильных SQL-проверок прошли41228ms без postgres-unavailable skip; собственные временная БД, роль и контейнер удалены. + +Backend build и frontend TypeScript passed. Все77 уникальных E2E трафика прошли1.6m; начальные4 focused cases22.4s входят в77 и повторно не считаются. Production backend/frontend build passed; source manifests совпали461 backend+524 frontend файлов,1040 compiled backend artifacts совпали. Runtime backend/frontend ux-peak191, PostgreSQL healthy; frontend healthcheck отсутствует, работа подтверждена HTTP/browser. До backend rollout новый frontend принят с backend190. Actual API200 и fresh measurements обоих CHR, live UI1440/320 без page errors/overflow. Native конфигурация/пароли не менялись, messages0. + +Протоколы: [SQL](ux-ui/acceptance/traffic-peak191-sql191-result.json), [source](ux-ui/acceptance/traffic-peak191-source191-result.json), [compiled](ux-ui/acceptance/traffic-peak191-compiled191-result.json), [runtime](ux-ui/acceptance/traffic-peak191-runtime191-result.json), [API](ux-ui/acceptance/traffic-peak191-peak191-api-result.json), [E2E](ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json), [interop](ux-ui/acceptance/traffic-peak-interop-2026-10-13.json), [live UI](ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json). + +| Референс | Схема | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Совпадающие интервалы всех привязок → подтверждённая сумма → максимум периода; нет совпадения → «—», объём сохранён | + +Следующий192: одна согласованная общая backend-регрессия; фиксировать реальные skipped/external ветки отдельно. Последующий объём определяется результатом этой проверки и матрицей внешней приёмки. Portal/Telegram/client OS/multi-WAN/scale не приняты по fixture-тестам.12.5 открыта. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index 02922196..03a7f4ca 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,12 +1,12 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-12. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. ## Актуальная точка продолжения — 2026-10-12 -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.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-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index a9e917dd..e0acb7e0 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -36,7 +36,25 @@ | 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–168 и ограничения ниже. Runtime backend ux-month149/frontend ux-sessions150. | +| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–191 и ограничения ниже. Runtime backend/frontend ux-peak191. | + +## 12.5.191 — подтверждённый общий пик привязок: реализация и приёмка (2026-10-13) + +Исправлен baseline ниже: индивидуальные максимумы в разные моменты больше не складываются. A=100Mbps на первой волне и B=100Mbps на следующей дают общий пик100, совпадающие интервалы —200. Сумма byte deltas/учтённый объём сохранена. Пик является максимумом подтверждённых средних скоростей соседних счётчиков за совпадающие интервалы, а не мгновенным максимумом линии или максимумом chart bucket average. + +Исходные интервалы и confidence parts хранятся во внутреннем WeakMap и не попадают в DTO/JSON. Merge, включая вложенный, требует совпадения начала и конца интервала и подтверждённых вкладов всех выбранных привязок для каждого направления. Jitter, отсутствие part, несовместимые интервалы или сериализованные parts без исходных точек не доказывают общий пик: observations.rxPeak/txPeak=false, UI показывает «—», а не ложный ноль. Подтверждённый ноль остаётся0. Для старого backend новый reader сохраняет прежнюю совместимость при отсутствии новых optional flags; interop проверен до переключения backend. История, объём и freshness metadata сохраняются. Данные разных серверов не интерполируются и не сдвигаются ради создания искусственного общего пика. + +Изменены traffic-rate.ts, lib/traffic-observations.ts и профильные тесты. ReUI PRO/base-nova/Frame/KpiStatGrid переиспользуются, vendor/theme/layout не менялись. Проверены different/coincident peaks, nested merge, measured zero, missing/empty/legacy parts, jitter внутри одинаковых chart bins, одинаковый конец с разным началом и recovery. Реальный PostgreSQL/API fixture добавляет3 сценария пользователя с двумя привязками, включая неизменный объём750000000bytes. Все71 профильных SQL-проверок прошли41228ms без postgres-unavailable skip; собственные временная БД, роль и контейнер удалены. + +Backend build и frontend TypeScript passed. Все77 уникальных E2E трафика прошли1.6m; начальные4 focused cases22.4s входят в77 и повторно не считаются. Production backend/frontend build passed; source manifests совпали461 backend+524 frontend файлов,1040 compiled backend artifacts совпали. Runtime backend/frontend ux-peak191, PostgreSQL healthy; frontend healthcheck отсутствует, работа подтверждена HTTP/browser. До backend rollout новый frontend принят с backend190. Actual API200 и fresh measurements обоих CHR, live UI1440/320 без page errors/overflow. Native конфигурация/пароли не менялись, messages0. + +Протоколы: [SQL](ux-ui/acceptance/traffic-peak191-sql191-result.json), [source](ux-ui/acceptance/traffic-peak191-source191-result.json), [compiled](ux-ui/acceptance/traffic-peak191-compiled191-result.json), [runtime](ux-ui/acceptance/traffic-peak191-runtime191-result.json), [API](ux-ui/acceptance/traffic-peak191-peak191-api-result.json), [E2E](ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json), [interop](ux-ui/acceptance/traffic-peak-interop-2026-10-13.json), [live UI](ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json). + +| Референс | Схема | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Совпадающие интервалы всех привязок → подтверждённая сумма → максимум периода; нет совпадения → «—», объём сохранён | + +Следующий192: одна согласованная общая backend-регрессия; фиксировать реальные skipped/external ветки отдельно. Последующий объём определяется результатом этой проверки и матрицей внешней приёмки. Portal/Telegram/client OS/multi-WAN/scale не приняты по fixture-тестам.12.5 открыта. ## 12.5.191 — общий пик нескольких привязок: baseline (2026-10-13) diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index 67b618e5..038a75a5 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,10 +1,10 @@ # Оставшаяся внешняя приёмка — 2026-10-13 -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. Это актуальная матрица после 12.5.191. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. -Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-peak190`, frontend `ux-warning183`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. +Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend/frontend `ux-peak191`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. | Раздел | Подтверждено | Осталось / условие завершения | | --- | --- | --- | @@ -1212,3 +1212,21 @@ Unit проверил partial high point → последующая complete0 wa Точный следующий шаг: общий peak вычислять из подтверждённых совпадающих временных срезов, сохраняя исходные timestamp/confidence внутренних parts; не складывать индивидуальные maxima. При отсутствии совместимого времени показывать неизвестное значение, сохраняя volumes/history/current metadata. Проверить разные времена peaks, совпадающий peak, missing contributor, jitter/неполные bins и recovery. Не подменять raw point peak максимумом bucket average без явной семантики. Нужны meaningful own SQL/API/UI cases перед production rollout. Стенд остаётся backend ux-peak190/frontend ux-warning183. Source/runtime190 и real CHR/config/passwords unchanged; messages0. После191 — scoped control затронутых разделов и одна согласованная общая регрессия; внешние Portal/Telegram/client OS/multi-WAN/scale требуют доступов/сценариев из матрицы.12.5 открыта. Локальный commit без push сохраняет точное продолжение. + +## 12.5.191 — подтверждённый общий пик привязок: реализация и приёмка (2026-10-13) + +Исправлен baseline ниже: индивидуальные максимумы в разные моменты больше не складываются. A=100Mbps на первой волне и B=100Mbps на следующей дают общий пик100, совпадающие интервалы —200. Сумма byte deltas/учтённый объём сохранена. Пик является максимумом подтверждённых средних скоростей соседних счётчиков за совпадающие интервалы, а не мгновенным максимумом линии или максимумом chart bucket average. + +Исходные интервалы и confidence parts хранятся во внутреннем WeakMap и не попадают в DTO/JSON. Merge, включая вложенный, требует совпадения начала и конца интервала и подтверждённых вкладов всех выбранных привязок для каждого направления. Jitter, отсутствие part, несовместимые интервалы или сериализованные parts без исходных точек не доказывают общий пик: observations.rxPeak/txPeak=false, UI показывает «—», а не ложный ноль. Подтверждённый ноль остаётся0. Для старого backend новый reader сохраняет прежнюю совместимость при отсутствии новых optional flags; interop проверен до переключения backend. История, объём и freshness metadata сохраняются. Данные разных серверов не интерполируются и не сдвигаются ради создания искусственного общего пика. + +Изменены traffic-rate.ts, lib/traffic-observations.ts и профильные тесты. ReUI PRO/base-nova/Frame/KpiStatGrid переиспользуются, vendor/theme/layout не менялись. Проверены different/coincident peaks, nested merge, measured zero, missing/empty/legacy parts, jitter внутри одинаковых chart bins, одинаковый конец с разным началом и recovery. Реальный PostgreSQL/API fixture добавляет3 сценария пользователя с двумя привязками, включая неизменный объём750000000bytes. Все71 профильных SQL-проверок прошли41228ms без postgres-unavailable skip; собственные временная БД, роль и контейнер удалены. + +Backend build и frontend TypeScript passed. Все77 уникальных E2E трафика прошли1.6m; начальные4 focused cases22.4s входят в77 и повторно не считаются. Production backend/frontend build passed; source manifests совпали461 backend+524 frontend файлов,1040 compiled backend artifacts совпали. Runtime backend/frontend ux-peak191, PostgreSQL healthy; frontend healthcheck отсутствует, работа подтверждена HTTP/browser. До backend rollout новый frontend принят с backend190. Actual API200 и fresh measurements обоих CHR, live UI1440/320 без page errors/overflow. Native конфигурация/пароли не менялись, messages0. + +Протоколы: [SQL](ux-ui/acceptance/traffic-peak191-sql191-result.json), [source](ux-ui/acceptance/traffic-peak191-source191-result.json), [compiled](ux-ui/acceptance/traffic-peak191-compiled191-result.json), [runtime](ux-ui/acceptance/traffic-peak191-runtime191-result.json), [API](ux-ui/acceptance/traffic-peak191-peak191-api-result.json), [E2E](ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json), [interop](ux-ui/acceptance/traffic-peak-interop-2026-10-13.json), [live UI](ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json). + +| Референс | Схема | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Совпадающие интервалы всех привязок → подтверждённая сумма → максимум периода; нет совпадения → «—», объём сохранён | + +Следующий192: одна согласованная общая backend-регрессия; фиксировать реальные skipped/external ветки отдельно. Последующий объём определяется результатом этой проверки и матрицей внешней приёмки. Portal/Telegram/client OS/multi-WAN/scale не приняты по fixture-тестам.12.5 открыта. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 0d45a35e..a58ef179 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -3601,3 +3601,21 @@ Unit проверил partial high point → последующая complete0 wa Точный следующий шаг: общий peak вычислять из подтверждённых совпадающих временных срезов, сохраняя исходные timestamp/confidence внутренних parts; не складывать индивидуальные maxima. При отсутствии совместимого времени показывать неизвестное значение, сохраняя volumes/history/current metadata. Проверить разные времена peaks, совпадающий peak, missing contributor, jitter/неполные bins и recovery. Не подменять raw point peak максимумом bucket average без явной семантики. Нужны meaningful own SQL/API/UI cases перед production rollout. Стенд остаётся backend ux-peak190/frontend ux-warning183. Source/runtime190 и real CHR/config/passwords unchanged; messages0. После191 — scoped control затронутых разделов и одна согласованная общая регрессия; внешние Portal/Telegram/client OS/multi-WAN/scale требуют доступов/сценариев из матрицы.12.5 открыта. Локальный commit без push сохраняет точное продолжение. + +## 12.5.191 — подтверждённый общий пик привязок: реализация и приёмка (2026-10-13) + +Исправлен baseline ниже: индивидуальные максимумы в разные моменты больше не складываются. A=100Mbps на первой волне и B=100Mbps на следующей дают общий пик100, совпадающие интервалы —200. Сумма byte deltas/учтённый объём сохранена. Пик является максимумом подтверждённых средних скоростей соседних счётчиков за совпадающие интервалы, а не мгновенным максимумом линии или максимумом chart bucket average. + +Исходные интервалы и confidence parts хранятся во внутреннем WeakMap и не попадают в DTO/JSON. Merge, включая вложенный, требует совпадения начала и конца интервала и подтверждённых вкладов всех выбранных привязок для каждого направления. Jitter, отсутствие part, несовместимые интервалы или сериализованные parts без исходных точек не доказывают общий пик: observations.rxPeak/txPeak=false, UI показывает «—», а не ложный ноль. Подтверждённый ноль остаётся0. Для старого backend новый reader сохраняет прежнюю совместимость при отсутствии новых optional flags; interop проверен до переключения backend. История, объём и freshness metadata сохраняются. Данные разных серверов не интерполируются и не сдвигаются ради создания искусственного общего пика. + +Изменены traffic-rate.ts, lib/traffic-observations.ts и профильные тесты. ReUI PRO/base-nova/Frame/KpiStatGrid переиспользуются, vendor/theme/layout не менялись. Проверены different/coincident peaks, nested merge, measured zero, missing/empty/legacy parts, jitter внутри одинаковых chart bins, одинаковый конец с разным началом и recovery. Реальный PostgreSQL/API fixture добавляет3 сценария пользователя с двумя привязками, включая неизменный объём750000000bytes. Все71 профильных SQL-проверок прошли41228ms без postgres-unavailable skip; собственные временная БД, роль и контейнер удалены. + +Backend build и frontend TypeScript passed. Все77 уникальных E2E трафика прошли1.6m; начальные4 focused cases22.4s входят в77 и повторно не считаются. Production backend/frontend build passed; source manifests совпали461 backend+524 frontend файлов,1040 compiled backend artifacts совпали. Runtime backend/frontend ux-peak191, PostgreSQL healthy; frontend healthcheck отсутствует, работа подтверждена HTTP/browser. До backend rollout новый frontend принят с backend190. Actual API200 и fresh measurements обоих CHR, live UI1440/320 без page errors/overflow. Native конфигурация/пароли не менялись, messages0. + +Протоколы: [SQL](ux-ui/acceptance/traffic-peak191-sql191-result.json), [source](ux-ui/acceptance/traffic-peak191-source191-result.json), [compiled](ux-ui/acceptance/traffic-peak191-compiled191-result.json), [runtime](ux-ui/acceptance/traffic-peak191-runtime191-result.json), [API](ux-ui/acceptance/traffic-peak191-peak191-api-result.json), [E2E](ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json), [interop](ux-ui/acceptance/traffic-peak-interop-2026-10-13.json), [live UI](ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json). + +| Референс | Схема | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Совпадающие интервалы всех привязок → подтверждённая сумма → максимум периода; нет совпадения → «—», объём сохранён | + +Следующий192: одна согласованная общая backend-регрессия; фиксировать реальные skipped/external ветки отдельно. Последующий объём определяется результатом этой проверки и матрицей внешней приёмки. Portal/Telegram/client OS/multi-WAN/scale не приняты по fixture-тестам.12.5 открыта. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index a39da410..42c22e6f 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -1,6 +1,6 @@ # Тестовый сервер UX/UI — 2026-10-10 -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. | Параметр | Проверенное состояние | | --- | --- | @@ -708,7 +708,7 @@ flowchart LR ## 12.5.77 — основной блок IPsec (2026-10-09) -Актуальное продолжение 2026-10-13: завершены185–190, backend ux-peak190/frontend ux-warning183 healthy; последний ownSQL68/38553ms/API/browser2 passed. Начат191 — baseline sum individual peaks200Mbps против complete simultaneous wave100Mbps; это не исправлено и не принято. Следующий шаг — temporal aggregate peak с confidence при несовпадающих timestamps.12.5 открыта. +Актуальное продолжение 2026-10-13: завершён191 — общий пик привязок по совпадающим подтверждённым интервалам; backend/frontend ux-peak191 развёрнуты. ownSQL71/41228ms, E2E77/1.6m, source985/compiled1040/API/live UI2 passed. Начата192 — общая backend-регрессия в отдельной временной БД.12.5 открыта. Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md). @@ -2027,3 +2027,21 @@ Unit проверил partial high point → последующая complete0 wa Точный следующий шаг: общий peak вычислять из подтверждённых совпадающих временных срезов, сохраняя исходные timestamp/confidence внутренних parts; не складывать индивидуальные maxima. При отсутствии совместимого времени показывать неизвестное значение, сохраняя volumes/history/current metadata. Проверить разные времена peaks, совпадающий peak, missing contributor, jitter/неполные bins и recovery. Не подменять raw point peak максимумом bucket average без явной семантики. Нужны meaningful own SQL/API/UI cases перед production rollout. Стенд остаётся backend ux-peak190/frontend ux-warning183. Source/runtime190 и real CHR/config/passwords unchanged; messages0. После191 — scoped control затронутых разделов и одна согласованная общая регрессия; внешние Portal/Telegram/client OS/multi-WAN/scale требуют доступов/сценариев из матрицы.12.5 открыта. Локальный commit без push сохраняет точное продолжение. + +## 12.5.191 — подтверждённый общий пик привязок: реализация и приёмка (2026-10-13) + +Исправлен baseline ниже: индивидуальные максимумы в разные моменты больше не складываются. A=100Mbps на первой волне и B=100Mbps на следующей дают общий пик100, совпадающие интервалы —200. Сумма byte deltas/учтённый объём сохранена. Пик является максимумом подтверждённых средних скоростей соседних счётчиков за совпадающие интервалы, а не мгновенным максимумом линии или максимумом chart bucket average. + +Исходные интервалы и confidence parts хранятся во внутреннем WeakMap и не попадают в DTO/JSON. Merge, включая вложенный, требует совпадения начала и конца интервала и подтверждённых вкладов всех выбранных привязок для каждого направления. Jitter, отсутствие part, несовместимые интервалы или сериализованные parts без исходных точек не доказывают общий пик: observations.rxPeak/txPeak=false, UI показывает «—», а не ложный ноль. Подтверждённый ноль остаётся0. Для старого backend новый reader сохраняет прежнюю совместимость при отсутствии новых optional flags; interop проверен до переключения backend. История, объём и freshness metadata сохраняются. Данные разных серверов не интерполируются и не сдвигаются ради создания искусственного общего пика. + +Изменены traffic-rate.ts, lib/traffic-observations.ts и профильные тесты. ReUI PRO/base-nova/Frame/KpiStatGrid переиспользуются, vendor/theme/layout не менялись. Проверены different/coincident peaks, nested merge, measured zero, missing/empty/legacy parts, jitter внутри одинаковых chart bins, одинаковый конец с разным началом и recovery. Реальный PostgreSQL/API fixture добавляет3 сценария пользователя с двумя привязками, включая неизменный объём750000000bytes. Все71 профильных SQL-проверок прошли41228ms без postgres-unavailable skip; собственные временная БД, роль и контейнер удалены. + +Backend build и frontend TypeScript passed. Все77 уникальных E2E трафика прошли1.6m; начальные4 focused cases22.4s входят в77 и повторно не считаются. Production backend/frontend build passed; source manifests совпали461 backend+524 frontend файлов,1040 compiled backend artifacts совпали. Runtime backend/frontend ux-peak191, PostgreSQL healthy; frontend healthcheck отсутствует, работа подтверждена HTTP/browser. До backend rollout новый frontend принят с backend190. Actual API200 и fresh measurements обоих CHR, live UI1440/320 без page errors/overflow. Native конфигурация/пароли не менялись, messages0. + +Протоколы: [SQL](ux-ui/acceptance/traffic-peak191-sql191-result.json), [source](ux-ui/acceptance/traffic-peak191-source191-result.json), [compiled](ux-ui/acceptance/traffic-peak191-compiled191-result.json), [runtime](ux-ui/acceptance/traffic-peak191-runtime191-result.json), [API](ux-ui/acceptance/traffic-peak191-peak191-api-result.json), [E2E](ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json), [interop](ux-ui/acceptance/traffic-peak-interop-2026-10-13.json), [live UI](ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json). + +| Референс | Схема | +| --- | --- | +| [ReUI Stats12](https://reui.io/preview/base/stats-12?ref=mcp) | Совпадающие интервалы всех привязок → подтверждённая сумма → максимум периода; нет совпадения → «—», объём сохранён | + +Следующий192: одна согласованная общая backend-регрессия; фиксировать реальные skipped/external ветки отдельно. Последующий объём определяется результатом этой проверки и матрицей внешней приёмки. Portal/Telegram/client OS/multi-WAN/scale не приняты по fixture-тестам.12.5 открыта. diff --git a/docs/ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json b/docs/ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json index a7c9c08d..af4815dc 100644 --- a/docs/ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json +++ b/docs/ux-ui/acceptance/traffic-peak-deployed-2026-10-13.json @@ -1,9 +1,9 @@ { "date": "2026-10-13", - "block": "12.5.190", + "block": "12.5.191", "runtime": { - "backend": "ux-peak190", - "frontend": "ux-warning183" + "backend": "ux-peak191", + "frontend": "ux-peak191" }, "apis": [ { diff --git a/docs/ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json b/docs/ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json new file mode 100644 index 00000000..556f4749 --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak-e2e-2026-10-13.json @@ -0,0 +1,16 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "command": "playwright test traffic-.*\\.spec\\.ts", + "uniqueCases": 77, + "passed": 77, + "duration": "1.6m", + "focusedInitialRun": { + "passed": 4, + "durationSeconds": 22.4, + "includedInUniqueCount": true + }, + "scope": "Ordinary HTTP API fixture path, not built-in mock mode; separate deployed read-only smoke", + "frontendTypeScript": true, + "backendBuild": true +} diff --git a/docs/ux-ui/acceptance/traffic-peak-interop-2026-10-13.json b/docs/ux-ui/acceptance/traffic-peak-interop-2026-10-13.json new file mode 100644 index 00000000..22c9e5ca --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak-interop-2026-10-13.json @@ -0,0 +1,10 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "newFrontend": "ux-peak191", + "oldBackend": "ux-peak190", + "readerAccepted": true, + "serverCount": 2, + "pageErrors": 0, + "bound": "Additive observed DTO reader compatibility; legacy numeric-only paths verified separately as unknown" +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/traffic-peak191-compiled191-result.json b/docs/ux-ui/acceptance/traffic-peak191-compiled191-result.json new file mode 100644 index 00000000..df64637a --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak191-compiled191-result.json @@ -0,0 +1,1050 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "backendVersion": "1.0.0-test.peak191", + "normalization": "CRLF to LF", + "matched": [ + "backend/dist/config.js", + "backend/dist/config.js.map", + "backend/dist/config.d.ts", + "backend/dist/config.d.ts.map", + "backend/dist/constants/ping-probe.js", + "backend/dist/constants/ping-probe.js.map", + "backend/dist/constants/ping-probe.d.ts", + "backend/dist/constants/ping-probe.d.ts.map", + "backend/dist/db/bootstrap.js", + "backend/dist/db/bootstrap.js.map", + "backend/dist/db/bootstrap.d.ts", + "backend/dist/db/bootstrap.d.ts.map", + "backend/dist/db/index.js", + "backend/dist/db/index.js.map", + "backend/dist/db/index.d.ts", + "backend/dist/db/index.d.ts.map", + "backend/dist/db/json.js", + "backend/dist/db/json.js.map", + "backend/dist/db/json.d.ts", + "backend/dist/db/json.d.ts.map", + "backend/dist/db/migrate.js", + "backend/dist/db/migrate.js.map", + "backend/dist/db/migrate.d.ts", + "backend/dist/db/migrate.d.ts.map", + "backend/dist/db/operation-lock.js", + "backend/dist/db/operation-lock.js.map", + "backend/dist/db/operation-lock.d.ts", + "backend/dist/db/operation-lock.d.ts.map", + "backend/dist/db/partitions.js", + "backend/dist/db/partitions.js.map", + "backend/dist/db/partitions.d.ts", + "backend/dist/db/partitions.d.ts.map", + "backend/dist/db/schema.js", + "backend/dist/db/schema.js.map", + "backend/dist/db/schema.d.ts", + "backend/dist/db/schema.d.ts.map", + "backend/dist/db/sql-bind.js", + "backend/dist/db/sql-bind.js.map", + "backend/dist/db/sql-bind.d.ts", + "backend/dist/db/sql-bind.d.ts.map", + "backend/dist/db/sqlite-import.js", + "backend/dist/db/sqlite-import.js.map", + "backend/dist/db/sqlite-import.d.ts", + "backend/dist/db/sqlite-import.d.ts.map", + "backend/dist/db/traffic-flags.js", + "backend/dist/db/traffic-flags.js.map", + "backend/dist/db/traffic-flags.d.ts", + "backend/dist/db/traffic-flags.d.ts.map", + "backend/dist/index.js", + "backend/dist/index.js.map", + "backend/dist/index.d.ts", + "backend/dist/index.d.ts.map", + "backend/dist/lib/permissions.js", + "backend/dist/lib/permissions.js.map", + "backend/dist/lib/permissions.d.ts", + "backend/dist/lib/permissions.d.ts.map", + "backend/dist/managed-markers.js", + "backend/dist/managed-markers.js.map", + "backend/dist/managed-markers.d.ts", + "backend/dist/managed-markers.d.ts.map", + "backend/dist/modules/events/repository/events-repository.js", + "backend/dist/modules/events/repository/events-repository.js.map", + "backend/dist/modules/events/repository/events-repository.d.ts", + "backend/dist/modules/events/repository/events-repository.d.ts.map", + "backend/dist/modules/events/service/events-service.js", + "backend/dist/modules/events/service/events-service.js.map", + "backend/dist/modules/events/service/events-service.d.ts", + "backend/dist/modules/events/service/events-service.d.ts.map", + "backend/dist/modules/servers/mapper/servers-mapper.js", + "backend/dist/modules/servers/mapper/servers-mapper.js.map", + "backend/dist/modules/servers/mapper/servers-mapper.d.ts", + "backend/dist/modules/servers/mapper/servers-mapper.d.ts.map", + "backend/dist/modules/servers/repository/servers-repository.js", + "backend/dist/modules/servers/repository/servers-repository.js.map", + "backend/dist/modules/servers/repository/servers-repository.d.ts", + "backend/dist/modules/servers/repository/servers-repository.d.ts.map", + "backend/dist/modules/servers/service/servers-service.js", + "backend/dist/modules/servers/service/servers-service.js.map", + "backend/dist/modules/servers/service/servers-service.d.ts", + "backend/dist/modules/servers/service/servers-service.d.ts.map", + "backend/dist/modules/users/iface-type.js", + "backend/dist/modules/users/iface-type.js.map", + "backend/dist/modules/users/iface-type.d.ts", + "backend/dist/modules/users/iface-type.d.ts.map", + "backend/dist/modules/users/interface-inventory.js", + "backend/dist/modules/users/interface-inventory.js.map", + "backend/dist/modules/users/interface-inventory.d.ts", + "backend/dist/modules/users/interface-inventory.d.ts.map", + "backend/dist/modules/users/peer-bind.js", + "backend/dist/modules/users/peer-bind.js.map", + "backend/dist/modules/users/peer-bind.d.ts", + "backend/dist/modules/users/peer-bind.d.ts.map", + "backend/dist/modules/users/repository/users-repository.js", + "backend/dist/modules/users/repository/users-repository.js.map", + "backend/dist/modules/users/repository/users-repository.d.ts", + "backend/dist/modules/users/repository/users-repository.d.ts.map", + "backend/dist/modules/users/service/users-service.js", + "backend/dist/modules/users/service/users-service.js.map", + "backend/dist/modules/users/service/users-service.d.ts", + "backend/dist/modules/users/service/users-service.d.ts.map", + "backend/dist/plugins/auth.js", + "backend/dist/plugins/auth.js.map", + "backend/dist/plugins/auth.d.ts", + "backend/dist/plugins/auth.d.ts.map", + "backend/dist/plugins/database-request-gate.js", + "backend/dist/plugins/database-request-gate.js.map", + "backend/dist/plugins/database-request-gate.d.ts", + "backend/dist/plugins/database-request-gate.d.ts.map", + "backend/dist/routes/alerts.js", + "backend/dist/routes/alerts.js.map", + "backend/dist/routes/alerts.d.ts", + "backend/dist/routes/alerts.d.ts.map", + "backend/dist/routes/backups.js", + "backend/dist/routes/backups.js.map", + "backend/dist/routes/backups.d.ts", + "backend/dist/routes/backups.d.ts.map", + "backend/dist/routes/bgp.js", + "backend/dist/routes/bgp.js.map", + "backend/dist/routes/bgp.d.ts", + "backend/dist/routes/bgp.d.ts.map", + "backend/dist/routes/certificates.js", + "backend/dist/routes/certificates.js.map", + "backend/dist/routes/certificates.d.ts", + "backend/dist/routes/certificates.d.ts.map", + "backend/dist/routes/containers.js", + "backend/dist/routes/containers.js.map", + "backend/dist/routes/containers.d.ts", + "backend/dist/routes/containers.d.ts.map", + "backend/dist/routes/events.js", + "backend/dist/routes/events.js.map", + "backend/dist/routes/events.d.ts", + "backend/dist/routes/events.d.ts.map", + "backend/dist/routes/evobgp-catalog.js", + "backend/dist/routes/evobgp-catalog.js.map", + "backend/dist/routes/evobgp-catalog.d.ts", + "backend/dist/routes/evobgp-catalog.d.ts.map", + "backend/dist/routes/evobgp-settings.js", + "backend/dist/routes/evobgp-settings.js.map", + "backend/dist/routes/evobgp-settings.d.ts", + "backend/dist/routes/evobgp-settings.d.ts.map", + "backend/dist/routes/evobgp.js", + "backend/dist/routes/evobgp.js.map", + "backend/dist/routes/evobgp.d.ts", + "backend/dist/routes/evobgp.d.ts.map", + "backend/dist/routes/exec.js", + "backend/dist/routes/exec.js.map", + "backend/dist/routes/exec.d.ts", + "backend/dist/routes/exec.d.ts.map", + "backend/dist/routes/filters.js", + "backend/dist/routes/filters.js.map", + "backend/dist/routes/filters.d.ts", + "backend/dist/routes/filters.d.ts.map", + "backend/dist/routes/firewall.js", + "backend/dist/routes/firewall.js.map", + "backend/dist/routes/firewall.d.ts", + "backend/dist/routes/firewall.d.ts.map", + "backend/dist/routes/geoip.js", + "backend/dist/routes/geoip.js.map", + "backend/dist/routes/geoip.d.ts", + "backend/dist/routes/geoip.d.ts.map", + "backend/dist/routes/gre.js", + "backend/dist/routes/gre.js.map", + "backend/dist/routes/gre.d.ts", + "backend/dist/routes/gre.d.ts.map", + "backend/dist/routes/internet-path.js", + "backend/dist/routes/internet-path.js.map", + "backend/dist/routes/internet-path.d.ts", + "backend/dist/routes/internet-path.d.ts.map", + "backend/dist/routes/ipsec.js", + "backend/dist/routes/ipsec.js.map", + "backend/dist/routes/ipsec.d.ts", + "backend/dist/routes/ipsec.d.ts.map", + "backend/dist/routes/network.js", + "backend/dist/routes/network.js.map", + "backend/dist/routes/network.d.ts", + "backend/dist/routes/network.d.ts.map", + "backend/dist/routes/ospf.js", + "backend/dist/routes/ospf.js.map", + "backend/dist/routes/ospf.d.ts", + "backend/dist/routes/ospf.d.ts.map", + "backend/dist/routes/ping-probes-write.js", + "backend/dist/routes/ping-probes-write.js.map", + "backend/dist/routes/ping-probes-write.d.ts", + "backend/dist/routes/ping-probes-write.d.ts.map", + "backend/dist/routes/probes.js", + "backend/dist/routes/probes.js.map", + "backend/dist/routes/probes.d.ts", + "backend/dist/routes/probes.d.ts.map", + "backend/dist/routes/recursive-routes.js", + "backend/dist/routes/recursive-routes.js.map", + "backend/dist/routes/recursive-routes.d.ts", + "backend/dist/routes/recursive-routes.d.ts.map", + "backend/dist/routes/scheduler.js", + "backend/dist/routes/scheduler.js.map", + "backend/dist/routes/scheduler.d.ts", + "backend/dist/routes/scheduler.d.ts.map", + "backend/dist/routes/servers-api-ping.js", + "backend/dist/routes/servers-api-ping.js.map", + "backend/dist/routes/servers-api-ping.d.ts", + "backend/dist/routes/servers-api-ping.d.ts.map", + "backend/dist/routes/servers.js", + "backend/dist/routes/servers.js.map", + "backend/dist/routes/servers.d.ts", + "backend/dist/routes/servers.d.ts.map", + "backend/dist/routes/sidebar-counts.js", + "backend/dist/routes/sidebar-counts.js.map", + "backend/dist/routes/sidebar-counts.d.ts", + "backend/dist/routes/sidebar-counts.d.ts.map", + "backend/dist/routes/speed-probes-write.js", + "backend/dist/routes/speed-probes-write.js.map", + "backend/dist/routes/speed-probes-write.d.ts", + "backend/dist/routes/speed-probes-write.d.ts.map", + "backend/dist/routes/speed-test.js", + "backend/dist/routes/speed-test.js.map", + "backend/dist/routes/speed-test.d.ts", + "backend/dist/routes/speed-test.d.ts.map", + "backend/dist/routes/statistics.js", + "backend/dist/routes/statistics.js.map", + "backend/dist/routes/statistics.d.ts", + "backend/dist/routes/statistics.d.ts.map", + "backend/dist/routes/system-database.js", + "backend/dist/routes/system-database.js.map", + "backend/dist/routes/system-database.d.ts", + "backend/dist/routes/system-database.d.ts.map", + "backend/dist/routes/traffic-flow-purge.js", + "backend/dist/routes/traffic-flow-purge.js.map", + "backend/dist/routes/traffic-flow-purge.d.ts", + "backend/dist/routes/traffic-flow-purge.d.ts.map", + "backend/dist/routes/traffic-flow-settings.js", + "backend/dist/routes/traffic-flow-settings.js.map", + "backend/dist/routes/traffic-flow-settings.d.ts", + "backend/dist/routes/traffic-flow-settings.d.ts.map", + "backend/dist/routes/traffic-flow.js", + "backend/dist/routes/traffic-flow.js.map", + "backend/dist/routes/traffic-flow.d.ts", + "backend/dist/routes/traffic-flow.d.ts.map", + "backend/dist/routes/traffic.js", + "backend/dist/routes/traffic.js.map", + "backend/dist/routes/traffic.d.ts", + "backend/dist/routes/traffic.d.ts.map", + "backend/dist/routes/uptime.js", + "backend/dist/routes/uptime.js.map", + "backend/dist/routes/uptime.d.ts", + "backend/dist/routes/uptime.d.ts.map", + "backend/dist/routes/users.js", + "backend/dist/routes/users.js.map", + "backend/dist/routes/users.d.ts", + "backend/dist/routes/users.d.ts.map", + "backend/dist/routes/vxlan.js", + "backend/dist/routes/vxlan.js.map", + "backend/dist/routes/vxlan.d.ts", + "backend/dist/routes/vxlan.d.ts.map", + "backend/dist/routes/wireguard.js", + "backend/dist/routes/wireguard.js.map", + "backend/dist/routes/wireguard.d.ts", + "backend/dist/routes/wireguard.d.ts.map", + "backend/dist/scripts/migrate-sqlite-to-pg.js", + "backend/dist/scripts/migrate-sqlite-to-pg.js.map", + "backend/dist/scripts/migrate-sqlite-to-pg.d.ts", + "backend/dist/scripts/migrate-sqlite-to-pg.d.ts.map", + "backend/dist/scripts/rebuild-flow-facts.js", + "backend/dist/scripts/rebuild-flow-facts.js.map", + "backend/dist/scripts/rebuild-flow-facts.d.ts", + "backend/dist/scripts/rebuild-flow-facts.d.ts.map", + "backend/dist/services/acme-cloudflare.js", + "backend/dist/services/acme-cloudflare.js.map", + "backend/dist/services/acme-cloudflare.d.ts", + "backend/dist/services/acme-cloudflare.d.ts.map", + "backend/dist/services/alert-collector-hooks.js", + "backend/dist/services/alert-collector-hooks.js.map", + "backend/dist/services/alert-collector-hooks.d.ts", + "backend/dist/services/alert-collector-hooks.d.ts.map", + "backend/dist/services/alert-engine/bgp-signals.js", + "backend/dist/services/alert-engine/bgp-signals.js.map", + "backend/dist/services/alert-engine/bgp-signals.d.ts", + "backend/dist/services/alert-engine/bgp-signals.d.ts.map", + "backend/dist/services/alert-engine/collector-context-reader.js", + "backend/dist/services/alert-engine/collector-context-reader.js.map", + "backend/dist/services/alert-engine/collector-context-reader.d.ts", + "backend/dist/services/alert-engine/collector-context-reader.d.ts.map", + "backend/dist/services/alert-engine/collector-source-signals.js", + "backend/dist/services/alert-engine/collector-source-signals.js.map", + "backend/dist/services/alert-engine/collector-source-signals.d.ts", + "backend/dist/services/alert-engine/collector-source-signals.d.ts.map", + "backend/dist/services/alert-engine/confirm-stability.js", + "backend/dist/services/alert-engine/confirm-stability.js.map", + "backend/dist/services/alert-engine/confirm-stability.d.ts", + "backend/dist/services/alert-engine/confirm-stability.d.ts.map", + "backend/dist/services/alert-engine/cooldown.js", + "backend/dist/services/alert-engine/cooldown.js.map", + "backend/dist/services/alert-engine/cooldown.d.ts", + "backend/dist/services/alert-engine/cooldown.d.ts.map", + "backend/dist/services/alert-engine/decision-engine.js", + "backend/dist/services/alert-engine/decision-engine.js.map", + "backend/dist/services/alert-engine/decision-engine.d.ts", + "backend/dist/services/alert-engine/decision-engine.d.ts.map", + "backend/dist/services/alert-engine/evaluate-rule.js", + "backend/dist/services/alert-engine/evaluate-rule.js.map", + "backend/dist/services/alert-engine/evaluate-rule.d.ts", + "backend/dist/services/alert-engine/evaluate-rule.d.ts.map", + "backend/dist/services/alert-engine/gre-signals.js", + "backend/dist/services/alert-engine/gre-signals.js.map", + "backend/dist/services/alert-engine/gre-signals.d.ts", + "backend/dist/services/alert-engine/gre-signals.d.ts.map", + "backend/dist/services/alert-engine/groups.js", + "backend/dist/services/alert-engine/groups.js.map", + "backend/dist/services/alert-engine/groups.d.ts", + "backend/dist/services/alert-engine/groups.d.ts.map", + "backend/dist/services/alert-engine/monitoring-history.js", + "backend/dist/services/alert-engine/monitoring-history.js.map", + "backend/dist/services/alert-engine/monitoring-history.d.ts", + "backend/dist/services/alert-engine/monitoring-history.d.ts.map", + "backend/dist/services/alert-engine/outbox-execution.js", + "backend/dist/services/alert-engine/outbox-execution.js.map", + "backend/dist/services/alert-engine/outbox-execution.d.ts", + "backend/dist/services/alert-engine/outbox-execution.d.ts.map", + "backend/dist/services/alert-engine/outbox.js", + "backend/dist/services/alert-engine/outbox.js.map", + "backend/dist/services/alert-engine/outbox.d.ts", + "backend/dist/services/alert-engine/outbox.d.ts.map", + "backend/dist/services/alert-engine/prev-live-store.js", + "backend/dist/services/alert-engine/prev-live-store.js.map", + "backend/dist/services/alert-engine/prev-live-store.d.ts", + "backend/dist/services/alert-engine/prev-live-store.d.ts.map", + "backend/dist/services/alert-engine/rule-matcher.js", + "backend/dist/services/alert-engine/rule-matcher.js.map", + "backend/dist/services/alert-engine/rule-matcher.d.ts", + "backend/dist/services/alert-engine/rule-matcher.d.ts.map", + "backend/dist/services/alert-engine/run-once.js", + "backend/dist/services/alert-engine/run-once.js.map", + "backend/dist/services/alert-engine/run-once.d.ts", + "backend/dist/services/alert-engine/run-once.d.ts.map", + "backend/dist/services/alert-engine/server-signal-identity.js", + "backend/dist/services/alert-engine/server-signal-identity.js.map", + "backend/dist/services/alert-engine/server-signal-identity.d.ts", + "backend/dist/services/alert-engine/server-signal-identity.d.ts.map", + "backend/dist/services/alert-engine/signal-ingestor.js", + "backend/dist/services/alert-engine/signal-ingestor.js.map", + "backend/dist/services/alert-engine/signal-ingestor.d.ts", + "backend/dist/services/alert-engine/signal-ingestor.d.ts.map", + "backend/dist/services/alert-engine/signals-from-collectors.js", + "backend/dist/services/alert-engine/signals-from-collectors.js.map", + "backend/dist/services/alert-engine/signals-from-collectors.d.ts", + "backend/dist/services/alert-engine/signals-from-collectors.d.ts.map", + "backend/dist/services/alert-engine/snapshot.js", + "backend/dist/services/alert-engine/snapshot.js.map", + "backend/dist/services/alert-engine/snapshot.d.ts", + "backend/dist/services/alert-engine/snapshot.d.ts.map", + "backend/dist/services/alert-engine/source-watermark.js", + "backend/dist/services/alert-engine/source-watermark.js.map", + "backend/dist/services/alert-engine/source-watermark.d.ts", + "backend/dist/services/alert-engine/source-watermark.d.ts.map", + "backend/dist/services/alert-engine/state-machine.js", + "backend/dist/services/alert-engine/state-machine.js.map", + "backend/dist/services/alert-engine/state-machine.d.ts", + "backend/dist/services/alert-engine/state-machine.d.ts.map", + "backend/dist/services/alert-engine/target-issues.js", + "backend/dist/services/alert-engine/target-issues.js.map", + "backend/dist/services/alert-engine/target-issues.d.ts", + "backend/dist/services/alert-engine/target-issues.d.ts.map", + "backend/dist/services/alert-engine/telegram-emoji.js", + "backend/dist/services/alert-engine/telegram-emoji.js.map", + "backend/dist/services/alert-engine/telegram-emoji.d.ts", + "backend/dist/services/alert-engine/telegram-emoji.d.ts.map", + "backend/dist/services/alert-engine/types.js", + "backend/dist/services/alert-engine/types.js.map", + "backend/dist/services/alert-engine/types.d.ts", + "backend/dist/services/alert-engine/types.d.ts.map", + "backend/dist/services/alerts-config-execution.js", + "backend/dist/services/alerts-config-execution.js.map", + "backend/dist/services/alerts-config-execution.d.ts", + "backend/dist/services/alerts-config-execution.d.ts.map", + "backend/dist/services/alerts-outbox-overview.js", + "backend/dist/services/alerts-outbox-overview.js.map", + "backend/dist/services/alerts-outbox-overview.d.ts", + "backend/dist/services/alerts-outbox-overview.d.ts.map", + "backend/dist/services/alerts-outbox-retry.js", + "backend/dist/services/alerts-outbox-retry.js.map", + "backend/dist/services/alerts-outbox-retry.d.ts", + "backend/dist/services/alerts-outbox-retry.d.ts.map", + "backend/dist/services/alerts-overview.js", + "backend/dist/services/alerts-overview.js.map", + "backend/dist/services/alerts-overview.d.ts", + "backend/dist/services/alerts-overview.d.ts.map", + "backend/dist/services/alerts-revision.js", + "backend/dist/services/alerts-revision.js.map", + "backend/dist/services/alerts-revision.d.ts", + "backend/dist/services/alerts-revision.d.ts.map", + "backend/dist/services/alerts-service.js", + "backend/dist/services/alerts-service.js.map", + "backend/dist/services/alerts-service.d.ts", + "backend/dist/services/alerts-service.d.ts.map", + "backend/dist/services/alerts-telegram-delivery.js", + "backend/dist/services/alerts-telegram-delivery.js.map", + "backend/dist/services/alerts-telegram-delivery.d.ts", + "backend/dist/services/alerts-telegram-delivery.d.ts.map", + "backend/dist/services/alerts-telegram-send.js", + "backend/dist/services/alerts-telegram-send.js.map", + "backend/dist/services/alerts-telegram-send.d.ts", + "backend/dist/services/alerts-telegram-send.d.ts.map", + "backend/dist/services/alerts-telegram-settings.js", + "backend/dist/services/alerts-telegram-settings.js.map", + "backend/dist/services/alerts-telegram-settings.d.ts", + "backend/dist/services/alerts-telegram-settings.d.ts.map", + "backend/dist/services/backup-deletion.js", + "backend/dist/services/backup-deletion.js.map", + "backend/dist/services/backup-deletion.d.ts", + "backend/dist/services/backup-deletion.d.ts.map", + "backend/dist/services/backup-dto.js", + "backend/dist/services/backup-dto.js.map", + "backend/dist/services/backup-dto.d.ts", + "backend/dist/services/backup-dto.d.ts.map", + "backend/dist/services/backup-job-execution.js", + "backend/dist/services/backup-job-execution.js.map", + "backend/dist/services/backup-job-execution.d.ts", + "backend/dist/services/backup-job-execution.d.ts.map", + "backend/dist/services/backup-prune.js", + "backend/dist/services/backup-prune.js.map", + "backend/dist/services/backup-prune.d.ts", + "backend/dist/services/backup-prune.d.ts.map", + "backend/dist/services/backup-restore.js", + "backend/dist/services/backup-restore.js.map", + "backend/dist/services/backup-restore.d.ts", + "backend/dist/services/backup-restore.d.ts.map", + "backend/dist/services/backup-scheduler-collector.js", + "backend/dist/services/backup-scheduler-collector.js.map", + "backend/dist/services/backup-scheduler-collector.d.ts", + "backend/dist/services/backup-scheduler-collector.d.ts.map", + "backend/dist/services/backup-scheduler-run.js", + "backend/dist/services/backup-scheduler-run.js.map", + "backend/dist/services/backup-scheduler-run.d.ts", + "backend/dist/services/backup-scheduler-run.d.ts.map", + "backend/dist/services/backup-service.js", + "backend/dist/services/backup-service.js.map", + "backend/dist/services/backup-service.d.ts", + "backend/dist/services/backup-service.d.ts.map", + "backend/dist/services/backup-storage-update.js", + "backend/dist/services/backup-storage-update.js.map", + "backend/dist/services/backup-storage-update.d.ts", + "backend/dist/services/backup-storage-update.d.ts.map", + "backend/dist/services/bandwidth-test-rates.js", + "backend/dist/services/bandwidth-test-rates.js.map", + "backend/dist/services/bandwidth-test-rates.d.ts", + "backend/dist/services/bandwidth-test-rates.d.ts.map", + "backend/dist/services/bandwidth-test-status.js", + "backend/dist/services/bandwidth-test-status.js.map", + "backend/dist/services/bandwidth-test-status.d.ts", + "backend/dist/services/bandwidth-test-status.d.ts.map", + "backend/dist/services/bgp-catalog-poll.js", + "backend/dist/services/bgp-catalog-poll.js.map", + "backend/dist/services/bgp-catalog-poll.d.ts", + "backend/dist/services/bgp-catalog-poll.d.ts.map", + "backend/dist/services/bgp-parse-sessions.js", + "backend/dist/services/bgp-parse-sessions.js.map", + "backend/dist/services/bgp-parse-sessions.d.ts", + "backend/dist/services/bgp-parse-sessions.d.ts.map", + "backend/dist/services/bgp-peers-live.js", + "backend/dist/services/bgp-peers-live.js.map", + "backend/dist/services/bgp-peers-live.d.ts", + "backend/dist/services/bgp-peers-live.d.ts.map", + "backend/dist/services/btest-node-locks.js", + "backend/dist/services/btest-node-locks.js.map", + "backend/dist/services/btest-node-locks.d.ts", + "backend/dist/services/btest-node-locks.d.ts.map", + "backend/dist/services/certificate-issue-dto.js", + "backend/dist/services/certificate-issue-dto.js.map", + "backend/dist/services/certificate-issue-dto.d.ts", + "backend/dist/services/certificate-issue-dto.d.ts.map", + "backend/dist/services/certificate-issue-execution.js", + "backend/dist/services/certificate-issue-execution.js.map", + "backend/dist/services/certificate-issue-execution.d.ts", + "backend/dist/services/certificate-issue-execution.d.ts.map", + "backend/dist/services/certificate-issue-request.js", + "backend/dist/services/certificate-issue-request.js.map", + "backend/dist/services/certificate-issue-request.d.ts", + "backend/dist/services/certificate-issue-request.d.ts.map", + "backend/dist/services/certificate-issue-runner.js", + "backend/dist/services/certificate-issue-runner.js.map", + "backend/dist/services/certificate-issue-runner.d.ts", + "backend/dist/services/certificate-issue-runner.d.ts.map", + "backend/dist/services/certificate-parse.js", + "backend/dist/services/certificate-parse.js.map", + "backend/dist/services/certificate-parse.d.ts", + "backend/dist/services/certificate-parse.d.ts.map", + "backend/dist/services/certificate-renew-collector.js", + "backend/dist/services/certificate-renew-collector.js.map", + "backend/dist/services/certificate-renew-collector.d.ts", + "backend/dist/services/certificate-renew-collector.d.ts.map", + "backend/dist/services/certificates-service.js", + "backend/dist/services/certificates-service.js.map", + "backend/dist/services/certificates-service.d.ts", + "backend/dist/services/certificates-service.d.ts.map", + "backend/dist/services/certificates-state.js", + "backend/dist/services/certificates-state.js.map", + "backend/dist/services/certificates-state.d.ts", + "backend/dist/services/certificates-state.d.ts.map", + "backend/dist/services/complete-count.js", + "backend/dist/services/complete-count.js.map", + "backend/dist/services/complete-count.d.ts", + "backend/dist/services/complete-count.d.ts.map", + "backend/dist/services/config-apply-plan.js", + "backend/dist/services/config-apply-plan.js.map", + "backend/dist/services/config-apply-plan.d.ts", + "backend/dist/services/config-apply-plan.d.ts.map", + "backend/dist/services/config-revisions.js", + "backend/dist/services/config-revisions.js.map", + "backend/dist/services/config-revisions.d.ts", + "backend/dist/services/config-revisions.d.ts.map", + "backend/dist/services/containers-live.js", + "backend/dist/services/containers-live.js.map", + "backend/dist/services/containers-live.d.ts", + "backend/dist/services/containers-live.d.ts.map", + "backend/dist/services/containers-state.js", + "backend/dist/services/containers-state.js.map", + "backend/dist/services/containers-state.d.ts", + "backend/dist/services/containers-state.d.ts.map", + "backend/dist/services/database-background-work.js", + "backend/dist/services/database-background-work.js.map", + "backend/dist/services/database-background-work.d.ts", + "backend/dist/services/database-background-work.d.ts.map", + "backend/dist/services/database-request-gate.js", + "backend/dist/services/database-request-gate.js.map", + "backend/dist/services/database-request-gate.d.ts", + "backend/dist/services/database-request-gate.d.ts.map", + "backend/dist/services/entity-snapshots.js", + "backend/dist/services/entity-snapshots.js.map", + "backend/dist/services/entity-snapshots.d.ts", + "backend/dist/services/entity-snapshots.d.ts.map", + "backend/dist/services/evobgp-catalog.js", + "backend/dist/services/evobgp-catalog.js.map", + "backend/dist/services/evobgp-catalog.d.ts", + "backend/dist/services/evobgp-catalog.d.ts.map", + "backend/dist/services/firewall-live.js", + "backend/dist/services/firewall-live.js.map", + "backend/dist/services/firewall-live.d.ts", + "backend/dist/services/firewall-live.d.ts.map", + "backend/dist/services/firewall-poll.js", + "backend/dist/services/firewall-poll.js.map", + "backend/dist/services/firewall-poll.d.ts", + "backend/dist/services/firewall-poll.d.ts.map", + "backend/dist/services/geoip-settings.js", + "backend/dist/services/geoip-settings.js.map", + "backend/dist/services/geoip-settings.d.ts", + "backend/dist/services/geoip-settings.d.ts.map", + "backend/dist/services/geoip-update-collector.js", + "backend/dist/services/geoip-update-collector.js.map", + "backend/dist/services/geoip-update-collector.d.ts", + "backend/dist/services/geoip-update-collector.d.ts.map", + "backend/dist/services/gre-bgp-snapshot-collector.js", + "backend/dist/services/gre-bgp-snapshot-collector.js.map", + "backend/dist/services/gre-bgp-snapshot-collector.d.ts", + "backend/dist/services/gre-bgp-snapshot-collector.d.ts.map", + "backend/dist/services/gre-bgp-snapshot-history.js", + "backend/dist/services/gre-bgp-snapshot-history.js.map", + "backend/dist/services/gre-bgp-snapshot-history.d.ts", + "backend/dist/services/gre-bgp-snapshot-history.d.ts.map", + "backend/dist/services/gre-bgp-timing.js", + "backend/dist/services/gre-bgp-timing.js.map", + "backend/dist/services/gre-bgp-timing.d.ts", + "backend/dist/services/gre-bgp-timing.d.ts.map", + "backend/dist/services/gre-catalog-poll.js", + "backend/dist/services/gre-catalog-poll.js.map", + "backend/dist/services/gre-catalog-poll.d.ts", + "backend/dist/services/gre-catalog-poll.d.ts.map", + "backend/dist/services/gre-comment.js", + "backend/dist/services/gre-comment.js.map", + "backend/dist/services/gre-comment.d.ts", + "backend/dist/services/gre-comment.d.ts.map", + "backend/dist/services/gre-live.js", + "backend/dist/services/gre-live.js.map", + "backend/dist/services/gre-live.d.ts", + "backend/dist/services/gre-live.d.ts.map", + "backend/dist/services/gre-tunnels-live.js", + "backend/dist/services/gre-tunnels-live.js.map", + "backend/dist/services/gre-tunnels-live.d.ts", + "backend/dist/services/gre-tunnels-live.d.ts.map", + "backend/dist/services/internet-path-collector.js", + "backend/dist/services/internet-path-collector.js.map", + "backend/dist/services/internet-path-collector.d.ts", + "backend/dist/services/internet-path-collector.d.ts.map", + "backend/dist/services/internet-path-snapshot.js", + "backend/dist/services/internet-path-snapshot.js.map", + "backend/dist/services/internet-path-snapshot.d.ts", + "backend/dist/services/internet-path-snapshot.d.ts.map", + "backend/dist/services/ipsec-ca.js", + "backend/dist/services/ipsec-ca.js.map", + "backend/dist/services/ipsec-ca.d.ts", + "backend/dist/services/ipsec-ca.d.ts.map", + "backend/dist/services/ipsec-certificate-dn.js", + "backend/dist/services/ipsec-certificate-dn.js.map", + "backend/dist/services/ipsec-certificate-dn.d.ts", + "backend/dist/services/ipsec-certificate-dn.d.ts.map", + "backend/dist/services/ipsec-cleanup.js", + "backend/dist/services/ipsec-cleanup.js.map", + "backend/dist/services/ipsec-cleanup.d.ts", + "backend/dist/services/ipsec-cleanup.d.ts.map", + "backend/dist/services/ipsec-config.js", + "backend/dist/services/ipsec-config.js.map", + "backend/dist/services/ipsec-config.d.ts", + "backend/dist/services/ipsec-config.d.ts.map", + "backend/dist/services/ipsec-live.js", + "backend/dist/services/ipsec-live.js.map", + "backend/dist/services/ipsec-live.d.ts", + "backend/dist/services/ipsec-live.d.ts.map", + "backend/dist/services/ipsec-operation.js", + "backend/dist/services/ipsec-operation.js.map", + "backend/dist/services/ipsec-operation.d.ts", + "backend/dist/services/ipsec-operation.d.ts.map", + "backend/dist/services/ipsec-ros.js", + "backend/dist/services/ipsec-ros.js.map", + "backend/dist/services/ipsec-ros.d.ts", + "backend/dist/services/ipsec-ros.d.ts.map", + "backend/dist/services/mikrotik.js", + "backend/dist/services/mikrotik.js.map", + "backend/dist/services/mikrotik.d.ts", + "backend/dist/services/mikrotik.d.ts.map", + "backend/dist/services/monitoring-server-catalog.js", + "backend/dist/services/monitoring-server-catalog.js.map", + "backend/dist/services/monitoring-server-catalog.d.ts", + "backend/dist/services/monitoring-server-catalog.d.ts.map", + "backend/dist/services/ospf-catalog-poll.js", + "backend/dist/services/ospf-catalog-poll.js.map", + "backend/dist/services/ospf-catalog-poll.d.ts", + "backend/dist/services/ospf-catalog-poll.d.ts.map", + "backend/dist/services/ospf-effective-disabled.js", + "backend/dist/services/ospf-effective-disabled.js.map", + "backend/dist/services/ospf-effective-disabled.d.ts", + "backend/dist/services/ospf-effective-disabled.d.ts.map", + "backend/dist/services/ospf-observed-values.js", + "backend/dist/services/ospf-observed-values.js.map", + "backend/dist/services/ospf-observed-values.d.ts", + "backend/dist/services/ospf-observed-values.d.ts.map", + "backend/dist/services/ospf-optimizer-identity.js", + "backend/dist/services/ospf-optimizer-identity.js.map", + "backend/dist/services/ospf-optimizer-identity.d.ts", + "backend/dist/services/ospf-optimizer-identity.d.ts.map", + "backend/dist/services/ospf-optimizer-metrics.js", + "backend/dist/services/ospf-optimizer-metrics.js.map", + "backend/dist/services/ospf-optimizer-metrics.d.ts", + "backend/dist/services/ospf-optimizer-metrics.d.ts.map", + "backend/dist/services/ospf-optimizer-plan.js", + "backend/dist/services/ospf-optimizer-plan.js.map", + "backend/dist/services/ospf-optimizer-plan.d.ts", + "backend/dist/services/ospf-optimizer-plan.d.ts.map", + "backend/dist/services/ospf-route-parse.js", + "backend/dist/services/ospf-route-parse.js.map", + "backend/dist/services/ospf-route-parse.d.ts", + "backend/dist/services/ospf-route-parse.d.ts.map", + "backend/dist/services/ping-probe-replacement.js", + "backend/dist/services/ping-probe-replacement.js.map", + "backend/dist/services/ping-probe-replacement.d.ts", + "backend/dist/services/ping-probe-replacement.d.ts.map", + "backend/dist/services/poller.js", + "backend/dist/services/poller.js.map", + "backend/dist/services/poller.d.ts", + "backend/dist/services/poller.d.ts.map", + "backend/dist/services/recursive-apply.js", + "backend/dist/services/recursive-apply.js.map", + "backend/dist/services/recursive-apply.d.ts", + "backend/dist/services/recursive-apply.d.ts.map", + "backend/dist/services/recursive-route-catalog.js", + "backend/dist/services/recursive-route-catalog.js.map", + "backend/dist/services/recursive-route-catalog.d.ts", + "backend/dist/services/recursive-route-catalog.d.ts.map", + "backend/dist/services/recursive-route-validation.js", + "backend/dist/services/recursive-route-validation.js.map", + "backend/dist/services/recursive-route-validation.d.ts", + "backend/dist/services/recursive-route-validation.d.ts.map", + "backend/dist/services/ros-metric-parse.js", + "backend/dist/services/ros-metric-parse.js.map", + "backend/dist/services/ros-metric-parse.d.ts", + "backend/dist/services/ros-metric-parse.d.ts.map", + "backend/dist/services/ros-ops.js", + "backend/dist/services/ros-ops.js.map", + "backend/dist/services/ros-ops.d.ts", + "backend/dist/services/ros-ops.d.ts.map", + "backend/dist/services/s3-backup-client.js", + "backend/dist/services/s3-backup-client.js.map", + "backend/dist/services/s3-backup-client.d.ts", + "backend/dist/services/s3-backup-client.d.ts.map", + "backend/dist/services/scheduler-recorded-run.js", + "backend/dist/services/scheduler-recorded-run.js.map", + "backend/dist/services/scheduler-recorded-run.d.ts", + "backend/dist/services/scheduler-recorded-run.d.ts.map", + "backend/dist/services/scheduler-running.js", + "backend/dist/services/scheduler-running.js.map", + "backend/dist/services/scheduler-running.d.ts", + "backend/dist/services/scheduler-running.d.ts.map", + "backend/dist/services/scheduler.js", + "backend/dist/services/scheduler.js.map", + "backend/dist/services/scheduler.d.ts", + "backend/dist/services/scheduler.d.ts.map", + "backend/dist/services/serial-operation.js", + "backend/dist/services/serial-operation.js.map", + "backend/dist/services/serial-operation.d.ts", + "backend/dist/services/serial-operation.d.ts.map", + "backend/dist/services/servers-rest-ping-collector.js", + "backend/dist/services/servers-rest-ping-collector.js.map", + "backend/dist/services/servers-rest-ping-collector.d.ts", + "backend/dist/services/servers-rest-ping-collector.d.ts.map", + "backend/dist/services/speed-history-dto.js", + "backend/dist/services/speed-history-dto.js.map", + "backend/dist/services/speed-history-dto.d.ts", + "backend/dist/services/speed-history-dto.d.ts.map", + "backend/dist/services/speed-probe-dto.js", + "backend/dist/services/speed-probe-dto.js.map", + "backend/dist/services/speed-probe-dto.d.ts", + "backend/dist/services/speed-probe-dto.d.ts.map", + "backend/dist/services/speed-probe-replacement.js", + "backend/dist/services/speed-probe-replacement.js.map", + "backend/dist/services/speed-probe-replacement.d.ts", + "backend/dist/services/speed-probe-replacement.d.ts.map", + "backend/dist/services/speed-run-error-message.js", + "backend/dist/services/speed-run-error-message.js.map", + "backend/dist/services/speed-run-error-message.d.ts", + "backend/dist/services/speed-run-error-message.d.ts.map", + "backend/dist/services/speed-run-persistence.js", + "backend/dist/services/speed-run-persistence.js.map", + "backend/dist/services/speed-run-persistence.d.ts", + "backend/dist/services/speed-run-persistence.d.ts.map", + "backend/dist/services/statistics-aggregate.js", + "backend/dist/services/statistics-aggregate.js.map", + "backend/dist/services/statistics-aggregate.d.ts", + "backend/dist/services/statistics-aggregate.d.ts.map", + "backend/dist/services/system-database-backup.js", + "backend/dist/services/system-database-backup.js.map", + "backend/dist/services/system-database-backup.d.ts", + "backend/dist/services/system-database-backup.d.ts.map", + "backend/dist/services/system-database-cache.js", + "backend/dist/services/system-database-cache.js.map", + "backend/dist/services/system-database-cache.d.ts", + "backend/dist/services/system-database-cache.d.ts.map", + "backend/dist/services/system-database-operation.js", + "backend/dist/services/system-database-operation.js.map", + "backend/dist/services/system-database-operation.d.ts", + "backend/dist/services/system-database-operation.d.ts.map", + "backend/dist/services/system-database-partition-restore.js", + "backend/dist/services/system-database-partition-restore.js.map", + "backend/dist/services/system-database-partition-restore.d.ts", + "backend/dist/services/system-database-partition-restore.d.ts.map", + "backend/dist/services/system-database-restore-execution.js", + "backend/dist/services/system-database-restore-execution.js.map", + "backend/dist/services/system-database-restore-execution.d.ts", + "backend/dist/services/system-database-restore-execution.d.ts.map", + "backend/dist/services/traffic-collection-state.js", + "backend/dist/services/traffic-collection-state.js.map", + "backend/dist/services/traffic-collection-state.d.ts", + "backend/dist/services/traffic-collection-state.d.ts.map", + "backend/dist/services/traffic-collector.js", + "backend/dist/services/traffic-collector.js.map", + "backend/dist/services/traffic-collector.d.ts", + "backend/dist/services/traffic-collector.d.ts.map", + "backend/dist/services/traffic-flow-analytics.js", + "backend/dist/services/traffic-flow-analytics.js.map", + "backend/dist/services/traffic-flow-analytics.d.ts", + "backend/dist/services/traffic-flow-analytics.d.ts.map", + "backend/dist/services/traffic-flow-apps.js", + "backend/dist/services/traffic-flow-apps.js.map", + "backend/dist/services/traffic-flow-apps.d.ts", + "backend/dist/services/traffic-flow-apps.d.ts.map", + "backend/dist/services/traffic-flow-brands.js", + "backend/dist/services/traffic-flow-brands.js.map", + "backend/dist/services/traffic-flow-brands.d.ts", + "backend/dist/services/traffic-flow-brands.d.ts.map", + "backend/dist/services/traffic-flow-classify.js", + "backend/dist/services/traffic-flow-classify.js.map", + "backend/dist/services/traffic-flow-classify.d.ts", + "backend/dist/services/traffic-flow-classify.d.ts.map", + "backend/dist/services/traffic-flow-collector-ipc.js", + "backend/dist/services/traffic-flow-collector-ipc.js.map", + "backend/dist/services/traffic-flow-collector-ipc.d.ts", + "backend/dist/services/traffic-flow-collector-ipc.d.ts.map", + "backend/dist/services/traffic-flow-collector-worker.js", + "backend/dist/services/traffic-flow-collector-worker.js.map", + "backend/dist/services/traffic-flow-collector-worker.d.ts", + "backend/dist/services/traffic-flow-collector-worker.d.ts.map", + "backend/dist/services/traffic-flow-dedup.js", + "backend/dist/services/traffic-flow-dedup.js.map", + "backend/dist/services/traffic-flow-dedup.d.ts", + "backend/dist/services/traffic-flow-dedup.d.ts.map", + "backend/dist/services/traffic-flow-dest.js", + "backend/dist/services/traffic-flow-dest.js.map", + "backend/dist/services/traffic-flow-dest.d.ts", + "backend/dist/services/traffic-flow-dest.d.ts.map", + "backend/dist/services/traffic-flow-engine.js", + "backend/dist/services/traffic-flow-engine.js.map", + "backend/dist/services/traffic-flow-engine.d.ts", + "backend/dist/services/traffic-flow-engine.d.ts.map", + "backend/dist/services/traffic-flow-facts-filter.js", + "backend/dist/services/traffic-flow-facts-filter.js.map", + "backend/dist/services/traffic-flow-facts-filter.d.ts", + "backend/dist/services/traffic-flow-facts-filter.d.ts.map", + "backend/dist/services/traffic-flow-facts-rebuild.js", + "backend/dist/services/traffic-flow-facts-rebuild.js.map", + "backend/dist/services/traffic-flow-facts-rebuild.d.ts", + "backend/dist/services/traffic-flow-facts-rebuild.d.ts.map", + "backend/dist/services/traffic-flow-facts.js", + "backend/dist/services/traffic-flow-facts.js.map", + "backend/dist/services/traffic-flow-facts.d.ts", + "backend/dist/services/traffic-flow-facts.d.ts.map", + "backend/dist/services/traffic-flow-geoip.js", + "backend/dist/services/traffic-flow-geoip.js.map", + "backend/dist/services/traffic-flow-geoip.d.ts", + "backend/dist/services/traffic-flow-geoip.d.ts.map", + "backend/dist/services/traffic-flow-host-file-builders.js", + "backend/dist/services/traffic-flow-host-file-builders.js.map", + "backend/dist/services/traffic-flow-host-file-builders.d.ts", + "backend/dist/services/traffic-flow-host-file-builders.d.ts.map", + "backend/dist/services/traffic-flow-host-files.js", + "backend/dist/services/traffic-flow-host-files.js.map", + "backend/dist/services/traffic-flow-host-files.d.ts", + "backend/dist/services/traffic-flow-host-files.d.ts.map", + "backend/dist/services/traffic-flow-ifaces.js", + "backend/dist/services/traffic-flow-ifaces.js.map", + "backend/dist/services/traffic-flow-ifaces.d.ts", + "backend/dist/services/traffic-flow-ifaces.d.ts.map", + "backend/dist/services/traffic-flow-ifindex.js", + "backend/dist/services/traffic-flow-ifindex.js.map", + "backend/dist/services/traffic-flow-ifindex.d.ts", + "backend/dist/services/traffic-flow-ifindex.d.ts.map", + "backend/dist/services/traffic-flow-ingest.js", + "backend/dist/services/traffic-flow-ingest.js.map", + "backend/dist/services/traffic-flow-ingest.d.ts", + "backend/dist/services/traffic-flow-ingest.d.ts.map", + "backend/dist/services/traffic-flow-ip.js", + "backend/dist/services/traffic-flow-ip.js.map", + "backend/dist/services/traffic-flow-ip.d.ts", + "backend/dist/services/traffic-flow-ip.d.ts.map", + "backend/dist/services/traffic-flow-key-execution.js", + "backend/dist/services/traffic-flow-key-execution.js.map", + "backend/dist/services/traffic-flow-key-execution.d.ts", + "backend/dist/services/traffic-flow-key-execution.d.ts.map", + "backend/dist/services/traffic-flow-map-exporter.js", + "backend/dist/services/traffic-flow-map-exporter.js.map", + "backend/dist/services/traffic-flow-map-exporter.d.ts", + "backend/dist/services/traffic-flow-map-exporter.d.ts.map", + "backend/dist/services/traffic-flow-map-hops.js", + "backend/dist/services/traffic-flow-map-hops.js.map", + "backend/dist/services/traffic-flow-map-hops.d.ts", + "backend/dist/services/traffic-flow-map-hops.d.ts.map", + "backend/dist/services/traffic-flow-overlay.js", + "backend/dist/services/traffic-flow-overlay.js.map", + "backend/dist/services/traffic-flow-overlay.d.ts", + "backend/dist/services/traffic-flow-overlay.d.ts.map", + "backend/dist/services/traffic-flow-parse.js", + "backend/dist/services/traffic-flow-parse.js.map", + "backend/dist/services/traffic-flow-parse.d.ts", + "backend/dist/services/traffic-flow-parse.d.ts.map", + "backend/dist/services/traffic-flow-planes.js", + "backend/dist/services/traffic-flow-planes.js.map", + "backend/dist/services/traffic-flow-planes.d.ts", + "backend/dist/services/traffic-flow-planes.d.ts.map", + "backend/dist/services/traffic-flow-purge-execution.js", + "backend/dist/services/traffic-flow-purge-execution.js.map", + "backend/dist/services/traffic-flow-purge-execution.d.ts", + "backend/dist/services/traffic-flow-purge-execution.d.ts.map", + "backend/dist/services/traffic-flow-ripe.js", + "backend/dist/services/traffic-flow-ripe.js.map", + "backend/dist/services/traffic-flow-ripe.d.ts", + "backend/dist/services/traffic-flow-ripe.d.ts.map", + "backend/dist/services/traffic-flow-settings.js", + "backend/dist/services/traffic-flow-settings.js.map", + "backend/dist/services/traffic-flow-settings.d.ts", + "backend/dist/services/traffic-flow-settings.d.ts.map", + "backend/dist/services/traffic-flow-topology.js", + "backend/dist/services/traffic-flow-topology.js.map", + "backend/dist/services/traffic-flow-topology.d.ts", + "backend/dist/services/traffic-flow-topology.d.ts.map", + "backend/dist/services/traffic-flow-worker-shutdown.js", + "backend/dist/services/traffic-flow-worker-shutdown.js.map", + "backend/dist/services/traffic-flow-worker-shutdown.d.ts", + "backend/dist/services/traffic-flow-worker-shutdown.d.ts.map", + "backend/dist/services/traffic-freshness.js", + "backend/dist/services/traffic-freshness.js.map", + "backend/dist/services/traffic-freshness.d.ts", + "backend/dist/services/traffic-freshness.d.ts.map", + "backend/dist/services/traffic-live.js", + "backend/dist/services/traffic-live.js.map", + "backend/dist/services/traffic-live.d.ts", + "backend/dist/services/traffic-live.d.ts.map", + "backend/dist/services/traffic-observation.js", + "backend/dist/services/traffic-observation.js.map", + "backend/dist/services/traffic-observation.d.ts", + "backend/dist/services/traffic-observation.d.ts.map", + "backend/dist/services/traffic-peer-observation.js", + "backend/dist/services/traffic-peer-observation.js.map", + "backend/dist/services/traffic-peer-observation.d.ts", + "backend/dist/services/traffic-peer-observation.d.ts.map", + "backend/dist/services/traffic-rate.js", + "backend/dist/services/traffic-rate.js.map", + "backend/dist/services/traffic-rate.d.ts", + "backend/dist/services/traffic-rate.d.ts.map", + "backend/dist/services/traffic-users.js", + "backend/dist/services/traffic-users.js.map", + "backend/dist/services/traffic-users.d.ts", + "backend/dist/services/traffic-users.d.ts.map", + "backend/dist/services/uptime-collector.js", + "backend/dist/services/uptime-collector.js.map", + "backend/dist/services/uptime-collector.d.ts", + "backend/dist/services/uptime-collector.d.ts.map", + "backend/dist/services/uptime-probe-observations.js", + "backend/dist/services/uptime-probe-observations.js.map", + "backend/dist/services/uptime-probe-observations.d.ts", + "backend/dist/services/uptime-probe-observations.d.ts.map", + "backend/dist/services/uptime-speed-service.js", + "backend/dist/services/uptime-speed-service.js.map", + "backend/dist/services/uptime-speed-service.d.ts", + "backend/dist/services/uptime-speed-service.d.ts.map", + "backend/dist/services/vxlan-live.js", + "backend/dist/services/vxlan-live.js.map", + "backend/dist/services/vxlan-live.d.ts", + "backend/dist/services/vxlan-live.d.ts.map", + "backend/dist/services/wg-keys.js", + "backend/dist/services/wg-keys.js.map", + "backend/dist/services/wg-keys.d.ts", + "backend/dist/services/wg-keys.d.ts.map", + "backend/dist/services/wireguard-config.js", + "backend/dist/services/wireguard-config.js.map", + "backend/dist/services/wireguard-config.d.ts", + "backend/dist/services/wireguard-config.d.ts.map", + "backend/dist/services/wireguard-delete.js", + "backend/dist/services/wireguard-delete.js.map", + "backend/dist/services/wireguard-delete.d.ts", + "backend/dist/services/wireguard-delete.d.ts.map", + "backend/dist/services/wireguard-import-apply.js", + "backend/dist/services/wireguard-import-apply.js.map", + "backend/dist/services/wireguard-import-apply.d.ts", + "backend/dist/services/wireguard-import-apply.d.ts.map", + "backend/dist/services/wireguard-import-revision.js", + "backend/dist/services/wireguard-import-revision.js.map", + "backend/dist/services/wireguard-import-revision.d.ts", + "backend/dist/services/wireguard-import-revision.d.ts.map", + "backend/dist/services/wireguard-import.js", + "backend/dist/services/wireguard-import.js.map", + "backend/dist/services/wireguard-import.d.ts", + "backend/dist/services/wireguard-import.d.ts.map", + "backend/dist/services/wireguard-live.js", + "backend/dist/services/wireguard-live.js.map", + "backend/dist/services/wireguard-live.d.ts", + "backend/dist/services/wireguard-live.d.ts.map", + "backend/dist/services/wireguard-observed-values.js", + "backend/dist/services/wireguard-observed-values.js.map", + "backend/dist/services/wireguard-observed-values.d.ts", + "backend/dist/services/wireguard-observed-values.d.ts.map", + "backend/dist/services/wireguard-ros.js", + "backend/dist/services/wireguard-ros.js.map", + "backend/dist/services/wireguard-ros.d.ts", + "backend/dist/services/wireguard-ros.d.ts.map", + "backend/dist/test/pg.js", + "backend/dist/test/pg.js.map", + "backend/dist/test/pg.d.ts", + "backend/dist/test/pg.d.ts.map", + "backend/dist/types/scheduler-run-snapshot.js", + "backend/dist/types/scheduler-run-snapshot.js.map", + "backend/dist/types/scheduler-run-snapshot.d.ts", + "backend/dist/types/scheduler-run-snapshot.d.ts.map", + "backend/dist/types/server.js", + "backend/dist/types/server.js.map", + "backend/dist/types/server.d.ts", + "backend/dist/types/server.d.ts.map", + "backend/dist/utils/abort-signals.js", + "backend/dist/utils/abort-signals.js.map", + "backend/dist/utils/abort-signals.d.ts", + "backend/dist/utils/abort-signals.d.ts.map", + "backend/dist/utils/ros-src-address.js", + "backend/dist/utils/ros-src-address.js.map", + "backend/dist/utils/ros-src-address.d.ts", + "backend/dist/utils/ros-src-address.d.ts.map", + "backend/dist/utils/server-id.js", + "backend/dist/utils/server-id.js.map", + "backend/dist/utils/server-id.d.ts", + "backend/dist/utils/server-id.d.ts.map", + "packages/contracts/dist/alerts.js", + "packages/contracts/dist/alerts.js.map", + "packages/contracts/dist/alerts.d.ts", + "packages/contracts/dist/alerts.d.ts.map", + "packages/contracts/dist/backups.js", + "packages/contracts/dist/backups.js.map", + "packages/contracts/dist/backups.d.ts", + "packages/contracts/dist/backups.d.ts.map", + "packages/contracts/dist/certificates.js", + "packages/contracts/dist/certificates.js.map", + "packages/contracts/dist/certificates.d.ts", + "packages/contracts/dist/certificates.d.ts.map", + "packages/contracts/dist/containers.js", + "packages/contracts/dist/containers.js.map", + "packages/contracts/dist/containers.d.ts", + "packages/contracts/dist/containers.d.ts.map", + "packages/contracts/dist/events.js", + "packages/contracts/dist/events.js.map", + "packages/contracts/dist/events.d.ts", + "packages/contracts/dist/events.d.ts.map", + "packages/contracts/dist/evobgp.js", + "packages/contracts/dist/evobgp.js.map", + "packages/contracts/dist/evobgp.d.ts", + "packages/contracts/dist/evobgp.d.ts.map", + "packages/contracts/dist/geoip.js", + "packages/contracts/dist/geoip.js.map", + "packages/contracts/dist/geoip.d.ts", + "packages/contracts/dist/geoip.d.ts.map", + "packages/contracts/dist/index.js", + "packages/contracts/dist/index.js.map", + "packages/contracts/dist/index.d.ts", + "packages/contracts/dist/index.d.ts.map", + "packages/contracts/dist/ipsec.js", + "packages/contracts/dist/ipsec.js.map", + "packages/contracts/dist/ipsec.d.ts", + "packages/contracts/dist/ipsec.d.ts.map", + "packages/contracts/dist/ospf-optimizer.js", + "packages/contracts/dist/ospf-optimizer.js.map", + "packages/contracts/dist/ospf-optimizer.d.ts", + "packages/contracts/dist/ospf-optimizer.d.ts.map", + "packages/contracts/dist/servers.js", + "packages/contracts/dist/servers.js.map", + "packages/contracts/dist/servers.d.ts", + "packages/contracts/dist/servers.d.ts.map", + "packages/contracts/dist/statistics.js", + "packages/contracts/dist/statistics.js.map", + "packages/contracts/dist/statistics.d.ts", + "packages/contracts/dist/statistics.d.ts.map", + "packages/contracts/dist/traffic-flow.js", + "packages/contracts/dist/traffic-flow.js.map", + "packages/contracts/dist/traffic-flow.d.ts", + "packages/contracts/dist/traffic-flow.d.ts.map", + "packages/contracts/dist/uptime-probes.js", + "packages/contracts/dist/uptime-probes.js.map", + "packages/contracts/dist/uptime-probes.d.ts", + "packages/contracts/dist/uptime-probes.d.ts.map", + "packages/contracts/dist/uptime-speed.js", + "packages/contracts/dist/uptime-speed.js.map", + "packages/contracts/dist/uptime-speed.d.ts", + "packages/contracts/dist/uptime-speed.d.ts.map", + "packages/contracts/dist/users.js", + "packages/contracts/dist/users.js.map", + "packages/contracts/dist/users.d.ts", + "packages/contracts/dist/users.d.ts.map", + "packages/contracts/dist/wireguard.js", + "packages/contracts/dist/wireguard.js.map", + "packages/contracts/dist/wireguard.d.ts", + "packages/contracts/dist/wireguard.d.ts.map" + ], + "missing": [], + "different": [] +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/traffic-peak191-peak191-api-result.json b/docs/ux-ui/acceptance/traffic-peak191-peak191-api-result.json new file mode 100644 index 00000000..6a81caa0 --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak191-peak191-api-result.json @@ -0,0 +1,26 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "version": "1.0.0-test.peak191", + "passed": true, + "method": "Read-only actual application volume API; no new native RouterOS commands; exact edge values covered separately by owned SQL", + "cases": [ + { + "sourceId": "1", + "volumeUnit": "GiB", + "rxTotalGiB": 0.012759584002196789, + "txTotalGiB": 0.0008463365957140923, + "currentState": "current" + }, + { + "sourceId": "2", + "volumeUnit": "GiB", + "rxTotalGiB": 0.0011972729116678238, + "txTotalGiB": 0.0014407914131879807, + "currentState": "current" + } + ], + "newRouterOSCommands": 0, + "passwordChanges": 0, + "messages": 0 +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/traffic-peak191-runtime191-result.json b/docs/ux-ui/acceptance/traffic-peak191-runtime191-result.json new file mode 100644 index 00000000..83c93c30 --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak191-runtime191-result.json @@ -0,0 +1,25 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "secretEnvCopied": false, + "rollbackTags": { + "MMAPP_IMAGE_TAG": "ux-warning183", + "BACKEND_IMAGE_TAG": "ux-peak190" + }, + "services": { + "backend": { + "image": "mmapp-test/backend:ux-peak191", + "imageId": "sha256:f6db37afa8263cf16ddb955938c7c20796b49570a08f8f706803b94e30812fb7", + "state": "running", + "health": "healthy", + "matchedVerifiedImage": true + }, + "frontend": { + "image": "mmapp-test/frontend:ux-peak191", + "imageId": "sha256:1d9f85dbb5c791f09dad2863041d0fae5a291b02f5e73a5e96185a7866c673c7", + "state": "running", + "health": null, + "matchedVerifiedImage": true + } + } +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/traffic-peak191-source191-result.json b/docs/ux-ui/acceptance/traffic-peak191-source191-result.json new file mode 100644 index 00000000..94822f66 --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak191-source191-result.json @@ -0,0 +1,10 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "matched": { + "backend": 461, + "frontend": 524 + }, + "different": [], + "missing": [] +} \ No newline at end of file diff --git a/docs/ux-ui/acceptance/traffic-peak191-sql191-result.json b/docs/ux-ui/acceptance/traffic-peak191-sql191-result.json new file mode 100644 index 00000000..b9580944 --- /dev/null +++ b/docs/ux-ui/acceptance/traffic-peak191-sql191-result.json @@ -0,0 +1,31 @@ +{ + "date": "2026-10-13", + "block": "12.5.191", + "passed": true, + "profiles": [ + { + "date": "2026-10-13", + "block": "12.5.191", + "database": "mm_accept_166_1791874191164", + "scope": "ephemeral role and precreated owned database; no copied production credentials", + "tests": [ + { + "command": "npm --prefix backend run test:traffic-rate", + "passed": true, + "durationMs": 41228, + "ownedTrafficSqlCases": 9, + "ownedHistorySqlCases": 14, + "ownedLiveSqlCases": 10, + "ownedVolumeSqlCases": 17, + "ownedStatusSqlCases": 21, + "postgresUnavailableSkip": false + } + ], + "scopedRoleVerified": true, + "passed": true, + "databaseRemoved": true, + "roleRemoved": true, + "testContainerRemoved": true + } + ] +} \ No newline at end of file diff --git a/lib/traffic-observations.test.ts b/lib/traffic-observations.test.ts index b802ecf6..4b65c45b 100644 --- a/lib/traffic-observations.test.ts +++ b/lib/traffic-observations.test.ts @@ -12,3 +12,7 @@ const stale=projectTrafficObservations({...row,observations:obs},at+90_001);asse assert.equal(projectTrafficObservations({...row,observations:{...obs,currentState:"error"}},at).rxNow,null) for(const change of [{rxNow:-1},{observations:{...obs,sampledAt:"bad"}},{observations:{...obs,sampledAt:null}},{observations:{...obs,rxSeries:[]}}])assert.throws(()=>projectTrafficObservations({...row,...change},at)) console.log("traffic observations nullable/zero/gaps/expiry guards tests ok") +const noPeak=projectTrafficObservations({...row,volumeUnit:"GiB",observations:{...obs,rxPeak:false,txPeak:false}},at) +assert.equal(noPeak.rxPeak,null);assert.equal(noPeak.txPeak,null);assert.equal(noPeak.rxTotal,0) +assert.equal(projectTrafficObservations({...row,observations:{...obs,rxPeak:true,txPeak:true}},at).rxPeak,0) +console.log('aggregate peak confidence overrides bucket confidence; measured zero and volumes retained') diff --git a/lib/traffic-observations.ts b/lib/traffic-observations.ts index 5af232bd..896bdd8d 100644 --- a/lib/traffic-observations.ts +++ b/lib/traffic-observations.ts @@ -2,6 +2,7 @@ import { z } from "zod" const timestamp = z.string().refine(v => Number.isFinite(Date.parse(v))).nullable() const rate = z.number().finite().nonnegative().nullable() const meta = z.object({ rxNow: z.boolean(), txNow: z.boolean(), rxSeries: z.array(z.boolean()), txSeries: z.array(z.boolean()), + rxPeak: z.boolean().optional(), txPeak: z.boolean().optional(), sampledAt: timestamp, expiresAt: timestamp.optional(), lastAttemptAt: timestamp.optional(), lastSucceededAt: timestamp.optional(), error: z.string().nullable().optional(), currentState: z.enum(["current", "unknown", "pending", "error", "stale", "disabled"]).optional() }) export type TrafficObservationMeta = z.infer @@ -19,7 +20,7 @@ export function projectTrafficObservations(raw: unknown, now = Date.now()) { const rxSeries = r.rxSeries.map((v, i) => o?.rxSeries[i] ? v : null) const txSeries = r.txSeries.map((v, i) => o?.txSeries[i] ? v : null) return { observations: o, volumeUnit: r.volumeUnit, rxNow: current && o?.rxNow ? r.rxNow : null, txNow: current && o?.txNow ? r.txNow : null, - rxSeries, txSeries, rxPeak: rxSeries.some(v => v !== null) ? r.rxPeak : null, - txPeak: txSeries.some(v => v !== null) ? r.txPeak : null, + rxSeries, txSeries, rxPeak: (o?.rxPeak ?? rxSeries.some(v => v !== null)) ? r.rxPeak : null, + txPeak: (o?.txPeak ?? txSeries.some(v => v !== null)) ? r.txPeak : null, rxTotal: r.volumeUnit && rxSeries.some(v => v !== null) ? r.rxTotal : null, txTotal: r.volumeUnit && txSeries.some(v => v !== null) ? r.txTotal : null } } diff --git a/tests/e2e/traffic-peak-confidence.spec.ts b/tests/e2e/traffic-peak-confidence.spec.ts new file mode 100644 index 00000000..cb3c147a --- /dev/null +++ b/tests/e2e/traffic-peak-confidence.spec.ts @@ -0,0 +1,25 @@ +import {test,expect} from '@playwright/test' +for(const width of [1440,320])test(`Пик трафика: неизвестный интервал, подтверждённый пик и ноль ${width}`,async({page})=>{ + await page.setViewportSize({width,height:1000}) + let peakKnown=false,peak=100 + const server=()=>({id:'1',name:'Пик CHR',site:'TEST',country:'RU',status:'online',volumeUnit:'GiB',sessions:1, + rxNow:0,txNow:0,rxPeak:peak,txPeak:peak,rxTotal:1,txTotal:1,rxSeries:[0,100],txSeries:[0,100], + observations:{rxNow:true,txNow:true,rxPeak:peakKnown,txPeak:peakKnown,rxSeries:[false,true],txSeries:[false,true],sampledAt:'2026-10-13T00:00:00Z'}}) + await page.route('**/health',r=>r.fulfill({json:{ok:true}})) + await page.route('**/api/**',r=>{ + const p=new URL(r.request().url()).pathname + if(p.endsWith('/live'))return r.fulfill({status:503,json:{error:'Fixture без live'}}) + return r.fulfill({json:p==='/api/auth/config'?{required:false}:p==='/api/traffic/servers'?{servers:[server()]}: + p==='/api/traffic/servers/1'?{server:server()}:p.endsWith('/interfaces')||p==='/api/traffic/bound-interfaces'?{interfaces:[]}: + p==='/api/traffic/users'?{users:[]}:p==='/api/servers'?[]:{}}) + }) + await page.goto('/traffic') + const peakCard=page.locator('[data-slot="frame-panel"]').filter({has:page.getByText('Пик RX',{exact:true})}).first() + await expect(peakCard).toContainText('—') + await expect(page.getByRole('group',{name:'Учтённый объём по измерениям'})).toContainText('1 ГиБ') + peakKnown=true;await page.getByRole('button',{name:'15м',exact:true}).click() + await expect(peakCard).toContainText('100') + peak=0;await page.getByRole('button',{name:'24ч',exact:true}).click() + await expect(peakCard).toContainText('0') + expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth+1)).toBe(true) +})