Files
specs/openspec/changes/archive/2026-09-09-compact-portfolio-totals/specs/portfolio-view/spec.md
T

20 KiB
Raw Blame History

ADDED Requirements

Requirement: Компактная сводка валютных итогов Portfolio

На странице Brokerage Account клиент SHALL показывать каждый полученный валютный итог Portfolio отдельной компактной карточкой. При достаточной ширине карточки валютная метка и сумма MUST располагаться в одной строке; сумма MUST оставаться основной читаемой величиной. Обычная сводка с одной или тремя валютами MUST занимать меньше высоты, чем прежнее представление с меткой над суммой при тех же значениях и ширине экрана.

На широком экране несколько карточек SHALL располагаться рядом при наличии места; на узком экране MUST сохраняться одна карточка в ряду. Если полное значение не помещается рядом с меткой, клиент MUST предоставлять ему полную доступную ширину карточки и переносить содержимое с увеличением высоты. Сводка MUST NOT обрезать суммы, заменять их многоточием или требовать горизонтальной прокрутки для чтения карточек и значений.

Scenario: Обычная сводка на широком экране

  • WHEN User открывает Portfolio с итогами 125000.50 RUB, 320.00 USD и 9876.54321 EUR на широком экране с местом для трёх карточек
  • THEN клиент показывает три отдельные карточки рядом, метку и полную сумму в одной строке каждой карточки, с меньшей высотой сводки, чем при прежнем размещении метки над суммой в тех же условиях

Scenario: Обычная сводка на узком экране

  • WHEN User открывает тот же Portfolio с тремя валютными итогами на узком экране
  • THEN клиент показывает три карточки по одной в ряду, сохраняя полные читаемые суммы и меньшую общую высоту сводки, чем при прежнем размещении метки над суммой в тех же условиях

Scenario: Portfolio с одной валютой

  • WHEN Portfolio содержит один валютный итог
  • THEN клиент показывает одну компактную карточку без пустых карточек для других валют; обычная сумма и метка помещаются в одну строку при достаточной ширине на широком и узком экране

Scenario: Длинная сумма на узком экране

  • WHEN User просматривает итог 123456789012.345678901 RUB при ширине экрана 320 пикселей и значение не помещается рядом с валютной меткой
  • THEN сумма получает полную доступную ширину карточки и при необходимости переносится; все цифры и знак валюты читаемы без обрезания, многоточия и горизонтальной прокрутки

Requirement: Обозначение и доступная идентичность валюты в сводке

В валютных метках и суффиксах сумм сводки клиент MUST обозначать RUB знаком ₽, USD знаком $, EUR знаком € вместо видимых ISO-кодов этих валют. Каждая сумма MUST оставаться однозначно связанной со своей исходной валютой, включая чтение вспомогательными технологиями. Для RUB, USD и EUR MUST быть доступны названия «Российский рубль», «Доллар США» и «Евро» соответственно. Символ или цвет сами по себе MUST NOT быть единственным доступным способом определения валюты.

Другие полученные валюты MUST оставаться в сводке с понятным обозначением и доступной идентичностью. Если знак отсутствует или неоднозначен, клиент MUST сохранять возможность различить исходную валюту по её названию или ISO-коду, в том числе визуально; неизвестное полное название MUST NOT подменяться вымышленным. Совпадающие знаки разных валют MUST NOT приводить к объединению карточек или неразличимому представлению их валют.

Scenario: Рубль, доллар США и евро показаны знаками

  • WHEN сводка содержит RUB, USD и EUR
  • THEN метки показывают ₽, $ и €, а суммы заканчиваются теми же знаками; видимые RUB, USD и EUR не подменяют выбранные знаки

Scenario: Валютная сумма читается вспомогательной технологией

  • WHEN User читает валютный итог сводки вспомогательной технологией
  • THEN ему доступны полное значение и однозначная валютная идентичность, включая «Российский рубль», «Доллар США» или «Евро» для соответствующих валют

Scenario: Получена другая валюта

  • WHEN сводка содержит валюту помимо RUB, USD и EUR
  • THEN её отдельный итог остаётся доступным с понятным обозначением и доступным названием либо исходным ISO-кодом при неизвестном названии

