fix(terminal): показывать последние записи журнала RouterOS

This commit is contained in:
Denozordec committed 2026-10-11 11:26:59 +07:00
1 parent 1e4d3b4678
commit bd023b8aaa
15 files changed
+321 -16

No files matched your search

+1 -1
View File
@@ -176,7 +176,7 @@ function mockResolve(raw: string, serverName: string): string {
function Terminal({server,isLive,backendUrl,canExecute,blockedReason}:{server:TermServer;isLive:boolean;backendUrl:string;canExecute:boolean;blockedReason?:string}) {
const [lines,setLines]=useState<TermLine[]>([{id:0,kind:"info",text:isLive?"REST: каждое выполнение — отдельный запрос; соединение с устройством пока не проверено.":"Демо: команды возвращают синтетические данные."}])
const [lines,setLines]=useState<TermLine[]>([{id:0,kind:"info",text:isLive?"REST: каждая команда — отдельный запрос. Результат появится после ответа API.":"Демо: команды возвращают синтетические данные."}])
const [input,setInput]=useState(""),[history,setHistory]=useState<string[]>([]),[histIdx,setHistIdx]=useState(-1),[executing,setExecuting]=useState(false),[error,setError]=useState<string|null>(null),[completed,setCompleted]=useState<string|null>(null)
const nextId=useRef(1),lock=useRef(false),reader=useRef<{alive:boolean;controller:AbortController|null}>({alive:true,controller:null})
const inputRef=useRef<HTMLInputElement>(null),scrollRef=useRef<HTMLDivElement>(null),followOutput=useRef(true),pendingFocus=useRef(false)
+1 -1
View File
@@ -16,7 +16,7 @@
"db:migrate-from-sqlite": "tsx src/scripts/migrate-sqlite-to-pg.ts",
"facts:rebuild": "tsx src/scripts/rebuild-flow-facts.ts",
"test:probes": "tsx src/routes/probes.test.ts && tsx src/routes/probes.cancel.test.ts",
"test:exec": "tsx src/routes/exec.test.ts && tsx src/plugins/auth.exec.test.ts",
"test:exec": "tsx src/services/mikrotik-logs.test.ts && tsx src/routes/exec.test.ts && tsx src/plugins/auth.exec.test.ts",
"test:auth": "tsx src/lib/permissions.test.ts && tsx src/plugins/auth.smoke.test.ts && tsx src/plugins/auth.ospf-optimizer.test.ts",
"test:wireguard": "npx tsx src/services/wireguard-config.test.ts && npx tsx --test src/services/wireguard-import.test.ts src/services/wireguard-import-apply.test.ts src/services/wireguard-import-revision.test.ts && npx tsx src/routes/wireguard-import.test.ts",
"test:traffic-rate": "tsx src/services/traffic-rate.test.ts",
+2
View File
@@ -30,6 +30,8 @@ outputs.ping=[{sent:"1",received:"0","avg-rtt":"0ms"}];assert.match((await send(
outputs.ping=[{sent:"1",received:"1","avg-rtt":"0ms"}];assert.match((await send("ping 192.0.2.2 count=1")).json().output,/avg-rtt=0ms/)
assert.equal((await send("ping 192.0.2.2 count=99")).statusCode,200);assert.deepEqual(calls.at(-1),["ping","192.0.2.2",20])
assert.equal((await send("log print limit=500")).statusCode,200);assert.deepEqual(calls.at(-1),["getLogs",200])
outputs.getLogs=new Error("Журнал недоступен");const failedLogs=await send("log print limit=3");assert.equal(failedLogs.statusCode,502);assert.equal(failedLogs.json().error,"Журнал недоступен");assert.equal(failedLogs.json().output,undefined)
outputs.getLogs=[];const emptyLogs=await send("log print limit=3");assert.equal(emptyLogs.statusCode,200);assert.equal(emptyLogs.json().output,"(no log entries)")
for(const command of ["system reboot","pingbad 192.0.2.2","log printable","ping","ping 192.0.2.2 count=0","ping 192.0.2.2 count=1junk","ping 192.0.2.2 count=1 count=2","log print limit=0","log print limit=3junk"]){const before=calls.length;assert.equal((await send(command)).statusCode,400,command);assert.equal(calls.length,before)}
exists=false;assert.equal((await send("interface print")).statusCode,404);exists=true
enabled=false;const beforeDisabled={clients,calls:calls.length};for(const command of["interface print","ping 192.0.2.2 count=1","help"])assert.equal((await send(command)).statusCode,409);assert.deepEqual({clients,calls:calls.length},beforeDisabled);enabled=true
@@ -0,0 +1,44 @@
import assert from "node:assert/strict"
import { createServer } from "node:http"
import { test } from "node:test"
import { MikrotikClient } from "./mikrotik.js"
test("REST logs use the default buffer and return the latest bounded entries", async () => {
const history = Array.from({ length: 1000 }, (_, i) => ({
".id": `*${i.toString(16)}`, time: `time-${i}`, topics: "system,info", message: `entry-${i}`,
}))
let rows = history, denied = false, requests = 0
const server = createServer((req, res) => {
requests++
const url = new URL(req.url!, "http://127.0.0.1")
assert.equal(req.method, "GET")
assert.equal(url.pathname, "/rest/log")
assert.equal(url.searchParams.get("buffer"), "memory")
assert.equal(url.searchParams.get(".proplist"), ".id,time,topics,message")
assert.equal(url.searchParams.has("limit"), false)
res.writeHead(denied ? 401 : 200, { "content-type": "application/json" })
res.end(JSON.stringify(denied ? { message: "Unauthorized" } : rows))
})
await new Promise<void>(resolve => server.listen(0, "127.0.0.1", resolve))
const address = server.address()
assert.ok(address && typeof address !== "string")
const client = new MikrotikClient({ host: "127.0.0.1", port: address.port, useSsl: false, verifySsl: false, username: "fixture", password: "fixture" })
try {
assert.deepEqual(await client.getLogs(3), history.slice(-3))
assert.deepEqual(await client.getLogs(), history.slice(-50))
assert.deepEqual(await client.getLogs(500), history.slice(-200))
rows = history.slice(0, 2)
assert.deepEqual(await client.getLogs(3), rows)
rows = []
assert.deepEqual(await client.getLogs(3), [])
const before = requests
for (const limit of [0, -1, 1.5, NaN, Infinity, Number.MAX_SAFE_INTEGER + 1]) {
await assert.rejects(client.getLogs(limit), RangeError)
}
assert.equal(requests, before, "Invalid limits must not poll RouterOS")
denied = true
await assert.rejects(client.getLogs(3), /401.*Unauthorized/)
} finally {
await new Promise<void>((resolve, reject) => server.close(error => error ? reject(error) : resolve()))
}
})
+7 -1
View File
@@ -696,7 +696,13 @@ export class MikrotikClient {
}
async getLogs(limit = 50): Promise<RosLogEntry[]> {
return this.get<RosLogEntry[]>(`/log?limit=${limit}`)
if (!Number.isSafeInteger(limit) || limit < 1) {
throw new RangeError("limit должен быть положительным целым числом.")
}
// REST query parameters filter properties; limit is not a print row limit.
// Read only the default buffer and retain its latest entries in native order.
const entries = await this.get<RosLogEntry[]>("/log?buffer=memory&.proplist=.id,time,topics,message")
return entries.slice(-Math.min(limit, 200))
}
async ping(
+18 -2
View File
@@ -1,6 +1,6 @@
# UX/UI: протокол внешней приёмки 12.5
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
IPsec78: реальный PSK responder established, mode-config198.18.78.10 и online=true подтверждены API; точные собственные объекты удалены. Сертификатный/DN online, late failure и history restore остаются открытыми. [Отчёт](ux-ui/acceptance/ipsec-mode-config-2026-10-09.json), [журнал](ux-ui-progress.md).
@@ -696,7 +696,7 @@ flowchart LR
## 12.5.77 — основной блок IPsec (2026-10-09)
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
@@ -1413,3 +1413,19 @@ GET /log?buffer=ownAction тоже изолирует корректно. Пов
Все четыре собственных logger/action на каждом CHR удалены по exact-ID/name/prefix/action/topics preflight. Полные существующие logging/action rows до/после совпали на обоих устройствах; default buffer не очищался. Пароли и VPN-конфигурация не менялись. [Протокол и точный selector](ux-ui/acceptance/routeros-scoped-log-2026-10-11.json). Документация: [REST query](https://manual.mikrotik.com/docs/developer-guides/rest-api/), [раздельные memory buffers](https://manual.mikrotik.com/docs/diagnostics-monitoring-and-troubleshooting/log/).
Source/runtime/UI не менялись; build и регрессия не повторялись. Следующий133 — оставшиеся реальные сценарии и проверка расхождений API; external CRL distribution failures, другие ОС и независимые WAN остаются открыты.12.5 не завершён.
## 12.5.133 — реальные журналы в REST-терминале (2026-10-11)
Диагностика132 выявила продуктовый баг getLogs: GET /log?limit=N использовал limit как REST property filter. На обоих CHR default memory содержал1000 строк, но SDK возвращал0, а API log print limit=3 —200/(no log entries). Исправлен SDK: чтение default memory с проекцией полей, последние N строк в native chronological order, максимум200. Невалидный limit отклоняется до опроса. Это лимит вывода: native buffer читается целиком перед slice; лимит сетевой передачи не обещается.
Проверены реальные API limits3/50/500→3/50/200 на каждом CHR, own marker виден, latest native IDs совпадают; limit0→400. Live терминал1280/320 получил по3 реальные строки, очистил поле команды после успеха и не имеет document overflow. Уточнена исходная подпись: «REST: каждая команда — отдельный запрос. Результат появится после ответа API.»; постоянная фраза о непроверенном соединении больше не противоречит успешному результату. ReUI Frame/Button/Input и base-nova сохраняются, vendor/layout не менялись.
Профильный HTTP SDK test (tail/default50/cap200/short/empty/invalid limits/401) passed, включён в npm test:exec. HTTP route/empty-versus-error и signed JWT/RBAC passed; backend build passed; source-only TypeScript и frontend production build passed. Scoped ESLint страницы/тестов passed; SDK lint имеет две исходные prefer-const ошибки125/899, проверка с отключением только этой rule passed. Обычный root tsc захватил ignored historical tmp и failed; существующий source-only config passed. Initial SDK test sandbox EACCES исправлен разрешённым loopback запуском. Первый UI assertion сравнивал newline string с отдельными div и failed; исправлен только способ проверки, final2/2 passed. Эти initial failures не скрыты и не прибавлены к уникальным сценариям.
Развёрнуты production backend/frontend ux-log133; backend/PostgreSQL healthy, frontend running/live UI. SDK source и compiled output SHA256 совпали с Docker; source страницы совпал с build context. Сохранены private rollback env и предыдущие образы. Только script/info markers добавлены в default logs; журнал не очищался, новых конфигурационных/VPN fixtures нет, оба CHR доступны, пароли не менялись. [До/после и проверки](ux-ui/acceptance/terminal-log-limit-2026-10-11.json), [live UI](ux-ui/acceptance/browser-terminal-logs-2026-10-11.json).
Следующий134 — external CRL distribution/failure и оставшаяся матрица. Полная итоговая регрессия после последнего product изменения ещё требуется;12.5 открыт.
| Референс | Схема |
| --- | --- |
| [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Устройство → log print limit=N → default memory tail → ответ API → реальные строки |
+3 -3
View File
@@ -1,12 +1,12 @@
# План реализации UX/UI по пятичасовым окнам
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-10. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
## Актуальная точка продолжения — 2026-10-10
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
Этапы0–11 завершены в локальных границах журнала. История выполненных внешних блоков и доказательства сохранены в [журнале](ux-ui-stage-12.md) и [протоколе](ux-ui-external-acceptance.md). Реальная Telegram доставка, Portal SSO, multi-instance и оставшиеся профильные сетевые ограничения открыты.
@@ -371,6 +371,6 @@ flowchart LR
## 12.5.77 — основной блок IPsec (2026-10-09)
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
Подробный объём, протоколы, схема и ограничения: [12.5.77 в журнале](ux-ui-progress.md).
+18 -2
View File
@@ -1,6 +1,6 @@
# UX/UI: журнал реализации
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
@@ -36,7 +36,23 @@
| 10 | Маршрутизация, диагностика, карта и терминал | Завершён в границах локальной приёмки 2026-10-01; блоки 10.1–10.71, внешние ограничения в 10.71 |
| 11А | Пользователи, контейнеры, сертификаты и резервные копии | Завершён в границах локальной приёмки 2026-10-01; 11А.1–11А.33, внешние ограничения в 11А.33 |
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–132 и ограничения ниже. Runtime backend ux-crl127/frontend ux-ike124. |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка завершена в границах12.3.83; внешняя12.5 в работе, выполненные блоки1–133 и ограничения ниже. Runtime backend/frontend ux-log133. |
## 12.5.133 — реальные журналы в REST-терминале (2026-10-11)
Диагностика132 выявила продуктовый баг getLogs: GET /log?limit=N использовал limit как REST property filter. На обоих CHR default memory содержал1000 строк, но SDK возвращал0, а API log print limit=3 —200/(no log entries). Исправлен SDK: чтение default memory с проекцией полей, последние N строк в native chronological order, максимум200. Невалидный limit отклоняется до опроса. Это лимит вывода: native buffer читается целиком перед slice; лимит сетевой передачи не обещается.
Проверены реальные API limits3/50/500→3/50/200 на каждом CHR, own marker виден, latest native IDs совпадают; limit0→400. Live терминал1280/320 получил по3 реальные строки, очистил поле команды после успеха и не имеет document overflow. Уточнена исходная подпись: «REST: каждая команда — отдельный запрос. Результат появится после ответа API.»; постоянная фраза о непроверенном соединении больше не противоречит успешному результату. ReUI Frame/Button/Input и base-nova сохраняются, vendor/layout не менялись.
Профильный HTTP SDK test (tail/default50/cap200/short/empty/invalid limits/401) passed, включён в npm test:exec. HTTP route/empty-versus-error и signed JWT/RBAC passed; backend build passed; source-only TypeScript и frontend production build passed. Scoped ESLint страницы/тестов passed; SDK lint имеет две исходные prefer-const ошибки125/899, проверка с отключением только этой rule passed. Обычный root tsc захватил ignored historical tmp и failed; существующий source-only config passed. Initial SDK test sandbox EACCES исправлен разрешённым loopback запуском. Первый UI assertion сравнивал newline string с отдельными div и failed; исправлен только способ проверки, final2/2 passed. Эти initial failures не скрыты и не прибавлены к уникальным сценариям.
Развёрнуты production backend/frontend ux-log133; backend/PostgreSQL healthy, frontend running/live UI. SDK source и compiled output SHA256 совпали с Docker; source страницы совпал с build context. Сохранены private rollback env и предыдущие образы. Только script/info markers добавлены в default logs; журнал не очищался, новых конфигурационных/VPN fixtures нет, оба CHR доступны, пароли не менялись. [До/после и проверки](ux-ui/acceptance/terminal-log-limit-2026-10-11.json), [live UI](ux-ui/acceptance/browser-terminal-logs-2026-10-11.json).
Следующий134 — external CRL distribution/failure и оставшаяся матрица. Полная итоговая регрессия после последнего product изменения ещё требуется;12.5 открыт.
| Референс | Схема |
| --- | --- |
| [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Устройство → log print limit=N → default memory tail → ответ API → реальные строки |
## 12.5.132 — изоляция диагностических буферов RouterOS (2026-10-11)
+19 -3
View File
@@ -1,8 +1,8 @@
# Оставшаяся внешняя приёмка — 2026-10-11
Это актуальная матрица после 12.5.132. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
Это актуальная матрица после 12.5.133. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-crl127`, frontend `ux-ike124`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-log133`, frontend `ux-log133`; production lab использует AUTH_REQUIRED=false. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
| Раздел | Подтверждено | Осталось / условие завершения |
| --- | --- | --- |
@@ -16,7 +16,7 @@
| OSPF/BFD | Real Full/own routes84–85, раздельные наблюдения BFD86, effective disabled/optimizer cost/partial/RBAC87, alternate path90 и CIDR91 | Sustained BFD-only gate не принят: в86 сосед мог вновь статьFull при доступныхHello. В90 переходный Ping18/40 с55% loss: бесшовность не принята. REST timing — наблюдаемая граница, не SLA; IPv6/scale/independent WAN открыты |
| BGP | Established83, exact /32 exchange/API/UI/administrative withdrawal92, BFD primary GRE loss/alternate/recovery93 | Hold timer/TCP loss безBFD принят104; packet loss в переходе, разные внешние peers/WAN policy, IPv6/scale. Два логических пути используют тот же public WAN; physical redundancy не принята |
| Recursive routes | Production PUT/change/own history restore88, disabled guards, partial/unknown/applied outcomes, live формы/контекст | Автоматический rollback/retry, durable receipts и несколько экземпляров отсутствуют; PUT не является idempotent noop. Полная произвольная legacy catalog миграция не принята |
| Diagnostics/terminal | Allowlist/native reads, Ping/trace/route/MTU/DNS, actual avg-rtt, disabled guards, JWT/live PC/mobile89 | DNS использует backend resolver; MTU — ограниченная оценка, не гарантированный максимум. Stop ожидания не доказывает остановку RouterOS команды; arbitrary CLI и physical disconnect не приняты |
| Diagnostics/terminal | Allowlist/native reads, Ping/trace/route/MTU/DNS, actual avg-rtt, disabled guards, JWT/live PC/mobile89; real default memory tail/log limits/API/UI133 | DNS использует backend resolver; MTU — ограниченная оценка, не гарантированный максимум. Stop ожидания не доказывает остановку RouterOS команды; arbitrary CLI и physical disconnect не приняты |
| Portal/интеграции | Локальные и isolated JWT guards; UI/API error states в границах журналов | Настоящий Portal issuer/login/отзыв прав; внешние RIPE/MaxMind/S3/container/certificate jobs и Gitea delivery требуют отдельных тестовых endpoints/аккаунтов. Не отправлять сообщения и не публиковать релиз без соответствующего поручения |
| Общая приёмка | Локальная12.3.83 и профильные build/E2E/live проверки последующих блоков | Итоговая согласованная версия, профильная проверка нового deployment, сквозная регрессия после последнего product изменения; scoped axe не означает полную WCAG сертификацию |
@@ -328,3 +328,19 @@ GET /log?buffer=ownAction тоже изолирует корректно. Пов
Все четыре собственных logger/action на каждом CHR удалены по exact-ID/name/prefix/action/topics preflight. Полные существующие logging/action rows до/после совпали на обоих устройствах; default buffer не очищался. Пароли и VPN-конфигурация не менялись. [Протокол и точный selector](ux-ui/acceptance/routeros-scoped-log-2026-10-11.json). Документация: [REST query](https://manual.mikrotik.com/docs/developer-guides/rest-api/), [раздельные memory buffers](https://manual.mikrotik.com/docs/diagnostics-monitoring-and-troubleshooting/log/).
Source/runtime/UI не менялись; build и регрессия не повторялись. Следующий133 — оставшиеся реальные сценарии и проверка расхождений API; external CRL distribution failures, другие ОС и независимые WAN остаются открыты.12.5 не завершён.
## 12.5.133 — реальные журналы в REST-терминале (2026-10-11)
Диагностика132 выявила продуктовый баг getLogs: GET /log?limit=N использовал limit как REST property filter. На обоих CHR default memory содержал1000 строк, но SDK возвращал0, а API log print limit=3 —200/(no log entries). Исправлен SDK: чтение default memory с проекцией полей, последние N строк в native chronological order, максимум200. Невалидный limit отклоняется до опроса. Это лимит вывода: native buffer читается целиком перед slice; лимит сетевой передачи не обещается.
Проверены реальные API limits3/50/500→3/50/200 на каждом CHR, own marker виден, latest native IDs совпадают; limit0→400. Live терминал1280/320 получил по3 реальные строки, очистил поле команды после успеха и не имеет document overflow. Уточнена исходная подпись: «REST: каждая команда — отдельный запрос. Результат появится после ответа API.»; постоянная фраза о непроверенном соединении больше не противоречит успешному результату. ReUI Frame/Button/Input и base-nova сохраняются, vendor/layout не менялись.
Профильный HTTP SDK test (tail/default50/cap200/short/empty/invalid limits/401) passed, включён в npm test:exec. HTTP route/empty-versus-error и signed JWT/RBAC passed; backend build passed; source-only TypeScript и frontend production build passed. Scoped ESLint страницы/тестов passed; SDK lint имеет две исходные prefer-const ошибки125/899, проверка с отключением только этой rule passed. Обычный root tsc захватил ignored historical tmp и failed; существующий source-only config passed. Initial SDK test sandbox EACCES исправлен разрешённым loopback запуском. Первый UI assertion сравнивал newline string с отдельными div и failed; исправлен только способ проверки, final2/2 passed. Эти initial failures не скрыты и не прибавлены к уникальным сценариям.
Развёрнуты production backend/frontend ux-log133; backend/PostgreSQL healthy, frontend running/live UI. SDK source и compiled output SHA256 совпали с Docker; source страницы совпал с build context. Сохранены private rollback env и предыдущие образы. Только script/info markers добавлены в default logs; журнал не очищался, новых конфигурационных/VPN fixtures нет, оба CHR доступны, пароли не менялись. [До/после и проверки](ux-ui/acceptance/terminal-log-limit-2026-10-11.json), [live UI](ux-ui/acceptance/browser-terminal-logs-2026-10-11.json).
Следующий134 — external CRL distribution/failure и оставшаяся матрица. Полная итоговая регрессия после последнего product изменения ещё требуется;12.5 открыт.
| Референс | Схема |
| --- | --- |
| [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Устройство → log print limit=N → default memory tail → ответ API → реальные строки |
+17 -1
View File
@@ -1,6 +1,6 @@
# Этап 12: итоговая приёмка UX/UI
Актуальное продолжение 2026-10-11: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Актуальное продолжение 2026-10-11: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
@@ -2718,3 +2718,19 @@ GET /log?buffer=ownAction тоже изолирует корректно. Пов
Все четыре собственных logger/action на каждом CHR удалены по exact-ID/name/prefix/action/topics preflight. Полные существующие logging/action rows до/после совпали на обоих устройствах; default buffer не очищался. Пароли и VPN-конфигурация не менялись. [Протокол и точный selector](ux-ui/acceptance/routeros-scoped-log-2026-10-11.json). Документация: [REST query](https://manual.mikrotik.com/docs/developer-guides/rest-api/), [раздельные memory buffers](https://manual.mikrotik.com/docs/diagnostics-monitoring-and-troubleshooting/log/).
Source/runtime/UI не менялись; build и регрессия не повторялись. Следующий133 — оставшиеся реальные сценарии и проверка расхождений API; external CRL distribution failures, другие ОС и независимые WAN остаются открыты.12.5 не завершён.
## 12.5.133 — реальные журналы в REST-терминале (2026-10-11)
Диагностика132 выявила продуктовый баг getLogs: GET /log?limit=N использовал limit как REST property filter. На обоих CHR default memory содержал1000 строк, но SDK возвращал0, а API log print limit=3 —200/(no log entries). Исправлен SDK: чтение default memory с проекцией полей, последние N строк в native chronological order, максимум200. Невалидный limit отклоняется до опроса. Это лимит вывода: native buffer читается целиком перед slice; лимит сетевой передачи не обещается.
Проверены реальные API limits3/50/500→3/50/200 на каждом CHR, own marker виден, latest native IDs совпадают; limit0→400. Live терминал1280/320 получил по3 реальные строки, очистил поле команды после успеха и не имеет document overflow. Уточнена исходная подпись: «REST: каждая команда — отдельный запрос. Результат появится после ответа API.»; постоянная фраза о непроверенном соединении больше не противоречит успешному результату. ReUI Frame/Button/Input и base-nova сохраняются, vendor/layout не менялись.
Профильный HTTP SDK test (tail/default50/cap200/short/empty/invalid limits/401) passed, включён в npm test:exec. HTTP route/empty-versus-error и signed JWT/RBAC passed; backend build passed; source-only TypeScript и frontend production build passed. Scoped ESLint страницы/тестов passed; SDK lint имеет две исходные prefer-const ошибки125/899, проверка с отключением только этой rule passed. Обычный root tsc захватил ignored historical tmp и failed; существующий source-only config passed. Initial SDK test sandbox EACCES исправлен разрешённым loopback запуском. Первый UI assertion сравнивал newline string с отдельными div и failed; исправлен только способ проверки, final2/2 passed. Эти initial failures не скрыты и не прибавлены к уникальным сценариям.
Развёрнуты production backend/frontend ux-log133; backend/PostgreSQL healthy, frontend running/live UI. SDK source и compiled output SHA256 совпали с Docker; source страницы совпал с build context. Сохранены private rollback env и предыдущие образы. Только script/info markers добавлены в default logs; журнал не очищался, новых конфигурационных/VPN fixtures нет, оба CHR доступны, пароли не менялись. [До/после и проверки](ux-ui/acceptance/terminal-log-limit-2026-10-11.json), [live UI](ux-ui/acceptance/browser-terminal-logs-2026-10-11.json).
Следующий134 — external CRL distribution/failure и оставшаяся матрица. Полная итоговая регрессия после последнего product изменения ещё требуется;12.5 открыт.
| Референс | Схема |
| --- | --- |
| [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Устройство → log print limit=N → default memory tail → ответ API → реальные строки |
+18 -2
View File
@@ -1,6 +1,6 @@
# Тестовый сервер UX/UI — 2026-10-10
Сервер161.104.46.222: завершён12.5.132 — scoped POST /log/print .query проверен на обоих CHR: собственный маркер, другой буфер и отсутствующий буфер; logging baseline восстановлен. GET buffer также работает; смешение130 вызвано чтением общего /log внутри collector. Runtime backend ux-crl127/frontend ux-ike124. Следующий133 — оставшиеся реальные сценарии и обнаруженные расхождения API; external CRL failures/клиентские ОС ещё открыты.12.5 открыт.
Сервер161.104.46.222: завершён12.5.133 — исправлен пустой вывод log print: native1000 → последние3/50/200 строк, оба CHR/API и UI1280/320 приняты. Уточнена REST-подпись терминала. Production backend/frontend ux-log133, backend/PG healthy, source/runtime hashes совпали. Следующий134 — external CRL distribution/failure и оставшаяся внешняя матрица;12.5 открыт.
| Параметр | Проверенное состояние |
| --- | --- |
@@ -14,7 +14,7 @@
| PostgreSQL | postgres:18-alpine,18.6;mmapp-test-postgres healthy;SELECT version() passed |
| Данные | Отдельный Compose project mmapp-test,том mmapp-test_mmapp-pgdata и каталог ./data |
| Доступ | PostgreSQL не публикуется;frontend3000/backend8000 привязаны к127.0.0.1 после запуска |
| Образы приложения | mmapp-test/backend:ux-crl127 и mmapp-test/frontend:ux-ike124; запущены |
| Образы приложения | mmapp-test/backend:ux-log133 и mmapp-test/frontend:ux-log133; запущены |
Compose SHA256:3052bd6ab5d9865f97605cebfb5ff27a4410cd3357b81153a65a87fb7c92582f. OptionalBACKEND_IMAGE_TAG позволяетобновлятьbackendотдельно. Локальный и удалённый файлы совпали. Шаблоны: [Compose](../deploy/docker-compose.test.yml), [env без секретов](../deploy/env.test.example).
@@ -1144,3 +1144,19 @@ GET /log?buffer=ownAction тоже изолирует корректно. Пов
Все четыре собственных logger/action на каждом CHR удалены по exact-ID/name/prefix/action/topics preflight. Полные существующие logging/action rows до/после совпали на обоих устройствах; default buffer не очищался. Пароли и VPN-конфигурация не менялись. [Протокол и точный selector](ux-ui/acceptance/routeros-scoped-log-2026-10-11.json). Документация: [REST query](https://manual.mikrotik.com/docs/developer-guides/rest-api/), [раздельные memory buffers](https://manual.mikrotik.com/docs/diagnostics-monitoring-and-troubleshooting/log/).
Source/runtime/UI не менялись; build и регрессия не повторялись. Следующий133 — оставшиеся реальные сценарии и проверка расхождений API; external CRL distribution failures, другие ОС и независимые WAN остаются открыты.12.5 не завершён.
## 12.5.133 — реальные журналы в REST-терминале (2026-10-11)
Диагностика132 выявила продуктовый баг getLogs: GET /log?limit=N использовал limit как REST property filter. На обоих CHR default memory содержал1000 строк, но SDK возвращал0, а API log print limit=3 —200/(no log entries). Исправлен SDK: чтение default memory с проекцией полей, последние N строк в native chronological order, максимум200. Невалидный limit отклоняется до опроса. Это лимит вывода: native buffer читается целиком перед slice; лимит сетевой передачи не обещается.
Проверены реальные API limits3/50/500→3/50/200 на каждом CHR, own marker виден, latest native IDs совпадают; limit0→400. Live терминал1280/320 получил по3 реальные строки, очистил поле команды после успеха и не имеет document overflow. Уточнена исходная подпись: «REST: каждая команда — отдельный запрос. Результат появится после ответа API.»; постоянная фраза о непроверенном соединении больше не противоречит успешному результату. ReUI Frame/Button/Input и base-nova сохраняются, vendor/layout не менялись.
Профильный HTTP SDK test (tail/default50/cap200/short/empty/invalid limits/401) passed, включён в npm test:exec. HTTP route/empty-versus-error и signed JWT/RBAC passed; backend build passed; source-only TypeScript и frontend production build passed. Scoped ESLint страницы/тестов passed; SDK lint имеет две исходные prefer-const ошибки125/899, проверка с отключением только этой rule passed. Обычный root tsc захватил ignored historical tmp и failed; существующий source-only config passed. Initial SDK test sandbox EACCES исправлен разрешённым loopback запуском. Первый UI assertion сравнивал newline string с отдельными div и failed; исправлен только способ проверки, final2/2 passed. Эти initial failures не скрыты и не прибавлены к уникальным сценариям.
Развёрнуты production backend/frontend ux-log133; backend/PostgreSQL healthy, frontend running/live UI. SDK source и compiled output SHA256 совпали с Docker; source страницы совпал с build context. Сохранены private rollback env и предыдущие образы. Только script/info markers добавлены в default logs; журнал не очищался, новых конфигурационных/VPN fixtures нет, оба CHR доступны, пароли не менялись. [До/после и проверки](ux-ui/acceptance/terminal-log-limit-2026-10-11.json), [live UI](ux-ui/acceptance/browser-terminal-logs-2026-10-11.json).
Следующий134 — external CRL distribution/failure и оставшаяся матрица. Полная итоговая регрессия после последнего product изменения ещё требуется;12.5 открыт.
| Референс | Схема |
| --- | --- |
| [ReUI App Shell12](https://reui.io/preview/base/app-shell-12?ref=mcp) | Устройство → log print limit=N → default memory tail → ответ API → реальные строки |
@@ -0,0 +1,30 @@
{
"date": "2026-10-11",
"runtime": {
"backend": "ux-log133",
"frontend": "ux-log133"
},
"cases": [
{
"server": 1,
"width": 1280,
"apiStatus": 200,
"outputLines": 3,
"ownMarkerVisible": true,
"commandClearedAfterSuccess": true,
"accurateRestExplanation": true,
"noOverflow": true
},
{
"server": 2,
"width": 320,
"apiStatus": 200,
"outputLines": 3,
"ownMarkerVisible": true,
"commandClearedAfterSuccess": true,
"accurateRestExplanation": true,
"noOverflow": true
}
],
"pageErrors": []
}
@@ -0,0 +1,143 @@
{
"date": "2026-10-11",
"block": "12.5.133",
"before": {
"date": "2026-10-11",
"runtime": "ux-crl127",
"cases": [
{
"host": "194.226.121.150",
"nativeCount": 1000,
"sdkCount": 0,
"status": 200,
"output": "(no log entries)"
},
{
"host": "104.165.244.7",
"nativeCount": 1000,
"sdkCount": 0,
"status": 200,
"output": "(no log entries)"
}
]
},
"after": {
"date": "2026-10-11",
"runtime": "ux-log133",
"cases": [
{
"host": "194.226.121.150",
"nativeCount": 1000,
"sdkCount": 3,
"latestNativeIdsMatch": true,
"cases": [
{
"limit": 3,
"status": 200,
"lines": 3,
"ownMarkerVisible": true,
"emptyPlaceholder": false
},
{
"limit": 50,
"status": 200,
"lines": 50,
"ownMarkerVisible": true,
"emptyPlaceholder": false
},
{
"limit": 500,
"status": 200,
"lines": 200,
"ownMarkerVisible": true,
"emptyPlaceholder": false
}
],
"invalidLimitStatus": 400
},
{
"host": "104.165.244.7",
"nativeCount": 1000,
"sdkCount": 3,
"latestNativeIdsMatch": true,
"cases": [
{
"limit": 3,
"status": 200,
"lines": 3,
"ownMarkerVisible": true,
"emptyPlaceholder": false
},
{
"limit": 50,
"status": 200,
"lines": 50,
"ownMarkerVisible": true,
"emptyPlaceholder": false
},
{
"limit": 500,
"status": 200,
"lines": 200,
"ownMarkerVisible": true,
"emptyPlaceholder": false
}
],
"invalidLimitStatus": 400
}
],
"success": true
},
"runtime": {
"backend": "ux-log133",
"frontend": "ux-log133",
"backendHealthy": true,
"postgresHealthy": true,
"frontendRunning": true
},
"hashes": {
"serviceSource": "7216fd8b4c95cafeb72467c1015b207f1d760b792b0e6f1437c7ed7d188a2d1a",
"compiledService": "f3184e8c1f5cda41d02df0d248bfd520e21123558e35b5aa282f003028bf6a13",
"terminalPage": "c9ce468bac4cd5603ff028a4230f01989e5c5a464b10baff772c1bb98935acfe",
"sourceAndCompiledMatchDeployment": true
},
"checks": {
"sdkHttpTestPassed": true,
"execRoutePassed": true,
"execJwtRbacPassed": true,
"backendBuildPassed": true,
"frontendProductionBuildPassed": true,
"sourceTypeScriptPassed": true,
"eslintChangedTestPagePassed": true,
"serviceScopedLintPassedWithPreferConstDisabled": true,
"baselineServiceLintErrors": [
"prefer-const line125 req",
"prefer-const line899 entry"
],
"initialFailures": [
{
"check": "SDK loopback test",
"cause": "Sandbox EACCES; identical test passed with authorized local HTTP access"
},
{
"check": "UI output comparison",
"cause": "Expected newline string across separate divs; each API line confirmed separately on rerun"
},
{
"check": "Root TypeScript",
"cause": "Ignored historical tmp scripts/copies included by root tsconfig; existing source-only config passed, not a claim of root tsc pass"
}
]
},
"bounds": [
"Output limit enforced locally against latest default memory buffer entries, chronological native order, maximum200",
"Reads the default memory buffer before slicing; network transfer is not limited to N entries",
"Six live limit scenarios across two CHR; invalid0 returns400; two final live UI scenarios1280/320",
"Only script/info marker log entries added; no custom logger/config/network/tunnel fixture created in133 and default logs not cleared",
"Passwords unchanged; no new IPsec or external CRL failure acceptance in this terminal block",
"Source/runtime targeted verification, no full regression rerun"
],
"references": [
"https://manual.mikrotik.com/docs/developer-guides/rest-api/"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB