7 Commits
Author SHA1 Message Date
codex-bot 0f8bbee10a Merge pull request 'docs: document hourly sync history' (#31) from release/0.1.3 into develop
Docs security / security (push) Successful in 9s
Docs verify / verify (push) Successful in 14s
Merge hourly sync history documentation
2026-10-09 09:19:44 +03:00
ksv741 e0bceea936 docs: document hourly sync history
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 13s
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (pull_request) Successful in 7s
Docs verify / verify (pull_request) Successful in 13s
2026-10-09 09:05:08 +03:00
ksv741 9a9b0409cc chore(release): 0.1.3
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (pull_request) Successful in 10s
Docs verify / verify (pull_request) Successful in 12s
Docs security / security (push) Successful in 9s
Docs verify / verify (push) Successful in 12s
2026-10-07 18:13:58 +03:00
ksv741 256d49b045 fix(deps): refresh docs security baseline
Conventional commits / commits (pull_request) Successful in 12s
Docs security / security (pull_request) Successful in 7s
Docs verify / verify (pull_request) Successful in 14s
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 16s
2026-10-07 15:36:47 +03:00
ksv741 9477e688d1 fix(deps): remove vulnerable docs tooling
Docs security / security (push) Successful in 19s
Docs verify / verify (push) Successful in 13s
Replace CLI2's unpatched braces dependency with markdownlint-cli.

Preserve link checks and CHANGELOG rules; pin patched release and parser dependencies.
2026-10-03 21:32:35 +03:00
ksv741 0ee54ca952 docs: record minimal runtime coordination
Document accepted cross-tab reauthentication, on-demand candles,
native query/logging ownership and the complete deployment path.

Preserve historical ADR context and link amendments through ADR 018.
Related backend change: WealthLedger/backend@d698ed9
2026-10-03 21:32:35 +03:00
codex-bot 6fa62fb8b5 docs: record code quality review and refactoring
Docs security / security (push) Successful in 9s
Docs verify / verify (push) Successful in 14s
2026-09-27 18:26:55 +03:00
25 changed files with 1570 additions and 565 deletions
+6
View File
@@ -0,0 +1,6 @@
{
"extends": ".markdownlint.json",
"MD024": {
"siblings_only": true
}
}
-21
View File
@@ -1,21 +0,0 @@
{
"config": {
"MD013": false
},
"customRules": [
"markdownlint-rule-relative-links"
],
"overrides": [
{
"filter": [
"CHANGELOG.md"
],
"config": {
"MD024": {
"siblings_only": true
}
},
"combine": "merge"
}
]
}
+1
View File
@@ -0,0 +1 @@
module.exports = require('markdownlint-rule-relative-links').default;
+3
View File
@@ -0,0 +1,3 @@
{
"MD013": false
}
+12
View File
@@ -1,5 +1,17 @@
# Changelog # Changelog
## [0.1.3](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.2...v0.1.3) (2026-10-07)
### Bug Fixes
* **deps:** refresh docs security baseline ([256d49b](https://git.personal.ksv741.ru/WealthLedger/docs/commit/256d49b04591d55d980a22c49b413432c9bda746))
* **deps:** remove vulnerable docs tooling ([9477e68](https://git.personal.ksv741.ru/WealthLedger/docs/commit/9477e688d180783881abc92f8835517715880279))
### Documentation
* record code quality review and refactoring ([6fa62fb](https://git.personal.ksv741.ru/WealthLedger/docs/commit/6fa62fb8b51aba82766fb50b3e5871572af8be27))
* record minimal runtime coordination ([0ee54ca](https://git.personal.ksv741.ru/WealthLedger/docs/commit/0ee54ca952db6ca7264c0d7fe8cf5759b3187c5b))
## [0.1.2](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.1...v0.1.2) (2026-09-26) ## [0.1.2](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.1...v0.1.2) (2026-09-26)
### Documentation ### Documentation
+4 -3
View File
@@ -177,9 +177,10 @@ Markdown-only правки не требуют тестов приложения
`security.yml` при push, PR и ежедневно проверяет всю Git-историю через `security.yml` при push, PR и ежедневно проверяет всю Git-историю через
Gitleaks 8.30.1 с redacted-выводом и все npm dependencies через Gitleaks 8.30.1 с redacted-выводом и все npm dependencies через
`npm audit --include=dev --audit-level=low`. Override `smol-toml` исправляет `npm audit --include=dev --audit-level=low`. Overrides `smol-toml` и `js-yaml`
DoS в TOML parser markdownlint-cli2; его можно удалить, когда родительский исправляют DoS в parsers markdownlint-cli; overrides для release-it обновляют
пакет примет исправленную версию. уязвимые basic-ftp и undici. Их можно удалить, когда родительские пакеты
примут исправленные версии.
Renovate объединяет minor/patch updates; major требует согласования в Renovate объединяет minor/patch updates; major требует согласования в
Dependency Dashboard, automerge не включён. Required checks включаются Dependency Dashboard, automerge не включён. Required checks включаются
@@ -2,6 +2,9 @@
**Status:** Accepted; supersedes the refresh-token reuse rule in ADR-006. **Status:** Accepted; supersedes the refresh-token reuse rule in ADR-006.
Cookie-clearing policy уточнена в [ADR 018](018-minimal-runtime-coordination.md):
неуспешный refresh больше не удаляет cookie. CAS и отказ superseded token сохранены.
## Context ## Context
Два одновременных запроса могут предъявить один действительный refresh token. Отзыв Session для проигравшего запроса делает недействительной сессию успешного запроса, а сохранение отдельной истории token или grace-window для различения replay добавляет непропорциональное состояние локальному MVP. Два одновременных запроса могут предъявить один действительный refresh token. Отзыв Session для проигравшего запроса делает недействительной сессию успешного запроса, а сохранение отдельной истории token или grace-window для различения replay добавляет непропорциональное состояние локальному MVP.
@@ -2,6 +2,10 @@
**Status:** Accepted — архитектурное направление согласовано. **Status:** Accepted — архитектурное направление согласовано.
Prefetch policy ниже заменена [ADR 018](018-minimal-runtime-coordination.md):
свечи загружаются по запрошенному диапазону, без предварительной загрузки
всей истории бумаг портфеля. Остальные гарантии локального хранения сохранены.
Реализация `persist-tbank-data` добавлена в рабочие ветки приложения; Реализация `persist-tbank-data` добавлена в рабочие ветки приложения;
performance/browser и canonical application gates пройдены. Это не отметка performance/browser и canonical application gates пройдены. Это не отметка
развёртывания в production. Ниже сохранён контекст развёртывания в production. Ниже сохранён контекст
+45
View File
@@ -0,0 +1,45 @@
# 018. Минимальная runtime-координация
**Status:** Accepted. Уточняет cookie policy ADR 009 и prefetch policy ADR 017.
## Context
Изоляция владельцев данных, атомарные финансовые изменения и локальное чтение
не требуют отдельного протокола согласования каждого HTTP-ответа. Дополнительная
координация оправдана только наблюдаемым поведением, которое иначе нарушается.
## Decision
- Refresh сохраняет атомарную ротацию. Неуспешный refresh не меняет cookie:
поздний отказ не должен удалять cookie успешного запроса. Logout очищает cookie.
- Frontend объединяет refresh и упорядочивает cookie-writing requests только
внутри вкладки. Cross-tab auth synchronization не является требованием;
после изменения сессии в другой вкладке допускаются reload или re-login.
- Отменой, сбросом и публикацией query results владеет TanStack Query.
Смена session/connection очищает соответствующий cache; отдельные registries
HTTP-запросов, access epochs и URL-wide latest-read counters не используются.
Локальная auth boundary предотвращает применение старого auth result и
повтор mutation под другой identity.
- Status GET читает только состояние работы. Открытый экран перечитывает
resources через `sync=observe` во время работы и после завершения.
Сверка hashes между status и data GET, публичные progress counters и
невыдаваемые sync states не нужны. Полнота истории остаётся в resource metadata.
- Свечи загружаются для запрошенного диапазона. Предзагрузки всей истории
портфеля и автоматического расширения короткого периода до `all` нет.
- Backend формирует согласованные entries и aggregates из одних исходных
данных; frontend доверяет этому contract и не выполняет вторую сверку групп.
- Request context и HTTP completion принадлежат `nestjs-pino`/`pino-http`.
Проект сохраняет safe field filtering, redaction и route-template logging.
- Deployment всегда выполняет один stop → backup → migration → readiness
цикл. No-op и frontend-only оптимизации не обещаются; короткий простой принят.
## Consequences
Первое открытие нового диапазона свечей может ждать загрузку. Наблюдение активной
работы может перечитать неизменившиеся локальные данные, зато не требует
checksum protocol. Повтор deployment создаёт новый backup и может остановить API.
DB ownership подключения, conditional publication, coverage, staging,
банковские intent fingerprints и версии записей сохраняются. Отмена HTTP
не считается отменой уже выполняющейся server-side transaction.
Сохранённый полный forecast не заменяется candidate с изменившимися dependencies.
@@ -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.
@@ -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.
+3
View File
@@ -22,3 +22,6 @@
- [015 — SQLite в ограниченном single-server deployment](015-single-server-sqlite-deployment.md) - [015 — SQLite в ограниченном single-server deployment](015-single-server-sqlite-deployment.md)
- [016 — Версионируемый комплект развёртывания](016-versioned-deployment-bundle.md) - [016 — Версионируемый комплект развёртывания](016-versioned-deployment-bundle.md)
- [017 — Локальное чтение данных T-Bank и фоновая синхронизация](017-local-tbank-reads-and-background-sync.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)
+3 -3
View File
@@ -195,9 +195,9 @@ access token и вращаемый refresh token. [Политика query-кэш
Авторизация доступа, недопущение token в публичный ответ и атомарность Авторизация доступа, недопущение token в публичный ответ и атомарность
ротации сессии — отдельные свойства; наличие типизированного клиента ротации сессии — отдельные свойства; наличие типизированного клиента
не доказывает их. Известные расхождения регистрации и деталей валидации не доказывает их. Известное расхождение регистрации отмечено в
отмечены в [аутентификации](../domains/authentication/overview.md#регистрация-и-вход) [аутентификации](../domains/authentication/overview.md#регистрация-и-вход),
и [HTTP API](http-api.md#error-contract). а действующий формат ошибок описан в [HTTP API](http-api.md#error-contract).
Поддерживается локальный Compose и ограниченная single-server topology с SQLite. Поддерживается локальный Compose и ограниченная single-server topology с SQLite.
Origin браузера, адрес API и cookie policy должны быть согласованы. Origin браузера, адрес API и cookie policy должны быть согласованы.
+12 -5
View File
@@ -1,8 +1,9 @@
# Свежесть данных и повторное использование # Свежесть данных и повторное использование
WealthLedger читает инвестиционные данные из SQLite. Обычный GET возвращает WealthLedger читает инвестиционные данные из SQLite. Обычный GET возвращает
сохранённый результат и запрашивает фоновые зависимости, если они отсутствуют сохранённый результат и не запускает личную синхронизацию. Общие справочные
или устарели. HTTP-ответ не ждёт T-Bank. Модель принята в данные инструментов запрашиваются онлайн, когда это требуется карточке;
финансовый HTTP-ответ не ждёт T-Bank. Модель принята в
[ADR 017](../../adr/017-local-tbank-reads-and-background-sync.md). [ADR 017](../../adr/017-local-tbank-reads-and-background-sync.md).
## Клиентский и серверный снимки ## Клиентский и серверный снимки
@@ -23,7 +24,8 @@ WealthLedger читает инвестиционные данные из SQLite.
| --- | --- | | --- | --- |
| Portfolio, котировки, изменяемый хвост дневных свечей | Через 60 секунд | | Portfolio, котировки, изменяемый хвост дневных свечей | Через 60 секунд |
| Membership и изменяемый хвост операций | Через 5 минут | | Membership и изменяемый хвост операций | Через 5 минут |
| Metadata, поиск каталога, company и календари | Через сутки | | Metadata, поиск каталога и company | Онлайн при чтении |
| Календари | Через часовой обход |
| Полные прошлые интервалы операций и завершённые свечи | При явном обновлении показанного периода | | Полные прошлые интервалы операций и завершённые свечи | При явном обновлении показанного периода |
TTL не создаёт таймер импорта. Запрошенная работа может закончиться после TTL не создаёт таймер импорта. Запрошенная работа может закончиться после
@@ -31,8 +33,9 @@ TTL не создаёт таймер импорта. Запрошенная ра
следующий подходящий запрос повторяет незавершённый интервал с первой страницы, следующий подходящий запрос повторяет незавершённый интервал с первой страницы,
переиспользуя полные интервалы. Cursor брокера не служит durable checkpoint. переиспользуя полные интервалы. Cursor брокера не служит durable checkpoint.
Ручное «Обновить» перечитывает зависимости текущего экрана и применённый Повторное чтение перечитывает общие справочные данные онлайн, а финансовые
период независимо от TTL. Повторная сверка полного периода публикуется одной ресурсы используют сохранённый результат и применяемую политику свежести.
Повторная сверка полного периода публикуется одной
транзакцией после всех страниц, интервалов и счетов, включая `all`. транзакцией после всех страниц, интервалов и счетов, включая `all`.
Сбой сохраняет весь прежний результат. Первая загрузка может публиковать Сбой сохраняет весь прежний результат. Первая загрузка может публиковать
полные малые интервалы и показывать частичный период без окончательных сумм. полные малые интервалы и показывать частичный период без окончательных сумм.
@@ -43,6 +46,10 @@ Status GET и data GET с `sync=observe` не запускают работу.
наблюдение прекращается. Поздний ответ не заменяет уже принятый новый. наблюдение прекращается. Поздний ответ не заменяет уже принятый новый.
[HTTP API](../http-api.md) объясняет envelope и экранный refresh. [HTTP API](../http-api.md) объясняет envelope и экранный refresh.
Отменой query lifecycle владеет TanStack Query. Status не пересобирает
финансовые ответы и не передаёт hash notifications. Свечи нового диапазона
загружаются при его открытии; предзагрузка всей истории портфеля не выполняется.
## Смена подключения ## Смена подключения
Каждое чтение проверяет локальную сессию, текущее подключение, известный отказ Каждое чтение проверяет локальную сессию, текущее подключение, известный отказ
+6 -11
View File
@@ -142,20 +142,15 @@ backups находятся рядом с data directory, вне checkout, и а
не удаляются. Незавершённая копия помечается `.partial-` и не подходит для restore. не удаляются. Незавершённая копия помечается `.partial-` и не подходит для restore.
Ключ шифрования хранится отдельно. Локальная копия не защищает от потери диска. Ключ шифрования хранится отдельно. Локальная копия не защищает от потери диска.
## Независимое обновление frontend ## Единый цикл обновления
Если изменились только image или конфигурация frontend, backend не Каждое обновление, включая повтор того же тега и изменение только frontend,
пересоздаётся, backup и migration не выполняются. Возможен короткий перерыв выполняет stop → backup → migration → readiness. Сравнение hashes контейнеров
на внешней точке входа; старым browser tabs может потребоваться reload. и конфигурации не выполняется. Приняты короткий простой API и дополнительный
При неизменных исправных контейнерах повтор команды не пересоздаёт сервисы. backup; во время простоя возможен 502, вкладкам может потребоваться reload.
## Независимое обновление backend
Изменение image или конфигурации backend запускает stop → backup → migration →
readiness. Неизменный frontend не пересоздаётся. Во время простоя возможен 502.
Ошибка migration блокирует старт, ошибка готовности останавливает новый backend; Ошибка migration блокирует старт, ошибка готовности останавливает новый backend;
ошибка frontend не останавливает исправный backend. Успех фиксируется только ошибка frontend не останавливает исправный backend. Успех фиксируется только
после проверок запуска затронутых компонентов. после проверок запуска обоих компонентов.
Одна file lock защищает установку от параллельных команд. Маркер незавершённого Одна file lock защищает установку от параллельных команд. Маркер незавершённого
обновления блокирует повтор до разбора оператором. Он содержит этап, версии обновления блокирует повтор до разбора оператором. Он содержит этап, версии
+12 -12
View File
@@ -26,8 +26,8 @@ T-Bank data GET возвращают envelope `{ data, meta }`. `data` може
при missing или неполном финансовом агрегате; partial ledger/candles могут при missing или неполном финансовом агрегате; partial ledger/candles могут
содержать подтверждённые строки. `meta` разделяет availability, freshness, содержать подтверждённые строки. `meta` разделяет availability, freshness,
lastSuccessfulAt, sync, coverage и состояния зависимостей. `dataRevision` lastSuccessfulAt, sync, coverage и состояния зависимостей. `dataRevision`
описывает набор данных, `stateVersion` — наблюдаемое состояние, включая описывает набор данных; пустое завершённое покрытие явно представлено в coverage.
пустое завершённое покрытие. Ни одно поле не раскрывает connection revision. Публичной hash-версии состояния нет. Ни одно поле не раскрывает connection revision.
Обычный GET планирует missing/stale зависимости после проверки доступа. Обычный GET планирует missing/stale зависимости после проверки доступа.
GET с `sync=observe` только читает. `POST /api/v1/tbank-sync` принимает GET с `sync=observe` только читает. `POST /api/v1/tbank-sync` принимает
@@ -35,6 +35,11 @@ GET с `sync=observe` только читает. `POST /api/v1/tbank-sync` пр
scope. `GET /api/v1/tbank-sync/:id` наблюдает разрешённую работу; чужой или scope. `GET /api/v1/tbank-sync/:id` наблюдает разрешённую работу; чужой или
прежний handle возвращает `404`. Приём работы не означает её успех. прежний handle возвращает `404`. Приём работы не означает её успех.
Status возвращает state/errorCode без данных ресурсов и численных progress
counters. Клиент перечитывает показанные resources через `sync=observe` во время
работы и после завершения, сохраняя generated query identity. Sync states ресурса:
`idle`, `running`, `failed`; отдельного публичного `queued` нет.
Source failure принятой работы передаётся безопасным `meta.sync.errorCode`; Source failure принятой работы передаётся безопасным `meta.sync.errorCode`;
HTTP transport/access/input errors сохраняют Problem Details. Старые данные HTTP transport/access/input errors сохраняют Problem Details. Старые данные
при transient failure сохраняют исходное успешное время. Детали поведения — при transient failure сохраняют исходное успешное время. Детали поведения —
@@ -65,16 +70,11 @@ message/stack. Типичный ответ:
Для input validation контракт требует `400`, `VALIDATION_ERROR` и `errors` как Для input validation контракт требует `400`, `VALIDATION_ERROR` и `errors` как
массив `{ pointer, detail }`, где pointer адресует поле запроса. Это требование массив `{ pointer, detail }`, где pointer адресует поле запроса. Это требование
не считается проверенным одним описанием OpenAPI: нужна проверка реального проверяется реальным HTTP-ответом после всех стадий обработки запроса. Глобальная
HTTP-ответа после всех стадий обработки запроса. валидация передаёт фильтру структурированные ошибки без исходных значений и DTO,
а фильтр формирует JSON Pointer, включая вложенные поля. HTTP suites подтверждают
**Известное расхождение:** согласованная детали ошибок регистрации, банковской карты и синхронизации; OpenAPI отдельно
[спецификация аутентификации](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/user-authentication/spec.md#requirement-стандартные-ответы-об-ошибках) фиксирует форму ответа.
требует `pointer` и `detail` для невалидных полей. В текущей конфигурации
валидация формирует строковые сообщения, а фильтр ожидает структурированные
ошибки полей; поэтому корректность деталей `errors` не подтверждена.
Исправление требует отдельного изменения реализации и проверки полного
HTTP-потока. OpenAPI сам по себе этого расхождения не устраняет.
Ответ не включает автоматически все поля RFC (`type`, `title`, `instance`). Ответ не включает автоматически все поля RFC (`type`, `title`, `instance`).
Добавление обязательного поля является изменением публичного контракта. Добавление обязательного поля является изменением публичного контракта.
File diff suppressed because it is too large Load Diff
+6 -5
View File
@@ -55,15 +55,16 @@ sequenceDiagram
B-->>F: Access token, профиль, новая refresh-cookie B-->>F: Access token, профиль, новая refresh-cookie
F->>B: Protected request с Bearer F->>B: Protected request с Bearer
else Cookie нет или refresh отклонён else Cookie нет или refresh отклонён
B-->>F: 401 и очистка cookie B-->>F: 401 без изменения cookie
Note over F: Готовое неавторизованное состояние Note over F: Готовое неавторизованное состояние
end end
``` ```
В одном экземпляре frontend одновременные refresh используют один В одной вкладке одновременные refresh используют один незавершённый запрос;
незавершённый запрос. Между вкладками используется Web Locks, если браузер cookie-writing requests упорядочены локально. Межвкладочная синхронизация
его поддерживает. Backend всё равно защищает ротацию атомарно: координация не поддерживается: после смены сессии в другой вкладке допустимы reload/re-login.
браузеров не заменяет серверную проверку. Backend защищает ротацию атомарно. Неуспешный refresh не удаляет cookie
победившего запроса; недействительный token по-прежнему не восстанавливает сессию.
Обычный защищённый запрос с `401 UNAUTHORIZED` проходит refresh и один повтор Обычный защищённый запрос с `401 UNAUTHORIZED` проходит refresh и один повтор
через общий транспорт; auth endpoints из этого цикла исключены. Само через общий транспорт; auth endpoints из этого цикла исключены. Само
+5 -7
View File
@@ -91,13 +91,11 @@ Selected, previous и yearAgo имеют независимую готовнос
серверным правилом; клиент воспринимает ключ как непрозрачную строку. серверным правилом; клиент воспринимает ключ как непрозрачную строку.
Это поле принадлежит ответу аналитики; общий журнал операций его не требует. Это поле принадлежит ответу аналитики; общий журнал операций его не требует.
Frontend проверяет принадлежность выплат по полученному ключу до подготовки Backend обеспечивает принадлежность выплат, валюту и receipt count при
плоского списка выплат. Отсутствующий, пустой или построении entries и instrument groups из одного набора данных. Frontend
нестроковый ключ, неоднозначные ключи инструментов, неизвестная группа, другая доверяет типизированному contract, не восстанавливает формулу идентификации
валюта или несовпадение числа выплат приводят к существующему локальному и не выполняет второй consistency validator. Полностью пустой ответ допустим.
состоянию ошибки аналитики с повторной попыткой. Частичный список выплат не показывается как Состав и исходный серверный порядок записей и знак сумм
полный; формула идентификации в клиенте не восстанавливается. Полностью пустой
ответ допустим. Состав и исходный серверный порядок записей и знак сумм
сохраняются, frontend не пересчитывает денежные итоги. Стабильный ID в пределах подключения и счёта определяет одну операцию: сохраняются, frontend не пересчитывает денежные итоги. Стабильный ID в пределах подключения и счёта определяет одну операцию:
повторная сверка обновляет её без двойного учёта. Одинаковые ID разных счетов повторная сверка обновляет её без двойного учёта. Одинаковые ID разных счетов
остаются разными выплатами. Изменение источника логотипа позволяет заново остаются разными выплатами. Изменение источника логотипа позволяет заново
+6
View File
@@ -143,3 +143,9 @@ BondBy переиспользуется зависимостями выпуск
и [проверками](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/bonds/application/bond.spec.ts). и [проверками](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/bonds/application/bond.spec.ts).
Границы источников описаны в [разделе интеграций](../../integrations/README.md), Границы источников описаны в [разделе интеграций](../../integrations/README.md),
сходное разделение рыночных и личных данных — в [акциях](stocks.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.
+7
View File
@@ -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-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). [выплатам](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). Сопоставление с облигациями — на [странице облигаций](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.
+9
View File
@@ -152,6 +152,15 @@ _Не использовать_: валютная позиция, заблоки
_Не использовать_: история портфеля, snapshot для графика. _Не использовать_: история портфеля, snapshot для графика.
## Точка истории стоимости портфеля
Полная оценка одного Brokerage Account в одной валюте на момент успешного
обновления Portfolio; последовательность таких точек описывает изменение
оценки во времени, включая неторговые дни. Не является Portfolio Snapshot
или инвестиционной доходностью; отсутствие цены позиции не приравнивается к нулю.
_Не использовать_: снимок состава портфеля, доходность.
## Client Cached Snapshot ## Client Cached Snapshot
Технический термин: последний успешно полученный frontend-ответ React Query, который остаётся Технический термин: последний успешно полученный frontend-ответ React Query, который остаётся
+4 -7
View File
@@ -130,15 +130,12 @@ Backend хранит token в шифротексте AES-256-GCM с новым n
[validateEnv](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/config/env.validation.ts) (справочный источник). [validateEnv](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/config/env.validation.ts) (справочный источник).
Общий FIFO-лимитер ограничивает поток RPC и не допускает более 50 Общий FIFO-лимитер ограничивает поток RPC и не допускает более 50
ожидающих. Для `UNAVAILABLE`, `DEADLINE_EXCEEDED` и `RESOURCE_EXHAUSTED` ожидающих. Для `UNAVAILABLE`, `DEADLINE_EXCEEDED` и `RESOURCE_EXHAUSTED`
обычный RPC допускает один повтор через секунду. Deadline каждой попытки — 15 секунд, каждый RPC допускает один повтор через секунду. Deadline каждой попытки — 15 секунд,
а ожидание места в лимитере не является временем этой сетевой попытки. а ожидание места в лимитере не является временем этой сетевой попытки.
Для поиска метаданных `GetInstrumentBy` разрешены две повторные попытки Метаданные используют ту же retry policy. Переполненная очередь завершается
с паузами 2 и 4 секунды после неудачных попыток. Они применяются к тем же ошибкой сразу, без повторов admission. Постоянные ошибки и отказ авторизации
временным кодам и к переполнению локальной очереди; перед каждой попыткой
проверяется её вместимость. Постоянные ошибки и отказ авторизации
не повторяются. Подтверждённый `NOT_FOUND` при поиске метаданных означает не повторяются. Подтверждённый `NOT_FOUND` при поиске метаданных означает
отсутствие инструмента, а не временный сбой. Остальные RPC при полной отсутствие инструмента, а не временный сбой.
очереди завершаются сразу.
Параметры попыток принадлежат Параметры попыток принадлежат
[T-Bank client](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/integrations/tbank/tbank.client.ts) (справочный источник); [T-Bank client](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/integrations/tbank/tbank.client.ts) (справочный источник);
решение об ограниченных повторах — [ADR 005](../adr/005-tbank-upstream-resilience.md). решение об ограниченных повторах — [ADR 005](../adr/005-tbank-upstream-resilience.md).
+339 -485
View File
File diff suppressed because it is too large Load Diff
+12 -6
View File
@@ -1,12 +1,12 @@
{ {
"name": "wealth-ledger-docs", "name": "wealth-ledger-docs",
"version": "0.1.2", "version": "0.1.3",
"private": true, "private": true,
"engines": { "engines": {
"node": "24.21.0" "node": "24.21.0"
}, },
"scripts": { "scripts": {
"lint": "markdownlint-cli2 \"**/*.md\" \"#node_modules\"", "lint": "markdownlint --dot --rules .markdownlint-rule-relative-links.cjs --ignore node_modules --ignore CHANGELOG.md -- \"**/*.md\" && markdownlint --config .markdownlint-changelog.json --rules .markdownlint-rule-relative-links.cjs -- CHANGELOG.md",
"verify": "npm run lint && git diff --check", "verify": "npm run lint && git diff --check",
"release:preview": "release-it --dry-run --ci", "release:preview": "release-it --dry-run --ci",
"release:prepare": "release-it --ci", "release:prepare": "release-it --ci",
@@ -17,13 +17,19 @@
"@commitlint/config-conventional": "21.2.2", "@commitlint/config-conventional": "21.2.2",
"@release-it/conventional-changelog": "12.0.0", "@release-it/conventional-changelog": "12.0.0",
"conventional-changelog-conventionalcommits": "10.4.0", "conventional-changelog-conventionalcommits": "10.4.0",
"markdownlint-cli2": "0.23.2", "markdownlint-cli": "0.49.1",
"markdownlint-rule-relative-links": "5.1.2", "markdownlint-rule-relative-links": "5.1.3",
"release-it": "21.0.2" "release-it": "21.0.2"
}, },
"overrides": { "overrides": {
"markdownlint-cli2@0.23.2": { "katex": "0.19.0",
"smol-toml": "1.8.0" "markdownlint-cli@0.49.1": {
"js-yaml": "5.4.2",
"smol-toml": "1.9.0"
},
"release-it": {
"basic-ftp": "6.2.1",
"undici": "7.29.1"
} }
} }
} }