feat: redesign portfolio position cards

This commit is contained in:
2026-08-17 13:34:31 +03:00
parent aac1b435af
commit 6795ee6f96
6 changed files with 227 additions and 2 deletions
+26 -2
View File
@@ -20,7 +20,7 @@
### Requirement: Нормализованный состав Portfolio
Система MUST возвращать только обычные Portfolio Position с ненулевым количеством и доступные Cash Balance с ненулевой суммой. Cash Balance MUST быть отдельным от Portfolio Position элементом и агрегироваться до одного значения на валюту. Порядок Portfolio Position и Cash Balance MUST соответствовать upstream-порядку; система MUST NOT сортировать или объединять Portfolio Position с одинаковым FIGI. Виртуальные позиции и заблокированные денежные остатки MUST NOT входить в Portfolio.
Каждая Portfolio Position MUST содержать нормализованный тип `STOCK`, `BOND`, `FUND`, `CURRENCY`, `FUTURE`, `OPTION`, `STRUCTURED_NOTE`, `DIGITAL_FINANCIAL_ASSET` либо `OTHER`, строковое `quantity`, nullable `currentValue`, nullable `averagePurchasePrice` и nullable `absoluteReturn`. Система MUST искать metadata по instrument UID при его наличии, затем по FIGI. Отображаемый идентификатор MUST предпочитать name, затем ticker, а при недоступности metadata использовать FIGI, не скрывая финансовые значения.
Каждая Portfolio Position MUST содержать нормализованный тип `STOCK`, `BOND`, `FUND`, `CURRENCY`, `FUTURE`, `OPTION`, `STRUCTURED_NOTE`, `DIGITAL_FINANCIAL_ASSET` либо `OTHER`, строковое `quantity`, nullable `currentValue`, nullable `averagePurchasePrice`, nullable `absoluteReturn` и nullable `isin`. Система MUST искать metadata по instrument UID при его наличии, затем по FIGI. Отображаемый идентификатор MUST предпочитать name, затем ticker, а при недоступности metadata использовать FIGI, не скрывая финансовые значения.
#### Scenario: Позиция с неизвестным upstream-типом
- **WHEN** upstream возвращает обычную ненулевую позицию с нераспознанным типом инструмента
@@ -38,6 +38,14 @@
- **WHEN** FIGI позиции не даёт metadata, а её instrument UID возвращает непустое name
- **THEN** система возвращает name, полученное по instrument UID
#### Scenario: ISIN инструмента доступен
- **WHEN** metadata инструмента позиции содержит непустой `isin`
- **THEN** система возвращает его в поле `isin` позиции
#### Scenario: ISIN инструмента отсутствует
- **WHEN** у инструмента позиции нет ISIN либо metadata недоступна
- **THEN** система возвращает позицию с `isin: null`, не скрывая финансовые значения
#### Scenario: Денежные остатки в одной валюте
- **WHEN** upstream возвращает несколько ненулевых доступных денежных остатков одной валюты
- **THEN** система возвращает один Cash Balance с их точной суммой
@@ -89,7 +97,7 @@
Клиент 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 оставаться доступными в отдельной общей секции. При форматировании денежных значений в русской локали клиент MUST отображать RUB как символ `₽`; другие валюты MUST сохранять понятное обозначение.
Клиент MUST отображать `STOCK` и `BOND` отдельными секциями. Внутри каждой секции MUST сохраняться upstream-порядок позиций. Позиции иных типов MUST оставаться доступными в отдельной общей секции. Position Card MUST отображаться как компактная плитка в адаптивном grid: одна колонка на узком экране и несколько колонок на широком. Плитка MUST показывать отображаемый идентификатор позиции, количество, `currentValue` как главную метрику, `absoluteReturn` с цветовой индикацией знака, `averagePurchasePrice`, долю позиции среди позиций той же валюты и `isin`. Отсутствующие метрики MUST быть скрыты, а не отображаться заглушкой. При форматировании денежных значений в русской локали клиент MUST отображать RUB как символ `₽`; другие валюты MUST сохранять понятное обозначение.
#### Scenario: Показ устаревшего Portfolio
- **WHEN** клиент получает успешный ответ с `isStale: true`
@@ -106,3 +114,19 @@
#### Scenario: Отдельные акции и облигации
- **WHEN** Portfolio содержит позиции `STOCK` и `BOND`
- **THEN** клиент отображает их в отдельных секциях «Акции» и «Облигации» без изменения порядка в каждой секции
#### Scenario: Карточка позиции отображает доступные метрики
- **WHEN** позиция имеет значение текущей стоимости, абсолютного дохода, средней цены покупки и ISIN
- **THEN** клиент показывает идентификатор, количество, текущую стоимость, абсолютный доход, среднюю цену покупки, долю среди позиций той же валюты и ISIN
#### Scenario: Отсутствующие метрики скрыты
- **WHEN** у позиции отсутствует значение текущей стоимости, средней цены покупки или дохода
- **THEN** клиент скрывает соответствующую метрику вместо отображения заглушки
#### Scenario: Доход окрашен по знаку
- **WHEN** у позиции абсолютный доход положительный или отрицательный
- **THEN** клиент отображает его зелёным для положительного и красным для отрицательного, без цвета при его отсутствии
#### Scenario: Доля позиции в валюте
- **WHEN** позиция имеет вычислимую текущую стоимость в валюте
- **THEN** клиент отображает её долю среди всех позиций той же валюты, не включая Cash Balance