127 lines
10 KiB
Markdown
127 lines
10 KiB
Markdown
# Загрузка портфеля
|
|
|
|
Поток начинается при открытии `/accounts/:accountId` пользователем
|
|
с действующей сессией. Его результат — полный нормализованный снимок
|
|
доступного счёта либо объяснимая ошибка. Браузер обращается к backend;
|
|
доступ к брокерскому токену и внешние запросы остаются на сервере.
|
|
|
|
## Основной обмен
|
|
|
|
Сначала frontend проверяет свой успешный кэш: в течение 30 секунд повторное
|
|
открытие может показать ответ без нового HTTP-запроса. Следующая схема
|
|
описывает запрос, который действительно дошёл до backend.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant F as Frontend
|
|
participant B as Backend API
|
|
participant D as SQLite
|
|
participant T as T-Bank
|
|
F->>B: Запрос портфеля счёта с Bearer token
|
|
B->>B: Проверяет сессию
|
|
B->>D: Читает текущее подключение пользователя
|
|
D-->>B: Подключение либо отсутствие
|
|
alt Подключения нет
|
|
B-->>F: 409 TBANK_NOT_CONNECTED
|
|
else Подключение доступно
|
|
B->>B: Определяет поколение подключения
|
|
alt Снимок того же поколения не старше 30 секунд
|
|
B-->>F: Полный снимок, isStale=false
|
|
else Нужен новый снимок
|
|
B->>T: Получает открытые счета
|
|
T-->>B: Состав доступных счетов
|
|
alt Счёт недоступен
|
|
B-->>F: 404
|
|
else Счёт доступен
|
|
par Финансовые позиции
|
|
B->>T: GetPortfolio
|
|
T-->>B: Позиции и цены
|
|
and Доступные деньги
|
|
B->>T: GetPositions
|
|
T-->>B: Денежные остатки
|
|
end
|
|
B->>T: Метаданные отсутствующих инструментов по UID, затем FIGI
|
|
T-->>B: Метаданные, отсутствие или ошибка
|
|
B->>B: Нормализует состав и точно вычисляет суммы
|
|
B-->>F: Полный новый снимок, isStale=false
|
|
end
|
|
end
|
|
end
|
|
```
|
|
|
|
Свежий серверный снимок выдаётся после разрешения текущего сохранённого
|
|
подключения, но без нового `GetAccounts`. После истечения свежего кэша
|
|
проверка доступности счёта предшествует финансовым RPC. SQLite хранит
|
|
подключение, а не снимок или право владения счётом вне этого подключения.
|
|
|
|
Для нового снимка требуются оба финансовых ответа. Backend не выдаёт
|
|
позиции без денег или деньги без позиций как полный портфель.
|
|
Метаданные дополняют имя и идентификаторы, но их ошибка не срывает
|
|
финансовый результат. Общий серверный клиент обеспечивает TLS, очередь,
|
|
ограничение частоты, deadline RPC и разрешённые повторные попытки —
|
|
[граница интеграции](../../../integrations/tbank.md).
|
|
|
|
## Время и изменение подключения
|
|
|
|
| Слой | Что сохраняется | Условие повторного использования |
|
|
| --- | --- | --- |
|
|
| Frontend | Последний успешный HTTP-ответ для выбранного счёта и сессии | Свежим считается 30 секунд; при обычном обновлении уже показанный ответ остаётся видимым |
|
|
| Backend | Полный снимок пары пользователь–счёт в памяти процесса | До 30 секунд, только в том же поколении текущего подключения |
|
|
| Backend при временной ошибке | Тот же полный снимок | Не старше пяти минут с момента успешного сохранения, только в том же поколении |
|
|
| Метаданные инструмента | Успешный поиск или подтверждённое отсутствие | До 24 часов; общий ограниченный кэш на 500 ключей UID/FIGI, ошибки не сохраняются |
|
|
|
|
Это параметры текущей реализации, а не самостоятельная политика этого
|
|
документа: [снимки](../../../../backend/src/tbank/portfolio.service.ts),
|
|
[метаданные](../../../../backend/src/tbank/instrument-metadata.service.ts) и
|
|
[клиентский запрос](../../../../frontend/src/entities/portfolio/api/usePortfolio.ts).
|
|
|
|
Пять минут — предельный возраст успешного снимка, а не дополнительные
|
|
пять минут после окончания свежих 30 секунд. Запасной ответ сохраняет
|
|
исходное `lastSuccessfulAt` и получает `isStale: true`.
|
|
|
|
Успешное создание, замена или удаление подключения меняет границу
|
|
повторного использования финансовых данных. Старое или поздно завершившееся
|
|
получение снимка не делает его доступным новым запросам другого поколения.
|
|
Явная очистка памяти при изменении подключения дополняет эту проверку.
|
|
Frontend сбрасывает всё поддерево финансовых запросов при изменении
|
|
подключения и общий кэш сессии при выходе; старый портфель не служит
|
|
заглушкой загрузки нового подключения.
|
|
|
|
В общем режиме сначала определяется состав доступных счетов одного
|
|
подключения, затем получаются их снимки. Это
|
|
[не атомарное наблюдение нескольких счетов](../all-accounts.md#полнота-свежесть-и-доступ).
|
|
|
|
## Ошибки и результат для пользователя
|
|
|
|
| Причина | Ответ backend | Действие на экране |
|
|
| --- | --- | --- |
|
|
| Нет подключения | `409 TBANK_NOT_CONNECTED` | Открыть настройки T-Bank |
|
|
| Брокер отклонил токен | `400 INVALID_TBANK_TOKEN` | Открыть настройки; токен автоматически не удаляется |
|
|
| Счёт недоступен через текущее подключение | `404` | Вернуться к списку счетов |
|
|
| Временная ошибка, пригодный предыдущий снимок есть | `200`, `isStale: true` | Показать снимок и его исходное время с предупреждением |
|
|
| Временная ошибка, пригодного снимка нет | `503 TBANK_UNAVAILABLE` | Повторить загрузку |
|
|
| Неизвестная ошибка | Безопасная ошибка API | Повторить загрузку |
|
|
|
|
`INVALID_TBANK_TOKEN` и `404` не заменяются серверным запасным снимком.
|
|
Временная ошибка определения доступных счетов также может использовать
|
|
пригодный снимок того же поколения. Сбой метаданных использует идентификатор
|
|
инструмента и не устанавливает `isStale`.
|
|
|
|
На клиенте нет polling, автоматического повтора неуспешного запроса или
|
|
обновления при возврате фокуса. При обновлении того же уже показанного
|
|
результата клиент оставляет его на экране, добавляя индикатор загрузки
|
|
или предупреждение с доступной с клавиатуры повторной попыткой.
|
|
Это клиентский сохранённый ответ, независимо от серверного `isStale`.
|
|
|
|
Первое обращение к крупному портфелю может потребовать много метаданных.
|
|
Переполнение общей очереди RPC означает временную недоступность конкретного
|
|
поиска. После успешного поиска метаданные используются повторно до истечения
|
|
кэша. Значение `TBANK_RATE_LIMIT_PER_SECOND` следует соотносить с квотой
|
|
источника; его увеличение не является гарантированным исправлением
|
|
ограничения самого T-Bank.
|
|
|
|
Проверяемые правила: [свежесть и запасной снимок](../../../../specs/openspec/specs/portfolio-view/spec.md#requirement-свежесть-и-fallback-полного-portfolio-snapshot),
|
|
[клиентские состояния](../../../../specs/openspec/specs/portfolio-view/spec.md#requirement-состояния-и-ошибки-portfolio-на-клиенте).
|
|
Для расследования конкретного значения используйте
|
|
[порядок диагностики](../how-to/investigate-discrepancy.md).
|