feat(portfolio-view): sync delta spec and archive change

- Remove old combined requirement, add two focused requirements:
  'Состояния и ошибки Portfolio на клиенте' and
  'Представление карточек позиций на клиенте'
- Archive extend-instrument-logo-to-bonds change
This commit is contained in:
2026-08-25 09:48:21 +03:00
parent 70a200e1b4
commit 678a671d23
6 changed files with 224 additions and 21 deletions
+26 -21
View File
@@ -100,17 +100,11 @@
- **WHEN** T-Bank отклоняет token как неаутентифицированный или без прав при обновлении Portfolio
- **THEN** система не возвращает fallback Snapshot и отвечает `400` Problem Details с code `INVALID_TBANK_TOKEN`
### Requirement: Ошибки и состояния Portfolio на клиенте
### Requirement: Состояния и ошибки Portfolio на клиенте
Клиент SHALL загружать Portfolio при открытии защищённого маршрута `/accounts/:accountId`. Он MUST использовать успешный ответ в течение 30 секунд, без automatic retry, polling или refetch при возврате фокуса. После истечения срока клиент MUST скрыть предыдущий ответ и показать loading-состояние до нового результата.
Клиент MUST показать штатное empty-состояние только при пустых `positions` и `cashBalances`. При `isStale: true` клиент MUST показывать Snapshot, `lastSuccessfulAt` и нейтральное предупреждение о временной недоступности T-Bank. При `404` клиент MUST показать состояние недоступного счёта с действием возврата к списку счетов. При отсутствии Snapshot и `TBANK_NOT_CONNECTED`, `INVALID_TBANK_TOKEN`, `TBANK_UNAVAILABLE` или иной ошибке клиент MUST показать безопасное error-состояние с доступными для ошибки действиями; действие повтора разрешено только для временной и неизвестной ошибки.
Клиент MUST отображать `STOCK` и `BOND` отдельными секциями. Внутри каждой секции MUST сохраняться upstream-порядок позиций. Позиции иных типов MUST оставаться доступными в отдельной общей секции.
Карточки секции `STOCK` MUST отображаться по одной в ряду при любой ширине экрана. Карточка акции MUST показывать визуальный логотип бренда инструмента рядом с отображаемым идентификатором позиции; при отсутствии имени файла логотипа либо неудачной загрузке изображения вместо логотипа MUST отображаться первая буква отображаемого идентификатора позиции. Абсолютный доход в карточке акции MUST отображаться значением с явным знаком (`+` для положительного, `-` для отрицательного, без знака при нуле) с цветовой индикацией знака и без текстовой подписи доходности.
Карточки секции `BOND` и общей секции иных типов MUST сохранять прежнее поведение: компактная плитка в адаптивном grid (одна колонка на узком экране, несколько колонок на широком), абсолютный доход с текстовой подписью доходности и цветовой индикацией знака, без визуального логотипа. Плитки всех секций MUST показывать отображаемый идентификатор позиции, количество, `currentValue` как главную метрику, `absoluteReturn`, `averagePurchasePrice`, долю позиции среди позиций той же валюты и `isin`. Отсутствующие метрики MUST быть скрыты, а не отображаться заглушкой. При форматировании денежных значений в русской локали клиент MUST отображать RUB как символ `₽`; другие валюты MUST сохранять понятное обозначение.
#### Scenario: Показ устаревшего Portfolio
- **WHEN** клиент получает успешный ответ с `isStale: true`
- **THEN** клиент показывает позиции и остатки, время последнего успешного снимка и предупреждение без действия ручного обновления
@@ -119,14 +113,21 @@
- **WHEN** клиент получает `404` для Portfolio
- **THEN** клиент не показывает Portfolio и предлагает вернуться к списку Brokerage Account без действия повтора
#### Scenario: Портфель отображается на мобильном устройстве
- **WHEN** User открывает загруженный Portfolio на узком экране
- **THEN** клиент сохраняет читаемое одноколоночное отображение агрегатов, позиций и Cash Balance
### Requirement: Представление карточек позиций на клиенте
Клиент MUST отображать `STOCK` и `BOND` отдельными секциями. Внутри каждой секции MUST сохраняться upstream-порядок позиций. Позиции иных типов MUST оставаться доступными в отдельной общей секции.
Карточки секций `STOCK` и `BOND` MUST отображаться по одной в ряду при любой ширине экрана. Карточка акции или облигации MUST показывать визуальный логотип бренда инструмента рядом с отображаемым идентификатором позиции; при отсутствии имени файла логотипа либо неудачной загрузке изображения вместо логотипа MUST отображаться первая буква отображаемого идентификатора позиции. Абсолютный доход в карточке акции или облигации MUST отображаться значением с явным знаком (`+` для положительного, `-` для отрицательного, без знака при нуле) с цветовой индикацией знака и без текстовой подписи доходности.
Карточки общей секции иных типов MUST сохранять прежнее поведение: компактная плитка в адаптивном grid (одна колонка на узком экране, несколько колонок на широком), абсолютный доход с текстовой подписью доходности и цветовой индикацией знака, без визуального логотипа. Плитки всех секций MUST показывать отображаемый идентификатор позиции, количество, `currentValue` как главную метрику, `absoluteReturn`, `averagePurchasePrice`, долю позиции среди позиций той же валюты и `isin`. Отсутствующие метрики MUST быть скрыты, а не отображаться заглушкой. При форматировании денежных значений в русской локали клиент MUST отображать RUB как символ `₽`; другие валюты MUST сохранять понятное обозначение.
#### Scenario: Отдельные акции и облигации
- **WHEN** Portfolio содержит позиции `STOCK` и `BOND`
- **THEN** клиент отображает их в отдельных секциях «Акции» и «Облигации» без изменения порядка в каждой секции
#### Scenario: Портфель отображается на мобильном устройстве
- **WHEN** User открывает загруженный Portfolio на узком экране
- **THEN** клиент сохраняет читаемое одноколоночное отображение агрегатов, позиций и Cash Balance
#### Scenario: Карточка позиции отображает доступные метрики
- **WHEN** позиция имеет значение текущей стоимости, абсолютного дохода, средней цены покупки и ISIN
- **THEN** клиент показывает идентификатор, количество, текущую стоимость, абсолютный доход, среднюю цену покупки, долю среди позиций той же валюты и ISIN
@@ -143,22 +144,26 @@
- **WHEN** позиция имеет вычислимую текущую стоимость в валюте
- **THEN** клиент отображает её долю среди всех позиций той же валюты, не включая Cash Balance
#### Scenario: Одноколоночная секция акций
- **WHEN** User открывает загруженный Portfolio с позициями `STOCK` на широком экране
- **THEN** клиент отображает карточки акций по одной в ряду
#### Scenario: Одноколоночные секции акций и облигаций
- **WHEN** User открывает загруженный Portfolio с позициями `STOCK` или `BOND` на широком экране
- **THEN** клиент отображает карточки соответствующей секции по одной в ряду
#### Scenario: Логотип акции отображается
- **WHEN** позиция `STOCK` содержит непустое имя файла логотипа бренда и изображение успешно загружается
#### Scenario: Логотип акции или облигации отображается
- **WHEN** позиция `STOCK` или `BOND` содержит непустое имя файла логотипа бренда и изображение успешно загружается
- **THEN** клиент показывает изображение логотипа рядом с отображаемым идентификатором позиции
#### Scenario: Фолбэк без логотипа
- **WHEN** у позиции `STOCK` имя файла логотипа отсутствует либо изображение не загружается
#### Scenario: Фолбэк без логотипа у акции или облигации
- **WHEN** у позиции `STOCK` или `BOND` имя файла логотипа отсутствует либо изображение не загружается
- **THEN** вместо логотипа клиент показывает первую букву отображаемого идентификатора позиции
#### Scenario: Доходность акции со знаком без подписи
- **WHEN** карточка акции показывает абсолютный доход
#### Scenario: Доходность акции или облигации со знаком без подписи
- **WHEN** карточка акции или облигации показывает абсолютный доход
- **THEN** клиент отображает значение с явным знаком `+` или `-` (без знака при нуле) и без текстовой подписи доходности
#### Scenario: Секция облигаций сохраняет прежний вид
#### Scenario: Секция облигаций в едином стиле с акциями
- **WHEN** User открывает загруженный Portfolio с позициями `BOND`
- **THEN** клиент отображает облигации плитками в адаптивном grid с текстовой подписью доходности и без визуального логотипа
- **THEN** клиент отображает облигации по одной карточке в ряду с визуальным логотипом бренда либо фолбэком первой буквы и абсолютным доходом с явным знаком без текстовой подписи
#### Scenario: Секция иных типов сохраняет прежний вид
- **WHEN** User открывает загруженный Portfolio с позициями иных типов (не `STOCK` и не `BOND`)
- **THEN** клиент отображает их компактными плитками в адаптивном grid с текстовой подписью доходности и без визуального логотипа