Scenario: У разных валют совпадает знак

  • WHEN Portfolio содержит итоги двух исходных валют с одинаковым знаком
  • THEN сводка показывает два отдельных итога, и User может различить их валюты визуально и вспомогательной технологией без догадки по сумме

Requirement: Полные точные значения и смысл валютной сводки

Сводка MUST показывать полученные валютные итоги без изменения их знака, цифр и дробной точности. Для русской локали клиент SHALL сохранять группировку разрядов пробелами и десятичную запятую, не округляя значение, не отбрасывая дробные позиции и не сокращая сумму до тысяч, миллионов или экспоненциальной записи. Требование MUST сохраняться для длинных, отрицательных значений и отрицательных дробей с нулевой целой частью.

Каждая карточка MUST представлять только полученный итог позиций и Cash Balance своей исходной валюты. Сводка MUST NOT конвертировать или складывать разные валюты, показывать рублёвый итог как общую стоимость Portfolio, повторно добавлять Cash Balance либо обещать полную оценку при наличии позиций без вычислимой стоимости. Для отсутствующего валютного итога клиент MUST NOT создавать нулевую карточку. Отсутствие итогов само по себе MUST NOT обозначать пустой Portfolio, если позиции или Cash Balance присутствуют.

Scenario: Обычные суммы сохраняют дробные позиции

  • WHEN в сводку поступают значения 125000.50 RUB, 320.00 USD и 9876.54321 EUR
  • THEN клиент показывает 125 000,50 ₽, 320,00 $ и 9 876,54321 € с сохранением каждой исходной цифры и дробной позиции

Scenario: Длинные и отрицательные значения не теряют точность

  • WHEN в сводку поступают 123456789012.345678901 RUB, -1234567.890123 USD и 987654321.000001 EUR
  • THEN пользователь видит полные 123 456 789 012,345678901 ₽, -1 234 567,890123 $ и 987 654 321,000001 € без округления, сокращений и потери отрицательного знака на широком и узком экране

Scenario: Отрицательная сумма меньше единицы

  • WHEN полученный валютный итог равен -0.5 USD
  • THEN сводка показывает -0,5 $, сохраняя знак и дробную величину

Scenario: Несколько валют и денежные остатки

  • WHEN полученные итоги RUB и USD уже включают позиции и Cash Balance соответствующих валют
  • THEN клиент показывает эти два итога без повторного добавления денег, межвалютного итога или представления RUB как общей стоимости Portfolio

Scenario: Стоимость части позиций неизвестна

  • WHEN Portfolio содержит позиции без вычислимой стоимости и доступные валютные итоги, сформированные без этих позиций
  • THEN сводка показывает только полученные итоги, не добавляет нули за отсутствующие стоимости и не называет результат полной оценкой Portfolio

Scenario: Итоги отсутствуют при непустом Portfolio

  • WHEN totalsByCurrency пуст, но positions или cashBalances непусты
  • THEN клиент не создаёт валютные карточки и не заменяет доступный состав Portfolio состоянием пустого портфеля

MODIFIED Requirements

Requirement: Состояния и ошибки Portfolio на клиенте

Клиент SHALL загружать Portfolio при открытии защищённого маршрута /accounts/:accountId. Он MUST использовать успешный ответ в течение 30 секунд, без automatic retry, polling или refetch при возврате фокуса. При загрузке без ранее полученного успешного ответа для этого же Brokerage Account клиент MUST показывать структурное skeleton-состояние ожидаемого содержимого, включая сводку, без вымышленных сумм. Область загрузки MUST иметь доступное обозначение занятости; skeleton MUST NOT быть интерактивным или получать клавиатурный фокус.

Истечение срока свежести MUST NOT само по себе скрывать уже доступный Client Cached Snapshot. Во время фонового обновления и после его ошибки клиент MUST сохранять ранее полученные данные того же Portfolio, включая валютные итоги и исходное lastSuccessfulAt. При обновлении клиент MUST показывать компактную неблокирующую индикацию без замены данных skeleton. При ошибке обновления он MUST показывать локализованное неблокирующее предупреждение о последних полученных данных и предоставлять действие повторной попытки. Сохранённые данные MUST NOT считаться новым успешным снимком или подтверждением текущей доступности Brokerage Account.

