docs: reorganize system knowledge by domain
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# Загрузка портфеля
|
||||
|
||||
Поток начинается при открытии `/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).
|
||||
Reference in New Issue
Block a user