diff --git a/app/(main)/gre/page.tsx b/app/(main)/gre/page.tsx
index 191f019c..cb8b846f 100644
--- a/app/(main)/gre/page.tsx
+++ b/app/(main)/gre/page.tsx
@@ -357,6 +357,10 @@ function GrePageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, on
setFormError("Для IPsec нужен PSK не короче 8 символов")
return
}
+ if (![tForm.keepaliveInterval, tForm.keepaliveRetries].every(value => Number.isInteger(value) && value >= 1 && value <= 4294967295)) {
+ setFormError("Keepalive и число попыток: целые значения от 1 до 4294967295. Ноль не поддерживается этим API.")
+ return
+ }
if (!beginOperation(tForm.serverId)) { setFormError("Устройство не готово к изменению GRE; повторите опрос"); return }
formLock.current = true
try {
@@ -885,11 +889,11 @@ function GrePageContent({ selectedServerId, selectedTunnelId, allTunnelsHref, on
setT("mtu", Number(e.target.value))} />
-
- setT("keepaliveInterval", Number(e.target.value))} />
+
+ setT("keepaliveInterval", Number(e.target.value))} />
- setT("keepaliveRetries", Number(e.target.value))} />
+ setT("keepaliveRetries", Number(e.target.value))} />
diff --git a/app/(main)/network-map/page.tsx b/app/(main)/network-map/page.tsx
index 45ea1033..d7dc89a5 100644
--- a/app/(main)/network-map/page.tsx
+++ b/app/(main)/network-map/page.tsx
@@ -125,7 +125,7 @@ interface ApiGreTunnelRow {
localInnerIp: string
remoteInnerIp: string
poolId: string
- ipsec: null
+ ipsec: { secret: "" } | null
mtu: number
keepaliveInterval: number
keepaliveRetries: number
@@ -147,7 +147,7 @@ function apiGreToGreTunnel(t: ApiGreTunnelRow): GreTunnel {
localInnerIp: t.localInnerIp,
remoteInnerIp: t.remoteInnerIp,
poolId: t.poolId || "live",
- ipsec: null,
+ ipsec: t.ipsec,
mtu: t.mtu,
keepaliveInterval: t.keepaliveInterval,
keepaliveRetries: t.keepaliveRetries,
diff --git a/backend/package.json b/backend/package.json
index 3f45cf6e..9ab61d55 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -29,7 +29,7 @@
"test:scheduler": "tsx src/services/scheduler-running.test.ts && tsx src/services/scheduler-recorded-run.test.ts && tsx src/routes/scheduler.test.ts",
"test:backups": "tsx src/services/backup-scheduler-run.test.ts && tsx src/services/backup-restore.test.ts && tsx src/services/backup-deletion.test.ts && tsx src/services/backup-dto.test.ts && tsx src/services/backup-storage-update.test.ts && tsx src/services/backup-job-execution.test.ts && tsx src/routes/backups-operations.test.ts && tsx src/services/s3-backup-client.test.ts",
"test:ipsec": "tsx src/services/ipsec-config.test.ts && tsx src/services/ipsec-state.test.ts && tsx src/routes/ipsec-history.test.ts && tsx src/services/ipsec-restore.test.ts && tsx src/services/ipsec-operation.test.ts && tsx src/routes/ipsec-mutation.test.ts && tsx src/routes/ipsec-nat.test.ts && tsx src/routes/ipsec-group.test.ts",
- "test:live-maps": "tsx src/services/gre-read.test.ts && tsx src/services/ospf-route-parse.test.ts && tsx src/services/vxlan-live.test.ts && tsx src/routes/vxlan.test.ts && tsx src/services/containers-live.test.ts && tsx src/services/firewall-poll.test.ts && tsx src/services/gre-catalog-poll.test.ts && tsx src/routes/filters-gre-catalog.test.ts && tsx src/routes/bgp-catalog.test.ts && tsx src/services/bgp-catalog-parse.test.ts && tsx src/routes/ospf-catalog.test.ts && tsx src/services/ospf-observed-values.test.ts",
+ "test:live-maps": "tsx src/services/gre-keepalive.test.ts && tsx src/services/gre-read.test.ts && tsx src/services/ospf-route-parse.test.ts && tsx src/services/vxlan-live.test.ts && tsx src/routes/vxlan.test.ts && tsx src/services/containers-live.test.ts && tsx src/services/firewall-poll.test.ts && tsx src/services/gre-catalog-poll.test.ts && tsx src/routes/filters-gre-catalog.test.ts && tsx src/routes/bgp-catalog.test.ts && tsx src/services/bgp-catalog-parse.test.ts && tsx src/routes/ospf-catalog.test.ts && tsx src/services/ospf-observed-values.test.ts",
"test": "node scripts/test.mjs",
"test:evolution": "tsx src/services/evobgp-catalog.test.ts && tsx src/routes/evobgp-catalog.test.ts && tsx src/routes/evobgp-settings.test.ts && tsx src/plugins/auth.evolution-settings.test.ts",
"test:netflow-purge": "tsx src/db/operation-lock.test.ts && tsx src/services/traffic-flow-purge-execution.test.ts && tsx src/routes/traffic-flow-purge.test.ts",
diff --git a/backend/scripts/acceptance/gre-keepalive-sql.mjs b/backend/scripts/acceptance/gre-keepalive-sql.mjs
new file mode 100644
index 00000000..c16bc2ea
--- /dev/null
+++ b/backend/scripts/acceptance/gre-keepalive-sql.mjs
@@ -0,0 +1,18 @@
+import assert from 'node:assert/strict'
+import fs from 'node:fs'
+import {createServer} from 'node:http'
+import {randomBytes} from 'node:crypto'
+const database=process.env.MMAPP_OWN_SQL_DB,url=new URL(process.env.DATABASE_URL)
+assert(/^mm_accept_166_\d+$/.test(database??''));assert.equal(url.pathname,'/'+database);assert.equal(url.username,database)
+process.env.AUTH_REQUIRED='true';process.env.AUTH_JWT_SECRET=randomBytes(32).toString('hex');process.env.AUTH_ISSUER='https://own210.invalid';process.env.AUTH_PORTAL_URL='https://own210.invalid'
+const {pool,closePool}=await import('/app/backend/dist/db/index.js'),{initDatabase}=await import('/app/backend/dist/db/bootstrap.js'),{buildApp}=await import('/app/backend/dist/index.js')
+assert.equal((await pool.query('SELECT current_database() AS name')).rows[0].name,database);assert(Object.values((await pool.query('SELECT rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user')).rows[0]).every(v=>v===false))
+
+const rows=[],writes=[],cases=[];let app,serverId,nativeCalls=0;
+const native=createServer(async(req,res)=>{nativeCalls++;let text='';for await(const chunk of req)text+=chunk;const body=text?JSON.parse(text):{};res.setHeader('content-type','application/json');if(req.method==='GET'){res.end(JSON.stringify(req.url.endsWith('/interface/gre')?rows:[]));return}writes.push({method:req.method,path:req.url,body});if(req.method==='PUT'){const row={...body,'.id':'*'+(rows.length+1),running:'false'};rows.push(row);res.end(JSON.stringify(row));return}if(req.method==='PATCH'){const id=decodeURIComponent(req.url.split('/').pop()),row=rows.find(r=>r['.id']===id);assert(row);Object.assign(row,body);res.end(JSON.stringify(row));return}res.statusCode=500;res.end('{}')});await new Promise(r=>native.listen(0,'127.0.0.1',r));
+const report={date:'2026-10-13',block:'12.5.210',database,cases,scope:'Production compiled GRE create/patch using isolated PostgreSQL and native HTTP fixture',passed:false};
+try{await initDatabase();serverId=Number((await pool.query("INSERT INTO servers(name,host,port,use_ssl,enabled,username,password) VALUES('own210-native','127.0.0.1',$1,false,true,'fixture','fixture') RETURNING id",[native.address().port])).rows[0].id);app=await buildApp({logger:false,startScheduler:false});await app.ready();const token=app.jwt.sign({sub:'own210-writer',apps:['mm'],permissions:['mm:network:write'],iss:process.env.AUTH_ISSUER},{expiresIn:'5m'}),headers={authorization:'Bearer '+token};
+for(const field of ['keepaliveInterval','keepaliveRetries'])for(const value of [0,-1,1.5,4294967296]){const before=nativeCalls;const r=await app.inject({method:'POST',url:'/api/gre/tunnels',headers,payload:{serverId:String(serverId),name:'invalid',remoteAddress:'192.0.2.2',[field]:value}});assert.equal(r.statusCode,400);assert.equal(nativeCalls,before);cases.push({field,value,status:400,nativeCalls:0})}
+for(const params of [{},{keepaliveInterval:60},{keepaliveRetries:3},{keepaliveInterval:90,keepaliveRetries:7}]){const name='own210-'+rows.length;const r=await app.inject({method:'POST',url:'/api/gre/tunnels',headers,payload:{serverId:String(serverId),name,remoteAddress:'192.0.2.2',enabled:false,...params}});assert.equal(r.statusCode,201);const expected=(params.keepaliveInterval??10)+'s,'+(params.keepaliveRetries??10);assert.equal(rows.at(-1).keepalive,expected);cases.push({operation:'create',params,keepalive:expected,status:201})}
+rows[0].keepalive='1m,3';const patch=await app.inject({method:'PATCH',url:'/api/gre/tunnels',headers,payload:{serverId:String(serverId),rosId:rows[0]['.id'],comment:'own210 updated'}});assert.equal(patch.statusCode,200);assert.equal(rows[0].keepalive,'1m,3');assert.equal(rows[0].comment,'own210 updated');cases.push({operation:'patch-other-field',nativeKeepalivePreserved:'1m,3',status:200});const read=await app.inject({method:'GET',url:'/api/gre/tunnels?serverId='+serverId,headers});assert.equal(read.statusCode,200);assert.equal(read.json().tunnels.find(t=>t.name===rows[0].name).keepaliveInterval,60);cases.push({operation:'read-minutes',seconds:60,status:200});report.passed=true;report.nativeWrites=writes.length;
+}catch(e){report.errorName=e.name;fs.writeFileSync('/app/backend/acceptance/gre210-private.log',String(e.stack??e),{mode:0o600})}finally{if(app)await app.close();native.closeAllConnections();await new Promise(r=>native.close(r));await closePool();fs.writeFileSync('/app/backend/acceptance/gre210-keepalive-result.json',JSON.stringify(report,null,2));console.log(JSON.stringify(report))}if(!report.passed)process.exitCode=1;
diff --git a/backend/src/routes/filters.ts b/backend/src/routes/filters.ts
index 1f15b39a..d0d230fb 100644
--- a/backend/src/routes/filters.ts
+++ b/backend/src/routes/filters.ts
@@ -5,6 +5,7 @@ import { db } from "../db/index.js"
import { filterRules, recursiveRoutes, servers } from "../db/schema.js"
import { MikrotikClient } from "../services/mikrotik.js"
import { pollGreCatalog } from "../services/gre-catalog-poll.js"
+import { parseKeepalive } from "../services/gre-live.js"
import { parseDbServerId } from "../utils/server-id.js"
import { appendEvent } from "../modules/events/service/events-service.js"
import { managedComment } from "../managed-markers.js"
@@ -74,17 +75,6 @@ interface ApiFilterRule {
description: string
}
-function parseKeepalive(value: string | undefined): { interval: number; retries: number } {
- if (!value || value.toLowerCase() === "none") return { interval: 0, retries: 0 }
- const [intervalRaw, retriesRaw] = value.split(",")
- const interval = Number.parseInt((intervalRaw ?? "").trim(), 10)
- const retries = Number.parseInt((retriesRaw ?? "").trim(), 10)
- return {
- interval: Number.isFinite(interval) ? interval : 0,
- retries: Number.isFinite(retries) ? retries : 0,
- }
-}
-
function parseDscp(value: string | undefined): "inherit" | number {
if (!value || value === "inherit") return "inherit"
const n = Number.parseInt(value, 10)
diff --git a/backend/src/routes/gre.ts b/backend/src/routes/gre.ts
index b9d18935..6a53a5b6 100644
--- a/backend/src/routes/gre.ts
+++ b/backend/src/routes/gre.ts
@@ -43,8 +43,8 @@ const TunnelWriteSchema = z.object({
comment: z.string().optional(),
enabled: z.boolean().optional(),
mtu: z.number().optional(),
- keepaliveInterval: z.number().optional(),
- keepaliveRetries: z.number().optional(),
+ keepaliveInterval: z.number().int().min(1).max(4294967295).optional(),
+ keepaliveRetries: z.number().int().min(1).max(4294967295).optional(),
dscp: z.union([z.literal("inherit"), z.number(), z.string()]).optional(),
clampTcpMss: z.boolean().optional(),
allowFastPath: z.boolean().optional(),
@@ -84,9 +84,7 @@ function tunnelFromBody(body: z.infer & { keepaliveInt
: typeof body.dscp === "number"
? String(body.dscp)
: body.dscp
- const keepalive = body.keepaliveInterval === undefined && body.keepaliveRetries === undefined
- ? undefined
- : formatKeepalive(body.keepaliveInterval ?? 0, body.keepaliveRetries ?? 10)
+ const keepalive = formatKeepalive(body.keepaliveInterval ?? 10, body.keepaliveRetries ?? 10)
return canonicalGreSnapshot({
tunnels: [{
name: body.name,
@@ -97,7 +95,7 @@ function tunnelFromBody(body: z.infer & { keepaliveInt
comment: body.remoteInnerIp === undefined ? body.comment ?? "" : writeGreComment(body.comment ?? "", body.remoteInnerIp),
disabled: body.enabled === false,
mtu: body.mtu ?? 1476,
- keepalive: keepalive ?? "0",
+ keepalive,
dscp,
clampTcpMss: body.clampTcpMss,
allowFastPath: body.allowFastPath,
@@ -173,6 +171,10 @@ const greRoutes: FastifyPluginAsyncZod = async (app) => {
allowFastPath: body.allowFastPath ?? live.allowFastPath,
ipsecSecret: body.ipsecSecret ?? live.ipsecSecret,
})
+ // A patch to another field must not reformat an observed native timer.
+ if (body.keepaliveInterval === undefined && body.keepaliveRetries === undefined) {
+ merged.keepalive = original.keepalive
+ }
merged.innerAddresses = original.innerAddresses?.map(a => ({ ...a }))
if (body.localInnerIp !== undefined && body.localInnerIp !== original.localInnerIp) {
merged.innerAddresses = (merged.innerAddresses ?? []).filter(a => a.address !== original.localInnerIp)
diff --git a/backend/src/services/gre-keepalive.test.ts b/backend/src/services/gre-keepalive.test.ts
new file mode 100644
index 00000000..9af1d930
--- /dev/null
+++ b/backend/src/services/gre-keepalive.test.ts
@@ -0,0 +1,9 @@
+import assert from "node:assert/strict"
+import { parseKeepalive } from "./gre-live.js"
+
+for (const [native, seconds] of [["1m,3", 60], ["1m30s,3", 90], ["00:01:00,3", 60], ["1h2m3s,3", 3723], ["10s,3", 10], ["10,3", 10]] as const) {
+ assert.deepEqual(parseKeepalive(native), { interval: seconds, retries: 3 })
+}
+assert.deepEqual(parseKeepalive("invalid,3"), { interval: 0, retries: 3 })
+assert.deepEqual(parseKeepalive("10s,3garbage"), { interval: 10, retries: 0 })
+console.log("GRE keepalive: native units and clock parsed without prefix truncation")
diff --git a/backend/src/services/gre-live.ts b/backend/src/services/gre-live.ts
index c7951146..6b164224 100644
--- a/backend/src/services/gre-live.ts
+++ b/backend/src/services/gre-live.ts
@@ -3,6 +3,7 @@ import { db } from "../db/index.js"
import { servers } from "../db/schema.js"
import { MikrotikClient } from "./mikrotik.js"
import { readGreComment } from "./gre-comment.js"
+import { observedDurationMs, observedInteger } from "./ospf-observed-values.js"
import {
canonicalGreSnapshot,
greAddressPath,
@@ -69,11 +70,14 @@ export interface LiveGreTunnel {
export function parseKeepalive(value: string | undefined): { interval: number; retries: number } {
if (!value || value.toLowerCase() === "none") return { interval: 0, retries: 0 }
const [intervalRaw, retriesRaw] = value.split(",")
- const interval = Number.parseInt((intervalRaw ?? "").trim(), 10)
- const retries = Number.parseInt((retriesRaw ?? "").trim(), 10)
+ const intervalText = intervalRaw?.trim()
+ const interval = intervalText && /^\d+$/.test(intervalText)
+ ? observedInteger(intervalText)
+ : (observedDurationMs(intervalText) ?? 0) / 1000
+ const retries = observedInteger(retriesRaw)
return {
- interval: Number.isFinite(interval) ? interval : 0,
- retries: Number.isFinite(retries) ? retries : 0,
+ interval: interval ?? 0,
+ retries: retries ?? 0,
}
}
diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md
index 8416c79f..768a34e6 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: блок 209 завершён. GRE PSK скрыт от читателя; каталог Filters сохраняет признак настроенного IPsec без ключа. Пройдены 12 SQL/API-проверок, профиль live-maps, 4 E2E и 4 live UI-сценария. Два собственных отключённых GRE на CHR созданы и удалены. Backend/frontend: ux-gre209, 473/527 исходных файлов и 1048 compiled artifacts совпали. Следующий блок 210 — keepalive при создании GRE без явных параметров. Этап 12.5 открыт.
+Актуальное продолжение 2026-10-13: блок 210 завершён. GRE создаётся с default keepalive 10s,10; минутные значения читаются в секундах, PATCH другого поля сохраняет native timer. Валидатор каталога IPsec исправлен для Filters/карты/диагностики. Пройдены SQL/API14, E2E13 и live GRE/Filters UI4; собственные интерфейсы удалены. Backend/frontend ux-gre210, source475/527 и compiled1048 совпали. Срочный следующий блок 211 — auth/RBAC для закодированных URL; baseline анонимного обхода подтверждён. Этап 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).
@@ -2539,3 +2539,20 @@ Backend/frontend ux-gre209 развёрнуты; 473/527 source files и 1048 co
Следующий блок 210: исправить создание GRE с опущенным keepalive, проверить фактический RouterOS ответ и прежнее редактирование. Этап 12.5 открыт; внешние ограничения в актуальной матрице сохраняются.
+
+## 12.5.210 — GRE keepalive и совместимость публичного каталога (2026-10-13)
+
+На обоих CHR собственные отключённые интерфейсы подтвердили: native REST отклоняет 0, none, пустую строку, disabled, no и ноль попыток. Дробные интервалы принимаются, но сокращаются RouterOS до целых секунд. Поэтому форма и write schema требуют целые значения 1..4294967295 вместо обещания «0 = откл.». Неверный ввод сохраняет форму и не отправляет запрос. Официальный default 10s,10: [MikroTik GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE).
+
+Опущенные параметры создания теперь дают 10s,10; один заданный параметр сохраняется, второй получает default. Основной GET и каталог Filters используют общий разбор native единиц/clock: 1m = 60с, 1m30s = 90с. PATCH без параметров keepalive сохраняет исходную строку snapshot, не преобразует таймер при изменении комментария/PSK. Legacy snapshots не переписаны; произвольные legacy/unknown timers и их экспорт не приняты этим блоком.
+
+Аудит потребителей выявил несовместимость 209: shared schema Filters допускала только ipsec:null. Теперь она принимает {secret:""} или null, отвергает реальный ключ. Карта сохраняет configured IPsec; Filters и диагностика используют обновлённую схему. ReUI primitives и theme не менялись.
+
+Проверки: 24 direct native syntax cases на отключённых собственных GRE, с очисткой; production SQL/API14 на собственной ограниченной DB/role, включая 8 invalid cases до native requests, четыре создания, сохранение native timer и чтение минут. SQL DB/role/container удалены. Профиль live-maps, schema unit, 5 network-map units, TypeScript/backend build/ESLint прошли. 13 уникальных E2E: GRE формы/PSK/валидация9 и Filters gateway/retry4. Копии fixtures имеют configured IPsec; прежние повторные действия сохранены.
+
+Runtime ux-gre210: backend healthy, source475/527 и compiled1048 matched. На каждом CHR приложение создало отключённый GRE без keepalive и с явным allowFastPath=false для PSK; native default10s,10 подтверждён. После native 1m,3 GET показывает60с, PATCH комментария сохраняет1m,3, explicit0 даёт400 без изменения native. Два UI GRE и два UI Filters на1440/320 проверили форму, отсутствие запроса при invalid input и доступность собственного GRE с IPsec в каталоге шлюзов. Оба интерфейса удалены, отсутствие проверено. Пароли не менялись; это не data-plane test.
+
+Два первых create с PSK и опущенным allowFastPath получили502: текущий API default FastPath несовместим с PSK. Это отдельное обнаруженное ограничение, не скрытое успешным повтором; дальнейшая проверка задала false явно. Следующий приоритет211 — подтверждённый обход auth через encoded API prefix. После него исправить FastPath/PSK default и экспорт недопустимого/неизвестного keepalive.
+
+Протоколы: [native syntax](ux-ui/acceptance/gre210-native-range-2026-10-13.json), [дополнительный синтаксис](ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json), [SQL/API14](ux-ui/acceptance/gre210-keepalive-result.json), [профили](ux-ui/acceptance/gre210-profile-2026-10-13.json), [E2E13](ux-ui/acceptance/gre210-e2e-2026-10-13.json), [native/UI/cleanup](ux-ui/acceptance/gre210-native-live-2026-10-13.json), [source](ux-ui/acceptance/source210-result.json), [compiled](ux-ui/acceptance/compiled210-result.json), [deployment](ux-ui/acceptance/gre210-deployment-2026-10-13.json).
+
diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md
index 53a2c9ab..99a86e5f 100644
--- a/docs/ux-ui-plan.md
+++ b/docs/ux-ui-plan.md
@@ -1,6 +1,6 @@
# План реализации UX/UI по пятичасовым окнам
-Актуальное продолжение 2026-10-13: блок 209 завершён. GRE PSK скрыт от читателя; каталог Filters сохраняет признак настроенного IPsec без ключа. Пройдены 12 SQL/API-проверок, профиль live-maps, 4 E2E и 4 live UI-сценария. Два собственных отключённых GRE на CHR созданы и удалены. Backend/frontend: ux-gre209, 473/527 исходных файлов и 1048 compiled artifacts совпали. Следующий блок 210 — keepalive при создании GRE без явных параметров. Этап 12.5 открыт.
+Актуальное продолжение 2026-10-13: блок 210 завершён. GRE создаётся с default keepalive 10s,10; минутные значения читаются в секундах, PATCH другого поля сохраняет native timer. Валидатор каталога IPsec исправлен для Filters/карты/диагностики. Пройдены SQL/API14, E2E13 и live GRE/Filters UI4; собственные интерфейсы удалены. Backend/frontend ux-gre210, source475/527 и compiled1048 совпали. Срочный следующий блок 211 — auth/RBAC для закодированных URL; baseline анонимного обхода подтверждён. Этап 12.5 открыт.
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-13. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md
index 4294959d..cecfab36 100644
--- a/docs/ux-ui-progress.md
+++ b/docs/ux-ui-progress.md
@@ -1,6 +1,6 @@
# UX/UI: журнал реализации
-Актуальное продолжение 2026-10-13: блок 209 завершён. GRE PSK скрыт от читателя; каталог Filters сохраняет признак настроенного IPsec без ключа. Пройдены 12 SQL/API-проверок, профиль live-maps, 4 E2E и 4 live UI-сценария. Два собственных отключённых GRE на CHR созданы и удалены. Backend/frontend: ux-gre209, 473/527 исходных файлов и 1048 compiled artifacts совпали. Следующий блок 210 — keepalive при создании GRE без явных параметров. Этап 12.5 открыт.
+Актуальное продолжение 2026-10-13: блок 210 завершён. GRE создаётся с default keepalive 10s,10; минутные значения читаются в секундах, PATCH другого поля сохраняет native timer. Валидатор каталога IPsec исправлен для Filters/карты/диагностики. Пройдены SQL/API14, E2E13 и live GRE/Filters UI4; собственные интерфейсы удалены. Backend/frontend ux-gre210, source475/527 и compiled1048 совпали. Срочный следующий блок 211 — auth/RBAC для закодированных URL; baseline анонимного обхода подтверждён. Этап 12.5 открыт.
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
@@ -38,6 +38,22 @@
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–196 и ограничения ниже. Runtime backend/frontend ux-peak196. |
+## 12.5.210 — GRE keepalive и совместимость публичного каталога (2026-10-13)
+
+На обоих CHR собственные отключённые интерфейсы подтвердили: native REST отклоняет 0, none, пустую строку, disabled, no и ноль попыток. Дробные интервалы принимаются, но сокращаются RouterOS до целых секунд. Поэтому форма и write schema требуют целые значения 1..4294967295 вместо обещания «0 = откл.». Неверный ввод сохраняет форму и не отправляет запрос. Официальный default 10s,10: [MikroTik GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE).
+
+Опущенные параметры создания теперь дают 10s,10; один заданный параметр сохраняется, второй получает default. Основной GET и каталог Filters используют общий разбор native единиц/clock: 1m = 60с, 1m30s = 90с. PATCH без параметров keepalive сохраняет исходную строку snapshot, не преобразует таймер при изменении комментария/PSK. Legacy snapshots не переписаны; произвольные legacy/unknown timers и их экспорт не приняты этим блоком.
+
+Аудит потребителей выявил несовместимость 209: shared schema Filters допускала только ipsec:null. Теперь она принимает {secret:""} или null, отвергает реальный ключ. Карта сохраняет configured IPsec; Filters и диагностика используют обновлённую схему. ReUI primitives и theme не менялись.
+
+Проверки: 24 direct native syntax cases на отключённых собственных GRE, с очисткой; production SQL/API14 на собственной ограниченной DB/role, включая 8 invalid cases до native requests, четыре создания, сохранение native timer и чтение минут. SQL DB/role/container удалены. Профиль live-maps, schema unit, 5 network-map units, TypeScript/backend build/ESLint прошли. 13 уникальных E2E: GRE формы/PSK/валидация9 и Filters gateway/retry4. Копии fixtures имеют configured IPsec; прежние повторные действия сохранены.
+
+Runtime ux-gre210: backend healthy, source475/527 и compiled1048 matched. На каждом CHR приложение создало отключённый GRE без keepalive и с явным allowFastPath=false для PSK; native default10s,10 подтверждён. После native 1m,3 GET показывает60с, PATCH комментария сохраняет1m,3, explicit0 даёт400 без изменения native. Два UI GRE и два UI Filters на1440/320 проверили форму, отсутствие запроса при invalid input и доступность собственного GRE с IPsec в каталоге шлюзов. Оба интерфейса удалены, отсутствие проверено. Пароли не менялись; это не data-plane test.
+
+Два первых create с PSK и опущенным allowFastPath получили502: текущий API default FastPath несовместим с PSK. Это отдельное обнаруженное ограничение, не скрытое успешным повтором; дальнейшая проверка задала false явно. Следующий приоритет211 — подтверждённый обход auth через encoded API prefix. После него исправить FastPath/PSK default и экспорт недопустимого/неизвестного keepalive.
+
+Протоколы: [native syntax](ux-ui/acceptance/gre210-native-range-2026-10-13.json), [дополнительный синтаксис](ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json), [SQL/API14](ux-ui/acceptance/gre210-keepalive-result.json), [профили](ux-ui/acceptance/gre210-profile-2026-10-13.json), [E2E13](ux-ui/acceptance/gre210-e2e-2026-10-13.json), [native/UI/cleanup](ux-ui/acceptance/gre210-native-live-2026-10-13.json), [source](ux-ui/acceptance/source210-result.json), [compiled](ux-ui/acceptance/compiled210-result.json), [deployment](ux-ui/acceptance/gre210-deployment-2026-10-13.json).
+
## 12.5.209 — доступ к GRE PSK и достоверность каталога IPsec (2026-10-13)
В production baseline читатель получал PSK через GET /gre/tunnels. Каталог /filters/gre-tunnels ключ не раскрывал, но всегда возвращал ipsec:null, скрывая сам факт настройки IPsec. Основной GET теперь копирует публичный DTO и очищает secret при отсутствии mm:network:write/admin; алгоритмы и наличие объекта IPsec сохраняются. Internal snapshot и право редактирования для writer/admin не меняются. is_admin без permission не даёт доступ к ключу. Legacy AUTH_REQUIRED=false сохранён. Общий каталог Filters возвращает только признак IPsec и пустой secret для всех ролей.
diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md
index a2f00668..9940b60b 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: блок 209 завершён. GRE PSK скрыт от читателя; каталог Filters сохраняет признак настроенного IPsec без ключа. Пройдены 12 SQL/API-проверок, профиль live-maps, 4 E2E и 4 live UI-сценария. Два собственных отключённых GRE на CHR созданы и удалены. Backend/frontend: ux-gre209, 473/527 исходных файлов и 1048 compiled artifacts совпали. Следующий блок 210 — keepalive при создании GRE без явных параметров. Этап 12.5 открыт.
+Актуальное продолжение 2026-10-13: блок 210 завершён. GRE создаётся с default keepalive 10s,10; минутные значения читаются в секундах, PATCH другого поля сохраняет native timer. Валидатор каталога IPsec исправлен для Filters/карты/диагностики. Пройдены SQL/API14, E2E13 и live GRE/Filters UI4; собственные интерфейсы удалены. Backend/frontend ux-gre210, source475/527 и compiled1048 совпали. Срочный следующий блок 211 — auth/RBAC для закодированных URL; baseline анонимного обхода подтверждён. Этап 12.5 открыт.
-Это актуальная матрица после 12.5.209. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
+Это актуальная матрица после 12.5.210. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
-Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend/frontend `ux-gre209`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
+Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend/frontend `ux-gre210`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
| Раздел | Подтверждено | Осталось / условие завершения |
| --- | --- | --- |
@@ -26,7 +26,7 @@
## Следующая последовательность — 2026-10-13
-1. **210 — GRE keepalive:** исправить значение по умолчанию создания, которое RouterOS отклоняет; проверить отсутствие неожиданных изменений при PATCH.
+1. **211 — canonical auth path:** закрыть обход JWT/RBAC через encoded API prefix; actual anonymous baseline200 сохранён без raw body/секретов. После него — FastPath/PSK default и экспорт неизвестного keepalive.
2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания.
3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций.
@@ -1457,3 +1457,20 @@ Backend/frontend ux-gre209 развёрнуты; 473/527 source files и 1048 co
Следующий блок 210: исправить создание GRE с опущенным keepalive, проверить фактический RouterOS ответ и прежнее редактирование. Этап 12.5 открыт; внешние ограничения в актуальной матрице сохраняются.
+
+## 12.5.210 — GRE keepalive и совместимость публичного каталога (2026-10-13)
+
+На обоих CHR собственные отключённые интерфейсы подтвердили: native REST отклоняет 0, none, пустую строку, disabled, no и ноль попыток. Дробные интервалы принимаются, но сокращаются RouterOS до целых секунд. Поэтому форма и write schema требуют целые значения 1..4294967295 вместо обещания «0 = откл.». Неверный ввод сохраняет форму и не отправляет запрос. Официальный default 10s,10: [MikroTik GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE).
+
+Опущенные параметры создания теперь дают 10s,10; один заданный параметр сохраняется, второй получает default. Основной GET и каталог Filters используют общий разбор native единиц/clock: 1m = 60с, 1m30s = 90с. PATCH без параметров keepalive сохраняет исходную строку snapshot, не преобразует таймер при изменении комментария/PSK. Legacy snapshots не переписаны; произвольные legacy/unknown timers и их экспорт не приняты этим блоком.
+
+Аудит потребителей выявил несовместимость 209: shared schema Filters допускала только ipsec:null. Теперь она принимает {secret:""} или null, отвергает реальный ключ. Карта сохраняет configured IPsec; Filters и диагностика используют обновлённую схему. ReUI primitives и theme не менялись.
+
+Проверки: 24 direct native syntax cases на отключённых собственных GRE, с очисткой; production SQL/API14 на собственной ограниченной DB/role, включая 8 invalid cases до native requests, четыре создания, сохранение native timer и чтение минут. SQL DB/role/container удалены. Профиль live-maps, schema unit, 5 network-map units, TypeScript/backend build/ESLint прошли. 13 уникальных E2E: GRE формы/PSK/валидация9 и Filters gateway/retry4. Копии fixtures имеют configured IPsec; прежние повторные действия сохранены.
+
+Runtime ux-gre210: backend healthy, source475/527 и compiled1048 matched. На каждом CHR приложение создало отключённый GRE без keepalive и с явным allowFastPath=false для PSK; native default10s,10 подтверждён. После native 1m,3 GET показывает60с, PATCH комментария сохраняет1m,3, explicit0 даёт400 без изменения native. Два UI GRE и два UI Filters на1440/320 проверили форму, отсутствие запроса при invalid input и доступность собственного GRE с IPsec в каталоге шлюзов. Оба интерфейса удалены, отсутствие проверено. Пароли не менялись; это не data-plane test.
+
+Два первых create с PSK и опущенным allowFastPath получили502: текущий API default FastPath несовместим с PSK. Это отдельное обнаруженное ограничение, не скрытое успешным повтором; дальнейшая проверка задала false явно. Следующий приоритет211 — подтверждённый обход auth через encoded API prefix. После него исправить FastPath/PSK default и экспорт недопустимого/неизвестного keepalive.
+
+Протоколы: [native syntax](ux-ui/acceptance/gre210-native-range-2026-10-13.json), [дополнительный синтаксис](ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json), [SQL/API14](ux-ui/acceptance/gre210-keepalive-result.json), [профили](ux-ui/acceptance/gre210-profile-2026-10-13.json), [E2E13](ux-ui/acceptance/gre210-e2e-2026-10-13.json), [native/UI/cleanup](ux-ui/acceptance/gre210-native-live-2026-10-13.json), [source](ux-ui/acceptance/source210-result.json), [compiled](ux-ui/acceptance/compiled210-result.json), [deployment](ux-ui/acceptance/gre210-deployment-2026-10-13.json).
+
diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md
index f1e41446..17d0e056 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: блок 209 завершён. GRE PSK скрыт от читателя; каталог Filters сохраняет признак настроенного IPsec без ключа. Пройдены 12 SQL/API-проверок, профиль live-maps, 4 E2E и 4 live UI-сценария. Два собственных отключённых GRE на CHR созданы и удалены. Backend/frontend: ux-gre209, 473/527 исходных файлов и 1048 compiled artifacts совпали. Следующий блок 210 — keepalive при создании GRE без явных параметров. Этап 12.5 открыт.
+Актуальное продолжение 2026-10-13: блок 210 завершён. GRE создаётся с default keepalive 10s,10; минутные значения читаются в секундах, PATCH другого поля сохраняет native timer. Валидатор каталога IPsec исправлен для Filters/карты/диагностики. Пройдены SQL/API14, E2E13 и live GRE/Filters UI4; собственные интерфейсы удалены. Backend/frontend ux-gre210, source475/527 и compiled1048 совпали. Срочный следующий блок 211 — auth/RBAC для закодированных URL; baseline анонимного обхода подтверждён. Этап 12.5 открыт.
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
@@ -3846,3 +3846,20 @@ Backend/frontend ux-gre209 развёрнуты; 473/527 source files и 1048 co
Следующий блок 210: исправить создание GRE с опущенным keepalive, проверить фактический RouterOS ответ и прежнее редактирование. Этап 12.5 открыт; внешние ограничения в актуальной матрице сохраняются.
+
+## 12.5.210 — GRE keepalive и совместимость публичного каталога (2026-10-13)
+
+На обоих CHR собственные отключённые интерфейсы подтвердили: native REST отклоняет 0, none, пустую строку, disabled, no и ноль попыток. Дробные интервалы принимаются, но сокращаются RouterOS до целых секунд. Поэтому форма и write schema требуют целые значения 1..4294967295 вместо обещания «0 = откл.». Неверный ввод сохраняет форму и не отправляет запрос. Официальный default 10s,10: [MikroTik GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE).
+
+Опущенные параметры создания теперь дают 10s,10; один заданный параметр сохраняется, второй получает default. Основной GET и каталог Filters используют общий разбор native единиц/clock: 1m = 60с, 1m30s = 90с. PATCH без параметров keepalive сохраняет исходную строку snapshot, не преобразует таймер при изменении комментария/PSK. Legacy snapshots не переписаны; произвольные legacy/unknown timers и их экспорт не приняты этим блоком.
+
+Аудит потребителей выявил несовместимость 209: shared schema Filters допускала только ipsec:null. Теперь она принимает {secret:""} или null, отвергает реальный ключ. Карта сохраняет configured IPsec; Filters и диагностика используют обновлённую схему. ReUI primitives и theme не менялись.
+
+Проверки: 24 direct native syntax cases на отключённых собственных GRE, с очисткой; production SQL/API14 на собственной ограниченной DB/role, включая 8 invalid cases до native requests, четыре создания, сохранение native timer и чтение минут. SQL DB/role/container удалены. Профиль live-maps, schema unit, 5 network-map units, TypeScript/backend build/ESLint прошли. 13 уникальных E2E: GRE формы/PSK/валидация9 и Filters gateway/retry4. Копии fixtures имеют configured IPsec; прежние повторные действия сохранены.
+
+Runtime ux-gre210: backend healthy, source475/527 и compiled1048 matched. На каждом CHR приложение создало отключённый GRE без keepalive и с явным allowFastPath=false для PSK; native default10s,10 подтверждён. После native 1m,3 GET показывает60с, PATCH комментария сохраняет1m,3, explicit0 даёт400 без изменения native. Два UI GRE и два UI Filters на1440/320 проверили форму, отсутствие запроса при invalid input и доступность собственного GRE с IPsec в каталоге шлюзов. Оба интерфейса удалены, отсутствие проверено. Пароли не менялись; это не data-plane test.
+
+Два первых create с PSK и опущенным allowFastPath получили502: текущий API default FastPath несовместим с PSK. Это отдельное обнаруженное ограничение, не скрытое успешным повтором; дальнейшая проверка задала false явно. Следующий приоритет211 — подтверждённый обход auth через encoded API prefix. После него исправить FastPath/PSK default и экспорт недопустимого/неизвестного keepalive.
+
+Протоколы: [native syntax](ux-ui/acceptance/gre210-native-range-2026-10-13.json), [дополнительный синтаксис](ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json), [SQL/API14](ux-ui/acceptance/gre210-keepalive-result.json), [профили](ux-ui/acceptance/gre210-profile-2026-10-13.json), [E2E13](ux-ui/acceptance/gre210-e2e-2026-10-13.json), [native/UI/cleanup](ux-ui/acceptance/gre210-native-live-2026-10-13.json), [source](ux-ui/acceptance/source210-result.json), [compiled](ux-ui/acceptance/compiled210-result.json), [deployment](ux-ui/acceptance/gre210-deployment-2026-10-13.json).
+
diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md
index 3f73146c..8401ba36 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: блок 209 завершён. GRE PSK скрыт от читателя; каталог Filters сохраняет признак настроенного IPsec без ключа. Пройдены 12 SQL/API-проверок, профиль live-maps, 4 E2E и 4 live UI-сценария. Два собственных отключённых GRE на CHR созданы и удалены. Backend/frontend: ux-gre209, 473/527 исходных файлов и 1048 compiled artifacts совпали. Следующий блок 210 — keepalive при создании GRE без явных параметров. Этап 12.5 открыт.
+Актуальное продолжение 2026-10-13: блок 210 завершён. GRE создаётся с default keepalive 10s,10; минутные значения читаются в секундах, PATCH другого поля сохраняет native timer. Валидатор каталога IPsec исправлен для Filters/карты/диагностики. Пройдены SQL/API14, E2E13 и live GRE/Filters UI4; собственные интерфейсы удалены. Backend/frontend ux-gre210, source475/527 и compiled1048 совпали. Срочный следующий блок 211 — auth/RBAC для закодированных URL; baseline анонимного обхода подтверждён. Этап 12.5 открыт.
| Параметр | Проверенное состояние |
| --- | --- |
@@ -2270,3 +2270,20 @@ Backend/frontend ux-gre209 развёрнуты; 473/527 source files и 1048 co
Следующий блок 210: исправить создание GRE с опущенным keepalive, проверить фактический RouterOS ответ и прежнее редактирование. Этап 12.5 открыт; внешние ограничения в актуальной матрице сохраняются.
+
+## 12.5.210 — GRE keepalive и совместимость публичного каталога (2026-10-13)
+
+На обоих CHR собственные отключённые интерфейсы подтвердили: native REST отклоняет 0, none, пустую строку, disabled, no и ноль попыток. Дробные интервалы принимаются, но сокращаются RouterOS до целых секунд. Поэтому форма и write schema требуют целые значения 1..4294967295 вместо обещания «0 = откл.». Неверный ввод сохраняет форму и не отправляет запрос. Официальный default 10s,10: [MikroTik GRE](https://help.mikrotik.com/docs/spaces/ROS/pages/24805531/GRE).
+
+Опущенные параметры создания теперь дают 10s,10; один заданный параметр сохраняется, второй получает default. Основной GET и каталог Filters используют общий разбор native единиц/clock: 1m = 60с, 1m30s = 90с. PATCH без параметров keepalive сохраняет исходную строку snapshot, не преобразует таймер при изменении комментария/PSK. Legacy snapshots не переписаны; произвольные legacy/unknown timers и их экспорт не приняты этим блоком.
+
+Аудит потребителей выявил несовместимость 209: shared schema Filters допускала только ipsec:null. Теперь она принимает {secret:""} или null, отвергает реальный ключ. Карта сохраняет configured IPsec; Filters и диагностика используют обновлённую схему. ReUI primitives и theme не менялись.
+
+Проверки: 24 direct native syntax cases на отключённых собственных GRE, с очисткой; production SQL/API14 на собственной ограниченной DB/role, включая 8 invalid cases до native requests, четыре создания, сохранение native timer и чтение минут. SQL DB/role/container удалены. Профиль live-maps, schema unit, 5 network-map units, TypeScript/backend build/ESLint прошли. 13 уникальных E2E: GRE формы/PSK/валидация9 и Filters gateway/retry4. Копии fixtures имеют configured IPsec; прежние повторные действия сохранены.
+
+Runtime ux-gre210: backend healthy, source475/527 и compiled1048 matched. На каждом CHR приложение создало отключённый GRE без keepalive и с явным allowFastPath=false для PSK; native default10s,10 подтверждён. После native 1m,3 GET показывает60с, PATCH комментария сохраняет1m,3, explicit0 даёт400 без изменения native. Два UI GRE и два UI Filters на1440/320 проверили форму, отсутствие запроса при invalid input и доступность собственного GRE с IPsec в каталоге шлюзов. Оба интерфейса удалены, отсутствие проверено. Пароли не менялись; это не data-plane test.
+
+Два первых create с PSK и опущенным allowFastPath получили502: текущий API default FastPath несовместим с PSK. Это отдельное обнаруженное ограничение, не скрытое успешным повтором; дальнейшая проверка задала false явно. Следующий приоритет211 — подтверждённый обход auth через encoded API prefix. После него исправить FastPath/PSK default и экспорт недопустимого/неизвестного keepalive.
+
+Протоколы: [native syntax](ux-ui/acceptance/gre210-native-range-2026-10-13.json), [дополнительный синтаксис](ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json), [SQL/API14](ux-ui/acceptance/gre210-keepalive-result.json), [профили](ux-ui/acceptance/gre210-profile-2026-10-13.json), [E2E13](ux-ui/acceptance/gre210-e2e-2026-10-13.json), [native/UI/cleanup](ux-ui/acceptance/gre210-native-live-2026-10-13.json), [source](ux-ui/acceptance/source210-result.json), [compiled](ux-ui/acceptance/compiled210-result.json), [deployment](ux-ui/acceptance/gre210-deployment-2026-10-13.json).
+
diff --git a/docs/ux-ui/acceptance/compiled210-result.json b/docs/ux-ui/acceptance/compiled210-result.json
new file mode 100644
index 00000000..ae678f5f
--- /dev/null
+++ b/docs/ux-ui/acceptance/compiled210-result.json
@@ -0,0 +1,1058 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "backendVersion": "1.0.0-test.gre210",
+ "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-read.js",
+ "backend/dist/services/gre-read.js.map",
+ "backend/dist/services/gre-read.d.ts",
+ "backend/dist/services/gre-read.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-lock.js",
+ "backend/dist/services/traffic-collection-lock.js.map",
+ "backend/dist/services/traffic-collection-lock.d.ts",
+ "backend/dist/services/traffic-collection-lock.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/gre210-deployment-2026-10-13.json b/docs/ux-ui/acceptance/gre210-deployment-2026-10-13.json
new file mode 100644
index 00000000..960baf7e
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-deployment-2026-10-13.json
@@ -0,0 +1,35 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "runtime": "ux-gre210",
+ "services": {
+ "backend": {
+ "image": "mmapp-test/backend:ux-gre210",
+ "imageId": "sha256:9bce7d7505145a6479cf2920240abacc5e38aa1aafacfd7c69f1fcaaf3a900a7",
+ "running": true,
+ "health": "healthy"
+ },
+ "frontend": {
+ "image": "mmapp-test/frontend:ux-gre210",
+ "imageId": "sha256:b4b1280f729e89de83b30bd242d37bda831306720b3c78cb9eef6048c3e3178e",
+ "running": true,
+ "health": null
+ }
+ },
+ "rollbackTags": {
+ "MMAPP_IMAGE_TAG": "ux-gre209",
+ "BACKEND_IMAGE_TAG": "ux-gre209"
+ },
+ "chrPasswordsChanged": false,
+ "source": [
+ {
+ "kind": "backend",
+ "matched": 475
+ },
+ {
+ "kind": "frontend",
+ "matched": 527
+ }
+ ],
+ "compiledMatched": 1048
+}
\ No newline at end of file
diff --git a/docs/ux-ui/acceptance/gre210-e2e-2026-10-13.json b/docs/ux-ui/acceptance/gre210-e2e-2026-10-13.json
new file mode 100644
index 00000000..1059af38
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-e2e-2026-10-13.json
@@ -0,0 +1,30 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "uniqueCases": 13,
+ "groups": [
+ {
+ "scope": "GRE keepalive, PSK and form receipts",
+ "stats": {
+ "startTime": "2026-10-13T13:54:18.301Z",
+ "duration": 22078.386000000002,
+ "expected": 9,
+ "skipped": 0,
+ "unexpected": 0,
+ "flaky": 0
+ }
+ },
+ {
+ "scope": "Filters gateway catalog masked-IPsec and original retry",
+ "stats": {
+ "startTime": "2026-10-13T13:59:12.012Z",
+ "duration": 15935.284,
+ "expected": 4,
+ "skipped": 0,
+ "unexpected": 0,
+ "flaky": 0
+ }
+ }
+ ],
+ "apiMocked": true
+}
diff --git a/docs/ux-ui/acceptance/gre210-keepalive-result.json b/docs/ux-ui/acceptance/gre210-keepalive-result.json
new file mode 100644
index 00000000..fa855e2e
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-keepalive-result.json
@@ -0,0 +1,100 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "database": "mm_accept_166_1791900297484",
+ "cases": [
+ {
+ "field": "keepaliveInterval",
+ "value": 0,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveInterval",
+ "value": -1,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveInterval",
+ "value": 1.5,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveInterval",
+ "value": 4294967296,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveRetries",
+ "value": 0,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveRetries",
+ "value": -1,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveRetries",
+ "value": 1.5,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "field": "keepaliveRetries",
+ "value": 4294967296,
+ "status": 400,
+ "nativeCalls": 0
+ },
+ {
+ "operation": "create",
+ "params": {},
+ "keepalive": "10s,10",
+ "status": 201
+ },
+ {
+ "operation": "create",
+ "params": {
+ "keepaliveInterval": 60
+ },
+ "keepalive": "60s,10",
+ "status": 201
+ },
+ {
+ "operation": "create",
+ "params": {
+ "keepaliveRetries": 3
+ },
+ "keepalive": "10s,3",
+ "status": 201
+ },
+ {
+ "operation": "create",
+ "params": {
+ "keepaliveInterval": 90,
+ "keepaliveRetries": 7
+ },
+ "keepalive": "90s,7",
+ "status": 201
+ },
+ {
+ "operation": "patch-other-field",
+ "nativeKeepalivePreserved": "1m,3",
+ "status": 200
+ },
+ {
+ "operation": "read-minutes",
+ "seconds": 60,
+ "status": 200
+ }
+ ],
+ "scope": "Production compiled GRE create/patch using isolated PostgreSQL and native HTTP fixture",
+ "passed": true,
+ "nativeWrites": 5,
+ "databaseAndRoleRemoved": true
+}
\ No newline at end of file
diff --git a/docs/ux-ui/acceptance/gre210-native-live-2026-10-13.json b/docs/ux-ui/acceptance/gre210-native-live-2026-10-13.json
new file mode 100644
index 00000000..1bc12f33
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-native-live-2026-10-13.json
@@ -0,0 +1,65 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "runtime": "ux-gre210",
+ "cases": [
+ {
+ "host": "194.226.121.150",
+ "defaultCreateStatus": 201,
+ "defaultNative": "10s,10",
+ "minutesReadAsSeconds": 60,
+ "patchOtherFieldPreservesNative": "1m,3",
+ "invalidIntervalStatus": 400,
+ "invalidPatchLeavesNativeUnchanged": true,
+ "catalogSeconds": 60
+ },
+ {
+ "host": "104.165.244.7",
+ "defaultCreateStatus": 201,
+ "defaultNative": "10s,10",
+ "minutesReadAsSeconds": 60,
+ "patchOtherFieldPreservesNative": "1m,3",
+ "invalidIntervalStatus": 400,
+ "invalidPatchLeavesNativeUnchanged": true,
+ "catalogSeconds": 60
+ }
+ ],
+ "uiCases": [
+ {
+ "section": "gre",
+ "width": 1440,
+ "actualNativeRead": true,
+ "minutesFormSeconds": 60,
+ "invalidInputPreservesForm": true,
+ "mutationRequests": 0,
+ "pageErrors": 0
+ },
+ {
+ "section": "filters",
+ "width": 1440,
+ "actualNativeRead": true,
+ "configuredGreCatalogAccepted": true,
+ "mutationRequests": 0,
+ "pageErrors": 0
+ },
+ {
+ "section": "gre",
+ "width": 320,
+ "actualNativeRead": true,
+ "minutesFormSeconds": 60,
+ "invalidInputPreservesForm": true,
+ "mutationRequests": 0,
+ "pageErrors": 0
+ },
+ {
+ "section": "filters",
+ "width": 320,
+ "actualNativeRead": true,
+ "configuredGreCatalogAccepted": true,
+ "mutationRequests": 0,
+ "pageErrors": 0
+ }
+ ],
+ "scope": "Disabled own native GRE; defaults, unit parsing, patch preservation and UI validation; not data-plane",
+ "cleanupCompleted": true
+}
diff --git a/docs/ux-ui/acceptance/gre210-native-range-2026-10-13.json b/docs/ux-ui/acceptance/gre210-native-range-2026-10-13.json
new file mode 100644
index 00000000..3a1ed7f8
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-native-range-2026-10-13.json
@@ -0,0 +1,116 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "cases": [
+ {
+ "host": "194.226.121.150",
+ "value": "0",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-interval is out of range (00:00:01 .. 7101w3d06:28:15)"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "none",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "0s,0",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-interval is out of range (00:00:01 .. 7101w3d06:28:15)"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "1s,0",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-retries out of range (1..4294967295)"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "1m,3",
+ "status": 200,
+ "observed": "1m,3"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "500ms,3",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-interval is out of range (00:00:01 .. 7101w3d06:28:15)"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "00:01:00,3",
+ "status": 200,
+ "observed": "1m,3"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "0",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-interval is out of range (00:00:01 .. 7101w3d06:28:15)"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "none",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "0s,0",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-interval is out of range (00:00:01 .. 7101w3d06:28:15)"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "1s,0",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-retries out of range (1..4294967295)"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "1m,3",
+ "status": 200,
+ "observed": "1m,3"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "500ms,3",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "value of keepalive-interval is out of range (00:00:01 .. 7101w3d06:28:15)"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "00:01:00,3",
+ "status": 200,
+ "observed": "1m,3"
+ }
+ ],
+ "scope": "Direct native syntax exploration on disabled owned interfaces; application fixes not deployed",
+ "cleanupCompleted": true
+}
diff --git a/docs/ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json b/docs/ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json
new file mode 100644
index 00000000..18130f2d
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-native-range-extra-2026-10-13.json
@@ -0,0 +1,60 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "cases": [
+ {
+ "host": "194.226.121.150",
+ "value": "disabled",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "no",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "1.5s,3",
+ "status": 200,
+ "observed": "1s,3"
+ },
+ {
+ "host": "194.226.121.150",
+ "value": "1s500ms,3",
+ "status": 200,
+ "observed": "1s,3"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "disabled",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "no",
+ "status": 400,
+ "observed": "10s,3",
+ "error": "invalid time value for argument keepalive-interval"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "1.5s,3",
+ "status": 200,
+ "observed": "1s,3"
+ },
+ {
+ "host": "104.165.244.7",
+ "value": "1s500ms,3",
+ "status": 200,
+ "observed": "1s,3"
+ }
+ ],
+ "scope": "Direct native syntax exploration on disabled owned interfaces; application fixes not deployed",
+ "cleanupCompleted": false
+}
diff --git a/docs/ux-ui/acceptance/gre210-profile-2026-10-13.json b/docs/ux-ui/acceptance/gre210-profile-2026-10-13.json
new file mode 100644
index 00000000..121ac380
--- /dev/null
+++ b/docs/ux-ui/acceptance/gre210-profile-2026-10-13.json
@@ -0,0 +1,14 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "commands": [
+ "npm --prefix backend run test:live-maps",
+ "npx tsx lib/filters-response.test.ts",
+ "npx tsx lib/network-map-response.test.ts"
+ ],
+ "passed": true,
+ "networkMapUnitCases": 5,
+ "frontendTypecheckPassed": true,
+ "backendBuildPassed": true,
+ "eslintErrors": 0
+}
diff --git a/docs/ux-ui/acceptance/source210-result.json b/docs/ux-ui/acceptance/source210-result.json
new file mode 100644
index 00000000..d984d6a7
--- /dev/null
+++ b/docs/ux-ui/acceptance/source210-result.json
@@ -0,0 +1,14 @@
+{
+ "date": "2026-10-13",
+ "block": "12.5.210",
+ "kinds": [
+ {
+ "kind": "backend",
+ "matched": 475
+ },
+ {
+ "kind": "frontend",
+ "matched": 527
+ }
+ ]
+}
\ No newline at end of file
diff --git a/lib/filters-response.test.ts b/lib/filters-response.test.ts
new file mode 100644
index 00000000..80f6a5db
--- /dev/null
+++ b/lib/filters-response.test.ts
@@ -0,0 +1,7 @@
+import assert from 'node:assert/strict'
+import {filtersGreResponseSchema} from './filters-response'
+const t={id:'*1',serverId:'1',name:'own210',localAddress:'192.0.2.1',remoteAddress:'192.0.2.2',localInnerIp:'10.0.0.1/30',remoteInnerIp:'10.0.0.2/30',poolId:'',ipsec:{secret:''},mtu:1476,keepaliveInterval:60,keepaliveRetries:3,dscp:'inherit',clampTcpMss:true,allowFastPath:false,comment:'',enabled:true,status:'up'}
+assert.equal(filtersGreResponseSchema.safeParse({tunnels:[t]}).success,true)
+assert.equal(filtersGreResponseSchema.safeParse({tunnels:[{...t,ipsec:null}]}).success,true)
+assert.equal(filtersGreResponseSchema.safeParse({tunnels:[{...t,ipsec:{secret:'must-not-be-in-catalog'}}]}).success,false)
+console.log('Filters GRE catalog: configured IPsec accepted without key material')
diff --git a/lib/filters-response.ts b/lib/filters-response.ts
index 7759c95b..00b15064 100644
--- a/lib/filters-response.ts
+++ b/lib/filters-response.ts
@@ -15,7 +15,8 @@ export const filtersMutationSchema = z.object({ ok: z.literal(true), rules: filt
export const filtersGreResponseSchema = z.object({
tunnels: z.array(z.object({
id: z.string().min(1), serverId: z.string().min(1), name: z.string(), localAddress: z.string(), remoteAddress: z.string(),
- localInnerIp: z.string(), remoteInnerIp: z.string(), poolId: z.string(), ipsec: z.null(), mtu: z.number().int().nonnegative(),
+ localInnerIp: z.string(), remoteInnerIp: z.string(), poolId: z.string(),
+ ipsec: z.object({ secret: z.literal("") }).nullable(), mtu: z.number().int().nonnegative(),
keepaliveInterval: z.number().int().nonnegative(), keepaliveRetries: z.number().int().nonnegative(),
dscp: z.union([z.literal("inherit"), z.number().int().min(0).max(63)]), clampTcpMss: z.boolean(), allowFastPath: z.boolean(),
comment: z.string(), enabled: z.boolean(), status: z.enum(["up", "down", "degraded"]),
diff --git a/lib/network-map-response.test.ts b/lib/network-map-response.test.ts
index 71b7dc73..ea7a5743 100644
--- a/lib/network-map-response.test.ts
+++ b/lib/network-map-response.test.ts
@@ -2,6 +2,11 @@ import {test} from "node:test"
import assert from "node:assert/strict"
import {validateNetworkMapSnapshot} from "./network-map-response"
const server={id:1,name:"Router",host:"192.0.2.1",type:"home-router",country:"RU",enabled:true,status:null,latency:0}
+test("network map retains configured GRE IPsec without key material",()=>{
+ const tunnel={id:"*1",serverId:"1",name:"own210",localAddress:"192.0.2.1",remoteAddress:"192.0.2.2",localInnerIp:"10.0.0.1/30",remoteInnerIp:"10.0.0.2/30",poolId:"",ipsec:{secret:""},mtu:1476,keepaliveInterval:60,keepaliveRetries:3,dscp:"inherit",clampTcpMss:true,allowFastPath:false,comment:"",enabled:true,status:"up"}
+ const result=validateNetworkMapSnapshot([server],{tunnels:[tunnel],failures:[]},{probes:[]})
+ assert.deepEqual(result.tunnels[0].ipsec,{secret:""})
+})
test("network map requires complete envelopes and preserves zero/null",()=>{
const result=validateNetworkMapSnapshot([server],{tunnels:[],failures:[]},{probes:[]})
assert.equal(result.servers[0].latency,0);assert.equal(result.servers[0].status,null)
diff --git a/tests/e2e/filters-ipsec-gateways.spec.ts b/tests/e2e/filters-ipsec-gateways.spec.ts
new file mode 100644
index 00000000..02d38baa
--- /dev/null
+++ b/tests/e2e/filters-ipsec-gateways.spec.ts
@@ -0,0 +1,61 @@
+import { test, expect } from "@playwright/test"
+for (const kind of ["gre", "recursive"] as const) {
+ test(`Filters: каталог ${kind} с masked IPsec сохраняется при сбое и блокирует маршрут/копирование`, async ({ page }) => {
+ let phase = 0, writes = 0, catalogReads = 0
+ const tunnel = (id: string) => ({ id: "t" + id, serverId: id, name: "GRE-" + id, localAddress: "192.0.2." + id, remoteAddress: "198.51.100.1", localInnerIp: "10.0.0.1/30", remoteInnerIp: "10.0.0.2/30", poolId: "", ipsec: { secret: "" }, mtu: 1476, keepaliveInterval: 10, keepaliveRetries: 3, dscp: "inherit", clampTcpMss: true, allowFastPath: true, comment: "", enabled: true, status: "up" })
+ const rec = { id: "rec1", dstAddress: "10.0.0.2/32", gateway: "198.51.100.1", distance: 1, routingTable: "main", comment: "Рекурсивный шлюз", disabled: false }
+ const rule = { id: "rule-1", community: "65001:101", gateway: "10.0.0.2", gatewayTunnelId: kind === "gre" ? "t1" : "rec:rec1", action: "route", description: "Маршрут" }
+ await page.route("**/health", route => route.fulfill({ json: { ok: true } }))
+ await page.route("**/api/**", route => {
+ const url = new URL(route.request().url()), path = url.pathname, id = url.searchParams.get("serverId") ?? "1"
+ if (path === "/api/filters/rules" && route.request().method() === "PUT") { writes++; return route.fulfill({ json: { ok: true, rules: route.request().postDataJSON().rules } }) }
+ const catalog = kind === "gre" ? "/api/filters/gre-tunnels" : "/api/recursive-routes"
+ if (path === catalog) catalogReads++
+ if (path === catalog && phase === 1) return route.fulfill({ status: 503, json: { error: "Каталог недоступен тест" } })
+ if (path === catalog && phase === 2) return route.fulfill({ json: kind === "gre" ? { tunnels: [{ ...tunnel(id), name: null }] } : { routes: [rec], stale: true } })
+ return route.fulfill({ json: path === "/api/filters/rules" ? { rulesets: [{ serverId: "1", rules: [rule] }, { serverId: "2", rules: [] }], live: true, greTunnels: [] }
+ : path === "/api/servers" ? [1, 2].map(i => ({ id: i, name: "Роутер " + i, host: "192.0.2." + i, type: "exit-node", enabled: true, country: "RU", site: "TEST", asn: "", status: "online", latency: 1 }))
+ : path === "/api/filters/gre-tunnels" ? { tunnels: kind === "gre" && phase !== 3 ? [tunnel(id)] : [] }
+ : path === "/api/recursive-routes" ? { routes: kind === "recursive" && phase !== 3 ? [rec] : [], stale: false }
+ : path === "/api/auth/config" ? { required: false } : {} })
+ })
+ await page.goto("/filters")
+ const row = page.locator("tr[data-row-id]").first()
+ await expect(row).toContainText(kind === "gre" ? "GRE-1" : rec.dstAddress)
+ phase = 1
+ await page.getByRole("button", { name: "Обновить", exact: true }).click()
+ await expect(page.getByRole("alert").filter({ hasText: "Каталог недоступен тест" })).toBeVisible()
+ await expect(row).toContainText(kind === "gre" ? "GRE-1" : rec.dstAddress)
+ await row.hover()
+ await row.getByRole("button", { name: "Редактировать правило", exact: true }).click()
+ const dialog = page.getByRole("dialog")
+ await dialog.getByRole("textbox", { name: "Описание правила" }).fill("Сохранить маршрут")
+ await dialog.getByRole("button", { name: "Сохранить", exact: true }).click()
+ await expect(dialog.getByRole("alert")).toContainText("Шлюзы устройства не подтверждены")
+ expect(writes).toBe(0)
+ await dialog.getByRole("button", { name: "Отмена", exact: true }).click()
+ await page.getByRole("button", { name: "Копировать", exact: true }).click()
+ await dialog.getByRole("button", { name: /Роутер 2/ }).click()
+ const copy = dialog.getByRole("button", { name: "Копировать 1 правил", exact: true })
+ await expect(copy).toBeDisabled()
+ phase = 2
+ let priorReads = catalogReads
+ await dialog.getByRole("button", { name: "Обновить шлюзы", exact: true }).click()
+ await expect.poll(() => catalogReads).toBeGreaterThanOrEqual(priorReads + 2)
+ await expect(copy).toBeDisabled()
+ await expect(dialog.getByRole("alert")).toContainText("сопоставление шлюзов не подтверждены")
+ phase = 3
+ priorReads = catalogReads
+ await dialog.getByRole("button", { name: "Обновить шлюзы", exact: true }).click()
+ await expect.poll(() => catalogReads).toBeGreaterThanOrEqual(priorReads + 2)
+ await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => resolve())))
+ await expect(copy).toBeDisabled()
+ phase = 4
+ await dialog.getByRole("button", { name: "Обновить шлюзы", exact: true }).click()
+ await expect(copy).toBeEnabled()
+ await expect(dialog.getByRole("alert")).toHaveCount(0)
+ await copy.click()
+ await expect(dialog).toHaveCount(0)
+ expect(writes).toBe(1)
+ })
+}
diff --git a/tests/e2e/gre-keepalive.spec.ts b/tests/e2e/gre-keepalive.spec.ts
new file mode 100644
index 00000000..2c0c486c
--- /dev/null
+++ b/tests/e2e/gre-keepalive.spec.ts
@@ -0,0 +1,8 @@
+import {test,expect} from '@playwright/test'
+for(const width of [1440,320])test(`GRE: неверный keepalive сохраняет форму без запроса ${width}`,async({page})=>{
+ let writes=0;const tunnel={id:'*1',serverId:'1',name:'own210-gre',localAddress:'192.0.2.1',remoteAddress:'192.0.2.2',localInnerIp:'',remoteInnerIp:'',poolId:'live',ipsec:null,mtu:1476,keepaliveInterval:60,keepaliveRetries:3,dscp:'inherit',clampTcpMss:true,allowFastPath:false,comment:'own210',enabled:false,status:'down'}
+ await page.route('**/health',r=>r.fulfill({json:{ok:true}}));await page.route('**/api/**',r=>{if(r.request().method()!=='GET')writes++;const p=new URL(r.request().url()).pathname;return r.fulfill({json:p==='/api/auth/config'?{required:false}:p==='/api/servers'?[{id:1,name:'Own210 router',host:'192.0.2.1',enabled:true,country:'RU'}]:p==='/api/gre/tunnels'?{tunnels:[tunnel]}:{}})})
+ await page.setViewportSize({width,height:1000});await page.goto('/gre?server=1');await page.getByRole('button',{name:'Действия: own210-gre',exact:true}).click();await page.getByRole('menuitem',{name:'Редактировать',exact:true}).click();const form=page.getByRole('dialog');await form.getByRole('button',{name:'Дополнительно',exact:true}).click();await expect(form.getByLabel('Keepalive, с')).toHaveValue('60');await expect(form).not.toContainText('0 = откл.');await form.getByLabel('Комментарий').fill('сохранённый ввод');
+ for(const field of ['Keepalive, с','Попытки']){await form.getByLabel(field).fill('0');await form.getByRole('button',{name:'Сохранить',exact:true}).click();await expect(form.getByRole('alert')).toContainText('целые значения от 1');await expect(form.getByLabel('Комментарий')).toHaveValue('сохранённый ввод');await form.getByLabel(field).fill(field==='Попытки'?'3':'60')}
+ expect(writes).toBe(0);expect(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth+1)).toBe(true)
+})