Document ticker aliases, instrument identity, market data and dividend history, portfolio links, and updated brokerage account summaries.
79 lines
7.9 KiB
Markdown
79 lines
7.9 KiB
Markdown
# Брокерские счета
|
||
|
||
Авторизованный пользователь просматривает открытые поддерживаемые инвестиционные счета T-Bank, доступные через его текущее T-Bank connection, на странице `/accounts`. Для получения списка требуется сохранённое T-Bank connection; frontend никогда не обращается к T-Bank напрямую. WealthLedger не хранит Brokerage Account как долговременное владение отдельно от брокерского подключения.
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as User
|
||
participant F as Frontend
|
||
participant B as Backend
|
||
participant D as SQLite
|
||
participant T as T-Bank gRPC
|
||
U->>F: Открывает /accounts
|
||
F->>B: GET /api/v1/brokerage-accounts (Bearer)
|
||
B->>D: Читает T-Bank connection
|
||
alt Connection отсутствует
|
||
B-->>F: 409 TBANK_NOT_CONNECTED
|
||
F-->>U: Переход к настройкам T-Bank
|
||
else Connection существует
|
||
B->>T: GetAccounts(OPEN) over TLS
|
||
T-->>B: Счета или ошибка
|
||
par Для каждого поддерживаемого счета
|
||
B->>T: GetPortfolio + GetPositions over TLS
|
||
T-->>B: Исходные валютные значения или temporary unavailable
|
||
end
|
||
B-->>F: Нормализованный массив с локальными summary либо Problem Details
|
||
F-->>U: Карточки счетов или error-state
|
||
end
|
||
```
|
||
|
||
## API
|
||
|
||
`GET /api/v1/brokerage-accounts` требует Bearer access token и возвращает массив:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": "account-id",
|
||
"name": "Основной",
|
||
"type": "BROKERAGE",
|
||
"openedOn": "2024-08-13",
|
||
"portfolioSummary": {
|
||
"totalsByCurrency": [
|
||
{ "currency": "RUB", "value": "12500.50" },
|
||
{ "currency": "USD", "value": "40" }
|
||
],
|
||
"stockPositionCount": 5,
|
||
"bondPositionCount": 12
|
||
}
|
||
}
|
||
]
|
||
```
|
||
|
||
Поддерживаемые `type`: `BROKERAGE`, `INDIVIDUAL_INVESTMENT`, `INVEST_BOX`, `MONEY_MARKET_FUND`. Банковские и неизвестные типы T-Bank не возвращаются. Пустое upstream-название заменяется названием типа, а отсутствующая дата открытия передаётся как `null`.
|
||
|
||
`portfolioSummary` — nullable наблюдение текущего портфеля конкретного счета. `totalsByCurrency` точно складывает ненулевые текущие стоимости позиций и денежные остатки только в одинаковой исходной ISO-валюте; FX-конвертация и единый итог не выполняются. Успешный пустой портфель возвращает пустой массив. Когда T-Bank временно недоступен только для summary одного счета, этот счет всё равно остаётся в списке с `portfolioSummary: null`; переход к его деталям и остальные карточки не блокируются.
|
||
|
||
`stockPositionCount` и `bondPositionCount` — число ненулевых обычных позиций акций и облигаций по наименованиям, а не сумма штук или лотов. Подсчёт использует уже полученный `GetPortfolio`, без дополнительных запросов metadata; включает дробные и короткие позиции, даже если текущая стоимость неизвестна. Нулевые и виртуальные позиции, фонды, валютные и прочие инструменты не входят в эти два счётчика. Успешный пустой портфель возвращает оба счётчика равными нулю; недоступная сводка остаётся `null`.
|
||
|
||
Список является результатом текущего наблюдения T-Bank connection: если счёт больше не открыт, не поддерживается или недоступен через это подключение, он не считается доступным для WealthLedger. Ошибки connection или token, а также ошибки исходного получения списка, не превращаются в частичный ответ.
|
||
|
||
## Состояния
|
||
|
||
При первом запросе `/accounts` frontend показывает structural skeleton заголовка
|
||
и карточек, а не отдельный spinner; placeholder не содержит данных и не
|
||
участвует в keyboard focus. После успешного ответа либо ошибки используются
|
||
обычные нижеописанные состояния.
|
||
|
||
- `409 TBANK_NOT_CONNECTED`: список не запрашивается у T-Bank, экран ведёт в настройки.
|
||
- `400 INVALID_TBANK_TOKEN`: сохранённый token не удаляется, экран ведёт в настройки для замены или удаления.
|
||
- `503 TBANK_UNAVAILABLE`: экран предлагает повторить загрузку или открыть настройки.
|
||
- Неизвестная ошибка: экран предлагает только повторить загрузку.
|
||
- Успешный пустой ответ: штатное состояние отсутствия инвестиционных счетов.
|
||
|
||
Карточка ведёт на `/accounts/:accountId` по всей области и сохраняет нативную клавиатурную навигацию/focus. На широком экране карточки расположены в две колонки, на узком — в одну. Карточка показывает название, локализованный тип, крупный валютный итог и вторую валюту при наличии, число остальных валют, дату открытия без времени и видимое действие открытия. Отдельные цветные блоки «Акции» и «Облигации» показывают количество наименований бумаг. Недоступная или пустая summary отображается локально; отсутствие сумм не скрывает известные количества бумаг, а недоступная summary не подменяет их нулями. Hover и видимый keyboard focus подчёркивают переход; reduced motion отключает движение.
|
||
|
||
## Ограничения MVP
|
||
|
||
Список запрашивается при открытии экрана без ручного обновления и без refetch при возврате фокуса. Frontend использует успешный React Query-кэш в течение 60 секунд, поэтому повторный вход в этот интервал не выполняет новый GET. Когда уже показанный список обновляется в фоне, он остаётся на экране: индикатор обновления и ошибка с повторной попыткой отображаются рядом с последним успешным ответом, включая пустой список. Это **Client Cached Snapshot**, а не server-side fallback. Backend не хранит кэш и не передаёт метку свежести. Балансы, доходность, графики, портфель, закрытые счета и операции не входят в feature.
|