diff --git a/apps/docs/docs/adr/ADR-012-frontend-broker-account-aggregation.md b/apps/docs/docs/adr/ADR-012-frontend-broker-account-aggregation.md new file mode 100644 index 0000000..02027b7 --- /dev/null +++ b/apps/docs/docs/adr/ADR-012-frontend-broker-account-aggregation.md @@ -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` запросов; + - нескольким клиентам нужна одинаковая серверная сводка; + - появляется требование к согласованному серверному снимку или серверной валютной конвертации; + - правила агрегации становятся самостоятельной бизнес-логикой, а не логикой представления. diff --git a/apps/docs/docs/adr/index.md b/apps/docs/docs/adr/index.md index 58d9185..f2921a9 100644 --- a/apps/docs/docs/adr/index.md +++ b/apps/docs/docs/adr/index.md @@ -1,17 +1,18 @@ # Архитектурные решения (ADR) -| ADR | Статус | Описание | -|---|---|---| -| [ADR-001](ADR-001-backend-single-point-of-access) | Accepted | Backend — единственная точка доступа к MOEX | -| [ADR-002](ADR-002-in-memory-cache) | Accepted | Стратегия in-memory cache | -| [ADR-003](ADR-003-rate-limiting-strategy) | Accepted | Стратегия rate limiting | -| [ADR-004](ADR-004-feature-modules) | Accepted | Архитектура feature-модулей | -| [ADR-005](ADR-005-openapi-codegen-frontend) | Accepted | OpenAPI codegen для frontend | -| [ADR-006](ADR-006-no-cci) | Deprecated | CCI вынесен за пределы MVP | -| [ADR-007](ADR-007-two-level-caching) | Draft | Двухуровневый cache: backend + frontend | -| [ADR-008](ADR-008-auth-system) | Accepted | Authentication и Authorization | -| [ADR-009](ADR-009-portfolio-domain) | Accepted | Доменная модель портфеля | -| [ADR-010](ADR-010-backend-price-computation) | Accepted | Расчёт цен на backend | -| [ADR-011](ADR-011-tbank-invest-grpc) | Accepted | Интеграция с T-Bank Invest через gRPC | +| ADR | Статус | Описание | +| ------------------------------------------------------ | ---------- | ---------------------------------------------- | +| [ADR-001](ADR-001-backend-single-point-of-access) | Accepted | Backend — единственная точка доступа к MOEX | +| [ADR-002](ADR-002-in-memory-cache) | Accepted | Стратегия in-memory cache | +| [ADR-003](ADR-003-rate-limiting-strategy) | Accepted | Стратегия rate limiting | +| [ADR-004](ADR-004-feature-modules) | Accepted | Архитектура feature-модулей | +| [ADR-005](ADR-005-openapi-codegen-frontend) | Accepted | OpenAPI codegen для frontend | +| [ADR-006](ADR-006-no-cci) | Deprecated | CCI вынесен за пределы MVP | +| [ADR-007](ADR-007-two-level-caching) | Draft | Двухуровневый cache: backend + frontend | +| [ADR-008](ADR-008-auth-system) | Accepted | Authentication и Authorization | +| [ADR-009](ADR-009-portfolio-domain) | Accepted | Доменная модель портфеля | +| [ADR-010](ADR-010-backend-price-computation) | Accepted | Расчёт цен на backend | +| [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-разделе. diff --git a/docs/epics/BrokerPortfolio.md b/docs/epics/BrokerPortfolio.md index 62078e0..ba3fff0 100644 --- a/docs/epics/BrokerPortfolio.md +++ b/docs/epics/BrokerPortfolio.md @@ -27,6 +27,7 @@ - [T-Bank broker portfolios](../features/tbank-broker-portfolios/spec.md) - [Отображение брокерского портфеля](../features/broker-portfolio-display/spec.md) - [x] [Разделы брокерского счёта](../features/broker-account-sections/spec.md) — реализовано +- [Информативный обзор брокерских счетов](../features/broker-accounts-overview/spec.md) - [Улучшение UI операций](../features/broker-operations-ui-improvements/spec.md) - [Пагинация и загрузка позиций](../features/broker-positions-pagination-and-loading/spec.md) - [Исправление deadline и очереди T-Bank](../features/tbank-deadline-queue-fix/spec.md) diff --git a/docs/features/broker-accounts-overview/spec.md b/docs/features/broker-accounts-overview/spec.md new file mode 100644 index 0000000..67ffe0a --- /dev/null +++ b/docs/features/broker-accounts-overview/spec.md @@ -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-типов. diff --git a/docs/roadmap.md b/docs/roadmap.md index b621c47..16f19db 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -11,6 +11,7 @@ Roadmap отражает порядок продуктовой работы, н Цель: сделать реальные брокерские счета понятными на уровне обзора, позиций и операций. - [x] [Разделы брокерского счёта](features/broker-account-sections/spec.md) — реализовано. +- [ ] [Информативный обзор брокерских счетов](features/broker-accounts-overview/spec.md) — согласовано к планированию. ## Следующие этапы для активной фичи