codex/broker-accounts-overview #22
@ -0,0 +1,92 @@
|
|||||||
|
# ADR-012: Сводка брокерских счетов агрегируется на frontend
|
||||||
|
|
||||||
|
**Статус:** Accepted
|
||||||
|
|
||||||
|
**Дата:** 2026-06-19
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Страница списка брокерских счетов должна показывать общую стоимость, дневной результат, свободные
|
||||||
|
деньги и распределение активов, а также подробные показатели каждого счёта. Endpoint
|
||||||
|
`GET /api/v1/broker/accounts` возвращает только метаданные счетов. Все необходимые финансовые данные
|
||||||
|
уже доступны через `GET /api/v1/broker/accounts/:accountId/portfolio`.
|
||||||
|
|
||||||
|
Текущий продуктовый сценарий предполагает один–три открытых счёта. Backend кеширует ответы портфеля
|
||||||
|
и ограничивает запросы к T-Bank через общую очередь.
|
||||||
|
|
||||||
|
## Рассмотренные варианты
|
||||||
|
|
||||||
|
### 1. Агрегация существующих ответов на frontend
|
||||||
|
|
||||||
|
Frontend получает список счетов, параллельно запрашивает портфель каждого счёта и строит общую
|
||||||
|
сводку из успешно загруженных ответов.
|
||||||
|
|
||||||
|
Преимущества:
|
||||||
|
|
||||||
|
- не появляется новый API-контракт с данными, уже доступными в portfolio endpoint;
|
||||||
|
- каждый счёт может загружаться и восстанавливаться после ошибки независимо;
|
||||||
|
- при одном–трёх счетах число запросов остаётся ограниченным;
|
||||||
|
- используются существующие backend cache и rate limiting.
|
||||||
|
|
||||||
|
Недостатки:
|
||||||
|
|
||||||
|
- страница выполняет `1 + N` HTTP-запросов;
|
||||||
|
- ответы могут иметь разные значения `asOf` и не образуют атомарный снимок;
|
||||||
|
- правила презентационной агрегации находятся на frontend.
|
||||||
|
|
||||||
|
### 2. Новый aggregate endpoint
|
||||||
|
|
||||||
|
Добавить endpoint, который возвращает список счетов, их портфели и общую сводку одним ответом.
|
||||||
|
|
||||||
|
Преимущества:
|
||||||
|
|
||||||
|
- один HTTP-запрос с frontend;
|
||||||
|
- единый серверный контракт агрегации;
|
||||||
|
- проще переиспользовать сводку другими клиентами.
|
||||||
|
|
||||||
|
Недостатки:
|
||||||
|
|
||||||
|
- новый контракт дублирует существующие portfolio-данные;
|
||||||
|
- нужно определить семантику частичных ошибок и кеширования составного ответа;
|
||||||
|
- endpoint всё равно получает портфели нескольких счетов и не гарантирует атомарность данных T-Bank.
|
||||||
|
|
||||||
|
### 3. Расширение endpoint списка счетов
|
||||||
|
|
||||||
|
Добавить финансовую сводку каждого счёта в `GET /api/v1/broker/accounts`.
|
||||||
|
|
||||||
|
Преимущества:
|
||||||
|
|
||||||
|
- frontend получает всё одним запросом;
|
||||||
|
- карточки становятся простыми потребителями ответа.
|
||||||
|
|
||||||
|
Недостатки:
|
||||||
|
|
||||||
|
- лёгкий endpoint метаданных превращается в дорогой составной запрос;
|
||||||
|
- меняются его кеширование, время ответа и семантика ошибок;
|
||||||
|
- потребители списка счетов вынужденно получают финансовые данные.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
Использовать вариант 1: агрегировать существующие portfolio-ответы на frontend.
|
||||||
|
|
||||||
|
Frontend параллельно запрашивает портфели после получения списка счетов. Общая сводка строится только
|
||||||
|
из успешно загруженных ответов и явно помечается как частичная, если часть счетов недоступна. Ошибка
|
||||||
|
одного портфеля не блокирует остальные карточки.
|
||||||
|
|
||||||
|
Денежные значения группируются по валюте. Frontend не выполняет неявную валютную конвертацию и не
|
||||||
|
складывает несопоставимые суммы. Значения `asOf` отдельных ответов сохраняют свой смысл; сводка не
|
||||||
|
считается транзакционно согласованным снимком.
|
||||||
|
|
||||||
|
## Последствия
|
||||||
|
|
||||||
|
- Страница выполняет один запрос списка и до трёх параллельных запросов портфелей.
|
||||||
|
- Backend остаётся источником финансовых данных отдельного счёта, а frontend владеет только их
|
||||||
|
представлением и агрегацией для этой страницы.
|
||||||
|
- Частичные ошибки становятся штатным состоянием интерфейса и должны быть покрыты тестами.
|
||||||
|
- API, OpenAPI и frontend codegen для этой фичи не меняются.
|
||||||
|
- Решение следует пересмотреть, если выполняется хотя бы одно условие:
|
||||||
|
- продукт поддерживает более трёх одновременно отображаемых счетов;
|
||||||
|
- измерения показывают неприемлемую задержку или нагрузку от `1 + N` запросов;
|
||||||
|
- нескольким клиентам нужна одинаковая серверная сводка;
|
||||||
|
- появляется требование к согласованному серверному снимку или серверной валютной конвертации;
|
||||||
|
- правила агрегации становятся самостоятельной бизнес-логикой, а не логикой представления.
|
||||||
@ -1,17 +1,18 @@
|
|||||||
# Архитектурные решения (ADR)
|
# Архитектурные решения (ADR)
|
||||||
|
|
||||||
| ADR | Статус | Описание |
|
| ADR | Статус | Описание |
|
||||||
|---|---|---|
|
| ------------------------------------------------------ | ---------- | ---------------------------------------------- |
|
||||||
| [ADR-001](ADR-001-backend-single-point-of-access) | Accepted | Backend — единственная точка доступа к MOEX |
|
| [ADR-001](ADR-001-backend-single-point-of-access) | Accepted | Backend — единственная точка доступа к MOEX |
|
||||||
| [ADR-002](ADR-002-in-memory-cache) | Accepted | Стратегия in-memory cache |
|
| [ADR-002](ADR-002-in-memory-cache) | Accepted | Стратегия in-memory cache |
|
||||||
| [ADR-003](ADR-003-rate-limiting-strategy) | Accepted | Стратегия rate limiting |
|
| [ADR-003](ADR-003-rate-limiting-strategy) | Accepted | Стратегия rate limiting |
|
||||||
| [ADR-004](ADR-004-feature-modules) | Accepted | Архитектура feature-модулей |
|
| [ADR-004](ADR-004-feature-modules) | Accepted | Архитектура feature-модулей |
|
||||||
| [ADR-005](ADR-005-openapi-codegen-frontend) | Accepted | OpenAPI codegen для frontend |
|
| [ADR-005](ADR-005-openapi-codegen-frontend) | Accepted | OpenAPI codegen для frontend |
|
||||||
| [ADR-006](ADR-006-no-cci) | Deprecated | CCI вынесен за пределы MVP |
|
| [ADR-006](ADR-006-no-cci) | Deprecated | CCI вынесен за пределы MVP |
|
||||||
| [ADR-007](ADR-007-two-level-caching) | Draft | Двухуровневый cache: backend + frontend |
|
| [ADR-007](ADR-007-two-level-caching) | Draft | Двухуровневый cache: backend + frontend |
|
||||||
| [ADR-008](ADR-008-auth-system) | Accepted | Authentication и Authorization |
|
| [ADR-008](ADR-008-auth-system) | Accepted | Authentication и Authorization |
|
||||||
| [ADR-009](ADR-009-portfolio-domain) | Accepted | Доменная модель портфеля |
|
| [ADR-009](ADR-009-portfolio-domain) | Accepted | Доменная модель портфеля |
|
||||||
| [ADR-010](ADR-010-backend-price-computation) | Accepted | Расчёт цен на backend |
|
| [ADR-010](ADR-010-backend-price-computation) | Accepted | Расчёт цен на backend |
|
||||||
| [ADR-011](ADR-011-tbank-invest-grpc) | Accepted | Интеграция с T-Bank Invest через gRPC |
|
| [ADR-011](ADR-011-tbank-invest-grpc) | Accepted | Интеграция с T-Bank Invest через gRPC |
|
||||||
|
| [ADR-012](ADR-012-frontend-broker-account-aggregation) | Accepted | Агрегация сводки брокерских счетов на frontend |
|
||||||
|
|
||||||
Все опубликованные ADR находятся в `apps/docs/docs/adr/` и отображаются в этом Docusaurus-разделе.
|
Все опубликованные ADR находятся в `apps/docs/docs/adr/` и отображаются в этом Docusaurus-разделе.
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
- [T-Bank broker portfolios](../features/tbank-broker-portfolios/spec.md)
|
- [T-Bank broker portfolios](../features/tbank-broker-portfolios/spec.md)
|
||||||
- [Отображение брокерского портфеля](../features/broker-portfolio-display/spec.md)
|
- [Отображение брокерского портфеля](../features/broker-portfolio-display/spec.md)
|
||||||
- [x] [Разделы брокерского счёта](../features/broker-account-sections/spec.md) — реализовано
|
- [x] [Разделы брокерского счёта](../features/broker-account-sections/spec.md) — реализовано
|
||||||
|
- [Информативный обзор брокерских счетов](../features/broker-accounts-overview/spec.md)
|
||||||
- [Улучшение UI операций](../features/broker-operations-ui-improvements/spec.md)
|
- [Улучшение UI операций](../features/broker-operations-ui-improvements/spec.md)
|
||||||
- [Пагинация и загрузка позиций](../features/broker-positions-pagination-and-loading/spec.md)
|
- [Пагинация и загрузка позиций](../features/broker-positions-pagination-and-loading/spec.md)
|
||||||
- [Исправление deadline и очереди T-Bank](../features/tbank-deadline-queue-fix/spec.md)
|
- [Исправление deadline и очереди T-Bank](../features/tbank-deadline-queue-fix/spec.md)
|
||||||
|
|||||||
155
docs/features/broker-accounts-overview/spec.md
Normal file
155
docs/features/broker-accounts-overview/spec.md
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
# Информативный обзор брокерских счетов
|
||||||
|
|
||||||
|
Дата: 2026-06-19
|
||||||
|
Статус: согласовано к планированию
|
||||||
|
Эпик: [Портфель брокера](../../epics/BrokerPortfolio.md)
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Страница `/broker` показывает открытые брокерские счета и ИИС карточками, но полезная информация в
|
||||||
|
них ограничена названием, типом, техническим статусом и идентификатором. Пользователь не может на
|
||||||
|
одном экране оценить совокупный капитал, сравнить счета и понять структуру активов.
|
||||||
|
|
||||||
|
Страница предназначена преимущественно для одного–трёх счетов.
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
Превратить список брокерских счетов в компактный финансовый обзор, который с первого взгляда
|
||||||
|
отвечает на вопросы:
|
||||||
|
|
||||||
|
- сколько средств находится на всех доступных счетах;
|
||||||
|
- как изменилась их стоимость за день;
|
||||||
|
- сколько свободных денег доступно;
|
||||||
|
- как капитал распределён между счетами и основными классами активов;
|
||||||
|
- какой счёт нужно открыть для подробного анализа.
|
||||||
|
|
||||||
|
## Область изменений
|
||||||
|
|
||||||
|
Фича изменяет страницу списка брокерских счетов и включает:
|
||||||
|
|
||||||
|
- общую сводку по успешно загруженным счетам;
|
||||||
|
- информативные карточки отдельных счетов;
|
||||||
|
- независимую загрузку данных каждого счёта;
|
||||||
|
- состояния загрузки, частичной ошибки и отсутствия счетов;
|
||||||
|
- адаптивное отображение на широких и узких экранах.
|
||||||
|
|
||||||
|
Детальные страницы счёта, позиции, операции, торговые действия и правила расчёта показателей,
|
||||||
|
приходящих от T-Bank, не изменяются.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
### 1. Общая сводка
|
||||||
|
|
||||||
|
Над списком счетов отображается сводка по портфелям, данные которых успешно загружены:
|
||||||
|
|
||||||
|
- количество доступных счетов;
|
||||||
|
- совокупная стоимость портфелей;
|
||||||
|
- совокупный дневной результат в деньгах и процентах;
|
||||||
|
- свободные деньги;
|
||||||
|
- распределение стоимости по акциям, облигациям, фондам, деньгам и прочим активам.
|
||||||
|
|
||||||
|
Денежные значения разных валют не складываются и показываются отдельными суммами. Процентный
|
||||||
|
дневной результат и единое распределение активов показываются только для сопоставимых денежных
|
||||||
|
значений одной валюты. Интерфейс не выполняет неявную конвертацию валют.
|
||||||
|
|
||||||
|
Для каждой валюты совокупный дневной процент рассчитывается как отношение суммы дневных изменений
|
||||||
|
к суммарной стоимости портфелей на начало дня:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sum(daily) / (sum(portfolio) - sum(daily)) * 100
|
||||||
|
```
|
||||||
|
|
||||||
|
Процент не показывается, если хотя бы у одного включённого в валютную группу счёта отсутствует
|
||||||
|
стоимость или дневное изменение либо если стоимость на начало дня неположительна.
|
||||||
|
|
||||||
|
Если загружены не все счета, сводка явно сообщает, по скольким счетам рассчитаны показатели.
|
||||||
|
Недоступный счёт не включается в агрегированные значения.
|
||||||
|
|
||||||
|
### 2. Карточка счёта
|
||||||
|
|
||||||
|
Для каждого счёта показываются:
|
||||||
|
|
||||||
|
- название;
|
||||||
|
- понятный тип: `Брокерский счёт` или `ИИС`;
|
||||||
|
- дата открытия, если она доступна;
|
||||||
|
- текущая стоимость;
|
||||||
|
- дневной результат в деньгах и процентах;
|
||||||
|
- ожидаемая доходность;
|
||||||
|
- распределение стоимости по основным классам активов.
|
||||||
|
|
||||||
|
Технический идентификатор, сырой enum статуса и сырой enum уровня доступа в карточке не
|
||||||
|
отображаются.
|
||||||
|
|
||||||
|
Вся карточка является доступной с клавиатуры ссылкой на обзор выбранного счёта. Цвет доходности
|
||||||
|
используется только как дополнительный признак: знак и числовое значение остаются видимыми.
|
||||||
|
|
||||||
|
### 3. Загрузка
|
||||||
|
|
||||||
|
После получения списка счетов данные их портфелей загружаются независимо. До появления значений
|
||||||
|
общая сводка и карточки показывают skeleton-состояние с устойчивыми размерами, чтобы содержимое не
|
||||||
|
скакало при загрузке.
|
||||||
|
|
||||||
|
Появление данных одного счёта не должно ждать завершения остальных запросов.
|
||||||
|
|
||||||
|
### 4. Ошибки
|
||||||
|
|
||||||
|
Ошибка загрузки списка счетов показывает ошибку всей страницы.
|
||||||
|
|
||||||
|
Ошибка загрузки портфеля отдельного счёта:
|
||||||
|
|
||||||
|
- не скрывает другие счета;
|
||||||
|
- не блокирует переход в доступные счета;
|
||||||
|
- показывает локальное сообщение в карточке проблемного счёта;
|
||||||
|
- позволяет повторить загрузку этого счёта;
|
||||||
|
- исключает этот счёт из общей сводки и маркирует сводку как частичную.
|
||||||
|
|
||||||
|
### 5. Пустое состояние
|
||||||
|
|
||||||
|
Если открытых брокерских счетов и ИИС нет, страница показывает отдельное пустое состояние вместо
|
||||||
|
пустой сетки карточек. Текст объясняет, какие счета появятся на странице после подключения T-Bank.
|
||||||
|
|
||||||
|
### 6. Адаптивность
|
||||||
|
|
||||||
|
При одном–трёх счетах карточки располагаются вертикально и сохраняют единый порядок показателей для
|
||||||
|
быстрого сравнения.
|
||||||
|
|
||||||
|
На узком экране показатели переносятся на несколько строк, диаграмма распределения остаётся
|
||||||
|
читаемой, а интерактивные области не требуют горизонтальной прокрутки.
|
||||||
|
|
||||||
|
## Ограничения
|
||||||
|
|
||||||
|
- Страница остаётся read-only.
|
||||||
|
- Frontend не обращается к T-Bank напрямую.
|
||||||
|
- Агрегация не пересчитывает показатели отдельного счёта: исходные стоимости и доходность берутся
|
||||||
|
из существующих ответов портфеля. Единственный новый производный показатель — совокупный дневной
|
||||||
|
процент по явно заданной в этой спецификации формуле.
|
||||||
|
- Данные разных счетов могут иметь разные моменты `asOf`; интерфейс не представляет сводку как
|
||||||
|
транзакционно согласованный снимок.
|
||||||
|
- Решение рассчитано на один–три счёта. Расширение этого предположения требует пересмотра
|
||||||
|
[ADR-012](../../../apps/docs/docs/adr/ADR-012-frontend-broker-account-aggregation.md).
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- Над счетами показана общая стоимость, дневной результат, свободные деньги, число счетов и
|
||||||
|
распределение активов.
|
||||||
|
- Значения разных валют не складываются без курса конвертации.
|
||||||
|
- Каждая успешно загруженная карточка показывает стоимость, доходность, тип и распределение активов.
|
||||||
|
- Название и дата открытия показываются, когда доступны.
|
||||||
|
- Технический ID и сырые T-Bank enum-значения не отображаются.
|
||||||
|
- Вся карточка ведёт на обзор соответствующего счёта и доступна с клавиатуры.
|
||||||
|
- Во время загрузки отображаются skeleton-состояния без заметного изменения геометрии страницы.
|
||||||
|
- Ошибка одного портфеля не скрывает остальные счета и не включает недоступные данные в сводку.
|
||||||
|
- Пользователь может повторить запрос проблемного счёта.
|
||||||
|
- При отсутствии счетов отображается объясняющее пустое состояние.
|
||||||
|
- Страница не требует горизонтальной прокрутки на поддерживаемых мобильных ширинах.
|
||||||
|
- Unit-тесты покрывают агрегацию, валютные ограничения и расчёт распределения.
|
||||||
|
- Component-тесты покрывают успешную загрузку, skeleton, пустое состояние, частичную ошибку,
|
||||||
|
повторный запрос и переход в счёт.
|
||||||
|
|
||||||
|
## Не цели
|
||||||
|
|
||||||
|
- Добавление aggregate endpoint на backend.
|
||||||
|
- Конвертация валют и получение валютных курсов.
|
||||||
|
- Поддержка более трёх счетов как отдельного плотного режима.
|
||||||
|
- Изменение детальной страницы брокерского счёта.
|
||||||
|
- Изменение T-Bank DTO, OpenAPI-контракта или сгенерированных frontend-типов.
|
||||||
@ -11,6 +11,7 @@ Roadmap отражает порядок продуктовой работы, н
|
|||||||
Цель: сделать реальные брокерские счета понятными на уровне обзора, позиций и операций.
|
Цель: сделать реальные брокерские счета понятными на уровне обзора, позиций и операций.
|
||||||
|
|
||||||
- [x] [Разделы брокерского счёта](features/broker-account-sections/spec.md) — реализовано.
|
- [x] [Разделы брокерского счёта](features/broker-account-sections/spec.md) — реализовано.
|
||||||
|
- [ ] [Информативный обзор брокерских счетов](features/broker-accounts-overview/spec.md) — согласовано к планированию.
|
||||||
|
|
||||||
## Следующие этапы для активной фичи
|
## Следующие этапы для активной фичи
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user