From e0bceea936239c08f4717e264be23d7f60552398 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Fri, 9 Oct 2026 09:05:08 +0300 Subject: [PATCH] docs: document hourly sync history --- ...y-reads-and-online-instrument-reference.md | 25 +++++++++++ adr/020-hourly-sync-verification-evidence.md | 42 +++++++++++++++++++ adr/README.md | 2 + architecture/cross-cutting/data-freshness.md | 13 +++--- domains/instruments/bonds.md | 6 +++ domains/instruments/stocks.md | 7 ++++ glossary.md | 9 ++++ 7 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 adr/019-hourly-reads-and-online-instrument-reference.md create mode 100644 adr/020-hourly-sync-verification-evidence.md diff --git a/adr/019-hourly-reads-and-online-instrument-reference.md b/adr/019-hourly-reads-and-online-instrument-reference.md new file mode 100644 index 0000000..37a0d7b --- /dev/null +++ b/adr/019-hourly-reads-and-online-instrument-reference.md @@ -0,0 +1,25 @@ +# 019. Часовой обход и онлайн-справочник инструментов + +**Status:** Accepted. Дополняет [ADR 017](017-local-tbank-reads-and-background-sync.md) +и [ADR 018](018-minimal-runtime-coordination.md). + +## Decision + +- Личные T-Bank данные обновляются владельцами источников через durable hourly + walk; обычные GET не запускают screen import. +- Quotes, candles, operations, forecasts и события сохраняют собственные + локальные состояния и время последнего успешного чтения. +- Detail, company, catalog search и ticker lookup получают ответ онлайн через + существующие integration clients. Их ошибки не заменяют сохранённые + финансовые данные или подписи snapshot. +- Старые справочные строки не являются источником актуальности и удаляются + только отдельной совместимой миграцией после проверки FK и свечей. +- Клиент повторяет открытые инвестиционные GET не чаще одного раза в 30 минут; + retry повторяет чтение и не создаёт screen sync work. + +## Consequences + +Карточки инструментов зависят от доступности публичного upstream в момент +чтения. Финансовые экраны сохраняют последний успешный snapshot, а статус +последнего hourly walk показывается отдельно. OpenAPI backend остаётся единственным +источником HTTP-контракта; frontend использует опубликованный snapshot. diff --git a/adr/020-hourly-sync-verification-evidence.md b/adr/020-hourly-sync-verification-evidence.md new file mode 100644 index 0000000..5d3fb7c --- /dev/null +++ b/adr/020-hourly-sync-verification-evidence.md @@ -0,0 +1,42 @@ +# 020. Evidence for hourly sync read boundaries + +**Status:** Accepted. Evidence for [ADR 019](019-hourly-reads-and-online-instrument-reference.md). + +## Measurements + +The backend persisted-read budget was measured with `npm run test:performance` +using a synthetic SQLite dataset: three accounts, 100,000 operations per +account, 200 instruments, and 5,000 candles per instrument. The run used Node +24.21.0 on Apple M1 Pro with 32 GiB RAM and a failing synthetic upstream after +population. It measured 100 reads per route family, excluding transport +limiter cost. + +The generated evidence is written by the test to its temporary +`persistent-budget.json` file. This is a repeatable measurement, not a +production SLA: it does not include network latency, real T-Bank quotas, or +multi-process SQLite contention. + +The successful run produced a 617,263,104-byte SQLite database and measured +zero upstream calls during the persisted-read phase. Backend p50/p95 response +times were approximately 1.3/2.3 ms for account and portfolio reads, +3.9/4.5 ms for account operations, 6.7/7.2 ms for aggregate operations, +40.0/41.5 ms for account income analytics, and 128.1/134.2 ms for aggregate +income analytics. These figures are local synthetic measurements only. + +## Durability + +The migration durability check passes against a separately built repository at +the pre-history migration prefix. It verifies preservation of users, sessions, +T-Bank connection data, bank-card data, operations, categories, archive state, +and replay behavior across migration and restart. + +The executed command was `node test/bank-cards-durability.cjs` with a separately +built pre-history repository. It completed with `PASS durability`. + +## Limits + +The configured T-Bank start limiter is `TBANK_RATE_LIMIT_PER_SECOND`, default +`5` per backend instance. The hourly scheduler therefore remains a single +durable reservation owner; the measurement does not justify increasing this +limit or changing the hourly cadence. Any production tuning requires current +T-Bank documentation and a new measurement with the deployed topology. diff --git a/adr/README.md b/adr/README.md index efe8b86..2d1e314 100644 --- a/adr/README.md +++ b/adr/README.md @@ -23,3 +23,5 @@ - [016 — Версионируемый комплект развёртывания](016-versioned-deployment-bundle.md) - [017 — Локальное чтение данных T-Bank и фоновая синхронизация](017-local-tbank-reads-and-background-sync.md) - [018 — Минимальная runtime-координация](018-minimal-runtime-coordination.md) +- [019 — Часовой обход и онлайн-справочник инструментов](019-hourly-reads-and-online-instrument-reference.md) +- [020 — Evidence for hourly sync read boundaries](020-hourly-sync-verification-evidence.md) diff --git a/architecture/cross-cutting/data-freshness.md b/architecture/cross-cutting/data-freshness.md index 27da9b0..235125f 100644 --- a/architecture/cross-cutting/data-freshness.md +++ b/architecture/cross-cutting/data-freshness.md @@ -1,8 +1,9 @@ # Свежесть данных и повторное использование WealthLedger читает инвестиционные данные из SQLite. Обычный GET возвращает -сохранённый результат и запрашивает фоновые зависимости, если они отсутствуют -или устарели. HTTP-ответ не ждёт T-Bank. Модель принята в +сохранённый результат и не запускает личную синхронизацию. Общие справочные +данные инструментов запрашиваются онлайн, когда это требуется карточке; +финансовый HTTP-ответ не ждёт T-Bank. Модель принята в [ADR 017](../../adr/017-local-tbank-reads-and-background-sync.md). ## Клиентский и серверный снимки @@ -23,7 +24,8 @@ WealthLedger читает инвестиционные данные из SQLite. | --- | --- | | Portfolio, котировки, изменяемый хвост дневных свечей | Через 60 секунд | | Membership и изменяемый хвост операций | Через 5 минут | -| Metadata, поиск каталога, company и календари | Через сутки | +| Metadata, поиск каталога и company | Онлайн при чтении | +| Календари | Через часовой обход | | Полные прошлые интервалы операций и завершённые свечи | При явном обновлении показанного периода | TTL не создаёт таймер импорта. Запрошенная работа может закончиться после @@ -31,8 +33,9 @@ TTL не создаёт таймер импорта. Запрошенная ра следующий подходящий запрос повторяет незавершённый интервал с первой страницы, переиспользуя полные интервалы. Cursor брокера не служит durable checkpoint. -Ручное «Обновить» перечитывает зависимости текущего экрана и применённый -период независимо от TTL. Повторная сверка полного периода публикуется одной +Повторное чтение перечитывает общие справочные данные онлайн, а финансовые +ресурсы используют сохранённый результат и применяемую политику свежести. +Повторная сверка полного периода публикуется одной транзакцией после всех страниц, интервалов и счетов, включая `all`. Сбой сохраняет весь прежний результат. Первая загрузка может публиковать полные малые интервалы и показывать частичный период без окончательных сумм. diff --git a/domains/instruments/bonds.md b/domains/instruments/bonds.md index 7e030ae..ef47b3e 100644 --- a/domains/instruments/bonds.md +++ b/domains/instruments/bonds.md @@ -143,3 +143,9 @@ BondBy переиспользуется зависимостями выпуск и [проверками](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/bonds/application/bond.spec.ts). Границы источников описаны в [разделе интеграций](../../integrations/README.md), сходное разделение рыночных и личных данных — в [акциях](stocks.md). + +## Online reference + +Bond detail, search, and ticker lookup are read from the upstream integration +on each request. Saved quotes, candles, events, ratings, and portfolio labels +retain their own freshness and failure boundaries. diff --git a/domains/instruments/stocks.md b/domains/instruments/stocks.md index 6fc583f..8ae1ea3 100644 --- a/domains/instruments/stocks.md +++ b/domains/instruments/stocks.md @@ -184,3 +184,10 @@ scope. Частичные строки видны с предупреждени [рыночным данным](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/stocks/application/stock-market.service.ts), [выплатам](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/stocks/application/stock-income.service.ts) и [проверкам](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/stocks/application/stock.spec.ts). Сопоставление с облигациями — на [странице облигаций](bonds.md). + +## Online reference + +Stock detail, company data, search, and ticker lookup are read from the +upstream integration on each request. Saved positions, quotes, candles, and +events remain independent local resources and are not replaced by a reference +read failure. diff --git a/glossary.md b/glossary.md index f4eb653..728f2b5 100644 --- a/glossary.md +++ b/glossary.md @@ -152,6 +152,15 @@ _Не использовать_: валютная позиция, заблоки _Не использовать_: история портфеля, snapshot для графика. +## Точка истории стоимости портфеля + +Полная оценка одного Brokerage Account в одной валюте на момент успешного +обновления Portfolio; последовательность таких точек описывает изменение +оценки во времени, включая неторговые дни. Не является Portfolio Snapshot +или инвестиционной доходностью; отсутствие цены позиции не приравнивается к нулю. + +_Не использовать_: снимок состава портфеля, доходность. + ## Client Cached Snapshot Технический термин: последний успешно полученный frontend-ответ React Query, который остаётся