Files
specs/openspec/specs/brokerage-accounts/spec.md
T
codex-bot f0478c6d6b
Specs security / security (push) Successful in 8s
Specs verify / verify (push) Successful in 10s
spec: archive quiet-user-feedback and sync canonical specs (#50)
Native archive применил 9 added и 12 modified требований без удалений; все 10 сценариев сохранены. Новый canonical spec frontend-user-feedback внесён в AI_INDEX.
2026-10-17 22:18:27 +03:00

21 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 без ручного обновления. Клиент 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 видимым без предупреждения, времени получения и ручных действий восстановления