Итог тестирования 2026-05-12

Стенд: admin.nirbi.ru (PROD). Учётка тестера: admin@erp.local / <password — см. private/creds.md>. Источники: сессия test-base/sessions/2026-05-12-admin-prod-walkthrough.md, скриншоты test-base/screenshots/2026-05-12-admin-prod-walkthrough/.

TL;DR

За день закрыто 9 разделов admin-панели + работа на POS/KDS. 27 пользовательских находок (F76-F102), плюс по 7 пунктам backlog обновлены статусы.

Состояние на конец дня:

  • POS зарегистрирован на ТТ Smoke 001, Online. KDS зарегистрирован.
  • Через UI нельзя задать PIN сотруднику или привязку к ТТ (F102). Делали через прямой PATCH с тем же endpoint что UI.
  • admin@erp.local: PIN = 9999, привязан к ТТ Smoke 001 (роль Администратор).
  • Оплата картой отложена — PayKeeper-adapter недоступен.
  • Стенд наполнен: 12 категорий, 13 ингредиентов, 5 модификаторов, 67 товаров с тематическими картинками, 82 цены в Базовом прейскуранте, 3 временных тарифа, 1 расписание меню (Завтраки 07-11), 2 в стоп-листе.
  • POS/KDS happy-path запланирован на завтра.

🚫 BLOCKER — мешает работать прямо сейчас

F102 — Невозможно отредактировать сотрудника (PIN, привязка к ТТ)

Что видит пользователь: в карточке сотрудника жмёшь «Редактировать» → меняешь PIN или магазины роли → «Сохранить» → UI бесконечно висит на «Сохранение…» без сообщений. Перезагружаешь страницу — изменения частично применились (PIN записан как has_pin: true), но валидное состояние не достигнуто и UI не сообщил об ошибке. Эффект на работу: на ТТ Smoke 001 не можем задать PIN сотрудникам → KDS логин по PIN не работает → POS/KDS happy-path заблокирован. Где смотреть: PATCH /api/v1/admin/employees/<id> → возвращает 500 INTERNAL_ERROR на любое поле ({pin}, {pin_code}, {roles: [{role_id, store_ids}]}). Pod user-service-5dcbcb747d-l7gsl в namespace erp сам по себе здоров (Ready=1, Restarts=0), значит регрессия в свежем билде. UI кроме того не обрабатывает 500 и ERR_CONNECTION_CLOSED — нужен toast/баннер + сброс loading-state.

F78 — На странице ТТ во вкладке «Интеграции» показывается «Не удалось загрузить данные PayKeeper»

Что видит пользователь: открываешь карточку ТТ → вкладка «Интеграции» → сообщение «Не удалось загрузить данные PayKeeper». Подключить PayKeeper нельзя. Где смотреть: GET /api/v1/admin/paykeeper/accounts/by-store/<store_id> → 500 «fetch failed». Сервис erp-paykeeper-adapter сейчас недоступен (на проде Kafka не поднята — Сано отметил). Дополнительно: даже после починки PK эндпоинт должен возвращать 200 + null если PK к ТТ не привязан, а не 500.

F100 — Импорт сотрудников из PayKeeper не открывается

Что видит пользователь: Сотрудники → «Выгрузить из PK» → «Нет активных интеграций PayKeeper. Сначала подключите PayKeeper в карточке юридического лица.» Подключить нельзя — см. F78. Где смотреть: GET /api/v1/admin/paykeeper/accounts?status=active → 502 {"code":"PAYKEEPER_ADAPTER_UNAVAILABLE"}. UI же отдаёт пользователю общее «Нет интеграций», скрывая что сервис недоступен. Когда PK поднимется — F100 уйдёт сам.


🔴 CRITICAL — серьёзные пользовательские проблемы

F81 — В «Чаевые (Нетмонет)» на проде показаны фейковые цифры

