Files
docs/architecture/cross-cutting/data-freshness.md
T
ksv741 a45d3e77b9
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 13s
Conventional commits / commits (pull_request) Successful in 12s
Docs security / security (pull_request) Successful in 8s
Docs verify / verify (pull_request) Successful in 14s
docs: document hourly investment reads
2026-10-09 19:56:40 +03:00

84 lines
8.1 KiB
Markdown

# Свежесть данных и повторное использование
WealthLedger читает личные инвестиционные данные из SQLite. Обычный GET и его
HTTP retry возвращают сохранённый результат и не запускают личную работу с
T-Bank. Нормальным владельцем обновления служит часовой обход текущего
подключения: после успешного подключения он начинает первую попытку, затем
начинает следующую не ранее чем через 60 минут от начала предыдущей. После
простоя выполняется не более одна актуальная попытка, а перекрывающийся срок
пропускается, не ставится в очередь. Общие справочные данные инструментов
запрашиваются онлайн, когда это требуется карточке; финансовый HTTP-ответ не
ждёт T-Bank. Модель принята в
[ADR 019](../../adr/019-hourly-reads-and-online-instrument-reference.md).
## Клиентский и серверный снимки
[Client Cached Snapshot](../../glossary.md#client-cached-snapshot) — успешный
ответ в TanStack Query. Он сохраняет показанное содержимое при временной ошибке
HTTP-перечитывания в той же границе доступа. Это не серверный fallback и не
состояние часового обхода. SQLite независимо от браузера хранит membership,
последний полный portfolio, исполненные операции, прогнозы, общие сведения об
инструментах, котировки, свечи и календари.
[Полнота периода](../../glossary.md#полнота-истории-счёта) и свежесть различаются.
Успешно проверенный пустой результат полон и доступен; последняя страница
журнала сама по себе полноту не доказывает. Результат каждого личного ресурса
в `{ data, meta }` описывают пять независимых значений: freshness,
completeness, `lastSuccessfulAt`, `lastAttempt` и availability. Первые,
полнота и `lastSuccessfulAt` относятся только к возвращённому подтверждённому
результату. `lastAttempt` описывает относящуюся к ресурсу часовую попытку:
`none`, `running`, `succeeded`, `partial` или `failed`.
Поздняя неуспешная или частичная попытка сохраняет прежний полный результат и
его исходное время. Если полного результата нет, `data` равно `null`: состояние
availability объясняет первоначальную загрузку, временную недоступность либо
недоступность подключения. Пустой массив не означает отсутствие результата.
Старый полный portfolio не удаляется из-за возраста. `Portfolio.isStale`
сохраняет смысл возраста его snapshot, а не обозначает неуспех обхода или
клиентскую ошибку перечитывания.
| Источник | Владелец нормального обновления |
| --- | --- |
| Membership, portfolio, изменяемый хвост операций и события | Часовой обход текущего подключения |
| Котировки и изменяемый хвост дневных свечей | Установленная политика источника; не ordinary personal GET |
| Metadata, поиск каталога и company | Онлайн при чтении |
| Полные прошлые интервалы операций и завершённые свечи | Не обновляются часовым обходом или обычным GET |
Два исключения разрешают только первое получение отсутствующего результата:
первое открытие неподтверждённого исторического интервала операций получает
только этот интервал и возвращает локальные строки с неполным покрытием; первое
открытие диапазона свечей без подтверждённого локального результата получает
только этот диапазон. Ни одно исключение не обновляет membership, portfolio,
события, другой интервал или диапазон. Их HTTP retry также только перечитывает
локальное состояние. Подтверждённый полный интервал или диапазон остаётся
локальным.
Часовой обход сохраняет успешные разделы независимо, а failed section не
заменяет прежний complete result. Отменой query lifecycle владеет TanStack
Query. Открытый экран перечитывает ресурс не чаще одного раза в 30 минут;
это локальный HTTP read. Совместимый параметр `sync=observe`, пока он есть в
маршруте, также является только чтением и не представляет команду обходу.
[HTTP API](../http-api.md) описывает исполняемый контракт envelope.
## Смена подключения
Каждое чтение проверяет локальную сессию, текущее подключение, известный отказ
токена и сохранённый состав доступных счетов. Расшифровка token и GetAccounts
для локальной выдачи не нужны. Старый membership допускает выдачу и фоновую
сверку; это задержка обнаружения отзыва доступа, а не live-проверка брокера.
Unknown membership не даёт доступа к произвольному accountId: ответ сообщает
о загрузке доступа. Успешный новый список немедленно ограничивает последующие
чтения. Известный invalid token блокирует личные данные.
Успешный PUT атомарно сохраняет token, новую случайную внутреннюю revision
и membership из проверки token. Прежние личные datasets и work становятся
недоступны. DELETE удаляет подключение и личные данные; общие неперсональные
источники могут оставаться. Неуспешный PUT сохраняет действующую границу.
Публикация проверяет revision и attempt в той же SQLite-транзакции; поздняя
работа старого подключения не меняет даже timestamp. Revision не попадает
в API, логи или cursor. Frontend очищает personal queries при смене подключения
и известном отказе доступа; поздний ответ не восстанавливает скрытые данные.
Logout очищает сессию и query cache. Подробнее —
[интеграция T-Bank](../../integrations/tbank.md).