Клиент MUST показать штатное empty-состояние только при пустых positions и cashBalances, без нулевых валютных карточек. Для показываемого состава Portfolio клиент MUST сохранять время успешного получения снимка lastSuccessfulAt, форматируемое в UTC. При isStale: true клиент MUST показывать Snapshot, его исходное время и нейтральное предупреждение о временной недоступности T-Bank. Это предупреждение само по себе MUST NOT добавлять действие ручного обновления. Server-side stale и ошибка фонового обновления Client Cached Snapshot MUST оставаться раздельными состояниями: ошибка клиента MUST NOT менять или подменять isStale, а оба предупреждения и действие повтора клиентского обновления MUST оставаться доступными при одновременном наличии этих состояний.

При отсутствии ранее успешно полученного Client Cached Snapshot этого же Portfolio и ответе 404 клиент MUST показать состояние недоступного счёта с действием возврата к списку счетов без действия повтора. При отсутствии Snapshot и TBANK_NOT_CONNECTED, INVALID_TBANK_TOKEN, TBANK_UNAVAILABLE или иной ошибке клиент MUST показать безопасное error-состояние с доступными для ошибки действиями; действие повтора разрешено только для временной и неизвестной ошибки.

Scenario: Показ устаревшего Portfolio

  • WHEN клиент получает успешный ответ с isStale: true
  • THEN клиент показывает позиции, остатки, валютные итоги, время последнего успешного снимка и нейтральное предупреждение; само это предупреждение не добавляет действие ручного обновления

Scenario: Недоступный счёт на клиенте

  • WHEN для текущего Portfolio отсутствует ранее успешно полученный Client Cached Snapshot и клиент получает 404
  • THEN клиент не показывает Portfolio и предлагает вернуться к списку Brokerage Account без действия повтора

Scenario: Первичная загрузка Portfolio

  • WHEN клиент ожидает Portfolio этого Brokerage Account без ранее полученного успешного ответа
  • THEN он показывает структурный skeleton, включая место сводки, с доступным обозначением загрузки, без вымышленных или нулевых сумм и без фокусируемых placeholders

Scenario: Обновление после истечения срока свежести

  • WHEN срок свежести показанного Portfolio истёк и началось фоновое обновление данных того же Brokerage Account
  • THEN клиент сохраняет прежние валютные итоги и время их успешного получения, показывает неблокирующую индикацию обновления и не заменяет доступный состав и сводку skeleton-состоянием

Scenario: Ошибка обновления после успешного ответа

  • WHEN клиент уже показывает Client Cached Snapshot Portfolio, а обновление этих же данных завершается ошибкой
  • THEN клиент сохраняет данные, суммы и время прежнего снимка, показывает неблокирующее предупреждение и действие повтора; ошибка не делает сохранённый снимок свежим и не изменяет isStale

Scenario: Ошибка клиентского обновления при server-side stale

  • WHEN клиент показывает Portfolio с isStale: true, а фоновое обновление этого же Portfolio завершается ошибкой
  • THEN прежние суммы и время остаются видимыми одновременно с нейтральным server-side предупреждением, отдельным предупреждением об ошибке клиентского обновления и его действием повтора

Scenario: Повторное обновление успешно

  • WHEN после ошибки фонового обновления User запускает повторную попытку и получает успешный Portfolio Snapshot
  • THEN до ответа прежние суммы и время остаются видимыми, затем клиент показывает значения и lastSuccessfulAt успешного ответа, убирает предупреждение об ошибке клиентского обновления и показывает server-side предупреждение только в соответствии с новым isStale

Scenario: Штатный пустой Portfolio на клиенте

  • WHEN успешно полученный Portfolio содержит пустые positions и cashBalances
  • THEN клиент показывает существующее empty-состояние без валютных карточек с вымышленными нулевыми итогами