Files
specs/openspec/specs/brokerage-accounts/spec.md
T
ksv741 329d66e767
Specs security / security (push) Successful in 8s
Specs verify / verify (push) Successful in 11s
spec: finalize wealth-ledger SDD migration
2026-10-09 21:14:22 +03:00

20 KiB
Raw Blame History

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 без ручного обновления и без автоматического refetch при возврате фокуса. Он MUST использовать успешный Client Cached Snapshot списка в течение 30 минут. Открытый экран Accounts MUST перечитывать локальный backend-результат каждые 30 минут и MUST NOT запускать импорт T-Bank. Клиент MUST показывать наблюдаемые freshness, полноту, время последнего успешного результата, последнюю часовую попытку и доступность из meta понятным текстом или иконкой с доступным именем, а не только цветом. При уже имеющемся успешном списке клиент MUST сохранять последний успешный Client Cached Snapshot видимым во время фонового HTTP-перечитывания и после его ошибки, ясно отделяя это состояние от свежего backend-результата. При успешном непустом ответе клиент 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: Последняя попытка неуспешна после полного списка

  • WHEN клиент получает полный data списка и meta с неуспехом последней часовой попытки
  • THEN клиент сохраняет список видимым, показывает его исходное время и текстовое либо доступно именованное предупреждение о неуспешной попытке

Scenario: Первая загрузка списка выполняется или неуспешна

  • WHEN клиент получает data: null, а meta обозначает выполнение первой загрузки либо её неуспех
  • THEN клиент показывает соответственно доступное состояние загрузки либо ошибки без карточек счетов и без представления частичного списка как полного

Scenario: Список берётся из свежего frontend-кэша

  • WHEN User повторно открывает список в течение 30 минут после успешной загрузки
  • THEN клиент показывает сохранённые счета без нового API-запроса

Scenario: Устаревший список загружается повторно

  • WHEN User открывает список после истечения 30 минут frontend-кэша и уже существует последний успешный список
  • THEN клиент оставляет этот список видимым во время нового HTTP-чтения и ясно обозначает фоновое обновление

Scenario: Открытый экран перечитывает список

  • WHEN экран Accounts остаётся открытым 30 минут после последнего успешного HTTP-чтения
  • THEN клиент выполняет фоновое HTTP-перечитывание backend-результата, сохраняет видимый snapshot и не запускает импорт T-Bank

Scenario: Ошибка фонового обновления не скрывает snapshot

  • WHEN фоновое HTTP-перечитывание списка завершается ошибкой при наличии последнего успешного Client Cached Snapshot
  • THEN клиент сохраняет snapshot видимым, безопасно сообщает о неуспешном HTTP-чтении и предоставляет применимое действие повторной загрузки

Scenario: Карточка ограничивает валютные итоги

  • WHEN доступная сводка счёта содержит итоги в трёх или более валютах
  • THEN карточка показывает не более двух исходных валютных итогов и обозначает наличие остальных без общего сконвертированного значения

Scenario: Недоступность сводки локальна карточке

  • WHEN клиент получает список, в котором portfolioSummary одного счёта равна null
  • THEN он показывает временную недоступность только на этой карточке, не скрывает остальные карточки и сохраняет переход на детали недоступной сводки счёта

Scenario: Пустая сводка не является ошибкой

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

Requirement: Клиентские состояния ошибки списка счетов

Клиент MUST NOT автоматически повторять неуспешное HTTP-чтение списка. При TBANK_NOT_CONNECTED клиент SHALL показать объяснение отсутствия подключения и действие «Открыть настройки T-Bank». При INVALID_TBANK_TOKEN клиент SHALL показать объяснение недействительного token и то же действие. При TBANK_UNAVAILABLE клиент SHALL показать безопасное объяснение временной недоступности, действие повторного HTTP-чтения и действие открытия настроек T-Bank. При иной ошибке клиент MUST показать общий безопасный error-state только с действием повторного HTTP-чтения. Повтор MUST перечитывать backend-результат и MUST NOT запускать импорт T-Bank. Если последний успешный Client Cached Snapshot отсутствует, эти состояния MUST NOT показывать список; если snapshot существует во время фонового обновления, клиент MUST сохранить его видимым и показать соответствующее безопасное предупреждение и только применимые действия.

Scenario: Подключение требуется

  • WHEN клиент получает TBANK_NOT_CONNECTED
  • THEN клиент не показывает список и предлагает открыть настройки T-Bank

Scenario: Известная ошибка не повторяется автоматически

  • WHEN HTTP-чтение списка завершается известной ошибкой
  • THEN клиент не выполняет дополнительные запросы, пока User не выберет действие повторного HTTP-чтения

Scenario: Token требует внимания

  • WHEN клиент получает INVALID_TBANK_TOKEN
  • THEN клиент не показывает список и предлагает открыть настройки T-Bank

Scenario: Временная ошибка T-Bank

  • WHEN клиент получает TBANK_UNAVAILABLE
  • THEN клиент не показывает список и предлагает повторить HTTP-чтение либо открыть настройки T-Bank

Scenario: Неизвестная ошибка загрузки

  • WHEN клиент получает ошибку без известного кода списка счетов
  • THEN клиент не показывает список и предлагает только повторить HTTP-чтение

Scenario: Известная ошибка при сохранённом snapshot

  • WHEN фоновое HTTP-перечитывание списка с последним успешным Client Cached Snapshot получает TBANK_UNAVAILABLE
  • THEN клиент сохраняет snapshot видимым, сообщает о временной недоступности и предлагает повторить HTTP-чтение либо открыть настройки T-Bank