refactor: group canonical specs by domain and archive account-top-positions (#74)
Specs security / security (push) Successful in 7s
Specs verify / verify (push) Successful in 14s

This commit was merged in pull request #75.
This commit is contained in:
2026-11-02 21:50:49 +03:00
parent 1fd7e6ad97
commit 3821d9ed58
61 changed files with 707 additions and 1448 deletions
@@ -0,0 +1,493 @@
# portfolio-concentration Specification
## Purpose
Позволяет авторизованному User увидеть на странице одного Brokerage Account, какие акции, облигации, секторы и эмитенты занимают наибольшую часть текущей оценки Portfolio в выбранной валюте, без валютной конвертации.
## Requirements
### Requirement: Вкладка «Концентрация» страницы счёта
Система SHALL показывать на странице одного Brokerage Account вкладку «Концентрация» рядом с вкладкой «Позиции». Система SHALL NOT показывать вкладку в режиме «Все счета». Добавление вкладки SHALL NOT менять вкладку, открываемую по умолчанию, и содержание остальных вкладок.
#### Scenario: Вкладка на странице одного счёта
- **WHEN** User открывает страницу доступного Brokerage Account
- **THEN** рядом с вкладкой «Позиции» доступна вкладка «Концентрация», а по умолчанию открыта прежняя вкладка
#### Scenario: Режим «Все счета»
- **WHEN** User открывает общий портфель в режиме «Все счета»
- **THEN** вкладки «Концентрация» нет
### Requirement: Вкладка в состояниях страницы
Система SHALL NOT показывать вкладку «Концентрация», пока Portfolio загружается, при его ошибке или недоступности и при штатном пустом Portfolio по требованию «Состояния и ошибки Portfolio на клиенте» из `portfolio-view`. Вкладка SHALL показываться при Portfolio хотя бы с одной позицией или денежным остатком.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
#### Scenario: Загрузка и ошибка
- **WHEN** Portfolio загружается либо получение завершилось ошибкой
- **THEN** вкладки «Концентрация» нет
#### Scenario: Штатный пустой Portfolio
- **WHEN** у счёта нет позиций и денежных остатков
- **THEN** вкладки «Концентрация» нет
#### Scenario: Только денежные остатки
- **WHEN** у счёта есть Cash Balance и нет позиций
- **THEN** вкладка «Концентрация» есть, разрез показывает пустое состояние
### Requirement: Переключение разрезов
Вкладка «Концентрация» SHALL предоставлять разрезы «Акции», «Облигации», «Секторы», «Эмитенты» в этом порядке и показывать одновременно один из них. При новом заходе на страницу счёта SHALL быть открыт разрез «Акции» по требованию «Начальное состояние вкладки». Разрез — набор элементов, на которые делится оценка позиций; элемент — единица ранжирования разреза по требованию «Состав разрезов».
#### Scenario: Открытие вкладки
- **WHEN** User при новом заходе на страницу счёта открывает вкладку «Концентрация»
- **THEN** показан только разрез «Акции» и доступны переключатели «Акции», «Облигации», «Секторы», «Эмитенты»
#### Scenario: Переключение разреза
- **GIVEN** открыт разрез «Акции» с выбранной валютой USD
- **WHEN** User переключает разрез на «Секторы»
- **THEN** показан только разрез «Секторы» в валюте USD
### Requirement: Начальное состояние вкладки
Система SHALL открывать вкладку «Концентрация» при новом заходе на страницу счёта и после перезагрузки с разрезом «Акции» и первой валютой списка. Новый заход — открытие страницы после ухода с неё либо переключение счёта. Пока User остаётся на странице, включая переключение её вкладок, разрез и валюта SHALL сохраняться.
**Источник (ненормативно):** [3081](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
#### Scenario: Возврат с другой вкладки страницы
- **GIVEN** на вкладке выбраны разрез «Секторы» и валюта USD
- **WHEN** User переключается на вкладку «Позиции» и возвращается на «Концентрация»
- **THEN** выбраны разрез «Секторы» и валюта USD
#### Scenario: Повторный заход
- **GIVEN** User выбрал разрез «Секторы» и валюту USD, затем покинул страницу счёта
- **WHEN** User снова открывает страницу счёта и вкладку «Концентрация»
- **THEN** открыт разрез «Акции» с первой валютой списка
#### Scenario: Перезагрузка
- **GIVEN** на вкладке выбраны разрез «Эмитенты» и валюта USD
- **WHEN** User перезагружает страницу
- **THEN** после открытия вкладки показаны разрез «Акции» и первая валюта списка
### Requirement: Состав разрезов
Элементы разреза SHALL формироваться из позиций типов по таблице; другие типы, включая `CURRENCY`, SHALL NOT входить во вкладку.
| Разрез | Типы | Элемент |
| --- | --- | --- |
| Акции | `STOCK` | Позиция |
| Облигации | `BOND` | Позиция |
| Секторы | `STOCK`, `BOND`, `FUND` | Позиции с одним `sector` |
| Эмитенты | `STOCK`, `BOND` | Позиции с одним `issuer.id` |
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3077)
#### Scenario: Сектор объединяет акции, облигации и фонды
- **GIVEN** в RUB есть акция сектора `energy` на 400, облигация `energy` на 100, фонд `financial` на 300 и позиция `CURRENCY` на 50
- **WHEN** User открывает разрез «Секторы» в RUB
- **THEN** элементы — «Энергетика» 500 ₽ и «Финансы» 300 ₽, позиции `CURRENCY` в разрезе нет
#### Scenario: Акция и облигация одного эмитента
- **GIVEN** в RUB есть акция с `issuer.id` `brand-1` («Сбер») на 300, облигация `brand-1` на 200 и фонд `brand-1` на 100
- **WHEN** User открывает разрез «Эмитенты» в RUB
- **THEN** есть один элемент «Сбер» на 500 ₽, фонд в него не включён
#### Scenario: Фонд вне «Акций»
- **GIVEN** в RUB есть фонд на 100 и акция на 200
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** показана только акция на 200 ₽ с долей 100 %
### Requirement: Названия элементов
Название элемента в «Акциях» и «Облигациях» SHALL быть отображаемым идентификатором позиции по требованию «Нормализованный состав Portfolio» из `portfolio-view` (name, затем ticker, затем FIGI), в «Секторах» — подписью по требованию «Подписи секторов», в «Эмитентах» — `issuer.name`, то есть названием бренда актива T-Bank. Позиции с разными `issuer.id` SHALL NOT объединяться при одинаковом `issuer.name`.
#### Scenario: Идентификатор позиции без имени
- **GIVEN** акция не имеет name, но имеет ticker `SBER`
- **WHEN** User открывает разрез «Акции»
- **THEN** элемент назван `SBER`
#### Scenario: Название эмитента — название бренда
- **GIVEN** акция и облигация имеют `issuer.id` `brand-1` и `issuer.name` «Сбер»
- **WHEN** User открывает разрез «Эмитенты»
- **THEN** один элемент назван «Сбер»
#### Scenario: Разные эмитенты с одинаковым названием
- **GIVEN** две акции имеют `issuer.name` «Альфа» и разные `issuer.id`
- **WHEN** User открывает разрез «Эмитенты»
- **THEN** показаны два отдельных элемента «Альфа»
### Requirement: Название эмитента при разных названиях бренда
Если учитываемые позиции одного `issuer.id` имеют разные `issuer.name`, название элемента SHALL быть `issuer.name` позиции с наибольшим `currentValue` в выбранной валюте. При равных значениях SHALL выбираться название, меньшее по алфавитному порядку требования «Порядок элементов с равной суммой».
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)
#### Scenario: Название по наибольшей позиции
- **GIVEN** акция `brand-1` на 300 с названием «Сбер» и облигация `brand-1` на 200 с названием «Сбербанк»
- **WHEN** User открывает разрез «Эмитенты»
- **THEN** один элемент на 500 назван «Сбер»
#### Scenario: Равные наибольшие значения
- **GIVEN** акция `brand-1` на 200 с названием «Сбербанк» и облигация `brand-1` на 200 с названием «Сбер»
- **WHEN** User открывает разрез «Эмитенты»
- **THEN** элемент назван «Сбер»
### Requirement: Позиции, учитываемые в разрезе
Система SHALL учитывать позицию в ранжировании, долях и диаграмме только при `currentValue` больше нуля в выбранной валюте; остальные позиции SHALL NOT учитываться. Позиция с нулевым `currentValue` не показывается и не считается неучтённой, позиция другой валюты относится к другой валюте выбора.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
#### Scenario: Отрицательная и неоценённая позиции
- **GIVEN** в разрезе «Акции» в RUB есть акции на 600 и 400, акция со стоимостью -50 и акция без `currentValue`
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** сумма разреза 1 000 ₽, доли 60 % и 40 %
#### Scenario: Позиция с нулевой стоимостью
- **GIVEN** есть акции на 100 и 0 в выбранной валюте
- **WHEN** User открывает разрез «Акции»
- **THEN** показана только акция на 100 с долей 100 %, сноски нет
### Requirement: Сноска о не учтённых позициях
Система SHALL показывать сноску «Не учтено позиций: N» при N больше нуля. N — число позиций разреза с `currentValue` `null` (в любой валюте) либо отрицательным в выбранной.
**Источник (ненормативно):** [3080](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080). Примечание: при неполных данных «Структура портфеля» показывает «Доля недоступна», вкладка — доли по учтённым ([3078](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)).
#### Scenario: Сноска с числом позиций
- **GIVEN** в разрезе «Акции» в RUB есть акции на 600 и 400, акция со стоимостью -50 и акция без `currentValue`
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** показана сноска «Не учтено позиций: 2»
#### Scenario: Неоценённая позиция при смене валюты
- **GIVEN** есть акции на 100 USD и 200 RUB и одна акция без `currentValue`
- **WHEN** User выбирает USD
- **THEN** показаны акция на 100 $ с долей 100 % и сноска «Не учтено позиций: 1»
#### Scenario: Отрицательная позиция другой валюты
- **GIVEN** есть акции на 100 RUB и -50 USD
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** сноски нет
#### Scenario: Нет не учтённых позиций
- **GIVEN** все акции имеют положительную стоимость
- **WHEN** User открывает разрез «Акции»
- **THEN** сноски нет
### Requirement: Одна валюта за раз
Система SHALL показывать значения вкладки в одной выбранной валюте, общей для всех разрезов и сохраняемой при их переключении, и при нескольких доступных валютах предоставлять выбор из них. Смена валюты SHALL пересчитывать разрез по позициям этой валюты. Система SHALL NOT конвертировать валюты и показывать общий итог нескольких валют.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
#### Scenario: Смена валюты
- **GIVEN** акции стоят 1 000 RUB и 100 USD, выбрана RUB
- **WHEN** User выбирает USD
- **THEN** разрез «Акции» показывает только акции в USD, сумму 100 $ и долю 100 %, без рублёвых значений
#### Scenario: Валюта сохраняется при смене разреза
- **GIVEN** выбрана USD в разрезе «Акции»
- **WHEN** User переключает разрез на «Облигации»
- **THEN** показаны облигации в USD
### Requirement: Доступные валюты вкладки
Доступные валюты — валюты ненулевых `currentValue` позиций `STOCK`, `BOND` и `FUND`, включая отрицательные (для сноски). Валюта только с нулевой стоимостью в список не входит. Cash Balance и другие типы валюты не определяют. Список упорядочен по ISO-коду, сначала выбрана первая. При одной валюте или без валют выбор SHALL NOT показываться.
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
#### Scenario: Начальная валюта
- **GIVEN** акции оценены в USD, облигации в RUB, а Cash Balance есть ещё в EUR и позиция `CURRENCY` оценена в CHF
- **WHEN** User впервые открывает вкладку «Концентрация»
- **THEN** в выборе RUB и USD, выбрана RUB, EUR и CHF в выборе нет
#### Scenario: Единственная валюта
- **GIVEN** все оценённые акции, облигации и фонды стоят в RUB
- **WHEN** User открывает вкладку «Концентрация»
- **THEN** выбора валюты нет, значения показаны в RUB
#### Scenario: Валюта только у позиции с нулевой стоимостью
- **GIVEN** акции стоят 100 RUB, а единственная позиция в USD — акция со стоимостью 0
- **WHEN** User открывает вкладку «Концентрация»
- **THEN** в списке только RUB, USD в нём нет
#### Scenario: Валюта только у отрицательной позиции
- **GIVEN** акции стоят 100 RUB, а единственная позиция в USD — акция со стоимостью -50
- **WHEN** User выбирает USD в разрезе «Акции»
- **THEN** показаны пустое состояние и сноска «Не учтено позиций: 1»
#### Scenario: Нет оценённых позиций
- **GIVEN** у всех позиций `STOCK`, `BOND` и `FUND` `currentValue` равен `null`
- **WHEN** User открывает вкладку «Концентрация»
- **THEN** выбора валюты нет, разрез показывает пустое состояние без валюты и сноску с числом таких позиций
### Requirement: Независимый выбор валюты вкладки
Выбор валюты вкладки «Концентрация» SHALL быть независим от выбора валюты в «Структуре портфеля»: смена валюты в одном месте SHALL NOT менять валюту в другом. Если выбранная валюта вкладки пропала из списка после обновления Portfolio, система SHALL выбрать первую валюту списка.
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
#### Scenario: Структура портфеля не влияет
- **GIVEN** в «Структуре портфеля» выбрана USD, а на вкладке «Концентрация» выбрана RUB
- **WHEN** User меняет валюту в «Структуре портфеля» на RUB и обратно
- **THEN** выбранная на вкладке валюта остаётся RUB
#### Scenario: Валюта пропала после обновления
- **GIVEN** на вкладке выбрана USD
- **WHEN** обновлённый Portfolio не содержит позиций `STOCK`, `BOND` и `FUND` в USD
- **THEN** выбрана первая валюта обновлённого списка
### Requirement: Топ-5 и строка «Прочее»
Система SHALL упорядочивать элементы разреза по сумме по убыванию. Если элементов не больше шести, каждый SHALL показываться строкой с названием, суммой и долей. Если семь и больше, SHALL показываться пять первых строк и строка «Прочее» с суммой, долей и числом остальных элементов («2 элемента», «5 элементов»).
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3079)
#### Scenario: Семь акций
- **GIVEN** в RUB есть семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** показаны пять строк с суммами 400, 250, 150, 100, 50 и строка «Прочее» 50 ₽ (2 элемента) с долей 5 %
#### Scenario: Ровно шесть элементов
- **GIVEN** в RUB есть шесть акций с суммами 300, 250, 200, 150, 60 и 40
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** показаны шесть строк с долями 30 %, 25 %, 20 %, 15 %, 6 % и 4 %, строки «Прочее» нет
#### Scenario: Ровно пять элементов
- **GIVEN** в RUB есть пять акций с суммами 300, 250, 200, 150 и 100
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** показаны пять строк, строки «Прочее» нет
#### Scenario: Меньше пяти элементов
- **GIVEN** в RUB есть три акции
- **WHEN** User открывает разрез «Акции»
- **THEN** показаны три строки, строки «Прочее» нет
### Requirement: Раскрытие строки «Прочее»
По нажатию на «Прочее», в том числе с клавиатуры, система SHALL раскрывать полный список остальных элементов в порядке ранжирования с суммой и долей; повторное нажатие сворачивает его. Раскрытие SHALL NOT менять пять первых строк и диаграмму. При показе разреза и смене валюты «Прочее» SHALL быть свёрнуто.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3077)
#### Scenario: Раскрытие «Прочее»
- **GIVEN** показан разрез «Акции» из семи акций (400, 250, 150, 100, 50, 30, 20), «Прочее» свёрнуто
- **WHEN** User нажимает на строку «Прочее»
- **THEN** видны две акции с суммами 30 ₽ и 20 ₽ и долями 3 % и 2 %, пять первых строк прежние
#### Scenario: Повторное нажатие
- **GIVEN** «Прочее» раскрыто
- **WHEN** User нажимает на него ещё раз
- **THEN** список остальных элементов скрыт
#### Scenario: Смена валюты сворачивает «Прочее»
- **GIVEN** «Прочее» раскрыто в RUB
- **WHEN** User выбирает USD
- **THEN** «Прочее» свёрнуто
### Requirement: Порядок элементов с равной суммой
Элементы разреза с равной суммой SHALL упорядочиваться по названию по возрастанию без учёта регистра: сначала названия, начинающиеся с цифры, затем с латинской буквы, затем с кириллической; внутри группы — по алфавиту, при совпадении названия — по порядку первой позиции элемента в Portfolio.
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
#### Scenario: Равные суммы на границе пятой строки
- **GIVEN** в RUB семь акций: 400, 300, 200, 150, «Альфа» 100, «Бета» 100 и 50
- **WHEN** User открывает разрез «Акции»
- **THEN** «Альфа» пятая строка, а «Бета» и акция на 50 входят в «Прочее»
#### Scenario: Цифры, латиница и кириллица при равных суммах
- **GIVEN** в RUB три акции с равной суммой 100 и названиями «Сбер», «VK» и «X5»
- **WHEN** User открывает разрез «Акции»
- **THEN** порядок строк: «VK», «X5», «Сбер»
### Requirement: Расчёт долей
Точная доля элемента — сумма его учитываемых позиций, делённая на сумму всех учитываемых позиций разреза в выбранной валюте; Cash Balance в расчёте не участвует. Точные доли элементов SHALL давать в сумме ровно 100 %, точная доля «Прочее» — равняться сумме точных долей остальных элементов, суммы — быть без округления.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
#### Scenario: Доля без денежных остатков
- **GIVEN** акции на 600 RUB и 400 RUB и Cash Balance 1 000 RUB
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** доли 60 % и 40 %
#### Scenario: Доля «Прочее»
- **GIVEN** семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
- **WHEN** User открывает разрез «Акции» и раскрывает «Прочее»
- **THEN** доля «Прочее» 5 % равна сумме долей 3 % и 2 %
### Requirement: Показ долей
Доля SHALL показываться, как в карточке позиции: округление до десятых в русской локали, середина — вверх (6,25 % — «6,3 %»), без «,0» («40 %», «66,7 %»). Положительная доля меньше 0,1 % показывается как «< 0,1 %». Суммарная доля топ-5 — в том же формате; сумма показанных долей может не быть 100 %.
**Источник (ненормативно):** [3079](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3079), [3080](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
#### Scenario: Три равные доли
- **GIVEN** три акции «А», «Б» и «В» по 100 RUB
- **WHEN** User открывает разрез «Акции»
- **THEN** каждая доля показана как «33,3 %»
#### Scenario: Округление, сумма показанных долей не равна 100 %
- **GIVEN** две акции на 1 RUB и 15 RUB, точные доли 6,25 % и 93,75 %
- **WHEN** User открывает разрез «Акции»
- **THEN** доли показаны как «93,8 %» и «6,3 %», хотя в сумме дают 100,1 %
#### Scenario: Очень малая доля
- **GIVEN** акции на 100 000 000 RUB и 1 RUB
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** доли показаны как «100 %» и «< 0,1 %», сумма второй акции остаётся 1 ₽
### Requirement: Суммарная доля топ-5
Система SHALL показывать метрику «доля топ-5» — сумму точных долей пяти первых по сумме элементов разреза, в формате требования «Показ долей» — только когда элементов шесть и более. При пяти и менее элементах метрика SHALL NOT показываться.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
#### Scenario: Семь элементов
- **GIVEN** в RUB семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
- **WHEN** User открывает разрез «Акции»
- **THEN** доли строк 40 %, 25 %, 15 %, 10 %, 5 % и «Прочее» 5 %, доля топ-5 равна 95 %
#### Scenario: Ровно шесть элементов
- **GIVEN** в RUB шесть акций с суммами 300, 250, 200, 150, 60 и 40
- **WHEN** User открывает разрез «Акции»
- **THEN** доля топ-5 равна 96 %, а шестая строка показана с долей 4 %
#### Scenario: Ровно пять элементов
- **GIVEN** в RUB пять акций с суммами 300, 250, 200, 150 и 100
- **WHEN** User открывает разрез «Акции»
- **THEN** метрика «доля топ-5» не показывается
#### Scenario: Один элемент
- **GIVEN** в RUB одна акция
- **WHEN** User открывает разрез «Акции»
- **THEN** метрика «доля топ-5» не показывается
### Requirement: Группы «Сектор не указан» и «Эмитент не указан»
Система SHALL объединять учитываемые позиции с `sector: null` («Секторы») в элемент «Сектор не указан», а с `issuer: null` («Эмитенты») — в элемент «Эмитент не указан». Эти элементы SHALL ранжироваться и попадать в «Прочее» наравне с остальными, а их название SHALL быть видно в списке и диаграмме. Сектор и эмитент SHALL NOT выводиться из названия.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3078)
#### Scenario: Позиции без эмитента в топе
- **GIVEN** в RUB акции эмитента «Сбер» на 300, эмитента «Газпром» на 300 и без эмитента на 200 и 100
- **WHEN** User открывает разрез «Эмитенты» в RUB
- **THEN** по убыванию: «Газпром» 300, «Сбер» 300, «Эмитент не указан» 300 (две позиции), группа ранжируется наравне с другими
#### Scenario: Группа без сектора в «Прочее»
- **GIVEN** у шести секторов суммы 600, 500, 400, 300, 200 и 100, у позиций без сектора сумма 50
- **WHEN** User раскрывает «Прочее» в разрезе «Секторы»
- **THEN** «Прочее» содержит шестой сектор 100 ₽ и «Сектор не указан» 50 ₽
### Requirement: Подписи секторов
Система SHALL показывать известное значение `sector` русской подписью по требованию «Русские подписи известных секторов», неизвестное — как получено, без перевода и пояснений, в списке и текстовом эквиваленте диаграммы. Система SHALL NOT придумывать подписи сверх таблицы и собственную классификацию и SHALL NOT объединять позиции с разными `sector`.
**Источник (ненормативно):** [#48, подтверждено](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3080)
#### Scenario: Неизвестное значение сектора
- **GIVEN** облигация имеет `sector` `other`, которого нет в таблице подписей
- **WHEN** User открывает разрез «Секторы»
- **THEN** элемент назван `other`
### Requirement: Русские подписи известных секторов
Система SHALL показывать `sector` подписью по таблице.
| Значение | Подпись |
| --- | --- |
| `consumer` | Потребительский сектор |
| `energy` | Энергетика |
| `financial` | Финансы |
| `health_care` | Здравоохранение |
| `industrials` | Промышленность |
| `it` | Информационные технологии |
| `materials` | Материалы |
| `real_estate` | Недвижимость |
| `telecom` | Телекоммуникации |
| `utilities` | Коммунальные услуги |
| `government` | Государственный сектор |
#### Scenario: Известный сектор
- **GIVEN** позиция имеет `sector` `it`
- **WHEN** User открывает разрез «Секторы»
- **THEN** элемент назван «Информационные технологии»
#### Scenario: Государственные облигации
- **GIVEN** облигация имеет `sector` `government`
- **WHEN** User открывает разрез «Секторы»
- **THEN** элемент назван «Государственный сектор»
### Requirement: Диаграмма распределения разреза
Система SHALL показывать диаграмму разреза с теми же элементами, в том же порядке и с теми же долями, что в списке: для разреза не более чем из шести элементов — сегмент на каждый элемент, для разреза из семи и более — пять сегментов и один сегмент «Прочее», одинаково для свёрнутого и раскрытого списка. Для пустого разреза диаграмма SHALL NOT показываться. Не учтённые позиции SHALL NOT входить в диаграмму.
#### Scenario: Семь элементов
- **GIVEN** семь акций с суммами 400, 250, 150, 100, 50, 30 и 20 RUB
- **WHEN** User открывает разрез «Акции» и раскрывает «Прочее»
- **THEN** диаграмма состоит из шести сегментов с долями 40 %, 25 %, 15 %, 10 %, 5 %, 5 % в порядке списка, как и при свёрнутом «Прочее»
#### Scenario: Ровно шесть элементов
- **GIVEN** шесть акций с суммами 300, 250, 200, 150, 60 и 40 RUB
- **WHEN** User открывает разрез «Акции»
- **THEN** диаграмма состоит из шести сегментов с долями 30 %, 25 %, 20 %, 15 %, 6 %, 4 %
### Requirement: Центр диаграммы
Система SHALL показывать в центре диаграммы сумму разреза — точную сумму учитываемых позиций в выбранной валюте, а над ней, когда показывается метрика «доля топ-5», подпись «Топ-5 · N %», где N — доля в формате «Показ долей». Без метрики показывается только сумма. Эти значения SHALL входить в текстовый эквивалент диаграммы.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
#### Scenario: Центр при семи акциях
- **GIVEN** в RUB семь акций с суммами 400, 250, 150, 100, 50, 30 и 20
- **WHEN** User открывает разрез «Акции»
- **THEN** в центре «Топ-5 · 95 %» и «1 000 ₽»
#### Scenario: Центр при пяти акциях
- **GIVEN** в RUB пять акций с суммами 300, 250, 200, 150 и 100
- **WHEN** User открывает разрез «Акции»
- **THEN** в центре только «1 000 ₽»
### Requirement: Строки без переходов
Строка списка в любом разрезе SHALL NOT вести на другую страницу; единственное действие строки — раскрытие и сворачивание «Прочее». Строки разреза «Эмитенты» SHALL NOT содержать логотипов.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081)
#### Scenario: Нажатие на строку акции
- **WHEN** User нажимает на строку акции в разрезе «Акции»
- **THEN** страница не меняется
#### Scenario: Строка эмитента
- **WHEN** User открывает разрез «Эмитенты»
- **THEN** строки показаны без логотипов
### Requirement: Доступность диаграммы без цвета
Информация диаграммы SHALL NOT передаваться только цветом: каждый сегмент SHALL быть сопоставим со строкой списка по названию и доле, доступным как текст. Диаграмма SHALL иметь текстовый эквивалент с названиями, суммами и долями сегментов в порядке списка, доступный вспомогательным технологиям.
#### Scenario: Сегменты различимы без цвета
- **GIVEN** показан разрез из шести строк
- **WHEN** User читает диаграмму вспомогательной технологией
- **THEN** доступны название, сумма и доля каждого сегмента в порядке списка, сопоставление со строкой не требует различения цветов
### Requirement: Пустое состояние разреза
Если выбранный разрез не содержит учитываемых элементов, система SHALL показывать пустое состояние с названием разреза и выбранной валютой (если валюты доступны) вместо списка, суммарной доли и диаграммы. Выбор валюты, если он показывается, и сноска при N больше нуля SHALL оставаться доступными.
#### Scenario: Нет облигаций в выбранной валюте
- **GIVEN** есть акции в RUB и облигации только в USD
- **WHEN** User открывает разрез «Облигации» в RUB
- **THEN** показано пустое состояние, выбор валюты доступен (валют две)
#### Scenario: Все позиции разреза отрицательные
- **GIVEN** в RUB есть только одна акция со стоимостью -50
- **WHEN** User открывает разрез «Акции» в RUB
- **THEN** показано пустое состояние и сноска «Не учтено позиций: 1»
### Requirement: Предупреждение о неполных данных
Если `meta` обозначает неполноту по «Результат личного обновления остаётся наблюдаемым» из `tbank-data-sync`, вкладка SHALL показывать предупреждение «Данные неполные» над разрезом, считая разрезы по доступным данным. Страница SHALL NOT дублировать его; позиции без оценки его не вызывают.
**Источник (ненормативно):** [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3081), [#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48#issuecomment-3082)
#### Scenario: Неполный Portfolio
- **GIVEN** `meta` обозначает неполноту, акции стоят 600 и 400 RUB
- **WHEN** User открывает разрез «Акции»
- **THEN** показаны предупреждение «Данные неполные» и доли 60 % и 40 %
#### Scenario: Предупреждение не дублируется
- **GIVEN** `meta` обозначает неполноту
- **WHEN** User открывает вкладку «Концентрация»
- **THEN** на странице одно сообщение о неполноте — «Данные неполные» на вкладке
#### Scenario: Полный Portfolio с неоценённой позицией
- **GIVEN** Portfolio полный, одна акция без `currentValue`
- **WHEN** User открывает разрез «Акции»
- **THEN** предупреждения «Данные неполные» нет, есть сноска «Не учтено позиций: 1»
### Requirement: Состояния Portfolio на вкладке «Концентрация»
Загрузка, ошибка, устаревание и неполнота Portfolio на вкладке «Концентрация» SHALL соответствовать требованию «Состояния и ошибки Portfolio на клиенте» из `portfolio-view`, как на вкладке «Позиции». Отсутствие сектора или эмитента у позиций SHALL NOT скрывать вкладку и менять успешность и свежесть Portfolio.
#### Scenario: Устаревший Portfolio
- **GIVEN** клиент получает Portfolio с `isStale: true`
- **WHEN** User открывает вкладку «Концентрация»
- **THEN** разрезы рассчитаны по этому Portfolio, устаревание обозначено так же, как на вкладке «Позиции»
#### Scenario: Сектор и эмитент отсутствуют
- **GIVEN** у всех позиций `sector: null` и `issuer: null`, Portfolio успешен
- **WHEN** User открывает разрезы «Секторы» и «Эмитенты»
- **THEN** каждый разрез содержит один элемент «Сектор не указан» или «Эмитент не указан» с долей 100 %