docs: reorganize system knowledge by domain

This commit is contained in:
2026-09-12 14:45:42 +03:00
parent 3a99af1a6e
commit f20c3f47bc
83 changed files with 2229 additions and 7335 deletions
@@ -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).