Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 11s
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (pull_request) Successful in 6s
Docs verify / verify (pull_request) Successful in 12s
163 lines
14 KiB
Markdown
163 lines
14 KiB
Markdown
# Интеграция с T-Bank Invest
|
||
|
||
T-Bank — источник доступных пользователю инвестиционных счетов, текущих
|
||
позиций и денег, исполненных операций и рыночных сведений об инструментах.
|
||
WealthLedger обращается к Invest API на сервере по gRPC over TLS и преобразует
|
||
ответы в собственный HTTP API. Изображения логотипов загружаются браузером
|
||
отдельно из публичного CDN; это не доступ к личным брокерским данным.
|
||
|
||
## Данные и ответственность
|
||
|
||
| Категория | Для чего используется |
|
||
| --- | --- |
|
||
| Открытые счета | Определить доступный состав счетов и проверить доступ к конкретному счёту |
|
||
| Портфель и денежные остатки | Показать текущий состав инвестиций и итоги по исходным валютам |
|
||
| Исполненные операции | Построить журнал и выделить полученные купоны и дивиденды |
|
||
| Инструменты и рынок | Имена, идентификаторы, цены, свечи, параметры акций и облигаций |
|
||
| Купоны и дивиденды | Построить будущие события по текущим позициям и календарь инструмента |
|
||
|
||
T-Bank определяет исходные данные и права token. Backend проверяет локальную
|
||
сессию, выбирает подключение её пользователя и устанавливает доступ к счёту.
|
||
Наличие идентификатора счёта в URL этого доступа не подтверждает.
|
||
|
||
Скринер акций получает полный online-каталог акций T-Bank для каждого нового
|
||
поиска. В него входят только инструменты, для которых каталог подтверждает и
|
||
доступность покупки, и торговли через API. Эти признаки описывают полученный
|
||
снимок каталога: они не подтверждают личные права пользователя, состояние торгов
|
||
или исполнение будущей заявки. Скринер не использует личный портфель как каталог.
|
||
|
||
[MOEX](moex.md) и [НКР](nkr.md) дополняют публичные сведения об облигациях; они не заменяют
|
||
брокера как источник личных позиций и исполненных выплат. Границы источников
|
||
показаны в [контексте](../architecture/context.md), смысл дополнений — в
|
||
[описании облигаций](../domains/instruments/bonds.md).
|
||
|
||
## Публичные логотипы
|
||
|
||
T-Bank Brands CDN — отдельная публичная граница для изображений.
|
||
Backend передаёт имя файла `logoName` из метаданных инструмента; frontend
|
||
строит URL на `invest-brands.cdn-tinkoff.ru` и загружает изображение браузером.
|
||
Эти запросы не используют HTTP-клиент приложения, его Bearer token
|
||
или token Invest API. Лимитер и повторы серверных gRPC-вызовов к ним не относятся.
|
||
|
||
Логотипы используются в портфеле, операциях, будущих событиях, поиске и
|
||
страницах инструментов. Отсутствующее имя или ошибка изображения оставляют
|
||
буквенную заглушку и не меняют финансовые значения. Правило построения URL
|
||
принадлежит [форматированию frontend](https://git.personal.ksv741.ru/WealthLedger/frontend/src/commit/9f7e342333b80bfacfd5bc394a2dcd0613d33ff3/src/shared/lib/display.ts).
|
||
|
||
## Проверка и сохранение подключения
|
||
|
||
Авторизованный пользователь управляет одним подключением в настройках.
|
||
Интерфейс просит read-only T-Bank Invest token: он вводится в поле пароля
|
||
и отправляется backend. API возвращает только состояние подключения и время
|
||
его сохранения, не token. Успешное сохранение очищает поле, ошибка оставляет
|
||
введённое значение для исправления. Удаление требует подтверждения в форме;
|
||
во время изменения действия секции заблокированы.
|
||
|
||
Схема показывает динамический сценарий создания или замены подключения.
|
||
SQLite — локальное хранилище backend, а не отдельный сетевой участник.
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant U as Пользователь
|
||
participant F as React SPA
|
||
participant B as Backend API
|
||
participant T as T-Bank Invest API
|
||
participant D as Локальная SQLite
|
||
U->>F: Вводит token и сохраняет подключение
|
||
F->>B: PUT connection с Bearer и token
|
||
B->>T: GetAccounts OPEN по gRPC over TLS
|
||
alt Проверка успешна, в том числе при пустом списке счетов
|
||
T-->>B: Доступные открытые счета
|
||
B->>D: Атомарно сохранить token, новую revision и membership
|
||
B-->>F: Подключено и время сохранения
|
||
F->>F: Обновить статус и сбросить финансовые выборки
|
||
F-->>U: Показать подтверждённое подключение
|
||
else Token отклонён или источник недоступен
|
||
T-->>B: Ошибка проверки
|
||
B-->>F: INVALID_TBANK_TOKEN или TBANK_UNAVAILABLE
|
||
F-->>U: Локальная ошибка, прежнее подключение сохранено
|
||
end
|
||
```
|
||
|
||
Перед проверкой backend удаляет внешние пробелы token и отклоняет пустое
|
||
значение. Успешный пустой список счетов подтверждает token: наличие позиций
|
||
не является условием подключения. Ошибка проверки не заменяет уже сохранённое
|
||
подключение. Сетевой вызов T-Bank и запись SQLite выполняются последовательно,
|
||
но не образуют общую транзакцию между системами.
|
||
|
||
## Состояние и ошибки
|
||
|
||
Состояние без подключения содержит `connected: false` и `connectedAt: null`.
|
||
После создания или замены `connectedAt` содержит время успешного сохранения
|
||
в RFC 3339 UTC. Это время подключения, а не отметка свежести портфеля.
|
||
Чтение статуса показывает сохранённое состояние; оно не выполняет заново
|
||
проверку token у брокера. Если статус загрузить не удалось, интерфейс
|
||
показывает ошибку с повтором, а не форму с предполагаемым отсутствием
|
||
подключения.
|
||
|
||
`INVALID_TBANK_TOKEN` означает отказ внешней аутентификации или прав доступа.
|
||
`TBANK_UNAVAILABLE` сообщает о временной или иной upstream-ошибке, включая
|
||
исчерпание очереди. Ответы и ошибки не содержат token. Удаление подключения
|
||
идемпотентно: удаляются локальный секрет, личные datasets и work; поздняя
|
||
публикация прежней revision запрещена. Общие неперсональные источники могут
|
||
сохраняться. Оно не описывает отзыв token на стороне T-Bank.
|
||
|
||
Согласованное поведение сохранено в workspace-спецификации
|
||
[T-Bank connection](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/tbank-connection/spec.md).
|
||
Точные endpoints и формы ответов определяет backend OpenAPI;
|
||
[HTTP API](../architecture/http-api.md) описывает общую границу.
|
||
|
||
## Граница финансового кэша
|
||
|
||
Успешное создание, замена или удаление подключения меняет границу повторного
|
||
использования финансовых данных. Это относится и к сохранению того же самого
|
||
token: предыдущее подключение не становится источником данных нового.
|
||
Неуспешная операция сохраняет прежнее подключение и его доступные данные.
|
||
Механизм внутренней revision, поздние ответы и сброс клиентских выборок объясняет
|
||
[свежесть данных](../architecture/cross-cutting/data-freshness.md#смена-подключения).
|
||
|
||
## Конфигурация и ограничения
|
||
|
||
Backend хранит token в шифротексте AES-256-GCM с новым nonce при каждом
|
||
сохранении. Ключ находится только в серверном окружении. Расшифровка нужна
|
||
серверной интеграции; ни шифротекст, ни token не входят в публичное API.
|
||
Причины границы и шифрования сохранены в
|
||
[ADR 003](../adr/003-tbank-server-side-grpc-boundary.md) и
|
||
[ADR 004](../adr/004-encrypted-per-user-tbank-token.md).
|
||
|
||
| Настройка | Значение и смысл |
|
||
| --- | --- |
|
||
| `TOKEN_ENCRYPTION_KEY` | Обязательный ключ AES-256-GCM: 32 байта, закодированные в base64 |
|
||
| `TBANK_GRPC_ENDPOINT` | Адрес gRPC; по умолчанию `invest-public-api.tbank.ru:443` |
|
||
| `TBANK_RATE_LIMIT_PER_SECOND` | Число стартующих T-Bank RPC в секунду на экземпляр backend; по умолчанию `5` |
|
||
| `TBANK_CA_CERT_PATH` | Необязательный путь к доверенному корневому CA в PEM для сетей с TLS-инспекцией; проверка TLS сохраняется |
|
||
|
||
Параметры окружения определяет backend
|
||
[validateEnv](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/config/env.validation.ts) (справочный источник).
|
||
Общий FIFO-лимитер ограничивает поток RPC и не допускает более 50
|
||
ожидающих. Для `UNAVAILABLE`, `DEADLINE_EXCEEDED` и `RESOURCE_EXHAUSTED`
|
||
каждый RPC допускает один повтор через секунду. Deadline каждой попытки — 15 секунд,
|
||
а ожидание места в лимитере не является временем этой сетевой попытки.
|
||
Метаданные используют ту же retry policy. Переполненная очередь завершается
|
||
ошибкой сразу, без повторов admission. Постоянные ошибки и отказ авторизации
|
||
не повторяются. Подтверждённый `NOT_FOUND` при поиске метаданных означает
|
||
отсутствие инструмента, а не временный сбой.
|
||
Параметры попыток принадлежат
|
||
[T-Bank client](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/integrations/tbank/tbank.client.ts) (справочный источник);
|
||
решение об ограниченных повторах — [ADR 005](../adr/005-tbank-upstream-resilience.md).
|
||
|
||
Большое число ранее неизвестных инструментов требует отдельных запросов
|
||
metadata. При перегруженной очереди необязательные имена могут быть заменены
|
||
идентификаторами; это не доказывает потерю самой позиции. Изменение локального
|
||
лимита требует учёта разрешённой квоты T-Bank: оно не увеличивает квоту
|
||
поставщика.
|
||
|
||
Ключ шифрования не ротируется автоматически. Новый ключ не расшифрует
|
||
прежнее подключение: нужен исходный ключ либо повторный ввод собственного
|
||
token через настройки. Правила [резервного копирования](../architecture/containers.md#сохранение-и-восстановление-данных)
|
||
учитывают отдельное хранение ключа. Лимитер и кэши принадлежат
|
||
одному экземпляру; изменения подключения не координируются между
|
||
распределёнными экземплярами backend. Интеграция использует сохранённый
|
||
protobuf-контракт T-Bank: обновление внешнего протокола и проверка
|
||
совместимости требуют отдельного изменения интеграции.
|