chore(release): 0.1.4 #38
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: Неверное поведение
|
||||||
|
---
|
||||||
|
# Bug Report
|
||||||
|
|
||||||
|
## Проблема и шаги воспроизведения
|
||||||
|
|
||||||
|
## Факт / ожидание
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Окружение / ссылки (если применимо)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
name: Engineering Task
|
||||||
|
about: CI, тесты, документация, процесс и прочее
|
||||||
|
---
|
||||||
|
# Engineering Task
|
||||||
|
|
||||||
|
## Контекст и результат
|
||||||
|
|
||||||
|
## Scope / связанные Issues (если есть)
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Feature Request
|
||||||
|
about: Новое наблюдаемое поведение
|
||||||
|
---
|
||||||
|
# Feature Request
|
||||||
|
|
||||||
|
## Зачем и какой результат
|
||||||
|
|
||||||
|
## Ожидаемое поведение
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Зависимости / связанные Issues (если есть)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
name: Refactoring / Technical Debt
|
||||||
|
about: Улучшение без нового поведения
|
||||||
|
---
|
||||||
|
# Refactoring / Technical Debt
|
||||||
|
|
||||||
|
## Проблема и результат
|
||||||
|
|
||||||
|
## Сохраняемые инварианты / границы
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Зависимости / ссылки (если есть)
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Pull Request
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Краткий результат работы описывается здесь.
|
||||||
|
|
||||||
|
## Linked Issue
|
||||||
|
|
||||||
|
Refs `<owner/repo#number>` (заменить ссылкой на реальную Issue).
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
Затронутые части и изменения.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- Команда / результат / ограничения:
|
||||||
|
|
||||||
|
## Breaking Changes (если есть)
|
||||||
@@ -2,7 +2,11 @@ name: Conventional commits
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, synchronize, reopened, edited]
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: docs-commits-${{ gitea.event.pull_request.number }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
commits:
|
commits:
|
||||||
@@ -23,4 +27,8 @@ jobs:
|
|||||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||||
run: |
|
run: |
|
||||||
printf '%s\n' "$PR_TITLE" | npm run commitlint -- --strict
|
printf '%s\n' "$PR_TITLE" | npm run commitlint -- --strict
|
||||||
npm run commitlint -- --strict --from "$BASE_SHA" --to "$HEAD_SHA"
|
if [[ "$PR_TITLE" =~ ^chore\(release\):\ [0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
npm run commitlint -- --strict --from "$HEAD_SHA^" --to "$HEAD_SHA"
|
||||||
|
else
|
||||||
|
npm run commitlint -- --strict --from "$BASE_SHA" --to "$HEAD_SHA"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ name: Docs security
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches: [develop, main]
|
||||||
- '**'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '17 5 * * *'
|
- cron: '17 5 * * *'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: docs-security-${{ gitea.event_name }}-${{ gitea.event.pull_request.number || gitea.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
security:
|
security:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -2,8 +2,13 @@ name: Docs verify
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ['**']
|
branches: [develop, main]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: docs-verify-${{ gitea.event_name }}-${{ gitea.event.pull_request.number || gitea.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
verify:
|
verify:
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
Перед изменением прочитай [README](README.md) и [CONTRIBUTING](CONTRIBUTING.md),
|
Перед изменением прочитай [README](README.md) и [CONTRIBUTING](CONTRIBUTING.md),
|
||||||
затем только затронутую тему. Docs объясняет систему; требования принадлежат
|
затем только затронутую тему. Docs объясняет систему; требования принадлежат
|
||||||
основным спецификациям, реализация и coding conventions — соседним репозиториям.
|
основным спецификациям, реализация и coding conventions — соседним репозиториям.
|
||||||
|
До edits найди/создай подходящую Gitea Issue, проверь AC и ветку; чтение
|
||||||
|
допускается без Issue. Общий маршрут — [Engineering Workflow](https://git.personal.ksv741.ru/WealthLedger/main/src/commit/03b3b59e6ff2ba391f9dfc42a039a96d0d84c1c9/.ai/conventions/engineering-workflow.md)
|
||||||
|
(main#28; после merge — актуальная версия `develop`).
|
||||||
|
|
||||||
Проверь существенные факты по локальным тематическим страницам и ADR;
|
Проверь существенные факты по локальным тематическим страницам и ADR;
|
||||||
внешние источники используй как справочные свидетельства, когда они доступны.
|
внешние источники используй как справочные свидетельства, когда они доступны.
|
||||||
@@ -20,7 +23,8 @@
|
|||||||
|
|
||||||
## Ветки и релизы
|
## Ветки и релизы
|
||||||
|
|
||||||
Работа — в отдельной ветке от `develop`, затем PR в `develop`; в `main` напрямую
|
Работа — в issue-linked ветке от `develop`, затем PR в `develop`; в `main` напрямую
|
||||||
не пушить. Release/hotfix и синхронизация веток — по [README](README.md#релизы).
|
не пушить. Release/hotfix и синхронизация веток — по [README](README.md#релизы).
|
||||||
Commits и заголовки PR — Conventional Commits; для спецификаций допустим `spec:`.
|
Commits и заголовки PR — Conventional Commits со ссылкой на Issue (кроме release);
|
||||||
|
для спецификаций допустим `spec:`.
|
||||||
Перед подготовкой релиза прочитай местный README; версии вручную не повышать.
|
Перед подготовкой релиза прочитай местный README; версии вручную не повышать.
|
||||||
|
|||||||
@@ -1,5 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.1.4](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.3...v0.1.4) (2026-10-12)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* align docs commitlint workflow (WealthLedger/main[#27](https://git.personal.ksv741.ru/WealthLedger/docs/issues/27)) ([602eb43](https://git.personal.ksv741.ru/WealthLedger/docs/commit/602eb43294509274cbd9003be31f726b6e275a1e))
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
* clarify card summary totals ([df6f010](https://git.personal.ksv741.ru/WealthLedger/docs/commit/df6f0109ed696a529cf2622e23fceeab8133f932))
|
||||||
|
* document hourly attempt lifecycle semantics (WealthLedger/backend[#56](https://git.personal.ksv741.ru/WealthLedger/docs/issues/56)) ([1378ac9](https://git.personal.ksv741.ru/WealthLedger/docs/commit/1378ac9fe2fcfd43bd71421e62b02f00069be928))
|
||||||
|
* document hourly investment reads ([f0cab44](https://git.personal.ksv741.ru/WealthLedger/docs/commit/f0cab445d7e7076bf92a61f1023b8bf51e094d33))
|
||||||
|
* document hourly sync history ([e0bceea](https://git.personal.ksv741.ru/WealthLedger/docs/commit/e0bceea936239c08f4717e264be23d7f60552398))
|
||||||
|
* document stock screener ([2c34023](https://git.personal.ksv741.ru/WealthLedger/docs/commit/2c34023af8593f305f7c81e672b4e179c0992cf3))
|
||||||
|
* pin docs workflow reference (WealthLedger/main[#27](https://git.personal.ksv741.ru/WealthLedger/docs/issues/27)) ([c24e4b9](https://git.personal.ksv741.ru/WealthLedger/docs/commit/c24e4b990aaeffd02e05f7de21942579e452cecf))
|
||||||
|
|
||||||
|
### CI
|
||||||
|
|
||||||
|
* avoid duplicate PR checks ([4caa5e9](https://git.personal.ksv741.ru/WealthLedger/docs/commit/4caa5e92b7d2597e5c7725b2036007b71ece2abd))
|
||||||
|
* skip checks on PR metadata edits ([e6fd4f6](https://git.personal.ksv741.ru/WealthLedger/docs/commit/e6fd4f64b81dd73b33959b845a1babcfac1891c8))
|
||||||
|
|
||||||
|
### Maintenance
|
||||||
|
|
||||||
|
* align docs engineering workflow (WealthLedger/main[#27](https://git.personal.ksv741.ru/WealthLedger/docs/issues/27)) ([eaf7ede](https://git.personal.ksv741.ru/WealthLedger/docs/commit/eaf7ede8414f0df972f9ae7ab9e223a6350b5462))
|
||||||
|
|
||||||
## [0.1.3](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.2...v0.1.3) (2026-10-07)
|
## [0.1.3](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.2...v0.1.3) (2026-10-07)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ WealthLedger помогает частному инвестору понимат
|
|||||||
| [Операции](domains/operations/overview.md) | Исполненные операции, фильтры и пагинация |
|
| [Операции](domains/operations/overview.md) | Исполненные операции, фильтры и пагинация |
|
||||||
| [Доход](domains/income/overview.md) | Полученные купоны и дивиденды, периоды и состав расчёта |
|
| [Доход](domains/income/overview.md) | Полученные купоны и дивиденды, периоды и состав расчёта |
|
||||||
| [Будущие выплаты](domains/income/upcoming-events.md) | Календарь по текущим позициям и ограничения прогноза |
|
| [Будущие выплаты](domains/income/upcoming-events.md) | Календарь по текущим позициям и ограничения прогноза |
|
||||||
| [Акции](domains/instruments/stocks.md) и [облигации](domains/instruments/bonds.md) | Поиск выпуска, рыночные показатели и личная история |
|
| [Скринер акций](domains/instruments/stocks.md) и [облигации](domains/instruments/bonds.md) | Подбор акций по параметрам, поиск выпуска, рыночные показатели и личная история |
|
||||||
|
|
||||||
## Найти материал по задаче
|
## Найти материал по задаче
|
||||||
|
|
||||||
@@ -72,9 +72,11 @@ WealthLedger помогает частному инвестору понимат
|
|||||||
## Релизы
|
## Релизы
|
||||||
|
|
||||||
Репозиторий выпускается независимо. `develop` — интеграция, `main` — принятые
|
Репозиторий выпускается независимо. `develop` — интеграция, `main` — принятые
|
||||||
релизы. Работа: `codex/<task>` от актуального `develop`, PR в `develop`.
|
релизы. Обычная работа: issue-linked ветка от актуального `develop`, PR в `develop`;
|
||||||
|
общие правила — в Engineering Workflow по ссылке из AGENTS.
|
||||||
Обычные PR допускают squash; release и обратная синхронизация сохраняют историю.
|
Обычные PR допускают squash; release и обратная синхронизация сохраняют историю.
|
||||||
Commits и PR titles — Conventional Commits, включая `spec:`. Версии вручную не повышай.
|
Commits и PR titles — Conventional Commits со ссылкой на Issue (кроме release),
|
||||||
|
включая `spec:`. Версии вручную не повышай.
|
||||||
|
|
||||||
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Убедись, что
|
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Убедись, что
|
||||||
`develop` содержит последний релиз. Создай `release/<name>` от проверенного
|
`develop` содержит последний релиз. Создай `release/<name>` от проверенного
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# 017. Локальное чтение данных T-Bank и фоновая синхронизация
|
# 017. Локальное чтение данных T-Bank и фоновая синхронизация
|
||||||
|
|
||||||
**Status:** Accepted — архитектурное направление согласовано.
|
**Status:** Accepted — историческое архитектурное направление. Решения ниже о
|
||||||
|
request-driven запуске, ручном обновлении и отсутствии периодического обхода
|
||||||
|
заменены [ADR 019](019-hourly-reads-and-online-instrument-reference.md).
|
||||||
|
|
||||||
Prefetch policy ниже заменена [ADR 018](018-minimal-runtime-coordination.md):
|
Prefetch policy ниже заменена [ADR 018](018-minimal-runtime-coordination.md):
|
||||||
свечи загружаются по запрошенному диапазону, без предварительной загрузки
|
свечи загружаются по запрошенному диапазону, без предварительной загрузки
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# 019. Часовой обход и онлайн-справочник инструментов
|
||||||
|
|
||||||
|
**Status:** Accepted. Заменяет request-driven, manual-refresh и
|
||||||
|
no-periodic-walk части [ADR 017](017-local-tbank-reads-and-background-sync.md)
|
||||||
|
и дополняет [ADR 018](018-minimal-runtime-coordination.md).
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
- Личные T-Bank данные текущего подключения обновляются владельцами источников
|
||||||
|
через durable hourly walk; его результат ограничен этой connection boundary.
|
||||||
|
Обычный GET и retry читают только сохранённый результат и не запускают
|
||||||
|
personal work.
|
||||||
|
- Только первое открытие неподтверждённого исторического интервала operations
|
||||||
|
и первого неоткрытого диапазона candles может получить соответственно этот
|
||||||
|
интервал или диапазон. Это не manual sync; повторное чтение не расширяет и не
|
||||||
|
запускает такую работу заново.
|
||||||
|
- Portfolio, operations, forecasts и события сохраняют собственные complete
|
||||||
|
результаты и время последнего успешного чтения. Результат ресурса
|
||||||
|
(freshness, completeness, `lastSuccessfulAt`, availability) независим от
|
||||||
|
resource-relevant последней часовой попытки: поздняя partial/failed попытка
|
||||||
|
не заменяет сохранённый complete result. При его отсутствии `data: null`.
|
||||||
|
- Detail, company, catalog search и ticker lookup получают ответ онлайн через
|
||||||
|
существующие integration clients. Их ошибки не заменяют сохранённые
|
||||||
|
финансовые данные или подписи snapshot.
|
||||||
|
- Старые справочные строки не являются источником актуальности и удаляются
|
||||||
|
только отдельной совместимой миграцией после проверки FK и свечей.
|
||||||
|
- Клиент повторяет открытые инвестиционные GET не чаще одного раза в 30 минут;
|
||||||
|
retry повторяет чтение и не создаёт screen sync work. Наблюдение последней
|
||||||
|
попытки, включая Accounts `sync`, не является командой.
|
||||||
|
|
||||||
|
## 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.
|
||||||
@@ -23,3 +23,5 @@
|
|||||||
- [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)
|
- [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)
|
||||||
|
|||||||
@@ -1,51 +1,72 @@
|
|||||||
# Свежесть данных и повторное использование
|
# Свежесть данных и повторное использование
|
||||||
|
|
||||||
WealthLedger читает инвестиционные данные из SQLite. Обычный GET возвращает
|
WealthLedger читает личные инвестиционные данные из SQLite. Обычный GET и его
|
||||||
сохранённый результат и запрашивает фоновые зависимости, если они отсутствуют
|
HTTP retry возвращают сохранённый результат и не запускают личную работу с
|
||||||
или устарели. HTTP-ответ не ждёт T-Bank. Модель принята в
|
T-Bank. Нормальным владельцем обновления служит часовой обход текущего
|
||||||
[ADR 017](../../adr/017-local-tbank-reads-and-background-sync.md).
|
подключения: после успешного подключения он начинает первую попытку, затем
|
||||||
|
начинает следующую не ранее чем через 60 минут от начала предыдущей. После
|
||||||
|
простоя выполняется не более одна актуальная попытка, а перекрывающийся срок
|
||||||
|
пропускается, не ставится в очередь. Общие справочные данные инструментов
|
||||||
|
запрашиваются онлайн, когда это требуется карточке; финансовый HTTP-ответ не
|
||||||
|
ждёт T-Bank. Модель принята в
|
||||||
|
[ADR 019](../../adr/019-hourly-reads-and-online-instrument-reference.md).
|
||||||
|
|
||||||
## Клиентский и серверный снимки
|
## Клиентский и серверный снимки
|
||||||
|
|
||||||
[Client Cached Snapshot](../../glossary.md#client-cached-snapshot) — успешный
|
[Client Cached Snapshot](../../glossary.md#client-cached-snapshot) — успешный
|
||||||
ответ в TanStack Query. Он сохраняет показанное содержимое при временной ошибке
|
ответ в TanStack Query. Он сохраняет показанное содержимое при временной ошибке
|
||||||
запроса в той же границе доступа. SQLite сохраняет источники независимо от
|
HTTP-перечитывания в той же границе доступа. Это не серверный fallback и не
|
||||||
браузера: membership, последний полный portfolio, исполненные операции,
|
состояние часового обхода. SQLite независимо от браузера хранит membership,
|
||||||
общие сведения об инструментах, котировки, свечи и календари.
|
последний полный portfolio, исполненные операции, прогнозы, общие сведения об
|
||||||
|
инструментах, котировки, свечи и календари.
|
||||||
|
|
||||||
[Полнота периода](../../glossary.md#полнота-истории-счёта) и свежесть различаются.
|
[Полнота периода](../../glossary.md#полнота-истории-счёта) и свежесть различаются.
|
||||||
Успешно проверенный пустой интервал полон; последняя страница журнала сама
|
Успешно проверенный пустой результат полон и доступен; последняя страница
|
||||||
по себе полноту не доказывает. Ошибка сверки сохраняет прежние данные и время.
|
журнала сама по себе полноту не доказывает. Результат каждого личного ресурса
|
||||||
Старый полный портфель не удаляется по истечении TTL. `isStale` показывает
|
в `{ data, meta }` описывают пять независимых значений: freshness,
|
||||||
возраст portfolio source, а не сам факт неудачного обновления.
|
completeness, `lastSuccessfulAt`, `lastAttempt` и availability. Первые,
|
||||||
|
полнота и `lastSuccessfulAt` относятся только к возвращённому подтверждённому
|
||||||
|
результату. `lastAttempt` описывает относящуюся к ресурсу часовую попытку:
|
||||||
|
`none`, `running`, `succeeded`, `partial` или `failed`.
|
||||||
|
|
||||||
| Источник | Когда обычный запрос требует обновления |
|
Итог попытки выводится из фактических результатов её шагов: попытка, не
|
||||||
|
завершившая обязательный шаг, не обозначается полным успехом, а полученные
|
||||||
|
успешные результаты сохраняются. Ожидание каждого шага ограничено; зависший
|
||||||
|
шаг учитывается проблемным, а начатое обращение к T-Bank не отменяется.
|
||||||
|
Попытка, потерявшая выполнение после сбоя сохранения или остановки процесса,
|
||||||
|
закрывается частичным успехом либо неуспехом и не блокирует следующий обход
|
||||||
|
дольше обычного часового срока.
|
||||||
|
|
||||||
|
Поздняя неуспешная или частичная попытка сохраняет прежний полный результат и
|
||||||
|
его исходное время. Если полного результата нет, `data` равно `null`: состояние
|
||||||
|
availability объясняет первоначальную загрузку, временную недоступность либо
|
||||||
|
недоступность подключения. Пустой массив не означает отсутствие результата.
|
||||||
|
Старый полный portfolio не удаляется из-за возраста. `Portfolio.isStale`
|
||||||
|
сохраняет смысл возраста его snapshot, а не обозначает неуспех обхода или
|
||||||
|
клиентскую ошибку перечитывания.
|
||||||
|
|
||||||
|
| Источник | Владелец нормального обновления |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Portfolio, котировки, изменяемый хвост дневных свечей | Через 60 секунд |
|
| Membership, portfolio, изменяемый хвост операций и события | Часовой обход текущего подключения |
|
||||||
| Membership и изменяемый хвост операций | Через 5 минут |
|
| Котировки и изменяемый хвост дневных свечей | Установленная политика источника; не ordinary personal GET |
|
||||||
| Metadata, поиск каталога, company и календари | Через сутки |
|
| Metadata, поиск каталога и company | Онлайн при чтении |
|
||||||
| Полные прошлые интервалы операций и завершённые свечи | При явном обновлении показанного периода |
|
| Полные прошлые интервалы операций и завершённые свечи | Не обновляются часовым обходом или обычным GET |
|
||||||
|
|
||||||
TTL не создаёт таймер импорта. Запрошенная работа может закончиться после
|
Два исключения разрешают только первое получение отсутствующего результата:
|
||||||
ухода со страницы. После перезапуска нет автоматического обхода intent:
|
первое открытие неподтверждённого исторического интервала операций получает
|
||||||
следующий подходящий запрос повторяет незавершённый интервал с первой страницы,
|
только этот интервал и возвращает локальные строки с неполным покрытием; первое
|
||||||
переиспользуя полные интервалы. Cursor брокера не служит durable checkpoint.
|
открытие диапазона свечей без подтверждённого локального результата получает
|
||||||
|
только этот диапазон. Ни одно исключение не обновляет membership, portfolio,
|
||||||
|
события, другой интервал или диапазон. Их HTTP retry также только перечитывает
|
||||||
|
локальное состояние. Подтверждённый полный интервал или диапазон остаётся
|
||||||
|
локальным.
|
||||||
|
|
||||||
Ручное «Обновить» перечитывает зависимости текущего экрана и применённый
|
Часовой обход сохраняет успешные разделы независимо, а failed section не
|
||||||
период независимо от TTL. Повторная сверка полного периода публикуется одной
|
заменяет прежний complete result. Отменой query lifecycle владеет TanStack
|
||||||
транзакцией после всех страниц, интервалов и счетов, включая `all`.
|
Query. Открытый экран перечитывает ресурс не чаще одного раза в 30 минут;
|
||||||
Сбой сохраняет весь прежний результат. Первая загрузка может публиковать
|
это локальный HTTP read. Совместимый параметр `sync=observe`, пока он есть в
|
||||||
полные малые интервалы и показывать частичный период без окончательных сумм.
|
маршруте, также является только чтением и не представляет команду обходу.
|
||||||
|
[HTTP API](../http-api.md) описывает исполняемый контракт envelope.
|
||||||
Клиент наблюдает только известную активную работу открытого экрана.
|
|
||||||
Status GET и data GET с `sync=observe` не запускают работу. После изменения
|
|
||||||
состояния ответ попадает в ту же query identity; после ухода или завершения
|
|
||||||
наблюдение прекращается. Поздний ответ не заменяет уже принятый новый.
|
|
||||||
[HTTP API](../http-api.md) объясняет envelope и экранный refresh.
|
|
||||||
|
|
||||||
Отменой query lifecycle владеет TanStack Query. Status не пересобирает
|
|
||||||
финансовые ответы и не передаёт hash notifications. Свечи нового диапазона
|
|
||||||
загружаются при его открытии; предзагрузка всей истории портфеля не выполняется.
|
|
||||||
|
|
||||||
## Смена подключения
|
## Смена подключения
|
||||||
|
|
||||||
|
|||||||
+32
-20
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
## Источник контракта
|
## Источник контракта
|
||||||
|
|
||||||
Backend генерирует OpenAPI из собственного публичного API. Frontend использует
|
Backend генерирует OpenAPI из собственного публичного API. Этот сгенерированный
|
||||||
|
OpenAPI — исполняемый источник HTTP-контракта. Frontend использует
|
||||||
предоставленный OpenAPI snapshot как актуальный вход и локально генерирует
|
предоставленный OpenAPI snapshot как актуальный вход и локально генерирует
|
||||||
типизированный клиент. Backend владеет контрактом, а подготовка и доставка
|
типизированный клиент. Backend владеет контрактом, а подготовка и доставка
|
||||||
схемы находятся вне frontend. Это разделение принято в
|
схемы находятся вне frontend. Это разделение принято в
|
||||||
@@ -20,29 +21,40 @@ artifact у себя и проверяет соответствие generated ty
|
|||||||
API имеет prefix `/api/v1`; Swagger публикуется для локальной разработки по
|
API имеет prefix `/api/v1`; Swagger публикуется для локальной разработки по
|
||||||
environment policy, а не используется frontend в runtime.
|
environment policy, а не используется frontend в runtime.
|
||||||
|
|
||||||
|
## Скринер акций
|
||||||
|
|
||||||
|
`POST /api/v1/stocks/screener/search` всегда создаёт новый результат по
|
||||||
|
условиям скринера, включая пустой подтверждённый список. Ответ первой страницы
|
||||||
|
содержит непрозрачный `searchId`, время получения каталога и признак следующей
|
||||||
|
страницы. `GET /api/v1/stocks/screener/search/{searchId}?page=...` читает
|
||||||
|
последующую страницу того же результата, не запускает новый поиск и сохраняет
|
||||||
|
состав и время списка. Идентификатор результата принадлежит текущему пользователю
|
||||||
|
и его подключению; недоступный или чужой результат возвращает ошибку, а не
|
||||||
|
пустой список. Точные поля и статусы определяет backend-generated OpenAPI.
|
||||||
|
|
||||||
## Инвестиционные данные и синхронизация
|
## Инвестиционные данные и синхронизация
|
||||||
|
|
||||||
T-Bank data GET возвращают envelope `{ data, meta }`. `data` может быть `null`
|
Затронутые GET инвестиционных ресурсов возвращают сгенерированный contract
|
||||||
при missing или неполном финансовом агрегате; partial ledger/candles могут
|
`{ data, meta }`. `data` nullable: `null` означает отсутствие complete result,
|
||||||
содержать подтверждённые строки. `meta` разделяет availability, freshness,
|
а подтверждённый пустой массив является available complete result. `meta`
|
||||||
lastSuccessfulAt, sync, coverage и состояния зависимостей. `dataRevision`
|
независимо описывает freshness, completeness, `lastSuccessfulAt`,
|
||||||
описывает набор данных; пустое завершённое покрытие явно представлено в coverage.
|
resource-relevant `lastAttempt` и availability. `lastAttempt` имеет состояния
|
||||||
Публичной hash-версии состояния нет. Ни одно поле не раскрывает connection revision.
|
`none`, `running`, `succeeded`, `partial` и `failed`; его неуспех не заменяет
|
||||||
|
сохранённый complete result или его время. `Portfolio.isStale` остаётся
|
||||||
|
специфичным для snapshot полем, а не заменой состояния попытки.
|
||||||
|
|
||||||
Обычный GET планирует missing/stale зависимости после проверки доступа.
|
Только Accounts дополнительно возвращает top-level `sync`: `null`, если у
|
||||||
GET с `sync=observe` только читает. `POST /api/v1/tbank-sync` принимает
|
текущего подключения ещё не было часовой попытки, иначе connection-wide
|
||||||
валидированный screen descriptor и возвращает `202` с handle и нормализованным
|
наблюдаемый результат. Это наблюдение, не команда. Обычный GET и retry после
|
||||||
scope. `GET /api/v1/tbank-sync/:id` наблюдает разрешённую работу; чужой или
|
проверки доступа читают локальное состояние и не начинают личную работу.
|
||||||
прежний handle возвращает `404`. Приём работы не означает её успех.
|
Устаревший `sync=observe`, пока он сохранён для совместимости маршрута, также
|
||||||
|
только читает. Request-started screen-sync command/status не является текущей
|
||||||
|
AS-IS моделью.
|
||||||
|
|
||||||
Status возвращает state/errorCode без данных ресурсов и численных progress
|
Безопасные ошибки завершённой часовой попытки передаются в `lastAttempt` и
|
||||||
counters. Клиент перечитывает показанные resources через `sync=observe` во время
|
Accounts `sync`; HTTP transport/access/input errors сохраняют Problem Details.
|
||||||
работы и после завершения, сохраняя generated query identity. Sync states ресурса:
|
Старые данные при временной source failure сохраняют исходное успешное время.
|
||||||
`idle`, `running`, `failed`; отдельного публичного `queued` нет.
|
Ни одно поле не раскрывает connection revision. Детали поведения —
|
||||||
|
|
||||||
Source failure принятой работы передаётся безопасным `meta.sync.errorCode`;
|
|
||||||
HTTP transport/access/input errors сохраняют Problem Details. Старые данные
|
|
||||||
при transient failure сохраняют исходное успешное время. Детали поведения —
|
|
||||||
[свежесть и полнота](cross-cutting/data-freshness.md).
|
[свежесть и полнота](cross-cutting/data-freshness.md).
|
||||||
|
|
||||||
Envelope несовместим с прежними bare-array ответами: backend/frontend
|
Envelope несовместим с прежними bare-array ответами: backend/frontend
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
extends: ["@commitlint/config-conventional"],
|
extends: ["@commitlint/config-conventional"],
|
||||||
rules: { "type-enum": [2, "always", ["feat", "fix", "perf", "docs", "spec", "refactor", "build", "ci", "test", "style", "chore", "revert"]] },
|
defaultIgnores: false,
|
||||||
|
ignores: [
|
||||||
|
message => /^chore\(release\): \d+\.\d+\.\d+$/.test(message.trim()),
|
||||||
|
message => /^Merge pull request ['"].+['"] \(#\d+\) from .+ into .+$/.test(message.trim()),
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
"type-enum": [2, "always", ["feat", "fix", "perf", "docs", "spec", "refactor", "build", "ci", "test", "style", "chore", "revert"]],
|
||||||
|
"references-empty": [2, "never"],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,9 +89,8 @@ JavaScript Number. Отдельный ввод ограничен signed64: на
|
|||||||
следующие страницы. Баланс при выборе прошлого периода остаётся текущим.
|
следующие страницы. Баланс при выборе прошлого периода остаётся текущим.
|
||||||
Сводка учитывает все подходящие записи, включая не показанные на странице.
|
Сводка учитывает все подходящие записи, включая не показанные на странице.
|
||||||
|
|
||||||
Сводка одной или всех карт показывает одну итоговую сумму расходов с учётом
|
Сводка одной или всех карт отдельно показывает расходы, возвращённую сумму и
|
||||||
возвратов и компактные строки категорий по убыванию итоговых расходов. Отдельные показатели «Возвращено»
|
итог после возвратов, а также компактные строки категорий по убыванию итоговых расходов. Возврат уменьшает расходы месяца своего
|
||||||
и «После возвратов» в интерфейсе скрыты; расчёт и операции возврата сохранены. Возврат уменьшает расходы месяца своего
|
|
||||||
получения: августовская покупка 1 000 ₽ и сентябрьский возврат 600 ₽ дают
|
получения: августовская покупка 1 000 ₽ и сентябрьский возврат 600 ₽ дают
|
||||||
августовский итог 1 000 ₽ и сентябрьский −600 ₽ при отсутствии других трат.
|
августовский итог 1 000 ₽ и сентябрьский −600 ₽ при отсутствии других трат.
|
||||||
Начальный остаток, пополнения и переводы в эти показатели не входят.
|
Начальный остаток, пополнения и переводы в эти показатели не входят.
|
||||||
|
|||||||
@@ -40,10 +40,10 @@
|
|||||||
## Период и список
|
## Период и список
|
||||||
|
|
||||||
Без фильтра период начинается сегодня в UTC и заканчивается через 30 дней
|
Без фильтра период начинается сегодня в UTC и заканчивается через 30 дней
|
||||||
после начала, обе даты включены. Поля «С» и «По» позволяют изменить период:
|
после начала, обе даты включены. `from` и `to` принимают только строгие даты
|
||||||
«Применить» сохраняет выбранные календарные даты в URL и запрашивает результат,
|
`YYYY-MM-DD`; без `from` используется текущая дата UTC, без `to` — `from + 30`
|
||||||
«Сбросить» возвращает период по умолчанию. Обзор счёта сохраняет прогноз
|
календарных дней. Поля «С» и «По» сохраняют выбранные календарные даты в URL,
|
||||||
на текущую дату и следующие 30 дней.
|
а «Сбросить» возвращает период по умолчанию.
|
||||||
|
|
||||||
События упорядочены по календарной дате. У каждой строки видны тип,
|
События упорядочены по календарной дате. У каждой строки видны тип,
|
||||||
инструмент, дата и доступная сумма в исходной валюте. Список не имеет
|
инструмент, дата и доступная сумма в исходной валюте. Список не имеет
|
||||||
@@ -52,10 +52,13 @@
|
|||||||
отсутствия всех будущих выплат. Инструмент без поддерживаемых данных
|
отсутствия всех будущих выплат. Инструмент без поддерживаемых данных
|
||||||
не получает искусственную строку «нет данных».
|
не получает искусственную строку «нет данных».
|
||||||
|
|
||||||
API принимает необязательные `from` и `to` в формате `YYYY-MM-DD` для
|
Сохранённый forecast сохраняет свой `calculatedAt` и исходное включительное
|
||||||
отдельного и общего счёта. Без `from` используется сегодня в UTC,
|
окно. GET для отдельного счёта или `all` возвращает только пересечение этого
|
||||||
без `to` — 30 дней после начала. Неверный формат или несуществующая дата
|
окна и запрошенного UTC-периода, не меняя ни `calculatedAt`, ни исходное окно.
|
||||||
дают `400`; обратный период — `400 INVALID_EVENTS_PERIOD`.
|
Пустое пересечение или отсутствие событий в пересечении — успешный пустой
|
||||||
|
список с теми же metadata; это не отсутствие forecast. Неверный формат или
|
||||||
|
несуществующая дата дают `400`; обратный период — `400 INVALID_EVENTS_PERIOD`
|
||||||
|
без замены периода и без запуска личной работы.
|
||||||
Фильтрация на сервере предшествует сортировке и вычислению
|
Фильтрация на сервере предшествует сортировке и вычислению
|
||||||
`incomeTotalsByCurrency`, включающего только купоны и дивиденды.
|
`incomeTotalsByCurrency`, включающего только купоны и дивиденды.
|
||||||
Итоги остаются в ответе API; полный экран показывает список без общего итога.
|
Итоги остаются в ответе API; полный экран показывает список без общего итога.
|
||||||
@@ -63,26 +66,30 @@ API принимает необязательные `from` и `to` в форма
|
|||||||
## Получение и отказы
|
## Получение и отказы
|
||||||
|
|
||||||
Запрос требует сессии, подключения и локально подтверждённого membership.
|
Запрос требует сессии, подключения и локально подтверждённого membership.
|
||||||
Прогноз строится из личного сохранённого portfolio и общих календарей: T-Bank для
|
Он читает сохранённый forecast и не запускает личную синхронизацию. Часовой
|
||||||
дивидендов, MOEX для bond events. Отдельного синхронного получения portfolio
|
обход строит forecast из полного личного portfolio и общих календарей: T-Bank
|
||||||
нет. Личные оценки сохраняются отдельно от общих календарей.
|
для дивидендов, MOEX для bond events. Личные оценки сохраняются отдельно от
|
||||||
|
общих календарей.
|
||||||
|
|
||||||
Последний полный forecast привязан к scope, периоду и membership.
|
Последний полный forecast привязан к scope, исходному окну и membership. Если
|
||||||
Если новый portfolio требует ещё недоступного календаря, прежний полный
|
часовой обход не может получить полный новый forecast, прежний полный прогноз,
|
||||||
прогноз и его source times остаются, в том числе после рестарта. Новый
|
его `calculatedAt` и исходное окно остаются читаемыми, в том числе после
|
||||||
полный результат заменяет его атомарно. Без fallback показывается
|
рестарта; `meta.lastAttempt` отдельно сообщает об ошибке обновления. Без
|
||||||
missing/partial, а не подтверждённое отсутствие выплат. Другой период или
|
полного forecast `data: null` и metadata обозначает initial loading либо
|
||||||
изменившийся membership не получают старый прогноз под новым названием.
|
временную недоступность, а не подтверждённое отсутствие выплат. В режиме `all`
|
||||||
Source failure сообщается в metadata и не изменяет успешное время.
|
результат complete только при полном вкладе каждого включённого счёта. Другой
|
||||||
|
scope или изменившийся membership не получают старый forecast под новым
|
||||||
|
названием.
|
||||||
Успешный ответ MOEX без запрошенного блока означает отсутствие поддерживаемых
|
Успешный ответ MOEX без запрошенного блока означает отсутствие поддерживаемых
|
||||||
событий этого источника; это отличается от transport failure и повреждённого
|
событий этого источника; это отличается от transport failure и повреждённого
|
||||||
формата ответа.
|
формата ответа.
|
||||||
|
|
||||||
При первом открытии показан каркас заголовка и строк, без интерактивных
|
При первом открытии без complete forecast показан каркас заголовка и строк,
|
||||||
заглушек. Пустой ответ сохраняет возможность изменить период.
|
без интерактивных заглушек. Пустой успешный ответ сохраняет возможность
|
||||||
При обычном фоновом обновлении уже полученные данные остаются на экране,
|
изменить период. При failed HTTP reread уже полученный Client Cached Snapshot
|
||||||
ошибка получает предупреждение и повторную попытку. Без выбранного счёта
|
остаётся на экране; это отличается от server-side failed hourly attempt.
|
||||||
запрос не выполняется. Смена сессии и подключения следует
|
Повторная попытка перечитывает только HTTP-ответ. Без выбранного счёта запрос
|
||||||
|
не выполняется. Смена сессии и подключения следует
|
||||||
[общим правилам финансовых данных](../../architecture/cross-cutting/data-freshness.md).
|
[общим правилам финансовых данных](../../architecture/cross-cutting/data-freshness.md).
|
||||||
|
|
||||||
Внешние границы объясняют интеграции [T-Bank](../../integrations/tbank.md)
|
Внешние границы объясняют интеграции [T-Bank](../../integrations/tbank.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).
|
и [проверками](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.
|
||||||
|
|||||||
@@ -28,24 +28,29 @@
|
|||||||
на frontend. Общее для акций и облигаций восстановление справочных данных
|
на frontend. Общее для акций и облигаций восстановление справочных данных
|
||||||
принадлежит [загрузке портфеля на backend](../portfolio/flows/portfolio-loading.md).
|
принадлежит [загрузке портфеля на backend](../portfolio/flows/portfolio-loading.md).
|
||||||
|
|
||||||
Раздел «Акции» в боковой и мобильной навигации ведёт на `/stocks`: поиск
|
Раздел «Акции» в боковой и мобильной навигации ведёт на `/stocks`: скринер
|
||||||
по названию или тикеру через каталог Т-Банка, начиная с двух символов.
|
запускается кнопкой «Найти» с необязательным названием или тикером, сектором,
|
||||||
Результаты разных выпусков, включая обыкновенные и привилегированные акции,
|
типом акции, валютой расчётов, площадкой, страной риска и максимальным размером
|
||||||
имеют отдельные UID. Карточка результата показывает логотип, последнюю цену
|
лота. Он использует полный полученный каталог и показывает только акции, для
|
||||||
с её временем, тип бумаги, площадку, код режима, ISIN и доступность торгов через
|
которых каталог подтверждает доступность покупки и торговли через API. Это не
|
||||||
API. Поиск показывает одну карточку на нормализованный ISIN. До ограничения
|
гарантирует, что конкретная заявка пользователя будет исполнена прямо сейчас.
|
||||||
в 30 результатов выбирается представитель выпуска: доступность через API,
|
|
||||||
точное совпадение тикера, затем режим TQBR; равные варианты упорядочены по UID.
|
Скринер показывает одну карточку на выпуск с нормализованным ISIN, а выпуск
|
||||||
Записи без ISIN сохраняются отдельно по UID. Обыкновенные и привилегированные
|
без ISIN остаётся отдельной карточкой точного UID. Обыкновенные и
|
||||||
акции с разными ISIN не объединяются. Цена и ссылка принадлежат выбранному
|
привилегированные акции с разными ISIN не объединяются. После отбора карточки
|
||||||
UID; данные разных режимов не смешиваются. Прямые ссылки из портфеля сохраняют
|
упорядочены по тикеру и UID, разделены на страницы по 30 и показывают единое
|
||||||
|
время получения списка. Изменение условий не заменяет текущий список до
|
||||||
|
следующего нажатия «Найти». Повторный поиск получает новый каталог; страницы
|
||||||
|
одного результата не пересчитываются. Подтверждённый пустой результат отличается
|
||||||
|
от ошибки источника, для которой интерфейс предлагает повторить поиск.
|
||||||
|
|
||||||
|
Ссылка карточки принадлежит выбранному UID; данные разных режимов не смешиваются.
|
||||||
|
Прямые ссылки из портфеля сохраняют
|
||||||
исходный UID, даже если поиск выбрал другой режим этого выпуска; такая страница
|
исходный UID, даже если поиск выбрал другой режим этого выпуска; такая страница
|
||||||
сохраняет UUID в адресе. Если один точный тикер относится к разным выпускам,
|
сохраняет UUID в адресе. Если один точный тикер относится к разным выпускам,
|
||||||
сервер возвращает `409 STOCK_TICKER_AMBIGUOUS`, а страница предлагает поиск.
|
сервер возвращает `409 STOCK_TICKER_AMBIGUOUS`.
|
||||||
Поиск тикера нечувствителен к регистру, но использует точное совпадение:
|
|
||||||
SBER не заменяется на SBERP. Однобуквенные тикеры также поддерживаются.
|
|
||||||
Прямая ссылка не требует предварительного открытия портфеля. Хлебные крошки
|
Прямая ссылка не требует предварительного открытия портфеля. Хлебные крошки
|
||||||
«Акции → название» возвращают к поиску.
|
«Акции → название» возвращают к скринеру.
|
||||||
|
|
||||||
## Содержание и состояния
|
## Содержание и состояния
|
||||||
|
|
||||||
@@ -144,10 +149,11 @@ TTM означает последние 12 месяцев, MRQ — послед
|
|||||||
## Получение данных и ограничения
|
## Получение данных и ограничения
|
||||||
|
|
||||||
Общие metadata, discovery, company, quotes, свечи и календари сохраняются
|
Общие metadata, discovery, company, quotes, свечи и календари сохраняются
|
||||||
в SQLite. Поиск хранит подтверждённый набор UID для конкретного query;
|
в SQLite. Скринер получает каталог online и показывает время его получения;
|
||||||
успешный SBER не подтверждает пустой GAZP. Отсутствующее enrichment не
|
временная недоступность каталога не подтверждает отсутствие подходящих акций.
|
||||||
скрывает найденную бумагу. Сохранённые общие источники переиспользуются
|
Отсутствующее enrichment не скрывает найденную бумагу. Сохранённые общие
|
||||||
между пользователями, но личные позиции и выплаты всегда проверяют доступ.
|
источники переиспользуются между пользователями, но личные позиции и выплаты
|
||||||
|
всегда проверяют доступ.
|
||||||
|
|
||||||
Обычное чтение не ждёт RPC; missing/stale зависимости запрашиваются в фоне
|
Обычное чтение не ждёт RPC; missing/stale зависимости запрашиваются в фоне
|
||||||
через существующий T-Bank limiter. Минутная свежесть применяется к quotes
|
через существующий T-Bank limiter. Минутная свежесть применяется к quotes
|
||||||
@@ -184,3 +190,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.
|
||||||
|
|||||||
@@ -1,46 +1,47 @@
|
|||||||
# Загрузка портфеля
|
# Загрузка портфеля
|
||||||
|
|
||||||
Экран `/accounts/:accountId` читает последний полный snapshot из SQLite
|
Экран `/accounts/:accountId` читает последний полный snapshot из SQLite после
|
||||||
после проверки сессии, подключения и локального membership. Если список
|
проверки сессии, подключения и локального membership. Если список счетов ещё
|
||||||
счетов ещё неизвестен, сервер сообщает о загрузке доступа без выдачи личных
|
неизвестен, сервер сообщает о загрузке доступа без выдачи личных данных
|
||||||
данных неизвестного ID. Известный недоступный счёт возвращает `404`.
|
неизвестного ID. Известный недоступный счёт возвращает `404`.
|
||||||
|
|
||||||
## Основной обмен
|
## Основной обмен
|
||||||
|
|
||||||
Обычный GET возвращает локальный envelope. Missing/stale зависимости
|
Обычный GET и retry возвращают read-only локальный `{ data, meta }` envelope:
|
||||||
запрашиваются в фоне; чтение не ждёт T-Bank. Для нового полного snapshot
|
они не ждут и не вызывают T-Bank и не предлагают ручную синхронизацию. Часовой
|
||||||
нужны оба финансовых ответа `GetPortfolio` и `GetPositions`. Суммы и позиции
|
обход текущего подключения обновляет Portfolio независимо от экрана. Для нового
|
||||||
публикуются вместе; metadata дополняет представление независимо, с доступным
|
полного snapshot ему нужны оба финансовых ответа `GetPortfolio` и
|
||||||
UID/FIGI вместо имени до её загрузки.
|
`GetPositions`; суммы и позиции публикуются вместе. Metadata инструмента
|
||||||
|
дополняет представление независимо, с доступным UID/FIGI вместо имени до её
|
||||||
|
онлайн-загрузки.
|
||||||
|
|
||||||
Свежесть portfolio — 60 секунд. Истечение срока не удаляет snapshot и не
|
Открытый экран выполняет локальное перечитывание не чаще одного раза в
|
||||||
создаёт таймер. «Обновить» на обзоре перечитывает зависимости текущего экрана:
|
30 минут; retry также повторяет только HTTP GET. `data: null` означает, что
|
||||||
membership, portfolio, показанные операции, доход и будущие события.
|
полного snapshot ещё нет, а не нулевой портфель. Пустой подтверждённый portfolio
|
||||||
Секции могут быть готовы независимо. Подробнее —
|
остаётся available complete result. Секции могут быть готовы независимо.
|
||||||
[свежесть](../../../architecture/cross-cutting/data-freshness.md).
|
Подробнее — [свежесть](../../../architecture/cross-cutting/data-freshness.md).
|
||||||
|
|
||||||
## Границы доступа
|
## Границы доступа
|
||||||
|
|
||||||
Публикация проверяет connection revision и attempt в той же транзакции.
|
Публикация проверяет connection revision и attempt в той же транзакции. Замена
|
||||||
Замена или удаление подключения не допускает позднюю запись прежней работы.
|
или удаление подключения не допускает позднюю запись прежней работы. Frontend
|
||||||
Frontend очищает недоступный personal view и отклоняет запоздалые ответы.
|
очищает недоступный personal view и отклоняет запоздалые ответы. В режиме
|
||||||
В режиме [«Все счета»](../all-accounts.md#полнота-свежесть-и-доступ) состав
|
[«Все счета»](../all-accounts.md#полнота-свежесть-и-доступ) состав accounts и
|
||||||
accounts и snapshots читается согласованно, но их source times могут различаться.
|
snapshots читается согласованно, но их source times могут различаться.
|
||||||
|
|
||||||
## Ошибки и результат для пользователя
|
## Ошибки и результат для пользователя
|
||||||
|
|
||||||
Нет подключения — `409 TBANK_NOT_CONNECTED`, известный отказ токена —
|
Нет подключения — `409 TBANK_NOT_CONNECTED`, известный отказ токена —
|
||||||
`400 INVALID_TBANK_TOKEN`, недоступный счёт — `404`. Они не маскируются
|
`400 INVALID_TBANK_TOKEN`, недоступный счёт — `404`. Они не маскируются
|
||||||
запасным snapshot. Transient source failure оставляет прежний полный портфель
|
запасным snapshot. Временная ошибка часового обхода оставляет прежний полный
|
||||||
и его исходное время с безопасным предупреждением. При отсутствии snapshot
|
portfolio и его исходное `lastSuccessfulAt`; `meta.lastAttempt` сообщает о
|
||||||
показывается missing/failed, без нулевых итогов. `503` означает ошибку
|
failed или partial попытке отдельно. `Portfolio.isStale` сообщает возраст
|
||||||
обслуживания HTTP-запроса, а не принятой фоновой работы.
|
snapshot, а Client Cached Snapshot и ошибка браузерного HTTP-перечитывания
|
||||||
|
имеют независимый смысл. При отсутствии полного snapshot `data: null` и
|
||||||
|
metadata обозначает initial loading либо временную недоступность, без нулевых
|
||||||
|
итогов. `503` означает ошибку обслуживания самого HTTP-запроса, а не
|
||||||
|
завершившуюся фоновую работу.
|
||||||
|
|
||||||
Observer запрашивает статус известной работы, затем `sync=observe` читает
|
Денежные правила находятся в [справочнике](../data-reference.md), проверка
|
||||||
изменившийся ресурс без запуска синхронизации. При уходе и terminal outcome
|
расхождения — в [диагностике](../how-to/investigate-discrepancy.md), RPC/лимиты
|
||||||
наблюдение прекращается. Повторное открытие может запросить недостающее;
|
— в [интеграции T-Bank](../../../integrations/tbank.md).
|
||||||
после рестарта сохранённый snapshot доступен сразу.
|
|
||||||
|
|
||||||
Денежные правила находятся в [справочнике](../data-reference.md),
|
|
||||||
проверка расхождения — в [диагностике](../how-to/investigate-discrepancy.md),
|
|
||||||
RPC/лимиты — в [интеграции T-Bank](../../../integrations/tbank.md).
|
|
||||||
|
|||||||
+17
@@ -128,6 +128,14 @@ Instrument обогащают отображение Position или Event, но
|
|||||||
|
|
||||||
_Не использовать_: бумага, тикер, актив позиции.
|
_Не использовать_: бумага, тикер, актив позиции.
|
||||||
|
|
||||||
|
## Скринер акций
|
||||||
|
|
||||||
|
Подбор выпусков акций по заданным условиям из каталога T-Bank с указанием
|
||||||
|
времени получения списка. Скринер отличается от текстового поиска конкретного
|
||||||
|
инструмента, личного портфеля и подтверждения исполнимости сделки.
|
||||||
|
|
||||||
|
_Не использовать_: гарантия покупки, личная проверка доступа к сделке.
|
||||||
|
|
||||||
## Instrument Logo
|
## Instrument Logo
|
||||||
|
|
||||||
Имя файла бренда T-Bank для отображения Instrument в интерфейсе;
|
Имя файла бренда T-Bank для отображения Instrument в интерфейсе;
|
||||||
@@ -152,6 +160,15 @@ _Не использовать_: валютная позиция, заблоки
|
|||||||
|
|
||||||
_Не использовать_: история портфеля, snapshot для графика.
|
_Не использовать_: история портфеля, snapshot для графика.
|
||||||
|
|
||||||
|
## Точка истории стоимости портфеля
|
||||||
|
|
||||||
|
Полная оценка одного Brokerage Account в одной валюте на момент успешного
|
||||||
|
обновления Portfolio; последовательность таких точек описывает изменение
|
||||||
|
оценки во времени, включая неторговые дни. Не является Portfolio Snapshot
|
||||||
|
или инвестиционной доходностью; отсутствие цены позиции не приравнивается к нулю.
|
||||||
|
|
||||||
|
_Не использовать_: снимок состава портфеля, доходность.
|
||||||
|
|
||||||
## Client Cached Snapshot
|
## Client Cached Snapshot
|
||||||
|
|
||||||
Технический термин: последний успешно полученный frontend-ответ React Query, который остаётся
|
Технический термин: последний успешно полученный frontend-ответ React Query, который остаётся
|
||||||
|
|||||||
+12
-1
@@ -20,6 +20,12 @@ T-Bank определяет исходные данные и права token. B
|
|||||||
сессию, выбирает подключение её пользователя и устанавливает доступ к счёту.
|
сессию, выбирает подключение её пользователя и устанавливает доступ к счёту.
|
||||||
Наличие идентификатора счёта в URL этого доступа не подтверждает.
|
Наличие идентификатора счёта в URL этого доступа не подтверждает.
|
||||||
|
|
||||||
|
Скринер акций получает полный online-каталог акций T-Bank для каждого нового
|
||||||
|
поиска. В него входят только инструменты, для которых каталог подтверждает и
|
||||||
|
доступность покупки, и торговли через API. Эти признаки описывают полученный
|
||||||
|
снимок каталога: они не подтверждают личные права пользователя, состояние торгов
|
||||||
|
или исполнение будущей заявки. Скринер не использует личный портфель как каталог.
|
||||||
|
|
||||||
[MOEX](moex.md) и [НКР](nkr.md) дополняют публичные сведения об облигациях; они не заменяют
|
[MOEX](moex.md) и [НКР](nkr.md) дополняют публичные сведения об облигациях; они не заменяют
|
||||||
брокера как источник личных позиций и исполненных выплат. Границы источников
|
брокера как источник личных позиций и исполненных выплат. Границы источников
|
||||||
показаны в [контексте](../architecture/context.md), смысл дополнений — в
|
показаны в [контексте](../architecture/context.md), смысл дополнений — в
|
||||||
@@ -91,7 +97,12 @@ sequenceDiagram
|
|||||||
|
|
||||||
`INVALID_TBANK_TOKEN` означает отказ внешней аутентификации или прав доступа.
|
`INVALID_TBANK_TOKEN` означает отказ внешней аутентификации или прав доступа.
|
||||||
`TBANK_UNAVAILABLE` сообщает о временной или иной upstream-ошибке, включая
|
`TBANK_UNAVAILABLE` сообщает о временной или иной upstream-ошибке, включая
|
||||||
исчерпание очереди. Ответы и ошибки не содержат token. Удаление подключения
|
исчерпание очереди. Диагностические причины жизненного цикла часовой попытки
|
||||||
|
(`INTERRUPTED` — прерывание до нормального завершения, `DEADLINE` — истечение
|
||||||
|
ограничения ожидания шага) не относятся к ошибкам T-Bank: они остаются
|
||||||
|
внутренней диагностикой и не раскрываются в hourly-read. Истечение ограничения
|
||||||
|
ожидания не отменяет уже начатые обращения к T-Bank; их поздние результаты
|
||||||
|
остаются в строках шагов. Ответы и ошибки не содержат token. Удаление подключения
|
||||||
идемпотентно: удаляются локальный секрет, личные datasets и work; поздняя
|
идемпотентно: удаляются локальный секрет, личные datasets и work; поздняя
|
||||||
публикация прежней revision запрещена. Общие неперсональные источники могут
|
публикация прежней revision запрещена. Общие неперсональные источники могут
|
||||||
сохраняться. Оно не описывает отзыв token на стороне T-Bank.
|
сохраняться. Оно не описывает отзыв token на стороне T-Bank.
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ WealthLedger — локальное приложение для частного
|
|||||||
| Посчитать полученные выплаты | [Пассивный доход](domains/income/overview.md): исполненные купоны и дивиденды за календарный период |
|
| Посчитать полученные выплаты | [Пассивный доход](domains/income/overview.md): исполненные купоны и дивиденды за календарный период |
|
||||||
| Посмотреть ожидаемые события | [Будущие выплаты](domains/income/upcoming-events.md): купоны, дивиденды, погашения и оферты по текущим позициям |
|
| Посмотреть ожидаемые события | [Будущие выплаты](domains/income/upcoming-events.md): купоны, дивиденды, погашения и оферты по текущим позициям |
|
||||||
| Увидеть общий состав инвестиций | Режим [«Все счета»](domains/portfolio/all-accounts.md), сохраняющий принадлежность строк к счетам |
|
| Увидеть общий состав инвестиций | Режим [«Все счета»](domains/portfolio/all-accounts.md), сохраняющий принадлежность строк к счетам |
|
||||||
| Изучить конкретный инструмент | Поиск и страницы [акций](domains/instruments/stocks.md) и [облигаций](domains/instruments/bonds.md): рынок, личная позиция, история и события |
|
| Изучить конкретный инструмент | [Скринер акций](domains/instruments/stocks.md) по параметрам каталога, страницы акций и поиск [облигаций](domains/instruments/bonds.md): рынок, личная позиция, история и события |
|
||||||
|
|
||||||
## Как связаны представления
|
## Как связаны представления
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "wealth-ledger-docs",
|
"name": "wealth-ledger-docs",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "wealth-ledger-docs",
|
"name": "wealth-ledger-docs",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "21.2.2",
|
"@commitlint/cli": "21.2.2",
|
||||||
"@commitlint/config-conventional": "21.2.2",
|
"@commitlint/config-conventional": "21.2.2",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wealth-ledger-docs",
|
"name": "wealth-ledger-docs",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "24.21.0"
|
"node": "24.21.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user