Что видит пользователь: Финансы → Чаевые → таблица: ТТ «Кофейня Тверская» и «Кофейня Арбат», 4 официанта (Анна Белова, Борис Котов, Елена Сидорова, Максим Петров), 45 «транзакций» = 13 950 ₽, средний чек 310 ₽, журнал на 30+ строк. Этих ТТ и сотрудников в системе нет вообще — на нашей франшизе одна ТТ Smoke 001 и два сотрудника. Эффект на работу: менеджер может принять решение на основе этих цифр. Где смотреть: admin-spa маршрут /admin/tips. При открытии страницы — ни одного запроса к backend (только /auth/me). Данные захардкожены в коде SPA. Нужно: убрать mock, заменить на реальный API. Если API ещё не готов — показывать «Раздел в разработке» или скрывать пункт из sidebar до готовности.

F91 — Длинное название ТТ при сохранении ломает форму

Что видит пользователь: в edit-форме ТТ ввёл длинное название (~500+ символов) → «Сохранить» → ничего не происходит, UI остаётся на форме без сообщения. Изменение не сохранилось. Где смотреть: PATCH /api/v1/admin/stores/<id> с длинной строкой → 500. Backend не валидирует длину (нужен 400 «Имя слишком длинное, макс N»), UI беззвучен на 500 (нужен toast). Также добавить maxLength на input.

F93 — Не сохраняется отредактированный шаблон смены

Что видит пользователь: Сотрудники → Шаблоны смен → выбираешь ТТ → «Изменить» на шаблоне → «Сохранить» → UI отображает успех, но изменения не применились. Где смотреть: PUT /api/v1/admin/shift-templates/<id> → 500 даже без изменений. Подтверждает backlog BUG-018/019. Также UI после 500 не сообщает об ошибке.

F94 — Не сохраняется формула зарплаты «По роли»

Что видит пользователь: Сотрудники → Формулы зарплаты → «Изменить» на формуле → «Сохранить» → ошибки в UI нет, но изменение не применилось. Где смотреть: PUT /api/v1/admin/salary-formulas/<id> → 500. Подтверждает backlog BUG-023. UI беззвучен.

F95 — Кнопка «Экспорт CSV» в Ведомостях не скачивает файл

Что видит пользователь: Сотрудники → Ведомости → «Экспорт CSV» → ничего не происходит, файл не скачивается. Где смотреть: Клиент шлёт GET /api/v1/admin/payroll/?store_id=&period=2026-05/export → 422. URL составлен криво: пустой store_id + period с прилипшим /export. Скорее всего ошибка в template-литерале клиента. Подтверждает backlog BUG-024.

F98 — Кнопка «Дублировать» в карточке товара не работает

Что видит пользователь: Каталог → Товары → карточка → «Дублировать» → ничего не происходит, новой копии не создаётся. Где смотреть: POST /api/v1/admin/catalog/products/<id>/duplicate → 500. UI без сообщения. Возможно конфликт имён (если backend не суффиксит «копия») или сам endpoint сломан.

F99 — Кнопка «+ Дочерняя» создаёт категорию на корневом уровне

Что видит пользователь: Категории → у существующей категории «Кофе» жмёшь «+ Дочерняя» → форма создания открывается без указания, что это подкатегория → создаётся на корневом уровне рядом с «Кофе». Иерархия не работает. Где смотреть: форма создания при триггере с «+ Дочерняя» должна передавать parent_id. Сейчас, скорее всего, контекст родителя теряется в state SPA.


🟡 MAJOR — заметные баги, есть обход

F77 — При создании франчайзи можно ввести мусор в ИНН/ОГРН/Email

Что видит пользователь: Юр.лица → «+ Создать» → франчайзи → ИНН=5 цифр, ОГРН=7 цифр, Email без @ — нажимаешь «Создать» → клиент пропускает (только «Дата договора» подсвечена как обязательная). Где смотреть: клиентская валидация на форме /admin/legal-entities/new. Нужно: pattern на ИНН (10 или 12 цифр), ОГРН (13 или 15), HTML5 type=email или regex. Серверная — отдельно (не submit’или, чтобы не плодить мусор).

F80 — Через 15 минут работы в админке всё перестаёт показывать данные

Что видит пользователь: через ~15 минут открываешь любой раздел → экраны рендерятся пустыми, «Не удалось загрузить», некоторые поля без значений. Логин-форма не появляется. Перезагрузка → редирект на /login, но иногда сразу обратно на dashboard и снова пусто. Где смотреть: SPA не обрабатывает 401 после истечения JWT — нет refresh-token flow, нет 401-interceptor → logout+redirect. JWT TTL ~15 мин.

