diff --git a/app/(main)/terminal/page.tsx b/app/(main)/terminal/page.tsx index 09f9fded..33dda3ea 100644 --- a/app/(main)/terminal/page.tsx +++ b/app/(main)/terminal/page.tsx @@ -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([{id:0,kind:"info",text:isLive?"REST: каждое выполнение — отдельный запрос; соединение с устройством пока не проверено.":"Демо: команды возвращают синтетические данные."}]) + const [lines,setLines]=useState([{id:0,kind:"info",text:isLive?"REST: каждая команда — отдельный запрос. Результат появится после ответа API.":"Демо: команды возвращают синтетические данные."}]) const [input,setInput]=useState(""),[history,setHistory]=useState([]),[histIdx,setHistIdx]=useState(-1),[executing,setExecuting]=useState(false),[error,setError]=useState(null),[completed,setCompleted]=useState(null) const nextId=useRef(1),lock=useRef(false),reader=useRef<{alive:boolean;controller:AbortController|null}>({alive:true,controller:null}) const inputRef=useRef(null),scrollRef=useRef(null),followOutput=useRef(true),pendingFocus=useRef(false) diff --git a/backend/package.json b/backend/package.json index 3a1d7c5a..613bdd5f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -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", diff --git a/backend/src/routes/exec.test.ts b/backend/src/routes/exec.test.ts index c6df13b8..ed4e98d3 100644 --- a/backend/src/routes/exec.test.ts +++ b/backend/src/routes/exec.test.ts @@ -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 diff --git a/backend/src/services/mikrotik-logs.test.ts b/backend/src/services/mikrotik-logs.test.ts new file mode 100644 index 00000000..8cb39c48 --- /dev/null +++ b/backend/src/services/mikrotik-logs.test.ts @@ -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(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((resolve, reject) => server.close(error => error ? reject(error) : resolve())) + } +}) diff --git a/backend/src/services/mikrotik.ts b/backend/src/services/mikrotik.ts index 1ab933e5..a153d3e2 100644 --- a/backend/src/services/mikrotik.ts +++ b/backend/src/services/mikrotik.ts @@ -696,7 +696,13 @@ export class MikrotikClient { } async getLogs(limit = 50): Promise { - return this.get(`/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("/log?buffer=memory&.proplist=.id,time,topics,message") + return entries.slice(-Math.min(limit, 200)) } async ping( diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index f73661cf..6dfbd986 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-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 → реальные строки | diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index b8f14d94..5f2ff243 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -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). diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index 53799292..84d8da29 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -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) diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index f0ed9d05..3638c508 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -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 → реальные строки | diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 6e49e594..56569bdd 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -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 → реальные строки | diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 950edebb..48856ca6 100644 --- a/docs/ux-ui-test-server.md +++ b/docs/ux-ui-test-server.md @@ -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 → реальные строки | diff --git a/docs/ux-ui/acceptance/browser-terminal-logs-2026-10-11.json b/docs/ux-ui/acceptance/browser-terminal-logs-2026-10-11.json new file mode 100644 index 00000000..8d4693d9 --- /dev/null +++ b/docs/ux-ui/acceptance/browser-terminal-logs-2026-10-11.json @@ -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": [] +} diff --git a/docs/ux-ui/acceptance/terminal-log-limit-2026-10-11.json b/docs/ux-ui/acceptance/terminal-log-limit-2026-10-11.json new file mode 100644 index 00000000..618b20c3 --- /dev/null +++ b/docs/ux-ui/acceptance/terminal-log-limit-2026-10-11.json @@ -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/" + ] +} diff --git a/docs/ux-ui/screens/terminal-live-logs-1280-2026-10-11.png b/docs/ux-ui/screens/terminal-live-logs-1280-2026-10-11.png new file mode 100644 index 00000000..682b88ce Binary files /dev/null and b/docs/ux-ui/screens/terminal-live-logs-1280-2026-10-11.png differ diff --git a/docs/ux-ui/screens/terminal-live-logs-320-2026-10-11.png b/docs/ux-ui/screens/terminal-live-logs-320-2026-10-11.png new file mode 100644 index 00000000..9bfa915a Binary files /dev/null and b/docs/ux-ui/screens/terminal-live-logs-320-2026-10-11.png differ