diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md index 99a989b4..bb9636a8 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-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт. +Актуальное продолжение 2026-10-14:241 — после237 приняты1000 смешанных local/missing,both/missing,unknown,available строк:ПК1440/320, rendered50, DOM2477/2239, search/last-good/pagination/keyboard passed, scoped axe0, writes0. Runtime backend/frontend ux-backups237. S3 native/limitedUI/retention230–240 приняты в записанных границах. Следующий242 — доступный mirror GeoIP job в изолированном scope; paid MaxMind/Cloudflare/Gitea/container jobs отдельно. Этап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). @@ -18,6 +18,16 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json). +## 12.5.241 — тысяча бэкапов со смешанными состояниями файлов (2026-10-14) + +Изменение237 проверено на1000 обычных live-path HTTP DTO (199062bytes), по250 local/missing,both/missing,local/unknown,local/available. Два сценария1440/320 прошли25.2s. UI сохраняет pagination50 строк:DOM2477/2239, ready1203/806ms в dev fixture окружении. Это измерение конкретного запуска, не production SLA/сетевой latency и не доказательство скорости filesystem API1000 файлов. + +Глобальный поиск находит997–999 вне первой страницы и показывает правильные действия:missing local disabled download/restore иrecord-only dialog;both missing допускаетS3;unknown не превращается вmissing. При503 last-good row иdisabled state сохранены; после200 ошибка снята. Страница2/row51 сохранилась послеrefresh. Keyboard Enter/cancel возвращает focus на правильный delete trigger, global overflow отсутствует. Scoped axe по текущимWCAG tags:0violations; UI writes0. Эта проверка не заменяет screen-reader/manual WCAG приёмку. + +Новый large-backups-file-state.spec.ts и scoped ESLint прошли. Existing PNG/screens не перезаписывались; runtime код/образы не изменялись. [ПК metrics](ux-ui/acceptance/backups241-large-1440.json), [320px metrics](ux-ui/acceptance/backups241-large-320.json). Прежняя большая таблица с иными сценариями не считалась повторно новой приёмкой. + +Следующий242 — доступный GeoIP mirror job в own SQL/file scope. В коде есть публичный mirror без licence key; actual paid MaxMind, Cloudflare DNS ACME, registry/container/Gitea jobs требуют отдельного контроля и прав. Остальные внешние группы остаются в матрице. + ## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14) В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись. diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md index bccc09c4..561b04a4 100644 --- a/docs/ux-ui-plan.md +++ b/docs/ux-ui-plan.md @@ -1,9 +1,19 @@ # План реализации UX/UI по пятичасовым окнам -Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт. +Актуальное продолжение 2026-10-14:241 — после237 приняты1000 смешанных local/missing,both/missing,unknown,available строк:ПК1440/320, rendered50, DOM2477/2239, search/last-good/pagination/keyboard passed, scoped axe0, writes0. Runtime backend/frontend ux-backups237. S3 native/limitedUI/retention230–240 приняты в записанных границах. Следующий242 — доступный mirror GeoIP job в изолированном scope; paid MaxMind/Cloudflare/Gitea/container jobs отдельно. Этап12.5 открыт. Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-14. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат. +## 12.5.241 — тысяча бэкапов со смешанными состояниями файлов (2026-10-14) + +Изменение237 проверено на1000 обычных live-path HTTP DTO (199062bytes), по250 local/missing,both/missing,local/unknown,local/available. Два сценария1440/320 прошли25.2s. UI сохраняет pagination50 строк:DOM2477/2239, ready1203/806ms в dev fixture окружении. Это измерение конкретного запуска, не production SLA/сетевой latency и не доказательство скорости filesystem API1000 файлов. + +Глобальный поиск находит997–999 вне первой страницы и показывает правильные действия:missing local disabled download/restore иrecord-only dialog;both missing допускаетS3;unknown не превращается вmissing. При503 last-good row иdisabled state сохранены; после200 ошибка снята. Страница2/row51 сохранилась послеrefresh. Keyboard Enter/cancel возвращает focus на правильный delete trigger, global overflow отсутствует. Scoped axe по текущимWCAG tags:0violations; UI writes0. Эта проверка не заменяет screen-reader/manual WCAG приёмку. + +Новый large-backups-file-state.spec.ts и scoped ESLint прошли. Existing PNG/screens не перезаписывались; runtime код/образы не изменялись. [ПК metrics](ux-ui/acceptance/backups241-large-1440.json), [320px metrics](ux-ui/acceptance/backups241-large-320.json). Прежняя большая таблица с иными сценариями не считалась повторно новой приёмкой. + +Следующий242 — доступный GeoIP mirror job в own SQL/file scope. В коде есть публичный mirror без licence key; actual paid MaxMind, Cloudflare DNS ACME, registry/container/Gitea jobs требуют отдельного контроля и прав. Остальные внешние группы остаются в матрице. + ## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14) В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись. diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md index c718402a..ad3a1d9e 100644 --- a/docs/ux-ui-progress.md +++ b/docs/ux-ui-progress.md @@ -1,6 +1,6 @@ # UX/UI: журнал реализации -Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт. +Актуальное продолжение 2026-10-14:241 — после237 приняты1000 смешанных local/missing,both/missing,unknown,available строк:ПК1440/320, rendered50, DOM2477/2239, search/last-good/pagination/keyboard passed, scoped axe0, writes0. Runtime backend/frontend ux-backups237. S3 native/limitedUI/retention230–240 приняты в записанных границах. Следующий242 — доступный mirror GeoIP job в изолированном scope; paid MaxMind/Cloudflare/Gitea/container jobs отдельно. Этап12.5 открыт. Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md). @@ -38,6 +38,16 @@ | 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 | | 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка12.3.83 в границах журнала. Внешняя12.5: блоки1–236 завершены в записанных scopes, этап открыт. Runtime backend ux-backup234/frontend ux-routing218; backend25/UI52 и дополнительные SQL/UDP222 прошли. | +## 12.5.241 — тысяча бэкапов со смешанными состояниями файлов (2026-10-14) + +Изменение237 проверено на1000 обычных live-path HTTP DTO (199062bytes), по250 local/missing,both/missing,local/unknown,local/available. Два сценария1440/320 прошли25.2s. UI сохраняет pagination50 строк:DOM2477/2239, ready1203/806ms в dev fixture окружении. Это измерение конкретного запуска, не production SLA/сетевой latency и не доказательство скорости filesystem API1000 файлов. + +Глобальный поиск находит997–999 вне первой страницы и показывает правильные действия:missing local disabled download/restore иrecord-only dialog;both missing допускаетS3;unknown не превращается вmissing. При503 last-good row иdisabled state сохранены; после200 ошибка снята. Страница2/row51 сохранилась послеrefresh. Keyboard Enter/cancel возвращает focus на правильный delete trigger, global overflow отсутствует. Scoped axe по текущимWCAG tags:0violations; UI writes0. Эта проверка не заменяет screen-reader/manual WCAG приёмку. + +Новый large-backups-file-state.spec.ts и scoped ESLint прошли. Existing PNG/screens не перезаписывались; runtime код/образы не изменялись. [ПК metrics](ux-ui/acceptance/backups241-large-1440.json), [320px metrics](ux-ui/acceptance/backups241-large-320.json). Прежняя большая таблица с иными сценариями не считалась повторно новой приёмкой. + +Следующий242 — доступный GeoIP mirror job в own SQL/file scope. В коде есть публичный mirror без licence key; actual paid MaxMind, Cloudflare DNS ACME, registry/container/Gitea jobs требуют отдельного контроля и прав. Остальные внешние группы остаются в матрице. + ## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14) В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись. diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md index 908923bf..88a0c65a 100644 --- a/docs/ux-ui-remaining-acceptance.md +++ b/docs/ux-ui-remaining-acceptance.md @@ -1,11 +1,21 @@ # Оставшаяся внешняя приёмка — 2026-10-14 -Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт. +Актуальное продолжение 2026-10-14:241 — после237 приняты1000 смешанных local/missing,both/missing,unknown,available строк:ПК1440/320, rendered50, DOM2477/2239, search/last-good/pagination/keyboard passed, scoped axe0, writes0. Runtime backend/frontend ux-backups237. S3 native/limitedUI/retention230–240 приняты в записанных границах. Следующий242 — доступный mirror GeoIP job в изолированном scope; paid MaxMind/Cloudflare/Gitea/container jobs отдельно. Этап12.5 открыт. -Это актуальная матрица после 12.5.240. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. +Это актуальная матрица после 12.5.241. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии. Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-backups237`, frontend `ux-backups237`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись. +## 12.5.241 — тысяча бэкапов со смешанными состояниями файлов (2026-10-14) + +Изменение237 проверено на1000 обычных live-path HTTP DTO (199062bytes), по250 local/missing,both/missing,local/unknown,local/available. Два сценария1440/320 прошли25.2s. UI сохраняет pagination50 строк:DOM2477/2239, ready1203/806ms в dev fixture окружении. Это измерение конкретного запуска, не production SLA/сетевой latency и не доказательство скорости filesystem API1000 файлов. + +Глобальный поиск находит997–999 вне первой страницы и показывает правильные действия:missing local disabled download/restore иrecord-only dialog;both missing допускаетS3;unknown не превращается вmissing. При503 last-good row иdisabled state сохранены; после200 ошибка снята. Страница2/row51 сохранилась послеrefresh. Keyboard Enter/cancel возвращает focus на правильный delete trigger, global overflow отсутствует. Scoped axe по текущимWCAG tags:0violations; UI writes0. Эта проверка не заменяет screen-reader/manual WCAG приёмку. + +Новый large-backups-file-state.spec.ts и scoped ESLint прошли. Existing PNG/screens не перезаписывались; runtime код/образы не изменялись. [ПК metrics](ux-ui/acceptance/backups241-large-1440.json), [320px metrics](ux-ui/acceptance/backups241-large-320.json). Прежняя большая таблица с иными сценариями не считалась повторно новой приёмкой. + +Следующий242 — доступный GeoIP mirror job в own SQL/file scope. В коде есть публичный mirror без licence key; actual paid MaxMind, Cloudflare DNS ACME, registry/container/Gitea jobs требуют отдельного контроля и прав. Остальные внешние группы остаются в матрице. + ## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14) В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись. @@ -98,7 +108,7 @@ Portal offline JWT действует доexp после logout/role change; э ## Следующая последовательность — 2026-10-14 -1. **241 — большой список:** после изменения237 проверить1000 missing/unknown/both строк, global search/pagination, сохранение last-good и mobile controls. Затем — доступные external jobs и явные границы выпуска. +1. **242 — доступные external jobs:** actual GeoIP mirror без licence key в own SQL/files scope; отдельно сохранять ограничения paid MaxMind/Cloudflare/registry/Gitea. Затем — актуальная матрица границ выпуска. 2. **Профильный контроль:** для новых изменений выполнять затронутые SQL/API/UI проверки. Общая регрессия192 выполнена; не повторять её без изменений общей основы или нового основания. 3. **Внешние зависимости:** Portal issuer/login/revoke, Telegram bot/chat/разрешённое сообщение, клиентские ОС, независимые WAN/public IPv6 и scale/multi-instance — отдельные группы по таблице выше. Ограничения текущего стенда не превращать в обещание приёмки всех конфигураций. diff --git a/docs/ux-ui-stage-12.md b/docs/ux-ui-stage-12.md index 9700bea3..375837d3 100644 --- a/docs/ux-ui-stage-12.md +++ b/docs/ux-ui-stage-12.md @@ -1,6 +1,6 @@ # Этап 12: итоговая приёмка UX/UI -Актуальное продолжение 2026-10-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт. +Актуальное продолжение 2026-10-14:241 — после237 приняты1000 смешанных local/missing,both/missing,unknown,available строк:ПК1440/320, rendered50, DOM2477/2239, search/last-good/pagination/keyboard passed, scoped axe0, writes0. Runtime backend/frontend ux-backups237. S3 native/limitedUI/retention230–240 приняты в записанных границах. Следующий242 — доступный mirror GeoIP job в изолированном scope; paid MaxMind/Cloudflare/Gitea/container jobs отдельно. Этап12.5 открыт. План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push. @@ -4152,6 +4152,16 @@ Real Portal/browser API, provider local verified: создан один job ро Runtime backend ux-backup234/frontend ux-routing218 healthy; новое application image для volume-only fix не требовалось. Пароли CHR не менялись, S3 mutations0 в235, configs body/JWT не опубликованы, private local manifest удалён. Исходные10 missing local files не восстановлены и records не удалены. Force-recreate — не host reboot/power loss/fsync/DR приёмка. Далее236 — UX недоступных local files, затем version retention границы и оставшиеся7 группы матрицы; multi-instance guard не принимается. Этап12.5 открыт. +## 12.5.241 — тысяча бэкапов со смешанными состояниями файлов (2026-10-14) + +Изменение237 проверено на1000 обычных live-path HTTP DTO (199062bytes), по250 local/missing,both/missing,local/unknown,local/available. Два сценария1440/320 прошли25.2s. UI сохраняет pagination50 строк:DOM2477/2239, ready1203/806ms в dev fixture окружении. Это измерение конкретного запуска, не production SLA/сетевой latency и не доказательство скорости filesystem API1000 файлов. + +Глобальный поиск находит997–999 вне первой страницы и показывает правильные действия:missing local disabled download/restore иrecord-only dialog;both missing допускаетS3;unknown не превращается вmissing. При503 last-good row иdisabled state сохранены; после200 ошибка снята. Страница2/row51 сохранилась послеrefresh. Keyboard Enter/cancel возвращает focus на правильный delete trigger, global overflow отсутствует. Scoped axe по текущимWCAG tags:0violations; UI writes0. Эта проверка не заменяет screen-reader/manual WCAG приёмку. + +Новый large-backups-file-state.spec.ts и scoped ESLint прошли. Existing PNG/screens не перезаписывались; runtime код/образы не изменялись. [ПК metrics](ux-ui/acceptance/backups241-large-1440.json), [320px metrics](ux-ui/acceptance/backups241-large-320.json). Прежняя большая таблица с иными сценариями не считалась повторно новой приёмкой. + +Следующий242 — доступный GeoIP mirror job в own SQL/file scope. В коде есть публичный mirror без licence key; actual paid MaxMind, Cloudflare DNS ACME, registry/container/Gitea jobs требуют отдельного контроля и прав. Остальные внешние группы остаются в матрице. + ## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14) В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись. diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md index 22f7f1c6..d581888c 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-14:240 — retention принят в own PostgreSQL + real Selectel S3:8 copies/3 fixture servers, partial deletion1 с сохранением failed row/object, retry1/noop0, второй server prune2, latest contents/states подтверждены. Удалены5 versions+2markers, own catalog/DB/role/container и приватные ключи; CHRcontacts0/main catalog не использовался. Runtime backend/frontend ux-backups237. Следующий241 — большой список со статусами файлов после237, затем уточнение оставшихся внешних jobs/границ выпуска. Этап12.5 открыт. +Актуальное продолжение 2026-10-14:241 — после237 приняты1000 смешанных local/missing,both/missing,unknown,available строк:ПК1440/320, rendered50, DOM2477/2239, search/last-good/pagination/keyboard passed, scoped axe0, writes0. Runtime backend/frontend ux-backups237. S3 native/limitedUI/retention230–240 приняты в записанных границах. Следующий242 — доступный mirror GeoIP job в изолированном scope; paid MaxMind/Cloudflare/Gitea/container jobs отдельно. Этап12.5 открыт. | Параметр | Проверенное состояние | | --- | --- | @@ -34,6 +34,16 @@ OSPF84: real GRE Full adjacency/private routes/Ping3/3 и4 live PC/320px URL/bro BFD85: Up/Full/own route/Ping,4 live UI и loss/withdrawal/recovery приняты; exact own cleanup8 коллекций×2 passed. Withdrawal5,245ms не подтверждает sub-second BFD timing; этот вопрос открыт. Runtime routing83 без новой сборки. [Отчёт](ux-ui/acceptance/ospf-bfd-loss-2026-10-09.json). +## 12.5.241 — тысяча бэкапов со смешанными состояниями файлов (2026-10-14) + +Изменение237 проверено на1000 обычных live-path HTTP DTO (199062bytes), по250 local/missing,both/missing,local/unknown,local/available. Два сценария1440/320 прошли25.2s. UI сохраняет pagination50 строк:DOM2477/2239, ready1203/806ms в dev fixture окружении. Это измерение конкретного запуска, не production SLA/сетевой latency и не доказательство скорости filesystem API1000 файлов. + +Глобальный поиск находит997–999 вне первой страницы и показывает правильные действия:missing local disabled download/restore иrecord-only dialog;both missing допускаетS3;unknown не превращается вmissing. При503 last-good row иdisabled state сохранены; после200 ошибка снята. Страница2/row51 сохранилась послеrefresh. Keyboard Enter/cancel возвращает focus на правильный delete trigger, global overflow отсутствует. Scoped axe по текущимWCAG tags:0violations; UI writes0. Эта проверка не заменяет screen-reader/manual WCAG приёмку. + +Новый large-backups-file-state.spec.ts и scoped ESLint прошли. Existing PNG/screens не перезаписывались; runtime код/образы не изменялись. [ПК metrics](ux-ui/acceptance/backups241-large-1440.json), [320px metrics](ux-ui/acceptance/backups241-large-320.json). Прежняя большая таблица с иными сценариями не считалась повторно новой приёмкой. + +Следующий242 — доступный GeoIP mirror job в own SQL/file scope. В коде есть публичный mirror без licence key; actual paid MaxMind, Cloudflare DNS ACME, registry/container/Gitea jobs требуют отдельного контроля и прав. Остальные внешние группы остаются в матрице. + ## 12.5.240 — retention на реальном S3 и частичный отказ удаления (2026-10-14) В production image ux-backups237 запущен compiled pruneBackupsForServer/delete/read service в отдельной PostgreSQL базе с собственным NOSUPERUSER/NOCREATEDB/NOCREATEROLE/NOBYPASSRLS пользователем. Основной каталог/настройки не использовались. Seed8 harmless copies на3 собственных fixture servers:5 точных объектов в новом UUID S3 prefix и5 local files (both учитываются в обеих группах). RouterOS не опрашивался и не применялся; cfg bucket virtual-hosted Selectel, настройки бакета не менялись. diff --git a/docs/ux-ui/acceptance/backups241-large-1440.json b/docs/ux-ui/acceptance/backups241-large-1440.json new file mode 100644 index 00000000..6e7e430b --- /dev/null +++ b/docs/ux-ui/acceptance/backups241-large-1440.json @@ -0,0 +1,16 @@ +{ + "date": "2026-10-14", + "block": "12.5.241", + "width": 1440, + "fixtureRows": 1000, + "fixtureBytes": 199062, + "renderedRows": 50, + "domNodes": 2477, + "readyMs": 1203, + "globalSearchAllRows": true, + "lastGoodStatusRetained": true, + "pagePreservedOnRefresh": true, + "keyboardCancelFocusRestored": true, + "scopedAxeViolations": 0, + "backupWrites": 0 +} diff --git a/docs/ux-ui/acceptance/backups241-large-320.json b/docs/ux-ui/acceptance/backups241-large-320.json new file mode 100644 index 00000000..a55646a7 --- /dev/null +++ b/docs/ux-ui/acceptance/backups241-large-320.json @@ -0,0 +1,16 @@ +{ + "date": "2026-10-14", + "block": "12.5.241", + "width": 320, + "fixtureRows": 1000, + "fixtureBytes": 199062, + "renderedRows": 50, + "domNodes": 2239, + "readyMs": 806, + "globalSearchAllRows": true, + "lastGoodStatusRetained": true, + "pagePreservedOnRefresh": true, + "keyboardCancelFocusRestored": true, + "scopedAxeViolations": 0, + "backupWrites": 0 +} diff --git a/tests/e2e/large-backups-file-state.spec.ts b/tests/e2e/large-backups-file-state.spec.ts new file mode 100644 index 00000000..3ca9c7f9 --- /dev/null +++ b/tests/e2e/large-backups-file-state.spec.ts @@ -0,0 +1,62 @@ +import { test, expect } from "@playwright/test" +import { backupItemDtoSchema } from "../../packages/contracts/src/backups" +import { backup, setupBackups } from "./fixtures/backups" +import axe from "axe-core" +import { writeFileSync } from "node:fs" + +for (const width of [1440, 320]) test(`Backups1000: смешанные состояния файлов ${width}`, async ({ page }, info) => { + test.setTimeout(90000) + await page.setViewportSize({ width, height: 1000 }) + const states = ["missing", "missing", "unknown", "available"] as const + const catalog = Array.from({ length: 1000 }, (_, i) => backupItemDtoSchema.parse({ + ...backup, id: "backup-" + (i + 1), filename: "state-" + String(i + 1).padStart(4, "0") + ".rsc", + storage: i % 4 === 1 ? "both" : "local", localFileStatus: states[i % 4], sizeBytes: (i + 1) * 1024, + })) + let failed = false, reads = 0, writes = 0 + await setupBackups(page) + page.on("request", r => { if (new URL(r.url()).pathname.startsWith("/api/backups") && r.method() !== "GET") writes++ }) + await page.route("**/api/backups", r => { reads++; return r.fulfill(failed ? { status: 503, json: { error: "История недоступна" } } : { json: catalog }) }) + const start = Date.now(); await page.goto("/backups") + const rows = page.locator("tr[data-row-id]") + await expect(page.getByText("state-0001.rsc", { exact: true })).toBeVisible() + await expect(rows).toHaveCount(50) + const sample = { date: "2026-10-14", block: "12.5.241", width, fixtureRows: 1000, fixtureBytes: Buffer.byteLength(JSON.stringify(catalog)), renderedRows: await rows.count(), domNodes: await page.locator("*").count(), readyMs: Date.now() - start } + expect(sample.domNodes).toBeLessThan(5000) + const search = page.getByPlaceholder("Поиск по файлу, серверу, заметке…") + await search.fill("state-0997"); await expect(rows).toHaveCount(1) + await expect(rows.first()).toHaveAttribute("data-row-id", "backup-997") + await expect(page.getByRole("button", { name: "Скачать state-0997.rsc", exact: true })).toBeDisabled() + await expect(page.getByRole("button", { name: "Восстановить state-0997.rsc", exact: true })).toBeDisabled() + const refresh = page.getByRole("button", { name: "Обновить", exact: true }) + failed = true; await refresh.click() + await expect(page.getByRole("alert", { name: "Данные резервных копий: backups", exact: true })).toContainText("Последние данные сохранены") + await expect(rows).toHaveCount(1) + await expect(page.getByRole("button", { name: "Скачать state-0997.rsc", exact: true })).toBeDisabled() + failed = false; const before = reads; await refresh.click(); await expect.poll(() => reads).toBeGreaterThan(before) + await expect(page.getByRole("alert", { name: "Данные резервных копий: backups", exact: true })).toHaveCount(0) + const scroll = page.locator('[data-slot="data-grid"] [data-slot="scroll-area-viewport"]') + if (width === 320) await scroll.evaluate(el => { el.scrollLeft = el.scrollWidth }) + const remove = page.getByRole("button", { name: "Удалить state-0997.rsc", exact: true }) + await remove.focus(); await page.keyboard.press("Enter") + await expect(page.getByRole("alertdialog")).toContainText("Будет удалена только запись из истории.") + await page.getByRole("alertdialog").getByRole("button", { name: "Отмена", exact: true }).click() + await expect(remove).toBeFocused() + await search.fill("state-0998"); await expect(rows.first()).toHaveAttribute("data-row-id", "backup-998") + await expect(page.getByRole("button", { name: "Скачать state-0998.rsc", exact: true })).toBeEnabled() + await expect(page.getByRole("button", { name: "Восстановить state-0998.rsc", exact: true })).toBeEnabled() + await expect(page.getByText("Локальная копия отсутствует. Файл будет запрошен из S3.", { exact: true })).toBeVisible() + await search.fill("state-0999"); await expect(rows.first()).toHaveAttribute("data-row-id", "backup-999") + await expect(page.getByText("Не удалось проверить локальный файл.", { exact: true })).toBeVisible() + await expect(page.getByRole("button", { name: "Скачать state-0999.rsc", exact: true })).toBeEnabled() + await search.fill(""); await expect(rows).toHaveCount(50) + await page.getByRole("button", { name: "Следующая страница", exact: true }).click() + await expect(rows.first()).toHaveAttribute("data-row-id", "backup-51") + await refresh.click(); await expect(rows.first()).toHaveAttribute("data-row-id", "backup-51") + expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true) + await page.addScriptTag({ content: axe.source }) + const audit = await page.evaluate(async () => (window as unknown as { axe: typeof axe }).axe.run(document.querySelector('[data-slot="data-grid"]')!, { runOnly: { type: "tag", values: ["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"] } })) + expect(audit.violations).toEqual([]); expect(writes).toBe(0) + const report = { ...sample, globalSearchAllRows: true, lastGoodStatusRetained: true, pagePreservedOnRefresh: true, keyboardCancelFocusRestored: true, scopedAxeViolations: 0, backupWrites: writes } + await info.attach("large-backup-file-states", { body: JSON.stringify(report), contentType: "application/json" }) + writeFileSync(`docs/ux-ui/acceptance/backups241-large-${width}.json`, JSON.stringify(report, null, 2) + "\n") +})