F84 — Кнопка «Сохранить» в форме товара иногда «молчит»

Что видит пользователь: заполнил форму товара → жмёшь «Сохранить» → ничего не происходит. Если ввёл что-то невалидное в поле вне видимой области (например, отрицательное время приготовления внизу страницы) — браузерный popup появляется там, и его не видно. Где смотреть: форма /admin/catalog/products/new использует только нативную HTML5-валидацию. Нужны кастомные сообщения под каждым полем (как на форме ЮЛ), плюс автоскролл к первому invalid-полю.

F90 — Если два менеджера одновременно правят одну ТТ, второе сохранение тихо затирает первое

Что видит пользователь: менеджер А открыл ТТ → менеджер Б открыл ту же ТТ → оба меняют название → оба нажали «Сохранить» → правка Б осталась, правка А потерялась без предупреждения. Где смотреть: нет optimistic-lock. Минимум: при сохранении сравнивать updated_at от загрузки с текущим в БД → если изменился, показать «данные были изменены другим пользователем, обновите страницу».

F92 — Email-валидация работает в одной форме и не работает в другой

Что видит пользователь: в форме ТТ ввод неправильного email подсвечивается; в форме ЮЛ — пропускается без претензий. Где смотреть: на форме ТТ поле email с type="email", на форме ЮЛ — обычный type="text". Унифицировать.

F96 — После сохранения некоторых форм появляется английская ошибка

Что видит пользователь: Сотрудники → Роли → создание роли с уже существующим именем → внизу формы появляется текст «Role with this name already exists». Русскоязычный пользователь не понимает. Где смотреть: UI выводит сырое сообщение от backend при 409 (и других кодах). Нужно мапить error code → русский текст в SPA.


🟢 MINOR — мелочи UI/UX

F76 — В карточке ЮЛ ссылка «1 ТТ» уносит обратно в список ЮЛ

Где смотреть: в карточке /admin/legal-entities/<id> блок «Основные данные» → поле «Торговые точки» → ссылка 1 ТТ имеет href="/admin/legal-entities". Должна вести на /admin/stores (с фильтром по этому ЮЛ).

F79 — Названия везде показываются с кавычками: "Кассир", "Латте 0.3", "Кофе"

Что видит пользователь: в списках сотрудников, ролей, товаров, категорий, модификаторов, прейскурантов отображаются названия в кавычках, как будто это литералы. И в фильтрах те же кавычки. Где смотреть: какие-то поля имени сохранили в БД с обрамлением "...". Не убираются ни trim’ом, ни автоматически. Часть полей при создании trim’ит пробелы (категория, видел) — выборочная sanitization. Нужно: при сохранении убирать leading/trailing кавычки и пробелы единообразно.

F82 — В карточке товара можно ввести отрицательный вес и КБЖУ

Где смотреть: поля «Вес брутто/нетто (кг)», «Калории», «Белки», «Жиры», «Углеводы» — без атрибута min="0". У соседних number-полей («Порядок сортировки», «Время приготовления») min=0 настроен — inconsistency.

F83 — Поле «Цвет (HEX для POS)» принимает любой текст

Где смотреть: добавить pattern ^#[0-9A-Fa-f]{6}$ или color-picker.

F87 — В карточке товара поле «Категория» не отображается

Что видит пользователь: на странице товара виден тип, единица, статус, КБЖУ — но нет упоминания категории, к которой товар привязан. В списке товаров колонка «Категория» есть. Где смотреть: компонент детальной карточки /admin/catalog/products/<id> не выводит поле category.

F88 — В подтверждении удаления названия с кавычками отображаются с двойными кавычками

Что видит пользователь: диалог «Удалить категорию ""Кофе""?» (двойные кавычки вокруг названия, у которого они уже внутри). Где смотреть: UI оборачивает имя в кавычки → если имя уже с кавычками (см. F79), получается двойное обрамление. После фикса F79 проблема уйдёт.

F89 — В edit-форме ТТ селект «Прейскурант» содержит две опции «(дефолтный)»

