Files
docs/integrations/tbank.md
T
ksv741 1378ac9fe2
Conventional commits / commits (pull_request) Successful in 12s
Docs security / security (pull_request) Successful in 8s
Docs verify / verify (pull_request) Successful in 12s
docs: document hourly attempt lifecycle semantics (WealthLedger/backend#56)
2026-10-12 20:28:59 +03:00

168 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Интеграция с 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-ошибке, включая
исчерпание очереди. Диагностические причины жизненного цикла часовой попытки
(`INTERRUPTED` — прерывание до нормального завершения, `DEADLINE` — истечение
ограничения ожидания шага) не относятся к ошибкам T-Bank: они остаются
внутренней диагностикой и не раскрываются в hourly-read. Истечение ограничения
ожидания не отменяет уже начатые обращения к T-Bank; их поздние результаты
остаются в строках шагов. Ответы и ошибки не содержат 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: обновление внешнего протокола и проверка
совместимости требуют отдельного изменения интеграции.