refactor: group canonical specs by domain and archive account-top-positions (#74)
This commit was merged in pull request #75.
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# brokerage-accounts Specification
|
||||
|
||||
## Purpose
|
||||
|
||||
Позволяет авторизованному пользователю просматривать поддерживаемые активные инвестиционные счета подключенного T-Bank и переходить к их деталям.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: Список активных брокерских счетов
|
||||
Система SHALL предоставлять авторизованному User `GET /api/v1/brokerage-accounts`, возвращающий `{ data, meta }`, где `data` является сохранённым подтверждённым массивом открытых поддерживаемых инвестиционных счетов T-Bank текущего подключения User в ранее подтверждённом upstream-порядке, а `meta` соответствует наблюдаемому состоянию resource по `tbank-data-sync`. Обычный GET MUST NOT обращаться к T-Bank или запускать личную синхронизацию. Каждый элемент MUST содержать стабильный `id`, непустое `name`, нормализованный `type` (`BROKERAGE`, `INDIVIDUAL_INVESTMENT`, `INVEST_BOX` или `MONEY_MARKET_FUND`) и nullable `openedOn` в формате `YYYY-MM-DD`. Система MUST включать только счета T-Bank типов «брокерский счёт», «ИИС», «Инвесткопилка» и «фонд денежного рынка»; банковские и неизвестные типы MUST NOT возвращаться. Система MUST удалить внешние пробелы из имени и при пустом результате использовать непустое название соответствующего типа.
|
||||
|
||||
Каждый элемент MUST также содержать nullable `portfolioSummary`. Доступная сводка MUST содержать `totalsByCurrency`: точные Money-итоги последнего Portfolio по исходным ISO-валютам, включающие стоимость позиций и Cash Balance в той же валюте. Она MUST NOT содержать FX-конвертированный или межвалютный итог и MUST NOT выдавать Cash Balance за самостоятельный второй итог. Если последний Portfolio конкретного доступного счёта отсутствует либо временно недоступен, `portfolioSummary` MUST быть `null`, не исключая этот счёт из списка и не делая список неуспешным. Пустой доступный Portfolio MUST передаваться доступной сводкой с пустым `totalsByCurrency`, а не `null`.
|
||||
|
||||
Список Brokerage Account и его сводки являются результатом наблюдения текущего брокерского подключения и MUST NOT создавать ожидание, что WealthLedger хранит долговременное право владения счётом или Portfolio независимо от T-Bank connection.
|
||||
|
||||
#### Scenario: Поддерживаемые счета возвращаются в upstream-порядке
|
||||
- **WHEN** часовой обход подтвердил открытые брокерский счёт, ИИС и неподдержанный дебетовый счёт
|
||||
- **THEN** обычный GET отвечает `200` этими счетами в `data` в исходном порядке и наблюдаемым состоянием в `meta` без обращения к T-Bank
|
||||
|
||||
#### Scenario: Пустой список поддерживаемых счетов
|
||||
- **WHEN** последний успешный обход подтвердил отсутствие открытых поддерживаемых инвестиционных счетов
|
||||
- **THEN** система отвечает `200` с `data: []` и `meta`, обозначающим доступный полный результат
|
||||
|
||||
#### Scenario: Пустое название получает fallback
|
||||
- **WHEN** последний подтверждённый счёт имеет пустое либо состоящее из пробелов имя
|
||||
- **THEN** система отвечает этим счётом с непустым названием его нормализованного типа
|
||||
|
||||
#### Scenario: Дата открытия отсутствует
|
||||
- **WHEN** последний подтверждённый счёт не имеет даты открытия
|
||||
- **THEN** система отвечает этим счётом с `openedOn: null`
|
||||
|
||||
#### Scenario: Мультивалютная сводка счёта
|
||||
- **WHEN** последний Portfolio счёта содержит итоги в RUB и USD, включая Cash Balance в USD
|
||||
- **THEN** ответ содержит одну доступную `portfolioSummary` с отдельными Money-итогами RUB и USD без FX-конвертации, общего итога или отдельного итога Cash Balance
|
||||
|
||||
#### Scenario: Сводка одного счёта временно недоступна
|
||||
- **WHEN** подтверждённый список содержит счёт без последнего доступного Portfolio
|
||||
- **THEN** система отвечает `200` всеми счетами в исходном порядке и передаёт для этого счёта `portfolioSummary: null`
|
||||
|
||||
#### Scenario: Доступный Portfolio пуст
|
||||
- **WHEN** последний доступный Portfolio счёта не имеет ненулевых позиций и доступных денежных остатков
|
||||
- **THEN** система передаёт доступную `portfolioSummary` с пустым `totalsByCurrency`
|
||||
|
||||
### Requirement: Состояния недоступности списка счетов
|
||||
Система MUST читать подтверждённый список текущего подключения локально. При отсутствии T-Bank connection система MUST отвечать `409` Problem Details с code `TBANK_NOT_CONNECTED`. Если T-Bank отклонил сохранённый token как неаутентифицированный или без прав во время часового обхода, система MUST отвечать `400` Problem Details с code `INVALID_TBANK_TOKEN` и сохранять connection. Временная ошибка обхода MUST сохранять последний подтверждённый список доступным; до первого подтверждённого списка система MUST обозначать продолжающуюся первую загрузку и MUST NOT возвращать частичный список как полный.
|
||||
|
||||
#### Scenario: Подключение отсутствует
|
||||
- **WHEN** User без сохранённого T-Bank connection запрашивает список
|
||||
- **THEN** система не обращается к T-Bank и отвечает `409` Problem Details с code `TBANK_NOT_CONNECTED`
|
||||
|
||||
#### Scenario: Сохранённый token больше не действителен
|
||||
- **WHEN** T-Bank отклоняет сохранённый token при часовом обходе списка как неаутентифицированный или без прав
|
||||
- **THEN** последующее чтение отвечает `400` Problem Details с code `INVALID_TBANK_TOKEN` и не раскрывает личные данные
|
||||
|
||||
#### Scenario: Ошибка обхода после успешного списка
|
||||
- **WHEN** часовой обход списка завершается временной ошибкой после ранее успешной проверки
|
||||
- **THEN** обычный GET возвращает последний подтверждённый список без ожидания T-Bank
|
||||
|
||||
#### Scenario: T-Bank временно недоступен
|
||||
- **WHEN** User запрашивает список до первого подтверждённого списка, а часовой обход завершился временной либо иной upstream-ошибкой
|
||||
- **THEN** система сообщает о неуспешной первой загрузке без счетов
|
||||
|
||||
#### Scenario: Первый обход ещё не завершён
|
||||
- **WHEN** User открывает список после подключения до получения первого подтверждённого списка
|
||||
- **THEN** система сообщает о продолжающейся загрузке без частичного либо неподтверждённого списка
|
||||
|
||||
### Requirement: Экран списка брокерских счетов
|
||||
|
||||
Клиент SHALL загружать список при открытии защищённого маршрута `/accounts`
|
||||
без ручного обновления. Клиент MUST использовать успешный frontend-кэш списка
|
||||
в течение 60 секунд. После истечения этого срока открытие или возвращение
|
||||
на экран SHALL инициировать получение актуального списка; имеющийся Client
|
||||
Cached Snapshot MUST оставаться видимым во время обновления и после временной
|
||||
ошибки без индикации собственного чтения и действий повтора.
|
||||
Автоматическое восстановление SHALL соответствовать `frontend-data-resilience`.
|
||||
Открытый экран MAY периодически перечитывать backend-результат, сохраняя
|
||||
видимый snapshot, и MUST NOT создавать импорт T-Bank. Состояние источника из
|
||||
`meta` MUST представляться по `frontend-data-resilience`.
|
||||
|
||||
При успешном непустом ответе клиент MUST отобразить адаптивный одноколоночный
|
||||
список широких интерактивных карточек счетов с локализованными типом и, если
|
||||
доступна, датой открытия без времени; каждая карточка MUST ясно показывать тип,
|
||||
имя, финансовую сводку, вторичные метаданные и заметное действие открытия счёта,
|
||||
вести на `/accounts/:accountId` по всей области и сохранять доступное
|
||||
клавиатурное состояние. После успешной замены или удаления T-Bank connection
|
||||
клиент MUST инвалидировать список счетов.
|
||||
|
||||
Для доступной `portfolioSummary` карточка MUST показывать не более двух
|
||||
Money-итогов в исходных валютах и обозначать наличие остальных валют, если
|
||||
они есть; она MUST NOT показывать или подразумевать FX-конвертацию,
|
||||
межвалютный агрегированный итог либо Cash Balance как отдельный второй итог.
|
||||
При `portfolioSummary: null` карточка MUST показывать локальное нейтральное
|
||||
состояние недоступности сводки, сохраняя метаданные счёта и возможность открыть
|
||||
его. При доступной пустой сводке карточка MUST не выдавать отсутствие итогов
|
||||
за временную ошибку.
|
||||
|
||||
#### Scenario: Пользователь открывает счёт из списка
|
||||
- **WHEN** клиент успешно загрузил непустой список и User выбирает карточку счёта
|
||||
- **THEN** клиент переходит на `/accounts/:accountId` с `id` выбранного счёта
|
||||
|
||||
#### Scenario: Список пуст
|
||||
- **WHEN** клиент получает успешный полный пустой массив
|
||||
- **THEN** клиент показывает штатное сообщение об отсутствии инвестиционных счетов T-Bank
|
||||
|
||||
#### Scenario: Список берётся из свежего frontend-кэша
|
||||
- **WHEN** User повторно открывает список в течение 60 секунд после успешной загрузки
|
||||
- **THEN** клиент показывает сохранённые счета без нового API-запроса
|
||||
|
||||
#### Scenario: Устаревший список загружается повторно
|
||||
- **WHEN** User открывает список после истечения 60 секунд frontend-кэша и уже существует последний успешный список
|
||||
- **THEN** клиент оставляет этот список видимым во время нового запроса без индикации фонового обновления
|
||||
|
||||
#### Scenario: Открытый экран перечитывает список
|
||||
- **WHEN** экран Accounts остаётся открытым 30 минут после последнего успешного HTTP-чтения
|
||||
- **THEN** клиент выполняет фоновое HTTP-перечитывание backend-результата, сохраняет видимый snapshot и не запускает импорт T-Bank
|
||||
|
||||
#### Scenario: Последняя попытка неуспешна после полного списка
|
||||
- **WHEN** клиент получает полный `data` списка и `meta` с неуспехом последней часовой попытки
|
||||
- **THEN** клиент сохраняет список видимым, показывает его исходное время и текстовое либо доступно именованное предупреждение о неуспешной попытке, не предлагая ручной повтор
|
||||
|
||||
#### Scenario: Первая загрузка списка выполняется или неуспешна
|
||||
- **WHEN** клиент получает `data: null`, а `meta` обозначает выполнение первой загрузки либо её неуспех
|
||||
- **THEN** клиент показывает соответственно доступное состояние загрузки либо локальной недоступности без карточек счетов и без представления частичного списка как полного
|
||||
|
||||
#### Scenario: Ошибка фонового обновления не скрывает snapshot
|
||||
- **WHEN** обновление устаревшего списка завершается временной ошибкой при наличии последнего успешного Client Cached Snapshot
|
||||
- **THEN** клиент сохраняет snapshot видимым без предупреждения и ручного повтора и восстанавливает получение данных автоматически
|
||||
|
||||
#### Scenario: Карточка ограничивает валютные итоги
|
||||
- **WHEN** доступная сводка счёта содержит итоги в трёх или более валютах
|
||||
- **THEN** карточка показывает не более двух исходных валютных итогов и обозначает наличие остальных без общего сконвертированного значения
|
||||
|
||||
#### Scenario: Недоступность сводки локальна карточке
|
||||
- **WHEN** клиент получает список, в котором `portfolioSummary` одного счёта равна `null`
|
||||
- **THEN** он показывает нейтральную недоступность только этой сводки, не скрывает остальные карточки и сохраняет переход на детали счёта
|
||||
|
||||
#### Scenario: Пустая сводка не является ошибкой
|
||||
- **WHEN** клиент получает доступную `portfolioSummary` с пустым `totalsByCurrency`
|
||||
- **THEN** он показывает нейтральное состояние отсутствия финансовых итогов, а не состояние временной ошибки
|
||||
|
||||
### Requirement: Клиентские состояния ошибки списка счетов
|
||||
|
||||
Клиент SHALL автоматически восстанавливать временно неуспешное чтение списка
|
||||
по правилам `frontend-data-resilience` без кнопок обновления и повтора. При
|
||||
`TBANK_NOT_CONNECTED` клиент MUST показать необходимость подключения и действие
|
||||
открытия настроек T-Bank. При `INVALID_TBANK_TOKEN` клиент MUST показать
|
||||
необходимость восстановить подключение и то же действие. Эти подтверждённые
|
||||
состояния MUST скрывать личный список и MUST NOT запускать автоматические повторы.
|
||||
|
||||
При временной недоступности, включая `TBANK_UNAVAILABLE`, клиент MUST сохранять
|
||||
успешный результат текущей границы доступа без предупреждений. Если результата
|
||||
нет, после первичного ожидания клиент SHALL показать спокойную локальную
|
||||
недоступность без технических подробностей. Неизвестная ошибка MUST получать
|
||||
безопасное локальное представление; отсутствие известного кода MUST NOT
|
||||
разрешать бесконечные повторы или обход доступа. Временный сбой MUST NOT
|
||||
предлагать перенастройку действующего подключения как способ повторить загрузку.
|
||||
|
||||
#### Scenario: Подключение требуется
|
||||
- **WHEN** клиент получает `TBANK_NOT_CONNECTED`
|
||||
- **THEN** клиент не показывает список и предлагает открыть настройки T-Bank
|
||||
|
||||
#### Scenario: Известная ошибка не повторяется автоматически
|
||||
- **WHEN** запрос списка завершается подтверждённой ошибкой подключения или доступа, требующей действия пользователя
|
||||
- **THEN** клиент не выполняет автоматических повторов и предлагает соответствующее действие вместо технической повторной загрузки
|
||||
|
||||
#### Scenario: Token требует внимания
|
||||
- **WHEN** клиент получает `INVALID_TBANK_TOKEN`
|
||||
- **THEN** клиент скрывает личный список и предлагает восстановить подключение в настройках T-Bank
|
||||
|
||||
#### Scenario: Временная ошибка T-Bank
|
||||
- **WHEN** клиент получает `TBANK_UNAVAILABLE` без доступного результата списка
|
||||
- **THEN** клиент автоматически восстанавливает получение и после первичного ожидания показывает нейтральную недоступность без повторной загрузки и предложения перенастроить подключение
|
||||
|
||||
#### Scenario: Неизвестная ошибка загрузки
|
||||
- **WHEN** клиент получает ошибку без известного кода списка счетов и без доступного результата
|
||||
- **THEN** клиент показывает безопасное нейтральное состояние без технического сообщения или кнопки повтора, применяя только допустимое ограниченное восстановление
|
||||
|
||||
#### Scenario: Известная ошибка при сохранённом snapshot
|
||||
- **WHEN** фоновое обновление списка с последним успешным Client Cached Snapshot получает `TBANK_UNAVAILABLE`
|
||||
- **THEN** клиент сохраняет snapshot видимым без предупреждения, времени получения и ручных действий восстановления
|
||||
Reference in New Issue
Block a user