Направление работ: AdmLk Код раздела: 2.1.5 Раздел: Настройки > Основные > Типы позиций Статус: черновик Ответственный: Панкова Л.А. Версия: 0.1 Обновлено: 03.08.26
1. Назначение
Раздел обеспечивает сотруднику админского кабинета просмотр типов позиций и создание типов для оборудования и услуг.
Функциональные правила раздела связаны с Back: 8.2.4 Администрирование > Сервисные справочники > Фильтры и их типы, типы позиций и расходов.
Сотрудник может найти и отфильтровать типы позиций по сферам, выгрузить список, указать для нового типа связанные сферы и признак «Архив», а также увидеть статус типа в таблице.
2. Ключевые понятия
Тип позиции — элемент сервисного справочника, относящийся к оборудованию или услуге.
Сфера — направление деятельности, с которым может быть связан тип позиции.
Архивный тип позиции — тип оборудования или услуги, для которого при создании включен признак «Архив».
3. Scope
Входит
S1: Добавление типа для оборудования.
S2: Добавление типа для услуг.
S3: Адаптив и загрузка.
Не входит
- Создание, редактирование и настройка сфер — 2.1.1 «Сферы».
4. BR
Указаны в пункте 4 раздела Back: 8.2.4 Типы фильтров, позиций, шаблонов и расходов.
5. Функциональные требования (UC + FR)
| ID | Сценарий | Функциональное требование | BR | Вес | Статус |
|---|---|---|---|---|---|
| S1: FR2.1.5-1 | Сотрудник открывает раздел «Типы позиций» | Интерфейс показывает заголовок «Типы позиций», поле «Найти», фильтр «Сферы», вкладки «Оборудование» и «Услуги», действия добавления и выгрузки списка, а также элемент управления отображением архивных типов, который позволяет скрыть или показать архив. По умолчанию открыта вкладка «Оборудование». | 1 | Реализовано OQ2.1.5-13 | |
| S1: FR2.1.5-2 | Сотрудник просматривает вкладку «Оборудование» | Интерфейс показывает таблицу с колонками «Тип оборудования», «Сфера» и «Статус». Для каждой записи отображаются название типа, связанные сферы и индикатор видимости. Строки архивных типов визуально отличаются от остальных строк. | 1 | Реализовано OQ2.1.5-13, OQ2.1.5-8 | |
| S1: FR2.1.5-3 | Сотрудник вводит значение в поле «Найти» | Интерфейс выполняет поиск по названию типа позиции и фильтрует список активной вкладки по введенному значению. | 1 | Реализовано OQ2.1.5-14 | |
| S1: FR2.1.5-4 | Сотрудник открывает фильтр «Сферы» | Интерфейс показывает вариант «Все» и список доступных сфер с возможностью выбрать несколько значений. | 1 | Реализовано OQ2.1.5-14 | |
| S1: FR2.1.5-5 | Сотрудник выбирает одну или несколько сфер | Интерфейс фильтрует список активной вкладки и показывает типы позиций, связанные с выбранными сферами. | 1 | Реализовано OQ2.1.5-14 | |
| S1: FR2.1.5-6 | Сотрудник открывает действие выгрузки списка | Интерфейс показывает варианты «Скачать в CSV» и «Скачать в XLS» и выгружает список в выбранном формате. | 1 | Реализовано OQ2.1.5-9 | |
| S1: FR2.1.5-7 | Сотрудник выбирает действие добавления на вкладке «Оборудование» | Интерфейс открывает боковую панель «Добавление типа оборудования» поверх таблицы. Панель содержит поля «Название» и «Сферы», признак «Архив», действие закрытия и кнопку «Сохранить». | 1 | Реализовано OQ2.1.5-15 | |
| S1: FR2.1.5-8 | Сотрудник заполняет поле «Сферы» | Интерфейс позволяет выбрать для типа оборудования одну или несколько доступных сфер. | 1 | Реализовано OQ2.1.5-15 | |
| S1: FR2.1.5-9 | Сотрудник задает признак «Архив» | Интерфейс позволяет включить или выключить признак «Архив» для создаваемого типа оборудования. Признак определяет отображение типа как архивного и значение индикатора в колонке «Статус». При выключении признака интерфейс показывает уведомление. | 1 | Частично OQ2.1.5-4, OQ2.1.5-5 | |
| S1: FR2.1.5-10 | Сотрудник заполняет форму создания типа оборудования | Все поля формы обязательны для заполнения. Интерфейс оставляет кнопку «Сохранить» недоступной, пока все поля не содержат валидные значения, и делает ее доступной после корректного заполнения формы. | 1 | Реализовано OQ2.1.5-15 | |
| S1: FR2.1.5-11 | Сотрудник закрывает форму создания типа оборудования | Интерфейс закрывает боковую панель и возвращает сотрудника к таблице без создания типа оборудования. | 1 | Реализовано OQ2.1.5-15 | |
| S1: FR2.1.5-12 | Сотрудник сохраняет заполненную форму типа оборудования | Интерфейс передает данные формы для создания типа оборудования и после успешного создания показывает новый тип в таблице «Оборудование». | 1 | Реализовано OQ2.1.5-15, OQ2.1.5-10 | |
| S2: FR2.1.5-13 | Сотрудник переходит на вкладку «Услуги» | Интерфейс показывает таблицу с колонками «Тип услуг», «Сфера» и «Статус». Для каждой записи отображаются название типа, связанные сферы и индикатор видимости. Строки архивных типов визуально отличаются от остальных строк. | 1 | Реализовано OQ2.1.5-13, OQ2.1.5-8 | |
| S2: FR2.1.5-14 | Сотрудник выбирает действие добавления на вкладке «Услуги» | Интерфейс открывает боковую панель «Добавление типа услуги» поверх таблицы. Панель содержит поля «Название» и «Сферы», признак «Архив», действие закрытия и кнопку «Сохранить». | 1 | Реализовано OQ2.1.5-15 | |
| S2: FR2.1.5-15 | Сотрудник заполняет поле «Сферы» | Интерфейс позволяет выбрать для типа услуги одну или несколько доступных сфер. | 1 | Реализовано OQ2.1.5-15 | |
| S2: FR2.1.5-16 | Сотрудник задает признак «Архив» | Интерфейс позволяет включить или выключить признак «Архив» для создаваемого типа услуги. Признак определяет отображение типа как архивного и значение индикатора в колонке «Статус». При выключении признака интерфейс показывает уведомление. | 1 | Частично OQ2.1.5-4, OQ2.1.5-5 | |
| S2: FR2.1.5-17 | Сотрудник заполняет форму создания типа услуги | Все поля формы обязательны для заполнения. Интерфейс оставляет кнопку «Сохранить» недоступной, пока все поля не содержат валидные значения, и делает ее доступной после корректного заполнения формы. | 1 | Реализовано OQ2.1.5-15 | |
| S2: FR2.1.5-18 | Сотрудник закрывает форму создания типа услуги | Интерфейс закрывает боковую панель и возвращает сотрудника к таблице без создания типа услуги. | 1 | Реализовано OQ2.1.5-15 | |
| S2: FR2.1.5-19 | Сотрудник сохраняет заполненную форму типа услуги | Интерфейс передает данные формы для создания типа услуги и после успешного создания показывает новый тип в таблице «Услуги». | 1 | Реализовано OQ2.1.5-15, OQ2.1.5-10 | |
| S3: FR2.1.5-20 | Сотрудник открывает раздел до завершения загрузки данных | Интерфейс показывает скелетоны элементов управления и таблицы, а после загрузки заменяет их доступными данными и действиями. | 1 | Частично OQ2.1.5-7 | |
| S3: FR2.1.5-21 | Сотрудник открывает раздел «Типы позиций» на поддерживаемом устройстве | Интерфейс адаптирует страницу раздела, вкладки, элементы поиска и фильтрации, таблицу и боковые панели создания для desktop, laptop и tablet. | 1 | Не реализовано OQ2.1.5-6 |
6. Открытые вопросы
Пин контекста: BRD 2.1.5 «Типы позиций» v0.1 · репозиторий
musbooking.weblk.adminpanel· commitb0d9185/ веткаmain· дата сверки 2026-09-03 · якорь:pages/settings/main/position-groups.vue,pages/settings/main/index.vue,widgets/position-types/ui/PositionTypesWidget.vue,features/position-type-list/ui/PositionTypesList.vue,features/position-type-drawer/(ui/PositionTypeDrawer.vue,model/usePositionTypeDrawer.ts,model/store.ts),entities/position-type/(model/usePositionTypesQuery.ts,store/position-types.api.ts,lib/position-type.getters.ts),shared/api/PositionTypesService.ts,shared/api-contracts/position-types/position-types.schema.ts,entities/sphere/model/useSpheresQuery.ts,shared/ui/(drawer/SimpleDrawer.vue,toggle/ToggleSwitch.vue,modals/ConfirmDialog.vue,fields/SelectField.vue,data-table/DataTable.vue,skeleton/TableSkeleton.vue,button/ArchiveActionButton.vue,button/ExportActionMenu.vue,button/AddActionButton.vue,notifications/ErrorBar.vue),layouts/default.vue,shared/ui/button/BackButton.vueСводка: 14 вопросов — Open бизнесу 5 · Open разработке 6 · Подтверждено 3. Требования: Реализовано 17 · Частично 3 · Не реализовано 1 (из 21, все веса 1). Отрезано находок обратного прохода: 4. Маршрутизация без сверки с гайдбуком (гайдбук на вход не передавался — там, где нужно решение «как должно быть», вопрос уходит бизнесу со статусом Open, а не закрывается сам). Главное: раздел реализован почти полностью — 17 требований из 21 подтверждены кодом, включая обе вкладки, поиск, фильтр по сферам, выгрузку и создание типа через боковую панель. Расхождения не в объёме, а в трёх местах. Первое: код умеет редактировать тип позиции (клик по строке открывает панель правки, уходитUpdatePositionGroup), а в BRD этого нет ни в назначении, ни в Scope, ни в одном требовании — OQ2.1.5-3. Второе: признак «Архив» ведёт себя не так, как описано, и содержит воспроизводимый дефект — после отмены подтверждения переключатель перестаёт реагировать, то есть вернуть тип из архива нельзя до закрытия панели — OQ2.1.5-4, а текст подтверждения противоречит действию — OQ2.1.5-5. Третье: адаптив (FR2.1.5-21) не сделан вовсе — OQ2.1.5-6. Отдельно стоит вопрос терминологии: в интерфейсе и BRD это «типы позиций», в коде, API и файле выгрузки — «группы позиций» — OQ2.1.5-2. Раздел BRD и раздел в коде — один и тот же, это проверено по списку разделов Настроек. Об обходе: обход полный по репозиторию (поиск поposition/Position/PositionGroupи русскому «позиц» по всем*.vue/*.ts, плюсgenerated/proto,middleware/,server/,docs/), усечения нет. Автотестов на раздел в репозитории нет. Проверено отдельно и не подтвердилось (4 находки отрезаны): (1) утечка пункта «Все» со значениемnullв список сфер записи —SelectFieldподменяет «Все» на полный список реальных сфер иnullв форму не попадает,shared/ui/fields/SelectField.vue:206-241; (2) затирание привязки «тип позиции ↔ сферы» при сохранении сферы из раздела 2.1.1 —positionGroups: []уходит только при создании новой сферы, обновление это поле не передаёт вовсе,features/sphere-drawer/model/useSphereDrawer.ts:441-456,459-475; (3) неиспользуемый параметрshowArchivedу метода списка — фронт всегда запрашивает полный список и фильтрует на клиенте, поведение от этого не меняется,shared/api/PositionTypesService.ts:19-24иfeatures/position-type-list/ui/PositionTypesList.vue:176-188; (4) отсутствие в обработчике переключателя «Архив» проверки текущего значения (в соседнем разделе она есть) — на практике эквивалентно, так как переключатель отдаёт только новое значение.
| ID | Источник | Вопрос | Кому | Статус | Рекомендации | Итоговое решение |
|---|---|---|---|---|---|---|
| OQ2.1.5-1 | ||||||
| OQ2.1.5-2 | BRD 2.1.5, разделы 1-2 + Код (раздел целиком) | Требование говорит: раздел называется «Типы позиций», а его элемент — «тип позиции», относящийся к оборудованию или услуге. В коде так подписан только интерфейс: в списке разделов Настроек стоит пункт «Типы позиций», и заголовок страницы тоже «Типы позиций». Всё, что лежит под подписью, называется иначе — страница position-groups.vue, адрес раздела /settings/main/position-groups, сущность PositionGroupItem, методы бэкенда GetPositionGroupsWeb, CreatePositionGroup, UpdatePositionGroup. Слово «группа» доходит и до сотрудника: файл выгрузки называется position-groups.csv / position-groups.xlsx, а описание раздела в списке Настроек говорит про «группы и типы позиций» как про две разные вещи. Это один и тот же раздел — сверено по пункту меню и адресу, — но у него два имени: «тип позиции» в BRD и в интерфейсе, «группа позиций» в коде, в API и в выгрузке. \ pages/settings/main/index.vue:34-37, pages/settings/main/position-groups.vue:9-10, shared/api/PositionTypesService.ts:19,27,38, shared/api-contracts/position-types/position-types.schema.ts:15-22, features/position-type-list/ui/PositionTypesList.vue:246 | Бизнес | Open | (А) Зафиксировать «тип позиции» как единственный термин продукта и добавить в раздел 2 BRD пометку, что в коде и в API он называется группой позиций (PositionGroup) (рекомендуется) — переименовывать методы бэкенда дорого и рискованно, а расхождение всё равно надо где-то объяснить, иначе каждая следующая сверка и каждый новый разработчик будут упираться в него заново. Заодно поправить описание раздела в списке Настроек, чтобы оно не обещало две сущности вместо одной. (Б) Если «группа позиций» и «тип позиции» — по замыслу разные сущности (группа объединяет типы), то BRD 2.1.5 описывает не тот объект и раздел надо переписывать: тогда нужно решение бизнеса о модели справочника. Читать «Статус» ниже стоит с этой оговоркой: сверка велась по разделу интерфейса, а не по имени сущности. | |
| OQ2.1.5-3 | Код вне BRD (раздел 1, раздел 3, FR2.1.5-2, FR2.1.5-13) | Что нашли: раздел умеет не только смотреть и создавать, но и редактировать тип позиции — этого в BRD нет ни в назначении («просмотр типов позиций и создание типов для оборудования и услуг»), ни в Scope, ни в одном из 21 требования. Клик по любой строке таблицы открывает ту же боковую панель, но в режиме правки: заголовок «Редактирование типа оборудования» или «Редактирование типа услуги», поля заполнены значениями записи, «Сохранить» отправляет UpdatePositionGroup. То есть через раздел можно переименовать существующий тип, переназначить ему сферы и снять или поставить признак «Архив» у уже созданной записи — включая возврат архивного типа в работу, то есть ровно то «восстановление», которого в требованиях тоже нет. При этом строка таблицы ничем не подсказывает, что она открывает редактирование: колонка действий отсутствует, работает только клик по строке. \ features/position-type-list/ui/PositionTypesList.vue:62-74 (клик по строке отдаёт событие edit), widgets/position-types/ui/PositionTypesWidget.vue:34-39, features/position-type-drawer/ui/PositionTypeDrawer.vue:121-124 (заголовок в режиме правки), features/position-type-drawer/model/store.ts:37-44 (UpdatePositionGroup), features/position-type-drawer/model/usePositionTypeDrawer.ts:41-51 (заполнение формы значениями записи) | Бизнес | Open | (А) Дописать в BRD сценарий редактирования — 4-5 требований по образцу FR2.1.5-7…FR2.1.5-12 (открытие панели из строки таблицы, какие поля можно менять, снятие признака «Архив» как возврат типа в работу, сохранение) и расширить назначение раздела в разделе 1 (рекомендуется) — функциональность уже работает, и без описания её нельзя ни принять, ни проверить: сейчас примерно треть возможностей раздела не покрыта ни одним требованием, а значит и ни одним тестом. (Б) Если редактирование в этом разделе не предполагалось, это вопрос не к BRD, а к правам доступа: сейчас любой сотрудник с доступом к Настройкам может переименовать или архивировать тип позиции, на который опирается каталог. Порождает OQ2.1.5-4 и OQ2.1.5-5 — оба про признак «Архив», который в режиме правки ведёт себя иначе, чем при создании. | |
| OQ2.1.5-4 | Код FR2.1.5-9, FR2.1.5-16 | Требование говорит: интерфейс позволяет включить или выключить признак «Архив». В коде включить можно всегда, а выключить — только с первой попытки. Если сотрудник нажал переключатель и в появившемся диалоге выбрал «Отмена», переключатель дальше не реагирует на нажатия — вообще, до закрытия и повторного открытия панели. Причина: переключатель полностью управляется значением из формы (:checked="modelValue"), а при отмене значение не меняется, поэтому Vue не перерисовывает скрытый чекбокс, состояние которого браузер уже переключил при клике. Следующее нажатие отдаёт наверх то же значение, которое в форме уже стоит, и обработчик ничего не делает. Визуально переключатель при этом остаётся включённым, то есть выглядит как «нажми ещё раз», хотя нажатие уже бесполезно. Практический эффект: единственный способ вернуть тип позиции из архива (см. OQ2.1.5-3) ломается после одной отмены. Тот же приём — :model-value плюс обработчик без принудительной синхронизации — повторён в разделе «Типы и параметры фильтрации», значит и починка нужна общая. \ shared/ui/toggle/ToggleSwitch.vue:3-4,23-26, features/position-type-drawer/ui/PositionTypeDrawer.vue:49-52,147-164; тот же приём — features/filter-type-drawer/ui/FilterTypeDrawer.vue:64-65,118-129 | Разработка | Open | (А) Сделать состояние переключателя однозначно производным от формы и синхронизировать его после отмены — перевести ToggleSwitch на v-model либо принудительно возвращать el.checked к значению из формы в обработчике (рекомендуется) — дефект воспроизводится минимум в двух разделах и ломает основной сценарий работы с архивом, а правка локальна и лежит в общем компоненте. (Б) Убрать подтверждение при снятии признака — тогда проблема исчезает сама, но пропадёт защита от случайного возврата типа в работу; это уже продуктовое решение, см. OQ2.1.5-5. При любом варианте проверить заодно раздел «Типы и параметры фильтрации» — там тот же код. | |
| OQ2.1.5-5 | Код FR2.1.5-9, FR2.1.5-16 | Требование говорит: при выключении признака «Архив» интерфейс показывает уведомление. В коде вместо уведомления появляется модальное окно с двумя кнопками — «Отмена» и «Отключить» — и текстом «Вы действительно хотите отключить тип позиции?». Это не сообщение, а блокирующее подтверждение: пока сотрудник не ответит, признак не изменится, а по «Отмене» откатится. И главное — текст противоречит действию: окно всплывает в момент снятия признака «Архив», то есть когда тип возвращают в работу, а спрашивают при этом «хотите отключить?» и предлагают кнопку «Отключить». Сотрудник, который возвращает тип из архива, читает вопрос про отключение и с большой вероятностью нажмёт «Отмена» — после чего попадёт в дефект из OQ2.1.5-4. Обратное действие — постановка типа в архив, то есть скрытие его из каталога — проходит вообще без подтверждения. Ровно тот же текст стоит в разделе «Типы и параметры фильтрации», поэтому формулировку надо решать один раз для обоих. \ features/position-type-drawer/ui/PositionTypeDrawer.vue:73-80 (окно и его текст), :147-164 (окно только на снятии признака, включение — молча), shared/ui/modals/ConfirmDialog.vue:4,10-12,25-31 (кнопки «Отмена» / «Отключить»); тот же текст — features/filter-type-drawer/ui/FilterTypeDrawer.vue:5-12 | Бизнес | Open | (А) Определить, какое из двух действий опаснее, и переставить подтверждение под него, переписав текст под смысл: подтверждение при переводе в архив («Скрыть тип позиции из каталога?», кнопка «В архив») и обычное уведомление при возврате в работу (рекомендуется) — сейчас защита стоит на менее опасном действии, а более опасное (убрать тип из каталога, на который завязаны позиции партнёров) проходит молча. (Б) Оставить подтверждение на снятии признака, но переписать текст на «Вернуть тип позиции в работу?» — дешевле, зато тогда FR2.1.5-9 и FR2.1.5-16 надо переформулировать: «уведомление» и «подтверждение с возможностью отмены» — разные вещи, и по текущей формулировке приёмка пройдёт при любом поведении. Связать с OQ2.1.5-4: пока текст не решён, дефект переключателя будет попадаться сотрудникам регулярно. | |
| OQ2.1.5-6 | Код FR2.1.5-21 | Требование говорит: интерфейс адаптирует страницу раздела, вкладки, элементы поиска и фильтрации, таблицу и боковые панели создания для desktop, laptop и tablet. В коде адаптива в разделе нет ни в одной из перечисленных частей: ширины заданы жёстко — поле «Найти» 360 px (одновременно width, min-width и max-width, то есть сжаться не может), фильтр «Сферы» 240 px, первая колонка таблицы 400 px, боковая панель 460 px, — и ни одного медиазапроса нет ни в списке, ни в панели. Единственное, что подстраивается под ширину экрана, — общие отступы страницы на экранах уже 640 px, но это код макета, общий для всей админ-панели, а не код раздела. Механизм в репозитории есть и применяется штатно: медиазапросы стоят в соседних разделах — «Сервисные параметры», «Рассылки», «Партнёрские тарифы». То есть это не отсутствие механизма, а неприменённый в разделе механизм. \ features/position-type-list/ui/PositionTypesList.vue:33 (поле «Найти» 360 px), :37 (фильтр 240 px), :213 (колонка 400 px), features/position-type-drawer/ui/PositionTypeDrawer.vue:5 (панель 460 px), оба файла без @media; layouts/default.vue:43-46,56-58 (единственные медиазапросы, уровень макета); примеры адаптива в репозитории — features/system-parameter-list/ui/SystemParameterList.vue:152, features/mailing-list/ui/MailingList.vue:207, features/partner-tariff-list/ui/PartnerTariffList.vue:564,571 | Разработка | Open | (А) Заменить фиксированные ширины на гибкие и добавить точки перелома для laptop и tablet по образцу «Рассылок» и «Сервисных параметров» (рекомендуется) — на tablet строка «поиск 360 px + фильтр 240 px» уже не встаёт рядом с вкладками и панелью действий, а таблица с колонкой 400 px уезжает по горизонтали; переиспользовать готовые точки перелома дешевле, чем придумывать свои. (Б) Сузить FR2.1.5-21 до desktop, а laptop и tablet вынести отдельным требованием с меньшим весом — если планшет для сервисного кабинета не приоритет. Это решение бизнеса, а не разработки: сейчас требование веса 1 не выполнено ни в одной части, и в таком виде оно будет держать раздел «незакрытым» бессрочно. | |
| OQ2.1.5-7 | Код FR2.1.5-20 | Требование говорит: до завершения загрузки интерфейс показывает скелетоны элементов управления и таблицы, а после загрузки заменяет их доступными данными и действиями. В коде скелетон есть только у таблицы. Вкладки, поле «Найти», фильтр «Сферы» и все три кнопки действий отрисовываются сразу и полностью рабочими — по ним можно нажать до того, как данные пришли. Отдельная проблема с фильтром «Сферы»: список сфер грузится своим запросом, у которого нет ни скелетона, ни блокировки, а скелетон таблицы его не ждёт — он привязан только к списку типов позиций. Пока сферы не пришли, фильтр открывается и показывает единственный пункт «Все», то есть выглядит рабочим, но отфильтровать нечем. \ features/position-type-list/ui/PositionTypesList.vue:58-59 (скелетон только у таблицы), :160 (флаг загрузки считается только по списку типов), :10-56 (вкладки, поиск, фильтр и кнопки без состояния загрузки), :157,191-196 (отдельный запрос сфер, без скелетона), shared/ui/skeleton/TableSkeleton.vue:19-25 | Разработка | Open | (А) Добавить скелетоны панели действий и строки фильтров и считать флаг загрузки по двум запросам сразу — типы позиций и сферы (рекомендуется) — в репозитории для этого есть готовый UiBlockSkeleton (shared/ui/skeleton/index.ts), он уже применяется в других разделах, так что достроить надо только вторую половину уже принятого в разделе подхода. Это же закрывает половину OQ2.1.5-8. (Б) Сузить FR2.1.5-20 до скелетона таблицы, если скелетоны элементов управления сознательно не нужны — тогда требование закрывается как есть, но отдельно понадобится решение по фильтру сфер: показывать его пустым или блокировать до загрузки. | |
| OQ2.1.5-8 | Код FR2.1.5-2, FR2.1.5-13, FR2.1.5-6 | Что нашли: в колонке «Сфера» вместо названия сферы может оказаться её технический идентификатор. Названия подставляются поиском по загруженному списку сфер, а если сфера в списке не нашлась, в ячейку выводится сам идентификатор. Список сфер запрашивается отдельно и без кэша (staleTime: 0, то есть перезапрашивается при каждом открытии раздела), а скелетон таблицы его не ждёт — значит окно, в котором таблица уже отрисована, а сферы ещё не пришли, воспроизводится штатно, и в этот момент в колонке «Сфера» стоят GUID. Тот же fallback попадает в выгрузку: если нажать «Скачать в CSV» или «Скачать в XLS» до загрузки сфер, идентификаторы уйдут в файл. Для сотрудника это выглядит как испорченные данные, хотя данные целы. \ features/position-type-list/ui/PositionTypesList.vue:199-204 (подстановка названия и fallback на идентификатор), :76-78 (колонка «Сфера»), :236-240 (та же функция в выгрузке), :58-60,160 (скелетон не ждёт сферы), entities/sphere/model/useSpheresQuery.ts:11-15 (staleTime: 0) | Разработка | Open | (А) Не показывать таблицу, пока не загружены оба списка (общий флаг загрузки из OQ2.1.5-7), а в fallback выводить пустую ячейку или «—» вместо идентификатора (рекомендуется) — GUID в справочнике читается сотрудником как поломка и приходит в поддержку как баг данных; правка на несколько строк. (Б) Кэшировать список сфер так же, как список типов позиций (staleTime 5 минут) — уменьшит окно, но не уберёт его при первом открытии раздела и не решит проблему в выгрузке. Связать с OQ2.1.5-7 — это одна и та же причина. | |
| OQ2.1.5-9 | Код FR2.1.5-6 | Требование говорит: интерфейс показывает варианты «Скачать в CSV» и «Скачать в XLS» и выгружает список в выбранном формате. В коде оба пункта есть и выгрузка работает, но отдаёт она не то, что видит сотрудник. Пункт «Скачать в XLS» сохраняет файл в формате XLSX; имя файла — position-groups.xlsx или position-groups.csv, то есть без названия раздела, без вкладки и без даты, и одинаковое для «Оборудования» и «Услуг» — две выгрузки подряд не различить. Внутри файла три колонки «Название», «Сфера», «Статус», тогда как в таблице первая колонка называется «Тип оборудования» или «Тип услуг» в зависимости от вкладки, а «Статус» показан иконкой — в файле это слова «архив» и «действует». Выгружается именно текущая выборка (вкладка, поиск, фильтр по сферам, признак показа архивных), но в файле не остаётся никаких следов того, какая это была выборка. \ features/position-type-list/ui/PositionTypesList.vue:171-174 (пункты меню), :234-249 (формирование и имя файла), :207-225 (заголовки таблицы), :88-95 (иконка в колонке «Статус») | Разработка | Open | (А) Привести файл к тому, что на экране: первая колонка — как в активной вкладке, имя файла — с названием раздела, вкладкой и датой (рекомендуется) — выгрузку делают, чтобы отдать список дальше, и он должен читаться без пояснений; сейчас получатель файла не знает ни раздела, ни вкладки. (Б) Оставить как есть и дописать в FR2.1.5-6 фактический состав файла — расхождения тогда нет, но выгрузки двух вкладок так и останутся неотличимыми по имени файла. Отдельно уточнить у бизнеса, обязателен ли именно формат XLS (устаревший бинарный) или пункт «Скачать в XLS» может отдавать XLSX, как сейчас. | |
| OQ2.1.5-10 | Код FR2.1.5-12, FR2.1.5-19 | Что нашли: успешный путь сохранения сделан полностью — данные уходят в CreatePositionGroup, кэш списка сбрасывается по тому же ключу, которым список загружается, и новый тип появляется в таблице без перезагрузки страницы. А неуспешный путь не сделан никак: текст ошибки записывается в состояние (store.error), но нигде не выводится — панель просто остаётся открытой с заполненными полями, кнопка «Сохранить» снова становится активной, и сотрудник не знает, создан тип или нет. Проверить он может только закрыв панель и поискав запись в таблице. Полоса ошибок в разделе есть, но подключена только к загрузке списка, не к сохранению. Дополнительно: панель отправляет наверх событие saved, а виджет его не слушает — обработчика нет, событие висит впустую. \ features/position-type-drawer/model/store.ts:54-59 (ошибка только в состояние), features/position-type-drawer/ui/PositionTypeDrawer.vue:64,166-173 (в интерфейсе используется только loading), features/position-type-list/ui/PositionTypesList.vue:7,162-169 (полоса ошибок — только для загрузки списка), widgets/position-types/ui/PositionTypesWidget.vue:8-12 (событие saved без обработчика) | Разработка | Open | (А) Показывать ошибку сохранения в самой панели, переиспользовав ErrorBar, который уже стоит в списке (рекомендуется) — работы немного, а сейчас любой сбой бэкенда выглядит для сотрудника как «кнопка не работает» и приходит в поддержку как баг интерфейса, то есть уходит не в ту команду. (Б) Дописать в BRD требование на состояние ошибки сохранения: сейчас FR2.1.5-12 и FR2.1.5-19 описывают только успешный путь, поэтому формально код им соответствует и приёмка этот пробел не поймает. В соседних разделах BRD состояния ошибки описаны отдельным Scope — можно взять оттуда формулировку. | |
| OQ2.1.5-11 | Код вне BRD | Что нашли: в разделе работает поведение, которого нет ни в одном из 21 требования. Пагинация: таблица показывает 25 записей на страницу с выбором 10 / 25 / 50 / 100 — при большом справочнике сотрудник видит только первую страницу, тогда как поиск и фильтр в BRD описаны так, как будто список всегда целиком на экране. Сортировка: щелчком по заголовку сортируется только колонка «Статус» (то есть архивные и действующие), а по названию и по сфере отсортировать нельзя — для справочника это наименее полезная из трёх. Обрезка названий: длиннее 40 символов название обрезается многоточием, полное видно только во всплывающей подсказке. Полоса ошибки загрузки: при сбое запроса сверху появляется красная полоса с крестиком. Общие фильтры у вкладок: поиск, фильтр по сферам и признак показа архивных не сбрасываются при переключении «Оборудование» ↔ «Услуги» и продолжают действовать на второй вкладке. Поле «Описание»: есть в контракте записи, но нигде не заполняется и не показывается. \ features/position-type-list/ui/PositionTypesList.vue:68-69 (пагинация), :216-224 (сортировка только у «Статуса»), :81-85 (обрезка до 40 символов), :7,162-169 (полоса ошибки), :148-152,176-188 (фильтры общие для вкладок), shared/api-contracts/position-types/position-types.schema.ts:18 (description) | Бизнес | Open | (А) Дописать в FR2.1.5-2 и FR2.1.5-13 пагинацию и сортировку, а в FR2.1.5-3 и FR2.1.5-5 — что поиск и фильтр применяются к активной вкладке и не сбрасываются при переключении (рекомендуется) — всё это уже в работе и будет замечено на приёмке; описать дешевле, чем разбирать как расхождение. (Б) Отдельно решить два вопроса, где нужен именно выбор бизнеса: нужна ли сортировка по названию (сейчас её нет, а для справочника она полезнее сортировки по статусу) и нужно ли поле «Описание» — оно заложено в контракт, но не используется, и либо его надо выводить, либо убирать из планов. | |
| OQ2.1.5-12 | BRD 2.1.5, шапка, раздел 4, раздел 5 | Проблема: колонка «BR» пуста у всех 21 требования. Раздел 4 отсылает целиком к пункту 4 раздела Back 8.2.4, но ни одно требование интерфейса не привязано к конкретному бизнес-правилу. Из-за этого при сверке нечем проверить полноту набора требований: например, в коде есть редактирование типа позиции (OQ2.1.5-3) и поле «Описание» в контракте (OQ2.1.5-11) — предусмотрены ли они бизнес-правилами 8.2.4 или это самодеятельность реализации, по BRD 2.1.5 понять невозможно. Второе: документ помечен как «черновик» версии 0.1, тогда как раздел в коде уже работает почти целиком — то есть BRD описывает факт, а читается как план. \ BRD 2.1.5 v0.1 от 03.08.26, шапка (статус «черновик»), раздел 4 (ссылка на 8.2.4 целиком), раздел 5 (колонка «BR» пуста во всех 21 строках) | Бизнес | Open | (А) Проставить в колонке «BR» ссылки на конкретные правила Back 8.2.4 хотя бы там, где есть бизнес-смысл — связь со сферами, признак «Архив», разделение на оборудование и услуги (рекомендуется) — без этого раздел нельзя проверить на полноту, и каждая следующая сверка будет упираться в тот же вопрос. (Б) Отметить в шапке, что BRD 2.1.5 описывает уже реализованный раздел, и снять статус «черновик» после ответов на вопросы выше. Порождает OQ2.1.5-3: без привязки к бизнес-правилам неясно, редактирование — это пропуск в BRD или лишнее в коде. | |
| OQ2.1.5-13 | Код FR2.1.5-1, FR2.1.5-2, FR2.1.5-13 | Что подтверждено: состав раздела и обе таблицы — целиком, включая детали. Заголовок «Типы позиций» выводится в шапке страницы. Поле «Найти», фильтр «Сферы», вкладки «Оборудование» и «Услуги» с открытой по умолчанию «Оборудование», кнопки добавления и выгрузки, а также переключатель показа архивных (иконка «глаз», подсказка «Скрыть архивные» или «Показать архивные» по текущему состоянию) — все на месте. В таблице ровно три колонки: заголовок первой меняется на «Тип оборудования» или «Тип услуг» в зависимости от вкладки, вторая — «Сфера» со списком названий через запятую, третья — «Статус» с иконкой видимости (открытый глаз у действующего типа, зачёркнутый у архивного). Строки архивных типов получают класс disabled и отличаются визуально от остальных. \ pages/settings/main/position-groups.vue:9-10 и shared/ui/button/BackButton.vue:6-8,51-57 с layouts/default.vue:14-16 (заголовок раздела), features/position-type-list/ui/PositionTypesList.vue:26-34 (поле «Найти»), :39-54 (фильтр «Сферы»), :132-140 (вкладки, «Оборудование» по умолчанию), :18-20 (архив, выгрузка, добавление), shared/ui/button/ArchiveActionButton.vue:3-11,26-28 (подсказки переключателя), features/position-type-list/ui/PositionTypesList.vue:207-225 (колонки), :76-78 (сферы в ячейке), :88-95 (иконка статуса), :72,230-232 (выделение архивных строк) | Бизнес | Подтверждено | Отдельного решения не требуется — требования веса 1 закрыты кодом. Проверить глазами стоит одно: заголовок раздела совмещён с кнопкой «назад» (стрелка плюс надпись «Типы позиций» над блоком таблицы), отдельного заголовка внутри самого раздела нет. Если FR2.1.5-1 подразумевал именно заголовок над таблицей — это вопрос к макету, а не к коду, и его лучше закрыть сейчас, чем на приёмке. | — |
| OQ2.1.5-14 | Код FR2.1.5-3, FR2.1.5-4, FR2.1.5-5 | Что подтверждено: поиск и фильтрация по сферам. Поиск фильтрует список активной вкладки по названию типа: без учёта регистра, по вхождению подстроки, с обрезкой пробелов по краям; запрос к бэкенду при этом не уходит — фильтрация идёт по уже загруженному списку, поэтому результат появляется сразу при вводе. Фильтр «Сферы» — мультиселект с чекбоксами: первым пунктом «Все», далее только неархивные сферы; пункт «Все» выделяет и снимает весь список одним нажатием и не попадает в значение фильтра как отдельное значение. При выборе нескольких сфер показываются типы, связанные хотя бы с одной из выбранных. Фильтры складываются между собой: вкладка, затем признак показа архивных, затем поиск, затем сферы. \ features/position-type-list/ui/PositionTypesList.vue:176-188 (сложение фильтров, поиск по вхождению, отбор по любой из выбранных сфер), :191-196 (пункт «Все» и только неархивные сферы), shared/ui/fields/SelectField.vue:206-241 (поведение пункта «Все») | Бизнес | Подтверждено | Отдельного решения не требуется — требования веса 1 закрыты кодом. Одно уточнение для BRD: при выборе нескольких сфер код показывает типы, связанные хотя бы с одной из выбранных, а формулировка FR2.1.5-5 («связанные с выбранными сферами») допускает и второе чтение — «связанные со всеми выбранными». Стоит зафиксировать первое прямо в требовании, иначе на приёмке это станет спором без правых. | — |
| OQ2.1.5-15 | Код FR2.1.5-7, FR2.1.5-8, FR2.1.5-10, FR2.1.5-11, FR2.1.5-12, FR2.1.5-14, FR2.1.5-15, FR2.1.5-17, FR2.1.5-18, FR2.1.5-19 | Что подтверждено: боковая панель создания — оба варианта, «Оборудование» и «Услуги», одним и тем же компонентом. Заголовок собирается по типу: «Добавление типа оборудования» или «Добавление типа услуги». Панель открывается справа поверх таблицы с затемнением, содержит поле «Название», мультиселект «Сферы» (тот же список неархивных сфер, что и в фильтре), переключатель «Архив» (по умолчанию выключен) и кнопку «Сохранить» во всю ширину. Закрытие: круглая кнопка с крестиком в шапке панели и клик по затемнению (штатное поведение overlay-панели); при закрытии форма сбрасывается и запись не создаётся. Валидация: «Сохранить» недоступна, пока не заполнено название (строка из пробелов не считается) и не выбрана хотя бы одна сфера, а также на время запроса — на кнопке в этот момент «Сохранение…». Сохранение уходит в CreatePositionGroup с названием, типом из активной вкладки, списком сфер и признаком архива; после успеха сбрасывается кэш списка по тому же ключу, которым список загружается, и новый тип появляется в таблице своей вкладки без перезагрузки страницы. Отдельно проверена привязка «тип позиции ↔ сферы» на другой стороне: раздел «Сферы» при обновлении сферы список её типов не передаёт вовсе, так что затереть привязку из 2.1.1 нельзя. \ features/position-type-drawer/ui/PositionTypeDrawer.vue:5,121-124 (панель и заголовок), :11-41 (поля «Название» и «Сферы»), :46-54 (переключатель «Архив»), :58-69 (кнопка «Сохранить» и её блокировка), :137-144 (сброс формы при закрытии), shared/ui/drawer/SimpleDrawer.vue:2-12,23-25 (затемнение и крестик), features/position-type-drawer/model/usePositionTypeDrawer.ts:25-32 (валидация), :55-62 (сброс кэша), entities/position-type/model/usePositionTypesQuery.ts:13-14 (тот же ключ кэша), features/position-type-drawer/model/store.ts:45-52 (CreatePositionGroup), features/sphere-drawer/model/useSphereDrawer.ts:441-456 (обновление сферы не трогает привязку) | Бизнес | Подтверждено | Отдельного решения не требуется — требования веса 1 закрыты кодом. Два уточнения для BRD: (1) в мультиселекте «Сферы» внутри панели есть пункт «Все», который проставляет типу все неархивные сферы сразу — в FR2.1.5-8 и FR2.1.5-15 он не описан, и стоит решить, нужен ли он при создании (в фильтре он уместен, в форме означает «связать со всеми сферами», что может быть не тем, что хотел сотрудник); (2) если создать тип с включённым признаком «Архив», когда показ архивных выключен, новый тип в таблицу не попадёт — формально это расходится с «после успешного создания показывает новый тип в таблице» в FR2.1.5-12 и FR2.1.5-19, хотя запись создана. Оба пункта — уточнение текста, не переделка кода. | — |