Что видит пользователь: «По умолчанию (дефолтный)» и "Базовый" (дефолтный) — обе подписаны как дефолтный. Пользователь не понимает в чём разница. Где смотреть: одна опция — null-placeholder, другая — реальный default-прейскурант. Убрать пометку у placeholder.

F97 — На форме создания роли «Отмена» уносит не в список ролей, а на предыдущую страницу

Что видит пользователь: из /admin/roles/new нажал «Отмена» → попал обратно туда, откуда зашёл (например, в /admin/employees/new). Где смотреть: «Отмена» использует history.back(), нужен явный редирект на /admin/roles.

F101 — Кнопка «Улучшить с помощью AI» в edit-товаре не реагирует

Что видит пользователь: жмёшь кнопку — ничего. Ни модалки, ни запроса, ни ошибки. Где смотреть: скрыть кнопку до реализации фичи или показать «Скоро».


Backlog: статусы по итогам дня

IDСтароеНовое
BUG-002 (потеря фокуса)openverify-needed (на admin не воспроизводится — проверить под другой ролью)
BUG-005 (вкладки ЮЛ-карточки)openretracted (UI переделан: Реквизиты/ТТ/PayKeeper)
BUG-006 (404 на Save франшизы)openverify-needed (на admin не воспроизводится)
BUG-007 (поиск ФИО не работает)openverify-needed (на admin работает)
BUG-018, BUG-019 (Save шаблона смены 500)openreproduced = F93
BUG-023 (Save формулы зарплаты 500)openreproduced = F94
BUG-024 (Экспорт CSV 422)openreproduced = F95
BUG-051 (default-прейскурант не привязан)openreproduced (Назначено ТТ=0, но используется в карточке ТТ)
BUG-060 (catalog/menu 500)openfixed

Положительные подтверждения — что работает

  • Пагинация, сортировка A-Я, поиск по части слова (case-insensitive) — всё работает.
  • Inline toggle статуса товара в списке.
  • Backend защищает от каскадного удаления: категория с товарами → понятное русское сообщение «в категории есть товары».
  • Confirm-диалоги с «Это действие необратимо» на деструктивных действиях.
  • Trim пробелов в категории при создании.
  • PIN-валидация (4 цифры): блокирует буквы и >4 цифр.
  • Восстановление товаров и ролей из «Удалённые».
  • ЮЛ нельзя изменить у существующей ТТ (поле disabled с подписью).
  • Скачивание XLSX-шаблона для импорта ЮЛ.

Что НЕ покрыто сегодня и почему

  • RBAC под Manager/Franchisee/Кассир — нет credentials к существующим тестовым аккаунтам (по запросу пользователь решил пропустить).
  • Реальный импорт ЮЛ.xlsx — нет файла с данными.
  • Загрузка фото товара — не было тестового файла.
  • Удаление терминала ТТ + эффект на ТТ.
  • Деактивация ЮЛ (Активный → Приостановлен) + эффект на привязанные ТТ.
  • Концепт «Приостановлена» для ТТ — есть в фильтре, но UI-переход не нашёл (не показано в карточке).
  • POS/KDS happy-path (заказ → кухня → оплата → Z-отчёт) — заблокирован F102: нельзя задать PIN сотрудникам, KDS логин по PIN не пройдёт.
  • PayKeeper-flow (оплата картой, фискализация через PK) — adapter недоступен, deferred до подъёма Kafka.

Артефакты [TEST]-объектов на стенде

  • Товар [TEST] Капучино 0.4 (id d1224622-a76d-4bce-bee8-64bf2cc3411e) — в Удалённых. Hard-delete endpoint вернул 404, оставлен админу на очистку.
  • Остальные [TEST]-объекты вычищены.

Что в первую очередь отдать на фикс

  1. F102 — без него заблокирован POS/KDS happy-path.
  2. F81 — фейк-данные на продакшен-странице (риск принятия решений на основе мусора).
  3. F91 — backend падает 500 при длинном имени ТТ (риск рандомного 500 на любом пользовательском вводе длинной строки).
  4. F78/F100 — PayKeeper после поднятия Kafka. Заодно — добавить обработку 200+null для F78 (когда PK не привязан к ТТ).