Files
MikrotikManager/docs/ux-ui-external-acceptance.md
T

91 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UX/UI: протокол внешней приёмки 12.5
Статус на 2026-10-07: подготовлен по исходникам; на реальном стенде не выполнен. Локальные браузерные и DI-проверки записаны в [журнале](ux-ui-progress.md), общий объём — в [плане](ux-ui-plan.md). Результат каждого внешнего сценария заполняется после выполнения, с указанием HEAD и стенда.
## Паспорт стенда
Перед внешним запуском зафиксировать отдельные PostgreSQL и RouterOS тестовые устройства, версии server/client PostgreSQL и RouterOS, HEAD backend/frontend, роли пользователей, число экземпляров backend/планировщика/отправителей и способ их остановки. Для Telegram использовать тестовый чат, для остальных интеграций — тестовые endpoints и учётные записи. Зафиксировать ожидаемые изменения и способ восстановления стенда.
Пароли, JWT, REUI_LICENSE_KEY, DATABASE_URL, дампы БД и исходные приватные журналы хранить вне Git. В отчёт включать очищенные ответы, ID тестовых объектов, UTC-время, request ID, HTTP-код и проверенные изменения. Контрольный снимок данных должен позволять сравнить состояние до/после; успешный toast без независимой проверки не завершает сценарий.
## PostgreSQL и восстановление
| ID | Сценарий | Проверяемый результат | Доказательство |
| --- | --- | --- | --- |
| PG-1 | Штатный bootstrap чистой тестовой БД и повторный старт | Миграции 0008/0009 отражены в schema_migrations; constraint допускает pending/processing/unknown/sent/failed; resolution_version неотрицательна. Повторный старт сохраняет данные | Версии, очищенный журнал миграций, контрольные строки и ограничения |
| PG-2 | GET /api/system/database/backup с mm:settings:admin | Архив сформирован pg_dump, открывается совместимым pg_restore; контрольные бизнес-записи/схема присутствуют | Размер/SHA256 архива, список объектов, receipt и предупреждения |
| PG-3 | POST /api/system/database/restore из доверенного тестового архива | Данные тестовой БД соответствуют архиву; последующая запись получает корректный новый ID. UI различает завершение restore и ошибки перезапуска listener/scheduler/event | Сравнение схемы/контрольных записей, проверка последовательностей, HTTP/UI |
| PG-4 | Ошибка внутри реального pg_restore | Восстановление не объявляется успешным. Проверить rollback по контрольным бизнес-строкам и схеме, отдельно проверить последовательности | Ошибка процесса, HTTP/UI и независимые запросы до/после |
| PG-5 | Два конкурентных backup/restore запроса | Advisory lock исключает конкурирующее выполнение; второй запрос сообщает конфликт | Два request ID, HTTP-коды, журнал фактических процессов |
| PG-6 | Длительная фоновая запись и UDP-приём во время подготовки restore | Подтверждена остановка всех writers и отсутствие записей в критическом интервале; после операции потребители восстановлены либо показано предупреждение | Процесс/worker lifecycle, счётчики приёма/записей, состояния jobs |
| PG-8 | Ошибка записи speed snapshot/history и потеря commit acknowledgement | Снимок/история атомарны; неизвестный commit не выдаётся за гарантированный rollback и не вызывает автоматический повтор native test | Состояние PG после восстановления соединения, runId, HTTP/UI |
| PG-7 | Неавторизованный пользователь и обычный settings writer | Backup/restore требуют settings admin, отказ происходит до выполнения процесса | 401/403, неизменные контрольные данные, отсутствие pg_dump/pg_restore |
Реализация: [bootstrap](../backend/src/db/bootstrap.ts), [migrations](../backend/src/db/migrate.ts), [0008](../backend/drizzle/0008_alert_outbox_outcomes.sql), [0009](../backend/drizzle/0009_alert_outbox_resolution.sql), [database operation](../backend/src/services/system-database-operation.ts), [restore execution](../backend/src/services/system-database-restore-execution.ts).
Приложение использует pg_dump -Fc и pg_restore --single-transaction --clean --if-exists. Транзакционный режим описан в [документации PostgreSQL](https://www.postgresql.org/docs/current/app-pgrestore.html). Проверка пяти байтов PGDMP проверяет заголовок, но не полноту и не доверие к архиву. Для rollback нужен сценарий с ошибкой исполнения restore, а не только отказ HTTP до его начала.
Остановка таймеров scheduler и локальный вызов stopTrafficFlowListener сами по себе не доказывают завершение всех выполняющихся задач/flush или остановку экземпляров на других хостах. PG-6 остаётся открытым до наблюдаемого подтверждения; восстановление стенда выполняется после его получения. Реальные тесты backend, способные очищать таблицы, запускаются только против выделенной тестовой БД.
После bootstrap достаточно следующих запросов чтения для начальной проверки, без вывода секретов:
```sql
SELECT id FROM schema_migrations
WHERE id IN ('0008_alert_outbox_outcomes', '0009_alert_outbox_resolution');
SELECT status, count(*) FROM alert_outbox GROUP BY status;
SELECT min(resolution_version), max(resolution_version) FROM alert_outbox;
```
## Очередь уведомлений и Telegram
| ID | Сценарий | Проверяемый результат |
| --- | --- | --- |
| Q-1 | Два конкурентных claim одной записи | Один sender получает право отправить; duplicate claim не отправляет второй запрос |
| Q-2 | Telegram принял сообщение, затем settlement/history transaction отказала | Ответ Telegram не подменяет DB receipt; запись удерживается в unknown/processing, автоматического повторения нет |
| Q-3 | Timeout после возможной отправки | UI сообщает неизвестный исход; сообщение в чате и состояние БД проверяются независимо |
| Q-4 | POST /api/alerts/outbox/:id/retry для unknown с текущим expectedVersion | Одна транзакция переводит запись в pending и увеличивает resolutionVersion ровно на1; stale version даёт409 без нового изменения |
| Q-5 | Повтор processing или unknown без подтверждённой остановки всех отправителей | Processing не разрешается вручную через этот API. Перед повтором unknown зафиксированы остановка всех senders и осознанный риск дубликата |
| Q-6 | Два enqueue с одинаковым dedupe key | В PostgreSQL создана одна запись; нет двух отправок из-за race |
| Q-7 | Нарушение прав, malformed receipt, изменение источника при pending | Отказ до действия; UI сохраняет checkpoint/черновик и не переносит результат в другой источник |
Для Q-1/Q-6 нужны конкурентные соединения реального PG; in-memory DI не доказывает изоляцию. Для Q-2 проверить атомарность status/history при ошибке внутри транзакции. Остановка senders подтверждается процессами/контейнерами и завершением in-flight requests; checkbox, timeout и отсутствие недавних логов достаточным доказательством не являются. Различать принятие Telegram API и прочтение пользователем.
Источники: [outbox](../backend/src/services/alert-engine/outbox.ts), [delivery](../backend/src/services/alert-engine/outbox-execution.ts), [retry](../backend/src/services/alerts-outbox-retry.ts), [HTTP](../backend/src/routes/alerts.ts).
## RouterOS и сетевые операции
| ID | Сценарий | Проверяемый результат |
| --- | --- | --- |
| ROS-1 | Bandwidth-test transmit/receive/both на паре тестовых устройств | Реальный REST shape содержит native completion; TX — отправка клиента, RX — приём. Неизмеренная сторона null, измеренный0 сохраняется |
| ROS-2 | Authentication failed, unreachable, busy, disconnect и прерванный тест | Backend не пишет done и не заменяет старые probe averages; error run/HTTP/UI согласованы |
| ROS-3 | Выбранный srcInterface и тест скорости | Независимо проверить маршрут bandwidth-test и interface after-ping. UI не выдаёт выбор Ping-интерфейса за доказательство WAN скоростного теста |
| ROS-4 | Home→JH и JH↔Exit с асимметричной скоростью | Направления DL/UL соответствуют клиентской стороне; model limits применяются к правильному направлению |
| ROS-5 | OSPF preview → действие → перечитывание templates | Preview соответствует исправленным RX/DL и TX/UL. Применение подтверждается фактическим cost; частичный отказ не становится полным успехом |
| ROS-6 | WireGuard/IPsec/GRE/VXLAN/Firewall/BGP/маршруты | Проблема→устройство→форма→подтверждённое действие→возврат сохраняет контекст. Права и повторное нажатие проверены; фактическая конфигурация и connectivity сверены |
| ROS-9 | Смена пары в каталоге и конкурентное завершение native test | Новый snapshot unknown, старый run сохранён с actual endpoints; enable/reorder сохраняют измеренный0. Проверить row locks/условный UPDATE в реальном PG |
| ROS-8 | Смена пары/удаление speed-пробы до запуска и во время теста | Preflight409 до команды; при поздней смене новый snapshot не перезаписан, actual run сохранён без stale probe association |
| ROS-7 | Удаление/отсутствие доступа/частичный отказ одного устройства | Ошибка не стирает форму, последний снимок и объекты остальных устройств; неизвестные метрики не превращаются в0 |
Для ROS-1/ROS-2 зафиксировать версию RouterOS и очищенный сырой ответ. Строковый status подтверждается по [официальному CLI reference](https://manual.mikrotik.com/docs/cli-reference/tool/bandwidth-test/); несовместимый REST shape требует отдельной коррекции контракта. Тест скорости способен нагрузить канал — длительность и endpoints выбираются для выделенного стенда. Команды и правила маршрутизации этой UX/UI-серией не расширялись.
## Остальные интеграции
| Область | Минимальная реальная проверка |
| --- | --- |
| MaxMind/RIPE | Валидный ответ, отказ/timeout, свежесть источника и неизвестное значение; реальные данные сверены с тестовыми адресами |
| Portal/Evolution | Настоящие роли/JWT, истечение/отзыв прав, scope приложения и смена backend; отказ происходит до операции |
| Сертификаты/S3/контейнеры | Реальный job/файл/объект и права после receipt; ошибка/частичный исход, восстановление контекста |
| Gitea/CI/релизы | Сборка и delivery в выделенном стенде, отображение фактического статуса и версия. Git-коммиты текущей задачи остаются локальными; публикация — отдельное действие |
BGP-prefix evaluator, отдельное live GRE расписание и recovery processing не считать реализованными по UI или локальным тестам: текущие ограничения описаны в журналах11Б/12.
## Запись результата и критерий завершения
Для каждого ID сохранить: HEAD, UTC, идентификатор стенда/версию, роль, исходное состояние, действие, HTTP/native receipt, независимо подтверждённое итоговое состояние, результат passed/failed/blocked, способ возврата стенда и ссылку на очищенное доказательство. Пример строки:
| ID | HEAD / стенд | Доказательство | Результат | Следующий шаг |
| --- | --- | --- | --- | --- |
| ROS-1 | Заполнить при запуске | Очищенные native rows + GET истории + снимок UI | Не выполнен | Проверить transmit/receive/both |
12.5 закрывается после выполнения обязательных сценариев и разбора отказов на согласованном стенде. Подготовленный протокол, успешные browser/DI tests и автоматический axe-аудит не заменяют внешние результаты или ручную работу со screen reader.