diff --git a/app/(main)/certificates/page.tsx b/app/(main)/certificates/page.tsx
index 5363d6a9..d2b28d70 100644
--- a/app/(main)/certificates/page.tsx
+++ b/app/(main)/certificates/page.tsx
@@ -55,7 +55,7 @@ import {
StepperSeparator,
StepperTitle,
StepperTrigger,
-} from "@/components/reui/stepper"
+} from "@/components/reui-kit/accessible-stepper"
function mockToDto(cert: (typeof routerCertificates)[number]): CertificateDto {
return {
@@ -311,15 +311,16 @@ function CertPartIssueForm({
Trust store · www
Веб-интерфейс и HTTPS-сервисы
-
+
Trust store · api
REST API и управление
-
+
+ После импорта сертификат будет назначен сервисам www-ssl и api-ssl; оба сервиса будут включены. Переключатели выше задают trust store сертификата.
)}
@@ -331,6 +332,8 @@ function CertPartIssueForm({
Имя: {issueCertName || "—"}
CN: {issueCommonName || "—"}
Trust www: {issueTrustWww ? "да" : "нет"} · api: {issueTrustApi ? "да" : "нет"}
+ Сервисы: www-ssl и api-ssl будут включены и получат этот сертификат.
+ DNS: приложение попробует синхронизировать A-записи доменов с IPv4 сервера; CNAME сохраняются.
)}
diff --git a/app/(main)/servers/page.tsx b/app/(main)/servers/page.tsx
index 9fee3600..0f195e59 100644
--- a/app/(main)/servers/page.tsx
+++ b/app/(main)/servers/page.tsx
@@ -53,7 +53,7 @@ import {
StepperSeparator,
StepperTitle,
StepperTrigger,
-} from "@/components/reui/stepper"
+} from "@/components/reui-kit/accessible-stepper"
import {
RefreshCwIcon, PlusIcon, TrashIcon,
EyeIcon, EyeOffIcon,
diff --git a/components/backups/backup-create-sheet.tsx b/components/backups/backup-create-sheet.tsx
index e81abe85..15d37ee5 100644
--- a/components/backups/backup-create-sheet.tsx
+++ b/components/backups/backup-create-sheet.tsx
@@ -25,7 +25,7 @@ import {
StepperSeparator,
StepperTitle,
StepperTrigger,
-} from "@/components/reui/stepper"
+} from "@/components/reui-kit/accessible-stepper"
import { Alert, AlertDescription, AlertTitle } from "@/components/reui/alert"
import { cn } from "@/lib/utils"
diff --git a/components/reui-kit/accessible-stepper.tsx b/components/reui-kit/accessible-stepper.tsx
new file mode 100644
index 00000000..ea810718
--- /dev/null
+++ b/components/reui-kit/accessible-stepper.tsx
@@ -0,0 +1,49 @@
+"use client"
+
+import { createContext, useContext, useId, type ComponentProps } from "react"
+import {
+ Stepper as RegistryStepper,
+ StepperNav as RegistryNav,
+ StepperContent as RegistryContent,
+ StepperTrigger as RegistryTrigger,
+ useStepItem,
+ type StepperProps,
+} from "@/components/reui/stepper"
+
+export { StepperItem, StepperIndicator, StepperSeparator, StepperTitle, StepperPanel } from "@/components/reui/stepper"
+
+// The registry Nav/Content do not forward HTML attributes. Keep its layout,
+// focus handling and styling; supply tab semantics in transparent wrappers.
+const Context = createContext<{ prefix: string; orientation: "horizontal" | "vertical" } | null>(null)
+function useScope() {
+ const context = useContext(Context)
+ if (!context) throw new Error("Шаги должны находиться внутри Stepper")
+ return context
+}
+
+export function Stepper({ orientation = "horizontal", ...props }: StepperProps) {
+ const prefix = useId()
+ return
+
+
+}
+
+export function StepperNav({ children, className }: Pick, "children" | "className">) {
+ const { orientation } = useScope()
+ return
+ {children}
+
+}
+
+export function StepperTrigger(props: ComponentProps) {
+ const { prefix } = useScope()
+ const { step } = useStepItem()
+ return
+}
+
+export function StepperContent({ value, children, className }: Pick, "value" | "children" | "className">) {
+ const { prefix } = useScope()
+ return
+ {children}
+
+}
diff --git a/docs/ux-ui-external-acceptance.md b/docs/ux-ui-external-acceptance.md
index 2ca6e9b3..9e9f10d9 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: 250 — production ACME принят на точном mmt250-c22a9715.pngs.top/CHR104: Portal/UI один issue POST → done; DNS-01, native import/private key, trusted TLS/SAN и REST HTTPS200. Native services/certificates/files/export и ACME settings восстановлены, собственные job/A/TXT отсутствуют; оба CHR доступны. Backend249/frontend248 unchanged. Следующий251 — раскрыть в форме выпуска автоматическое назначение SSL-сервисам и DNS A-sync, затем проверить UI; renewal/CA revoke/multi-instance отдельно. Этап12.5 открыт.
+Актуальное продолжение 2026-10-14: 251 — форма выпуска раскрывает включение www-ssl/api-ssl и DNS A-sync, trust-store switches имеют доступные имена. Общий адаптер ReUI Stepper исправляет ARIA/уникальные ID в сертификатах, серверах и бэкапах без правок vendor/styles/motion. 69 unique E2E, TypeScript/lint/build passed; live PC/mobile keyboard/scoped axe4 violations0, writes0. Backend249/frontend ux-certificates251. Следующий252 — disabled/strict-ID guards сертификатов и достоверность результата renewal; реальное renewal ещё открыто. Этап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,22 @@ 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.251 — понятные последствия выпуска и доступные мастера ReUI (2026-10-14)
+
+После250 форма явно сообщает: импорт назначает сертификат обоим www-ssl/api-ssl и включает их; trust-store переключатели задают trust-store, не отменяют назначение. Итоговая сводка показывает DNS A-sync как попытку синхронизации с IPv4 сервера и сохранение CNAME. Сетевая логика/API не менялись. Оба trust-store switches получили доступные имена.
+
+Scoped axe live preview выявил прежние aria-required-children/parent и aria-valid-attr-value: установленный Stepper root role=tablist охватывал nav и контент, nav мешал родительской роли tabs, Content не передавал id/role/aria props. [API](https://reui.io/docs/components/base/stepper?ref=mcp), [preview](https://reui.io/components/stepper?ref=mcp) и примеры прочитаны через MCP; актуальный @reui/stepper прочитан shadcn view и имеет те же пропуски. Установка/переопределение vendor не решает их и не выполнена.
+
+Добавлен reui-kit/accessible-stepper: переиспользует установленные компоненты/keyboard/focus/styles, добавляет прозрачные display:contents обёртки с tablist/tabpanel, rootgroup без неподходящего aria-orientation, React useId для tab/panel namespace. Контент forceMount с штатным hidden сохраняет все IDREF. Vendor файл, shared theme и animation timings не менялись. Все три потребителя — сертификаты, создание/редактирование серверов, создание бэкапа — переведены на адаптер.
+
+69 уникальных E2E:57 existing certificates issue/layout + servers + backup operations и12 backup job + новые3 ARIA сценария. Первый набор57 прошёл2.1m, второй12 —32.1s; первоначальные7 issue повторяются в57 и не суммируются. Проверены операции/checkpoints/отказы/права/контекст, серверный wizard320/390/1440, certificate layout320/390/1440, связь каждой tab со своей существующей panel/unique IDs/одна видимая панель и4 ARIA rules во всех трёх формах. TypeScript и scoped ESLint passed. Не заявляем полного axe/WCAG аудита всех трёх страниц.
+
+Production frontend ux-certificates251 собран и развёрнут, source528 matched, backend ux-containers249 healthy сохранён, PostgreSQL/Portal не пересоздавались. До обнаружения ARIA дефекта выполнялись промежуточные сборки copy/labels; окончательный образ содержит adapter и все последние изменения. Это повтор из-за новых найденных ошибок, не дополнительные принятые сценарии. Для следующих сложных форм сначала локальный scoped axe, затем production build. [Deployment](ux-ui/acceptance/certificates251-deployment.json).
+
+Настоящий Portal/live preview1440/390: trust www переключается Space, step3/4 показывают назначение SSL независимо от trust toggle и DNS/CNAME; нет overflow/JS errors, четыре scoped axe WCAG2/2.1/2.2 scans violations0. Формы отменены Escape, API writes0/никаких выпусков/новых DNS/native objects. [Live UI](ux-ui/acceptance/certificates251-live-ui.json), [desktop](ux-ui/screens/certificates251-review-desktop.png), [mobile](ux-ui/screens/certificates251-review-mobile.png). Mobile screenshot просмотрен. ReUI checklist пройден в изменённом scope: reuse/семантика/security/scroll/typecheck/lint; неизменённые части не объявляются заново принятыми.
+
+Следующий252: чтение certificates-service поID всё ещё принимает numeric prefix и disabled row; renewal collector опрашивает его. Collector после runIssueJob прибавляет renewed без чтения terminal job status, хотя runner записывает failed и возвращается без throw; legacy parser подменяет неизвестный срок0. Исправить эти достоверные code-path дефекты и проверить соответствующие service/SQL случаи. Реальная повторная выдача/renewal/CA revoke/multi-instance остаются отдельными неподтверждёнными вариантами, первичный ACME250 уже принят.
+
## 12.5.250 — production ACME / Cloudflare / TLS через реальный UI (2026-10-14)
Пользователь предоставил pngs.top/Cloudflare и разрешил поддомены с префиксом mmt*. После уточнения звёздочки получено согласие на точное имя mmt250-c22a9715.pngs.top и временное назначение www-ssl/api-ssl с откатом. Cloudflare token verify и exact zone query200/success, token/zone active/account matched; оба собственных DNS имени до начала имели0 records. Ключ/почта/account ID только в ignored private fixture; на Debian ключ поступил через разрешённый временный API settings, отдельный secret файл туда не передавался. Native/private settings baseline снят до начала.
diff --git a/docs/ux-ui-plan.md b/docs/ux-ui-plan.md
index dfb2f1de..f80c07c3 100644
--- a/docs/ux-ui-plan.md
+++ b/docs/ux-ui-plan.md
@@ -1,9 +1,25 @@
# План реализации UX/UI по пятичасовым окнам
-Актуальное продолжение 2026-10-14: 250 — production ACME принят на точном mmt250-c22a9715.pngs.top/CHR104: Portal/UI один issue POST → done; DNS-01, native import/private key, trusted TLS/SAN и REST HTTPS200. Native services/certificates/files/export и ACME settings восстановлены, собственные job/A/TXT отсутствуют; оба CHR доступны. Backend249/frontend248 unchanged. Следующий251 — раскрыть в форме выпуска автоматическое назначение SSL-сервисам и DNS A-sync, затем проверить UI; renewal/CA revoke/multi-instance отдельно. Этап12.5 открыт.
+Актуальное продолжение 2026-10-14: 251 — форма выпуска раскрывает включение www-ssl/api-ssl и DNS A-sync, trust-store switches имеют доступные имена. Общий адаптер ReUI Stepper исправляет ARIA/уникальные ID в сертификатах, серверах и бэкапах без правок vendor/styles/motion. 69 unique E2E, TypeScript/lint/build passed; live PC/mobile keyboard/scoped axe4 violations0, writes0. Backend249/frontend ux-certificates251. Следующий252 — disabled/strict-ID guards сертификатов и достоверность результата renewal; реальное renewal ещё открыто. Этап12.5 открыт.
Общий план проекта MikrotikManager. Основан на согласованном плане из задачи; точка продолжения обновлена 2026-10-14. Источник фактического прогресса, проверок и ограничений — [журнал реализации](ux-ui-progress.md). Этот документ задаёт объём и критерии завершения, журнал фиксирует результат.
+## 12.5.251 — понятные последствия выпуска и доступные мастера ReUI (2026-10-14)
+
+После250 форма явно сообщает: импорт назначает сертификат обоим www-ssl/api-ssl и включает их; trust-store переключатели задают trust-store, не отменяют назначение. Итоговая сводка показывает DNS A-sync как попытку синхронизации с IPv4 сервера и сохранение CNAME. Сетевая логика/API не менялись. Оба trust-store switches получили доступные имена.
+
+Scoped axe live preview выявил прежние aria-required-children/parent и aria-valid-attr-value: установленный Stepper root role=tablist охватывал nav и контент, nav мешал родительской роли tabs, Content не передавал id/role/aria props. [API](https://reui.io/docs/components/base/stepper?ref=mcp), [preview](https://reui.io/components/stepper?ref=mcp) и примеры прочитаны через MCP; актуальный @reui/stepper прочитан shadcn view и имеет те же пропуски. Установка/переопределение vendor не решает их и не выполнена.
+
+Добавлен reui-kit/accessible-stepper: переиспользует установленные компоненты/keyboard/focus/styles, добавляет прозрачные display:contents обёртки с tablist/tabpanel, rootgroup без неподходящего aria-orientation, React useId для tab/panel namespace. Контент forceMount с штатным hidden сохраняет все IDREF. Vendor файл, shared theme и animation timings не менялись. Все три потребителя — сертификаты, создание/редактирование серверов, создание бэкапа — переведены на адаптер.
+
+69 уникальных E2E:57 existing certificates issue/layout + servers + backup operations и12 backup job + новые3 ARIA сценария. Первый набор57 прошёл2.1m, второй12 —32.1s; первоначальные7 issue повторяются в57 и не суммируются. Проверены операции/checkpoints/отказы/права/контекст, серверный wizard320/390/1440, certificate layout320/390/1440, связь каждой tab со своей существующей panel/unique IDs/одна видимая панель и4 ARIA rules во всех трёх формах. TypeScript и scoped ESLint passed. Не заявляем полного axe/WCAG аудита всех трёх страниц.
+
+Production frontend ux-certificates251 собран и развёрнут, source528 matched, backend ux-containers249 healthy сохранён, PostgreSQL/Portal не пересоздавались. До обнаружения ARIA дефекта выполнялись промежуточные сборки copy/labels; окончательный образ содержит adapter и все последние изменения. Это повтор из-за новых найденных ошибок, не дополнительные принятые сценарии. Для следующих сложных форм сначала локальный scoped axe, затем production build. [Deployment](ux-ui/acceptance/certificates251-deployment.json).
+
+Настоящий Portal/live preview1440/390: trust www переключается Space, step3/4 показывают назначение SSL независимо от trust toggle и DNS/CNAME; нет overflow/JS errors, четыре scoped axe WCAG2/2.1/2.2 scans violations0. Формы отменены Escape, API writes0/никаких выпусков/новых DNS/native objects. [Live UI](ux-ui/acceptance/certificates251-live-ui.json), [desktop](ux-ui/screens/certificates251-review-desktop.png), [mobile](ux-ui/screens/certificates251-review-mobile.png). Mobile screenshot просмотрен. ReUI checklist пройден в изменённом scope: reuse/семантика/security/scroll/typecheck/lint; неизменённые части не объявляются заново принятыми.
+
+Следующий252: чтение certificates-service поID всё ещё принимает numeric prefix и disabled row; renewal collector опрашивает его. Collector после runIssueJob прибавляет renewed без чтения terminal job status, хотя runner записывает failed и возвращается без throw; legacy parser подменяет неизвестный срок0. Исправить эти достоверные code-path дефекты и проверить соответствующие service/SQL случаи. Реальная повторная выдача/renewal/CA revoke/multi-instance остаются отдельными неподтверждёнными вариантами, первичный ACME250 уже принят.
+
## 12.5.250 — production ACME / Cloudflare / TLS через реальный UI (2026-10-14)
Пользователь предоставил pngs.top/Cloudflare и разрешил поддомены с префиксом mmt*. После уточнения звёздочки получено согласие на точное имя mmt250-c22a9715.pngs.top и временное назначение www-ssl/api-ssl с откатом. Cloudflare token verify и exact zone query200/success, token/zone active/account matched; оба собственных DNS имени до начала имели0 records. Ключ/почта/account ID только в ignored private fixture; на Debian ключ поступил через разрешённый временный API settings, отдельный secret файл туда не передавался. Native/private settings baseline снят до начала.
diff --git a/docs/ux-ui-progress.md b/docs/ux-ui-progress.md
index b89087de..ab57d587 100644
--- a/docs/ux-ui-progress.md
+++ b/docs/ux-ui-progress.md
@@ -1,6 +1,6 @@
# UX/UI: журнал реализации
-Актуальное продолжение 2026-10-14: 250 — production ACME принят на точном mmt250-c22a9715.pngs.top/CHR104: Portal/UI один issue POST → done; DNS-01, native import/private key, trusted TLS/SAN и REST HTTPS200. Native services/certificates/files/export и ACME settings восстановлены, собственные job/A/TXT отсутствуют; оба CHR доступны. Backend249/frontend248 unchanged. Следующий251 — раскрыть в форме выпуска автоматическое назначение SSL-сервисам и DNS A-sync, затем проверить UI; renewal/CA revoke/multi-instance отдельно. Этап12.5 открыт.
+Актуальное продолжение 2026-10-14: 251 — форма выпуска раскрывает включение www-ssl/api-ssl и DNS A-sync, trust-store switches имеют доступные имена. Общий адаптер ReUI Stepper исправляет ARIA/уникальные ID в сертификатах, серверах и бэкапах без правок vendor/styles/motion. 69 unique E2E, TypeScript/lint/build passed; live PC/mobile keyboard/scoped axe4 violations0, writes0. Backend249/frontend ux-certificates251. Следующий252 — disabled/strict-ID guards сертификатов и достоверность результата renewal; реальное renewal ещё открыто. Этап12.5 открыт.
Общий план: [UX/UI по этапам и пятичасовым окнам](ux-ui-plan.md). План задаёт объём, этот журнал фиксирует выполненные блоки и ограничения. Записи расположены от новых к старым; подробная история этапа12 также сохранена в [ux-ui-stage-12.md](ux-ui-stage-12.md).
@@ -38,6 +38,22 @@
| 11Б | Оповещения, сбор данных, интеграции, релизы и настройки | Завершён в границах локальной приёмки 2026-10-03; ограничения и evidence в11Б.7 |
| 12 | Итоговая доступность, адаптивность, производительность и регрессия | Локальная приёмка12.3.83 в границах журнала. Внешняя12.5: блоки1–236 завершены в записанных scopes, этап открыт. Runtime backend ux-backup234/frontend ux-routing218; backend25/UI52 и дополнительные SQL/UDP222 прошли. |
+## 12.5.251 — понятные последствия выпуска и доступные мастера ReUI (2026-10-14)
+
+После250 форма явно сообщает: импорт назначает сертификат обоим www-ssl/api-ssl и включает их; trust-store переключатели задают trust-store, не отменяют назначение. Итоговая сводка показывает DNS A-sync как попытку синхронизации с IPv4 сервера и сохранение CNAME. Сетевая логика/API не менялись. Оба trust-store switches получили доступные имена.
+
+Scoped axe live preview выявил прежние aria-required-children/parent и aria-valid-attr-value: установленный Stepper root role=tablist охватывал nav и контент, nav мешал родительской роли tabs, Content не передавал id/role/aria props. [API](https://reui.io/docs/components/base/stepper?ref=mcp), [preview](https://reui.io/components/stepper?ref=mcp) и примеры прочитаны через MCP; актуальный @reui/stepper прочитан shadcn view и имеет те же пропуски. Установка/переопределение vendor не решает их и не выполнена.
+
+Добавлен reui-kit/accessible-stepper: переиспользует установленные компоненты/keyboard/focus/styles, добавляет прозрачные display:contents обёртки с tablist/tabpanel, rootgroup без неподходящего aria-orientation, React useId для tab/panel namespace. Контент forceMount с штатным hidden сохраняет все IDREF. Vendor файл, shared theme и animation timings не менялись. Все три потребителя — сертификаты, создание/редактирование серверов, создание бэкапа — переведены на адаптер.
+
+69 уникальных E2E:57 existing certificates issue/layout + servers + backup operations и12 backup job + новые3 ARIA сценария. Первый набор57 прошёл2.1m, второй12 —32.1s; первоначальные7 issue повторяются в57 и не суммируются. Проверены операции/checkpoints/отказы/права/контекст, серверный wizard320/390/1440, certificate layout320/390/1440, связь каждой tab со своей существующей panel/unique IDs/одна видимая панель и4 ARIA rules во всех трёх формах. TypeScript и scoped ESLint passed. Не заявляем полного axe/WCAG аудита всех трёх страниц.
+
+Production frontend ux-certificates251 собран и развёрнут, source528 matched, backend ux-containers249 healthy сохранён, PostgreSQL/Portal не пересоздавались. До обнаружения ARIA дефекта выполнялись промежуточные сборки copy/labels; окончательный образ содержит adapter и все последние изменения. Это повтор из-за новых найденных ошибок, не дополнительные принятые сценарии. Для следующих сложных форм сначала локальный scoped axe, затем production build. [Deployment](ux-ui/acceptance/certificates251-deployment.json).
+
+Настоящий Portal/live preview1440/390: trust www переключается Space, step3/4 показывают назначение SSL независимо от trust toggle и DNS/CNAME; нет overflow/JS errors, четыре scoped axe WCAG2/2.1/2.2 scans violations0. Формы отменены Escape, API writes0/никаких выпусков/новых DNS/native objects. [Live UI](ux-ui/acceptance/certificates251-live-ui.json), [desktop](ux-ui/screens/certificates251-review-desktop.png), [mobile](ux-ui/screens/certificates251-review-mobile.png). Mobile screenshot просмотрен. ReUI checklist пройден в изменённом scope: reuse/семантика/security/scroll/typecheck/lint; неизменённые части не объявляются заново принятыми.
+
+Следующий252: чтение certificates-service поID всё ещё принимает numeric prefix и disabled row; renewal collector опрашивает его. Collector после runIssueJob прибавляет renewed без чтения terminal job status, хотя runner записывает failed и возвращается без throw; legacy parser подменяет неизвестный срок0. Исправить эти достоверные code-path дефекты и проверить соответствующие service/SQL случаи. Реальная повторная выдача/renewal/CA revoke/multi-instance остаются отдельными неподтверждёнными вариантами, первичный ACME250 уже принят.
+
## 12.5.250 — production ACME / Cloudflare / TLS через реальный UI (2026-10-14)
Пользователь предоставил pngs.top/Cloudflare и разрешил поддомены с префиксом mmt*. После уточнения звёздочки получено согласие на точное имя mmt250-c22a9715.pngs.top и временное назначение www-ssl/api-ssl с откатом. Cloudflare token verify и exact zone query200/success, token/zone active/account matched; оба собственных DNS имени до начала имели0 records. Ключ/почта/account ID только в ignored private fixture; на Debian ключ поступил через разрешённый временный API settings, отдельный secret файл туда не передавался. Native/private settings baseline снят до начала.
diff --git a/docs/ux-ui-remaining-acceptance.md b/docs/ux-ui-remaining-acceptance.md
index 15448e2f..c5e54b5a 100644
--- a/docs/ux-ui-remaining-acceptance.md
+++ b/docs/ux-ui-remaining-acceptance.md
@@ -1,10 +1,26 @@
# Оставшаяся внешняя приёмка — 2026-10-14
-Актуальное продолжение 2026-10-14: 250 — production ACME принят на точном mmt250-c22a9715.pngs.top/CHR104: Portal/UI один issue POST → done; DNS-01, native import/private key, trusted TLS/SAN и REST HTTPS200. Native services/certificates/files/export и ACME settings восстановлены, собственные job/A/TXT отсутствуют; оба CHR доступны. Backend249/frontend248 unchanged. Следующий251 — раскрыть в форме выпуска автоматическое назначение SSL-сервисам и DNS A-sync, затем проверить UI; renewal/CA revoke/multi-instance отдельно. Этап12.5 открыт.
+Актуальное продолжение 2026-10-14: 251 — форма выпуска раскрывает включение www-ssl/api-ssl и DNS A-sync, trust-store switches имеют доступные имена. Общий адаптер ReUI Stepper исправляет ARIA/уникальные ID в сертификатах, серверах и бэкапах без правок vendor/styles/motion. 69 unique E2E, TypeScript/lint/build passed; live PC/mobile keyboard/scoped axe4 violations0, writes0. Backend249/frontend ux-certificates251. Следующий252 — disabled/strict-ID guards сертификатов и достоверность результата renewal; реальное renewal ещё открыто. Этап12.5 открыт.
-Это актуальная матрица после 12.5.250. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
+Это актуальная матрица после 12.5.251. Исторические записи сохраняют версии и ограничения на момент выполнения; поздние проверки ниже уточняют их. Этап 12.5 открыт. Успех в двух CHR и одном backend не означает приёмку всех конфигураций, интеграций или полной регрессии.
-Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-containers249`, frontend `ux-containers248`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
+Стенд: Debian13/Compose, PostgreSQL18.6, два CHR RouterOS7.24.5. Backend `ux-containers249`, frontend `ux-certificates251`; production lab с195 использует AUTH_REQUIRED=true и Portal1.3.1. Подписанные JWT/RBAC проверялись в изолированных процессах. Все собственные объекты112 удалены, исходные13 коллекций×2 (включая logging/certificates/files/routes) проверены; пароли не менялись.
+
+## 12.5.251 — понятные последствия выпуска и доступные мастера ReUI (2026-10-14)
+
+После250 форма явно сообщает: импорт назначает сертификат обоим www-ssl/api-ssl и включает их; trust-store переключатели задают trust-store, не отменяют назначение. Итоговая сводка показывает DNS A-sync как попытку синхронизации с IPv4 сервера и сохранение CNAME. Сетевая логика/API не менялись. Оба trust-store switches получили доступные имена.
+
+Scoped axe live preview выявил прежние aria-required-children/parent и aria-valid-attr-value: установленный Stepper root role=tablist охватывал nav и контент, nav мешал родительской роли tabs, Content не передавал id/role/aria props. [API](https://reui.io/docs/components/base/stepper?ref=mcp), [preview](https://reui.io/components/stepper?ref=mcp) и примеры прочитаны через MCP; актуальный @reui/stepper прочитан shadcn view и имеет те же пропуски. Установка/переопределение vendor не решает их и не выполнена.
+
+Добавлен reui-kit/accessible-stepper: переиспользует установленные компоненты/keyboard/focus/styles, добавляет прозрачные display:contents обёртки с tablist/tabpanel, rootgroup без неподходящего aria-orientation, React useId для tab/panel namespace. Контент forceMount с штатным hidden сохраняет все IDREF. Vendor файл, shared theme и animation timings не менялись. Все три потребителя — сертификаты, создание/редактирование серверов, создание бэкапа — переведены на адаптер.
+
+69 уникальных E2E:57 existing certificates issue/layout + servers + backup operations и12 backup job + новые3 ARIA сценария. Первый набор57 прошёл2.1m, второй12 —32.1s; первоначальные7 issue повторяются в57 и не суммируются. Проверены операции/checkpoints/отказы/права/контекст, серверный wizard320/390/1440, certificate layout320/390/1440, связь каждой tab со своей существующей panel/unique IDs/одна видимая панель и4 ARIA rules во всех трёх формах. TypeScript и scoped ESLint passed. Не заявляем полного axe/WCAG аудита всех трёх страниц.
+
+Production frontend ux-certificates251 собран и развёрнут, source528 matched, backend ux-containers249 healthy сохранён, PostgreSQL/Portal не пересоздавались. До обнаружения ARIA дефекта выполнялись промежуточные сборки copy/labels; окончательный образ содержит adapter и все последние изменения. Это повтор из-за новых найденных ошибок, не дополнительные принятые сценарии. Для следующих сложных форм сначала локальный scoped axe, затем production build. [Deployment](ux-ui/acceptance/certificates251-deployment.json).
+
+Настоящий Portal/live preview1440/390: trust www переключается Space, step3/4 показывают назначение SSL независимо от trust toggle и DNS/CNAME; нет overflow/JS errors, четыре scoped axe WCAG2/2.1/2.2 scans violations0. Формы отменены Escape, API writes0/никаких выпусков/новых DNS/native objects. [Live UI](ux-ui/acceptance/certificates251-live-ui.json), [desktop](ux-ui/screens/certificates251-review-desktop.png), [mobile](ux-ui/screens/certificates251-review-mobile.png). Mobile screenshot просмотрен. ReUI checklist пройден в изменённом scope: reuse/семантика/security/scroll/typecheck/lint; неизменённые части не объявляются заново принятыми.
+
+Следующий252: чтение certificates-service поID всё ещё принимает numeric prefix и disabled row; renewal collector опрашивает его. Collector после runIssueJob прибавляет renewed без чтения terminal job status, хотя runner записывает failed и возвращается без throw; legacy parser подменяет неизвестный срок0. Исправить эти достоверные code-path дефекты и проверить соответствующие service/SQL случаи. Реальная повторная выдача/renewal/CA revoke/multi-instance остаются отдельными неподтверждёнными вариантами, первичный ACME250 уже принят.
## 12.5.250 — production ACME / Cloudflare / TLS через реальный UI (2026-10-14)
@@ -226,7 +242,7 @@ Portal offline JWT действует доexp после logout/role change; э
## Следующая последовательность — 2026-10-14
-1. **Сертификаты251:** issuance250 принят; раскрыть в UI включение обоих SSL-сервисов и DNS A-sync. Затем определить scope для automatic renewal/CA revoke/remote publishing/multi-instance; эти сценарии текущим выпуском не доказаны.
+1. **Сертификаты252:** issuance250 и UX/Stepper251 приняты. Исправить disabled/strict-ID и renewal result/unknown-expiry guards, затем профильная проверка. Реальное renewal/CA revoke/remote publishing/multi-instance остаются отдельными scope.
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 61d2130e..4eb108f7 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: 250 — production ACME принят на точном mmt250-c22a9715.pngs.top/CHR104: Portal/UI один issue POST → done; DNS-01, native import/private key, trusted TLS/SAN и REST HTTPS200. Native services/certificates/files/export и ACME settings восстановлены, собственные job/A/TXT отсутствуют; оба CHR доступны. Backend249/frontend248 unchanged. Следующий251 — раскрыть в форме выпуска автоматическое назначение SSL-сервисам и DNS A-sync, затем проверить UI; renewal/CA revoke/multi-instance отдельно. Этап12.5 открыт.
+Актуальное продолжение 2026-10-14: 251 — форма выпуска раскрывает включение www-ssl/api-ssl и DNS A-sync, trust-store switches имеют доступные имена. Общий адаптер ReUI Stepper исправляет ARIA/уникальные ID в сертификатах, серверах и бэкапах без правок vendor/styles/motion. 69 unique E2E, TypeScript/lint/build passed; live PC/mobile keyboard/scoped axe4 violations0, writes0. Backend249/frontend ux-certificates251. Следующий252 — disabled/strict-ID guards сертификатов и достоверность результата renewal; реальное renewal ещё открыто. Этап12.5 открыт.
План: [ux-ui-plan.md](ux-ui-plan.md). Фактические результаты: [ux-ui-progress.md](ux-ui-progress.md). Подготовлен после сводных проверок 11Б; завершение каждого блока требует локального коммита без push.
@@ -4152,6 +4152,22 @@ 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.251 — понятные последствия выпуска и доступные мастера ReUI (2026-10-14)
+
+После250 форма явно сообщает: импорт назначает сертификат обоим www-ssl/api-ssl и включает их; trust-store переключатели задают trust-store, не отменяют назначение. Итоговая сводка показывает DNS A-sync как попытку синхронизации с IPv4 сервера и сохранение CNAME. Сетевая логика/API не менялись. Оба trust-store switches получили доступные имена.
+
+Scoped axe live preview выявил прежние aria-required-children/parent и aria-valid-attr-value: установленный Stepper root role=tablist охватывал nav и контент, nav мешал родительской роли tabs, Content не передавал id/role/aria props. [API](https://reui.io/docs/components/base/stepper?ref=mcp), [preview](https://reui.io/components/stepper?ref=mcp) и примеры прочитаны через MCP; актуальный @reui/stepper прочитан shadcn view и имеет те же пропуски. Установка/переопределение vendor не решает их и не выполнена.
+
+Добавлен reui-kit/accessible-stepper: переиспользует установленные компоненты/keyboard/focus/styles, добавляет прозрачные display:contents обёртки с tablist/tabpanel, rootgroup без неподходящего aria-orientation, React useId для tab/panel namespace. Контент forceMount с штатным hidden сохраняет все IDREF. Vendor файл, shared theme и animation timings не менялись. Все три потребителя — сертификаты, создание/редактирование серверов, создание бэкапа — переведены на адаптер.
+
+69 уникальных E2E:57 existing certificates issue/layout + servers + backup operations и12 backup job + новые3 ARIA сценария. Первый набор57 прошёл2.1m, второй12 —32.1s; первоначальные7 issue повторяются в57 и не суммируются. Проверены операции/checkpoints/отказы/права/контекст, серверный wizard320/390/1440, certificate layout320/390/1440, связь каждой tab со своей существующей panel/unique IDs/одна видимая панель и4 ARIA rules во всех трёх формах. TypeScript и scoped ESLint passed. Не заявляем полного axe/WCAG аудита всех трёх страниц.
+
+Production frontend ux-certificates251 собран и развёрнут, source528 matched, backend ux-containers249 healthy сохранён, PostgreSQL/Portal не пересоздавались. До обнаружения ARIA дефекта выполнялись промежуточные сборки copy/labels; окончательный образ содержит adapter и все последние изменения. Это повтор из-за новых найденных ошибок, не дополнительные принятые сценарии. Для следующих сложных форм сначала локальный scoped axe, затем production build. [Deployment](ux-ui/acceptance/certificates251-deployment.json).
+
+Настоящий Portal/live preview1440/390: trust www переключается Space, step3/4 показывают назначение SSL независимо от trust toggle и DNS/CNAME; нет overflow/JS errors, четыре scoped axe WCAG2/2.1/2.2 scans violations0. Формы отменены Escape, API writes0/никаких выпусков/новых DNS/native objects. [Live UI](ux-ui/acceptance/certificates251-live-ui.json), [desktop](ux-ui/screens/certificates251-review-desktop.png), [mobile](ux-ui/screens/certificates251-review-mobile.png). Mobile screenshot просмотрен. ReUI checklist пройден в изменённом scope: reuse/семантика/security/scroll/typecheck/lint; неизменённые части не объявляются заново принятыми.
+
+Следующий252: чтение certificates-service поID всё ещё принимает numeric prefix и disabled row; renewal collector опрашивает его. Collector после runIssueJob прибавляет renewed без чтения terminal job status, хотя runner записывает failed и возвращается без throw; legacy parser подменяет неизвестный срок0. Исправить эти достоверные code-path дефекты и проверить соответствующие service/SQL случаи. Реальная повторная выдача/renewal/CA revoke/multi-instance остаются отдельными неподтверждёнными вариантами, первичный ACME250 уже принят.
+
## 12.5.250 — production ACME / Cloudflare / TLS через реальный UI (2026-10-14)
Пользователь предоставил pngs.top/Cloudflare и разрешил поддомены с префиксом mmt*. После уточнения звёздочки получено согласие на точное имя mmt250-c22a9715.pngs.top и временное назначение www-ssl/api-ssl с откатом. Cloudflare token verify и exact zone query200/success, token/zone active/account matched; оба собственных DNS имени до начала имели0 records. Ключ/почта/account ID только в ignored private fixture; на Debian ключ поступил через разрешённый временный API settings, отдельный secret файл туда не передавался. Native/private settings baseline снят до начала.
diff --git a/docs/ux-ui-test-server.md b/docs/ux-ui-test-server.md
index b7fb6c7f..a9898cdb 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: 250 — production ACME принят на точном mmt250-c22a9715.pngs.top/CHR104: Portal/UI один issue POST → done; DNS-01, native import/private key, trusted TLS/SAN и REST HTTPS200. Native services/certificates/files/export и ACME settings восстановлены, собственные job/A/TXT отсутствуют; оба CHR доступны. Backend249/frontend248 unchanged. Следующий251 — раскрыть в форме выпуска автоматическое назначение SSL-сервисам и DNS A-sync, затем проверить UI; renewal/CA revoke/multi-instance отдельно. Этап12.5 открыт.
+Актуальное продолжение 2026-10-14: 251 — форма выпуска раскрывает включение www-ssl/api-ssl и DNS A-sync, trust-store switches имеют доступные имена. Общий адаптер ReUI Stepper исправляет ARIA/уникальные ID в сертификатах, серверах и бэкапах без правок vendor/styles/motion. 69 unique E2E, TypeScript/lint/build passed; live PC/mobile keyboard/scoped axe4 violations0, writes0. Backend249/frontend ux-certificates251. Следующий252 — disabled/strict-ID guards сертификатов и достоверность результата renewal; реальное renewal ещё открыто. Этап12.5 открыт.
| Параметр | Проверенное состояние |
| --- | --- |
@@ -34,6 +34,22 @@ 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.251 — понятные последствия выпуска и доступные мастера ReUI (2026-10-14)
+
+После250 форма явно сообщает: импорт назначает сертификат обоим www-ssl/api-ssl и включает их; trust-store переключатели задают trust-store, не отменяют назначение. Итоговая сводка показывает DNS A-sync как попытку синхронизации с IPv4 сервера и сохранение CNAME. Сетевая логика/API не менялись. Оба trust-store switches получили доступные имена.
+
+Scoped axe live preview выявил прежние aria-required-children/parent и aria-valid-attr-value: установленный Stepper root role=tablist охватывал nav и контент, nav мешал родительской роли tabs, Content не передавал id/role/aria props. [API](https://reui.io/docs/components/base/stepper?ref=mcp), [preview](https://reui.io/components/stepper?ref=mcp) и примеры прочитаны через MCP; актуальный @reui/stepper прочитан shadcn view и имеет те же пропуски. Установка/переопределение vendor не решает их и не выполнена.
+
+Добавлен reui-kit/accessible-stepper: переиспользует установленные компоненты/keyboard/focus/styles, добавляет прозрачные display:contents обёртки с tablist/tabpanel, rootgroup без неподходящего aria-orientation, React useId для tab/panel namespace. Контент forceMount с штатным hidden сохраняет все IDREF. Vendor файл, shared theme и animation timings не менялись. Все три потребителя — сертификаты, создание/редактирование серверов, создание бэкапа — переведены на адаптер.
+
+69 уникальных E2E:57 existing certificates issue/layout + servers + backup operations и12 backup job + новые3 ARIA сценария. Первый набор57 прошёл2.1m, второй12 —32.1s; первоначальные7 issue повторяются в57 и не суммируются. Проверены операции/checkpoints/отказы/права/контекст, серверный wizard320/390/1440, certificate layout320/390/1440, связь каждой tab со своей существующей panel/unique IDs/одна видимая панель и4 ARIA rules во всех трёх формах. TypeScript и scoped ESLint passed. Не заявляем полного axe/WCAG аудита всех трёх страниц.
+
+Production frontend ux-certificates251 собран и развёрнут, source528 matched, backend ux-containers249 healthy сохранён, PostgreSQL/Portal не пересоздавались. До обнаружения ARIA дефекта выполнялись промежуточные сборки copy/labels; окончательный образ содержит adapter и все последние изменения. Это повтор из-за новых найденных ошибок, не дополнительные принятые сценарии. Для следующих сложных форм сначала локальный scoped axe, затем production build. [Deployment](ux-ui/acceptance/certificates251-deployment.json).
+
+Настоящий Portal/live preview1440/390: trust www переключается Space, step3/4 показывают назначение SSL независимо от trust toggle и DNS/CNAME; нет overflow/JS errors, четыре scoped axe WCAG2/2.1/2.2 scans violations0. Формы отменены Escape, API writes0/никаких выпусков/новых DNS/native objects. [Live UI](ux-ui/acceptance/certificates251-live-ui.json), [desktop](ux-ui/screens/certificates251-review-desktop.png), [mobile](ux-ui/screens/certificates251-review-mobile.png). Mobile screenshot просмотрен. ReUI checklist пройден в изменённом scope: reuse/семантика/security/scroll/typecheck/lint; неизменённые части не объявляются заново принятыми.
+
+Следующий252: чтение certificates-service поID всё ещё принимает numeric prefix и disabled row; renewal collector опрашивает его. Collector после runIssueJob прибавляет renewed без чтения terminal job status, хотя runner записывает failed и возвращается без throw; legacy parser подменяет неизвестный срок0. Исправить эти достоверные code-path дефекты и проверить соответствующие service/SQL случаи. Реальная повторная выдача/renewal/CA revoke/multi-instance остаются отдельными неподтверждёнными вариантами, первичный ACME250 уже принят.
+
## 12.5.250 — production ACME / Cloudflare / TLS через реальный UI (2026-10-14)
Пользователь предоставил pngs.top/Cloudflare и разрешил поддомены с префиксом mmt*. После уточнения звёздочки получено согласие на точное имя mmt250-c22a9715.pngs.top и временное назначение www-ssl/api-ssl с откатом. Cloudflare token verify и exact zone query200/success, token/zone active/account matched; оба собственных DNS имени до начала имели0 records. Ключ/почта/account ID только в ignored private fixture; на Debian ключ поступил через разрешённый временный API settings, отдельный secret файл туда не передавался. Native/private settings baseline снят до начала.
diff --git a/docs/ux-ui/acceptance/certificates251-deployment.json b/docs/ux-ui/acceptance/certificates251-deployment.json
new file mode 100644
index 00000000..47d5ff1e
--- /dev/null
+++ b/docs/ux-ui/acceptance/certificates251-deployment.json
@@ -0,0 +1,29 @@
+{
+ "date": "2026-10-14",
+ "block": "12.5.251",
+ "containers": [
+ {
+ "name": "mmapp-test-backend",
+ "image": "mmapp-test/backend:ux-containers249",
+ "imageId": "sha256:b0d1526c683c0ce02dcac89087e13a917e27f743af192d2fda4fe26e4f11f056",
+ "running": true,
+ "health": "healthy"
+ },
+ {
+ "name": "mmapp-test-frontend",
+ "image": "mmapp-test/frontend:ux-certificates251",
+ "imageId": "sha256:efe3023ec776516fd372417def52f4c59ed4d025bc9f7acf43eefdcec2c9e544",
+ "running": true,
+ "health": "not-configured"
+ }
+ ],
+ "frontendSourceAudit": [
+ {
+ "kind": "frontend",
+ "matched": 528
+ }
+ ],
+ "frontendBuildExit": 0,
+ "backendChanged": false,
+ "gitImagePush": false
+}
diff --git a/docs/ux-ui/acceptance/certificates251-live-ui.json b/docs/ux-ui/acceptance/certificates251-live-ui.json
new file mode 100644
index 00000000..d7ec7bf6
--- /dev/null
+++ b/docs/ux-ui/acceptance/certificates251-live-ui.json
@@ -0,0 +1,27 @@
+{
+ "date": "2026-10-14",
+ "block": "12.5.251",
+ "realPortalLogin": true,
+ "noMocks": true,
+ "views": [
+ {
+ "width": 1440,
+ "keyboardToggle": true,
+ "sslAndDnsDisclosed": true,
+ "step3Violations": [],
+ "step4Violations": [],
+ "overflow": false
+ },
+ {
+ "width": 390,
+ "keyboardToggle": true,
+ "sslAndDnsDisclosed": true,
+ "step3Violations": [],
+ "step4Violations": [],
+ "overflow": false
+ }
+ ],
+ "writes": [],
+ "pageErrors": [],
+ "step3Audit": []
+}
diff --git a/docs/ux-ui/screens/certificates251-review-desktop.png b/docs/ux-ui/screens/certificates251-review-desktop.png
new file mode 100644
index 00000000..39ab618e
Binary files /dev/null and b/docs/ux-ui/screens/certificates251-review-desktop.png differ
diff --git a/docs/ux-ui/screens/certificates251-review-mobile.png b/docs/ux-ui/screens/certificates251-review-mobile.png
new file mode 100644
index 00000000..6d612380
Binary files /dev/null and b/docs/ux-ui/screens/certificates251-review-mobile.png differ
diff --git a/tests/e2e/stepper-accessibility.spec.ts b/tests/e2e/stepper-accessibility.spec.ts
new file mode 100644
index 00000000..dd230b59
--- /dev/null
+++ b/tests/e2e/stepper-accessibility.spec.ts
@@ -0,0 +1,41 @@
+import { test, expect, type Locator, type Page } from "@playwright/test"
+import axe from "axe-core"
+import { certificateRoutes, openIssue } from "./fixtures/certificate-issue"
+import { setupBackups } from "./fixtures/backups"
+import { openBackup } from "./fixtures/backup-job"
+
+async function check(page: Page, dialog: Locator) {
+ const tabs = dialog.getByRole("tablist", { name: "Шаги формы" }).getByRole("tab")
+ const ids: string[] = []
+ for (const tab of await tabs.all()) {
+ const id = await tab.getAttribute("id"), panelId = await tab.getAttribute("aria-controls")
+ expect(id).toBeTruthy(); expect(panelId).toBeTruthy(); ids.push(id!, panelId!)
+ expect(await page.evaluate(id => document.getElementById(id!)?.getAttribute("aria-labelledby"), panelId)).toBe(id)
+ }
+ expect(new Set(ids).size).toBe(ids.length)
+ for (const tab of await tabs.all()) {
+ await tab.click()
+ await expect(tab).toHaveAttribute("aria-selected", "true")
+ await expect(dialog.getByRole("tabpanel")).toHaveCount(1)
+ expect(await dialog.getByRole("tabpanel").getAttribute("id")).toBe(await tab.getAttribute("aria-controls"))
+ }
+ await page.addScriptTag({ content: axe.source })
+ const violations = await dialog.evaluate(async element => {
+ const result = await (window as unknown as { axe: typeof axe }).axe.run(element, { runOnly: { type: "rule", values: ["aria-required-children", "aria-required-parent", "aria-valid-attr-value", "aria-valid-attr"] } })
+ return result.violations.map(v => v.id)
+ })
+ expect(violations).toEqual([])
+}
+
+test("Stepper: выпуск — панели связаны со всеми вкладками", async ({ page }) => {
+ await certificateRoutes(page); await check(page, await openIssue(page))
+})
+test("Stepper: backup — панели связаны со всеми вкладками", async ({ page }) => {
+ await setupBackups(page); await check(page, await openBackup(page))
+})
+test("Stepper: создание сервера — панели связаны со всеми вкладками", async ({ page }) => {
+ await page.route("**/health", r => r.fulfill({ json: { ok: true } }))
+ await page.route("**/api/**", r => r.fulfill({ json: new URL(r.request().url()).pathname === "/api/auth/config" ? { required: false } : new URL(r.request().url()).pathname === "/api/servers" ? [] : {} }))
+ await page.goto("/servers"); await page.getByRole("button", { name: "Добавить сервер", exact: true }).click()
+ await check(page, page.getByRole("dialog"))
+})