20 Commits
Author SHA1 Message Date
ksv741 40ea47a7c2 chore(release): 0.1.7
Conventional commits / commits (pull_request) Successful in 10s
Docs security / security (pull_request) Successful in 7s
Docs verify / verify (pull_request) Successful in 12s
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 11s
2026-11-01 19:33:26 +03:00
codex-bot 37430da4c9 docs: describe concentration tab and stored instrument classification (WealthLedger/main#48) (#60)
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 11s
2026-11-01 19:29:01 +03:00
codex-bot abe5b16241 chore(deps): resolve markdownlint audit advisory (WealthLedger/main#49) (#61)
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 11s
2026-11-01 19:13:01 +03:00
codex-bot dcb528fa9f docs: describe all-account row grouping (WealthLedger/main#47) (#59)
Docs security / security (push) Successful in 6s
Docs verify / verify (push) Successful in 9s
2026-10-30 07:28:25 +03:00
ksv741 8c6c2f84ce chore(release): 0.1.6
Conventional commits / commits (pull_request) Successful in 12s
Docs security / security (pull_request) Successful in 8s
Docs verify / verify (pull_request) Successful in 12s
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 13s
2026-10-24 19:15:05 +03:00
renovate-bot f9098d8409 chore(deps): update non-major dependencies (WealthLedger/docs#56)
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 12s
Co-authored-by: renovate-bot <renovate-bot@ksv741.ru>
2026-10-24 19:04:54 +03:00
codex-bot 4216eb815f chore: bump Node to 24.22.1 (WealthLedger/backend#122)
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 13s
2026-10-23 16:20:01 +03:00
ksv741 24ad250c02 chore(release): 0.1.5
Conventional commits / commits (pull_request) Successful in 13s
Docs security / security (pull_request) Successful in 7s
Docs verify / verify (pull_request) Successful in 13s
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 13s
2026-10-18 16:24:45 +03:00
codex-bot e8e3ef6285 docs: describe quiet reading and visible source state (#51)
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 13s
ADR 021 фиксирует решение о тихом чтении и видимом состоянии источника; ui-resilience и затронутые domains приведены к AS-IS.
2026-10-17 22:11:49 +03:00
codex-bot 11f819ed31 chore: adopt linear git model in docs instructions (#49)
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 14s
2026-10-17 14:14:16 +03:00
codex-bot 550143aea1 docs: document Nexus delivery with shared account (WealthLedger/docs#18) (#48)
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 14s
2026-10-17 13:01:25 +03:00
codex-bot 56885f450b docs: describe ASCII 8-72 password policy and drop resolved discrepancy (WealthLedger/docs#46) (#47)
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 12s
2026-10-16 10:47:42 +03:00
codex-bot 1c89d321b1 Merge pull request 'chore: synchronize release 0.1.4 into develop (WealthLedger/main#30)' (#45) from chore/30-sync-release into develop
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 11s
2026-10-16 07:48:19 +03:00
codex-bot ad1978c75e Merge pull request 'chore: bring develop into release sync branch (WealthLedger/main#30)' (#44) from develop into chore/30-sync-release
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (pull_request) Successful in 6s
Docs verify / verify (pull_request) Successful in 11s
2026-10-16 07:41:04 +03:00
codex-bot 77c1f44726 Merge pull request 'docs: describe events default period and picker bounds (WealthLedger/frontend#63)' (#43) from docs/63-upcoming-events-default-period into develop
Docs security / security (push) Successful in 11s
Docs verify / verify (push) Successful in 15s
Conventional commits / commits (pull_request) Successful in 10s
Docs security / security (pull_request) Successful in 6s
Docs verify / verify (pull_request) Successful in 11s
2026-10-14 21:35:00 +03:00
ksv741 8a2a62c611 docs: describe events default period and picker bounds (WealthLedger/frontend#63)
Conventional commits / commits (pull_request) Successful in 13s
Docs security / security (pull_request) Successful in 9s
Docs verify / verify (pull_request) Successful in 14s
2026-10-14 21:23:33 +03:00
codex-bot 7b61eb8e6b docs: align current pages with hourly freshness model (WealthLedger/docs#34) (#42)
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 13s
2026-10-14 14:03:58 +03:00
codex-bot cad0f31615 Merge pull request 'ci: rerun commits proof on PR title edit (WealthLedger/docs#35)' (#41) from docs/35-commits-workflow-edited into develop
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 13s
2026-10-13 20:33:45 +03:00
ksv741 03110e99ea ci: rerun commits proof on PR title edit (WealthLedger/docs#35)
Conventional commits / commits (pull_request) Successful in 13s
Docs security / security (pull_request) Successful in 9s
Docs verify / verify (pull_request) Successful in 13s
2026-10-13 20:18:59 +03:00
codex-bot 03fb045a9e docs: document income without comparisons and unified payouts (WealthLedger/main#33) (#40)
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 14s
docs: document income without comparisons and unified payouts (WealthLedger/main#33)
2026-10-13 18:16:59 +03:00
32 changed files with 831 additions and 868 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ name: Conventional commits
on:
pull_request:
types: [opened, synchronize, reopened]
types: [opened, synchronize, reopened, edited]
concurrency:
group: docs-commits-${{ gitea.event.pull_request.number }}
+1 -1
View File
@@ -1 +1 @@
24.21.0
24.22.1
+6 -1
View File
@@ -24,7 +24,12 @@
## Ветки и релизы
Работа — в issue-linked ветке от `develop`, затем PR в `develop`; в `main` напрямую
не пушить. Release/hotfix и синхронизация веток — по [README](README.md#релизы).
не пушить. PR сливается squash или rebase-merge; merge-коммит не используется.
`main` обновляется только fast-forward из `develop`, поэтому `origin/main`
всегда предок `origin/develop`:
`git merge-base --is-ancestor origin/main origin/develop`. Срочный fix —
обычная ветка `fix/*` от `develop`; пути hotfix от `main` нет.
Релиз — по [README](README.md#релизы).
Commits и заголовки PR — Conventional Commits со ссылкой на Issue (кроме release);
для спецификаций допустим `spec:`.
Перед подготовкой релиза прочитай местный README; версии вручную не повышать.
+37
View File
@@ -1,5 +1,42 @@
# Changelog
## [0.1.7](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.6...v0.1.7) (2026-11-01)
### Documentation
* describe all-account row grouping (WealthLedger/main[#47](https://git.personal.ksv741.ru/WealthLedger/docs/issues/47)) ([#59](https://git.personal.ksv741.ru/WealthLedger/docs/issues/59)) ([dcb528f](https://git.personal.ksv741.ru/WealthLedger/docs/commit/dcb528fa9f76f0d7aa98bd827cc7ee39024dbb13))
* describe concentration tab and stored instrument classification (WealthLedger/main[#48](https://git.personal.ksv741.ru/WealthLedger/docs/issues/48)) ([#60](https://git.personal.ksv741.ru/WealthLedger/docs/issues/60)) ([37430da](https://git.personal.ksv741.ru/WealthLedger/docs/commit/37430da4c99cb571ef5bc0676cad7b3a47bcb6f0))
### Maintenance
* **deps:** resolve markdownlint audit advisory (WealthLedger/main[#49](https://git.personal.ksv741.ru/WealthLedger/docs/issues/49)) ([#61](https://git.personal.ksv741.ru/WealthLedger/docs/issues/61)) ([abe5b16](https://git.personal.ksv741.ru/WealthLedger/docs/commit/abe5b16241d3002baa5d39c2a12949f23a75b968))
## [0.1.6](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.5...v0.1.6) (2026-10-24)
### Maintenance
* bump Node to 24.22.1 (WealthLedger/backend[#122](https://git.personal.ksv741.ru/WealthLedger/docs/issues/122)) ([4216eb8](https://git.personal.ksv741.ru/WealthLedger/docs/commit/4216eb815f59b7a284e679ccb1b725438da07882))
* **deps:** update non-major dependencies (WealthLedger/docs[#56](https://git.personal.ksv741.ru/WealthLedger/docs/issues/56)) ([f9098d8](https://git.personal.ksv741.ru/WealthLedger/docs/commit/f9098d84098467e41143bad5044085d6329099d9))
## [0.1.5](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.4...v0.1.5) (2026-10-18)
### Documentation
* align current pages with hourly freshness model (WealthLedger/docs[#34](https://git.personal.ksv741.ru/WealthLedger/docs/issues/34)) ([#42](https://git.personal.ksv741.ru/WealthLedger/docs/issues/42)) ([7b61eb8](https://git.personal.ksv741.ru/WealthLedger/docs/commit/7b61eb8e6ba93a765b1ae27ca31d77b5e422e149))
* describe ASCII 8-72 password policy and drop resolved discrepancy (WealthLedger/docs[#46](https://git.personal.ksv741.ru/WealthLedger/docs/issues/46)) ([#47](https://git.personal.ksv741.ru/WealthLedger/docs/issues/47)) ([56885f4](https://git.personal.ksv741.ru/WealthLedger/docs/commit/56885f450bc1298d383d496174d16e591926e047))
* describe events default period and picker bounds (WealthLedger/frontend[#63](https://git.personal.ksv741.ru/WealthLedger/docs/issues/63)) ([8a2a62c](https://git.personal.ksv741.ru/WealthLedger/docs/commit/8a2a62c611e1acc1c1e69048a88b049bbf0d9087))
* describe quiet reading and visible source state ([#51](https://git.personal.ksv741.ru/WealthLedger/docs/issues/51)) ([e8e3ef6](https://git.personal.ksv741.ru/WealthLedger/docs/commit/e8e3ef62854dae8448deaa66ac26e5b15d5c7d6a))
* document income without comparisons and unified payouts (WealthLedger/main[#33](https://git.personal.ksv741.ru/WealthLedger/docs/issues/33)) ([#40](https://git.personal.ksv741.ru/WealthLedger/docs/issues/40)) ([03fb045](https://git.personal.ksv741.ru/WealthLedger/docs/commit/03fb045a9ee8a36775599bda66e7f6a08362bd84))
* document Nexus delivery with shared account (WealthLedger/docs[#18](https://git.personal.ksv741.ru/WealthLedger/docs/issues/18)) ([#48](https://git.personal.ksv741.ru/WealthLedger/docs/issues/48)) ([550143a](https://git.personal.ksv741.ru/WealthLedger/docs/commit/550143aea1f0ac90630f326dd927091b0ec4f38e))
### CI
* rerun commits proof on PR title edit (WealthLedger/docs[#35](https://git.personal.ksv741.ru/WealthLedger/docs/issues/35)) ([03110e9](https://git.personal.ksv741.ru/WealthLedger/docs/commit/03110e99ea58600bacd4c091fda8591d374a5a8d))
### Maintenance
* adopt linear git model in docs instructions ([#49](https://git.personal.ksv741.ru/WealthLedger/docs/issues/49)) ([11f819e](https://git.personal.ksv741.ru/WealthLedger/docs/commit/11f819ed31226a05524ac35a893064525713e41b))
## [0.1.4](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.3...v0.1.4) (2026-10-12)
### Bug Fixes
+38 -15
View File
@@ -30,7 +30,7 @@ WealthLedger помогает частному инвестору понимат
| [Аутентификация](domains/authentication/overview.md) | Регистрация, вход, восстановление и завершение сессии |
| [Счета](domains/accounts/overview.md) | Доступные счета, сводки и состояния каждого счёта |
| [Банковские карты](domains/cards/overview.md) | Ручные остатки, операции, категории, возвраты, месячные сводки и исправления |
| [Портфель](domains/portfolio/overview.md) | Позиции, остатки, суммы, структура и свежесть |
| [Портфель](domains/portfolio/overview.md) | Позиции, остатки, суммы, структура, [концентрация](domains/portfolio/concentration.md) и свежесть |
| [Все счета](domains/portfolio/all-accounts.md) | Общий портфель, происхождение строк и сводные разделы |
| [Операции](domains/operations/overview.md) | Исполненные операции, фильтры и пагинация |
| [Доход](domains/income/overview.md) | Полученные купоны и дивиденды, периоды и состав расчёта |
@@ -74,35 +74,58 @@ WealthLedger помогает частному инвестору понимат
Репозиторий выпускается независимо. `develop` — интеграция, `main` — принятые
релизы. Обычная работа: issue-linked ветка от актуального `develop`, PR в `develop`;
общие правила — в Engineering Workflow по ссылке из AGENTS.
Обычные PR допускают squash; release и обратная синхронизация сохраняют историю.
PR сливается squash или rebase-merge; merge-коммит не используется. `main`
обновляется только fast-forward из `develop`, поэтому история линейна:
```text
<type>/<issue>-<slug> --squash--> develop --ff-only--> main --> tag vX.Y.Z
```
Инвариант: `origin/main` всегда предок `origin/develop`. Проверка:
```bash
git fetch -q origin
git merge-base --is-ancestor origin/main origin/develop && echo ok || echo BROKEN
```
Commits и PR titles — Conventional Commits со ссылкой на Issue (кроме release),
включая `spec:`. Версии вручную не повышай.
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Убедись, что
`develop` содержит последний релиз. Создай `release/<name>` от проверенного
`develop`; `nvm use --silent`, `npm ci`. Hotfix начинается от `main` в
`release/hotfix-<name>` и проходит тот же процесс.
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Проверь
инвариант. Создай `release/X.Y.Z` от проверенного `develop`;
`nvm use --silent`, `npm ci`.
2. На чистой ветке выполни `npm run release:preview`, просмотри версию/changelog,
затем `npm run release:prepare`. Команда создаёт `chore(release): X.Y.Z`,
обновляет manifest/lockfile/CHANGELOG; тег и push не выполняет. Не обходи
guards ветки, чистого дерева, отсутствующих тегов или уже подготовленной версии.
3. Проверь diff и штатные gates этого репозитория. Отправь только release-ветку,
открой PR в `main` с заголовком `chore(release): X.Y.Z`. После зелёных
`verify`, `security`, `commits` выполни fast-forward-only merge. Если `main`
изменился, согласуй историю и повтори проверки кандидата.
4. Получи удалённый `main`, сравни его HEAD с проверенным release SHA и версией
открой PR в **`develop`** с заголовком `chore(release): X.Y.Z`. После зелёных
`verify`, `security`, `commits` выполни fast-forward-only merge. Если
`develop` изменился, обнови release-ветку и повтори проверки кандидата.
4. Открой PR `develop → main` с тем же заголовком и слей fast-forward-only.
5. Получи удалённый `main`, сравни его HEAD с проверенным release SHA и версией
manifest/lockfile. Создай аннотированный `vX.Y.Z` именно на этом SHA:
`git tag -a vX.Y.Z <release-sha> -m "Release X.Y.Z"`, затем отправь только
`git push origin refs/tags/vX.Y.Z`. Не запускай release-it повторно на `main`.
5. Верни release-коммит через PR `main → develop` без squash/rebase; проверь,
что `develop` содержит тег. Опубликованные теги не перемещай. При сбое после
merge создай отсутствующий тег без нового bump; до merge исправь и проверь
существующий кандидат без повторного повышения версии.
Обратная синхронизация не нужна: release-коммит попал в `develop` на шаге 3.
Опубликованные теги не перемещай. При сбое после merge создай отсутствующий тег
без нового bump; до merge исправь и проверь существующий кандидат без
повторного повышения версии.
Freeze релиза не поддерживается: пока открыт релизный PR, `develop` не двигают.
Срочный fix — обычная ветка `fix/*` от `develop` с последующим релизом;
пути от `main` нет, он сделал бы `main` не-предком `develop`. Исключение
требует явного решения: `release/hotfix-<name>` от `main`, PR в `main`, тег,
затем merge `main → develop` для восстановления инварианта.
`feat:` повышает minor, `fix:`/`perf:` и прочие разрешённые типы — patch;
`!`/`BREAKING CHANGE:` — major, включая версии до 1.0. `chore(release):`
исключён из рекомендации и changelog. Конфигурация — `.release-it.json`.
В Gitea для `main`/`develop` должны быть запрещены прямой/force push и обход
администратором, обязательны `verify`, `security`, `commits`; теги `v*` защищены.
администратором, включена блокировка устаревшей ветки, обязательны `verify`,
`security`, `commits`; теги `v*` защищены. Линейность обеспечивают merge styles
репозитория: merge-коммиты и rebase `--no-ff` выключены, доступны squash,
rebase-merge и fast-forward-only; стиль по умолчанию — squash.
Workflow сам не включает эти настройки. Отдельное review approval для одного
владельца не требуется. Npm publishing, deploy и Gitea Releases не включены.
@@ -2,7 +2,10 @@
**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).
и дополняет [ADR 018](018-minimal-runtime-coordination.md). Правило «справочные
сведения запрашиваются онлайн» дополнено исключением для сектора и бренда
актива позиции — [ADR
022](022-stored-instrument-classification.md).
## Decision
@@ -0,0 +1,66 @@
# 021. Тихое чтение и редкие подтверждения
**Status:** Accepted. Заменяет manual-refresh часть
[ADR 019](019-hourly-reads-and-online-instrument-reference.md) на стороне
интерфейса и уточняет клиентскую часть
[ADR 007](007-react-query-fetch-policy.md). Не меняет владельцев обновления
и границы чтения из ADR 019.
## Context
Экраны просмотра перекладывали на пользователя контроль над получением данных:
кнопки «Обновить» и «Повторить», индикатор фонового обновления и сообщение
о неудачной синхронизации повторялись в разных разделах. Пользователь приходит
смотреть финансы, а не обслуживать загрузку; восстановление после временного
сбоя не должно зависеть от нажатия кнопки.
При этом состояние самих данных остаётся значимым: время последнего успешного
результата источника, устаревание и исход часовой попытки влияют на доверие
к показанным суммам и не могут быть просто скрыты.
## Decision
- Автоматическое чтение клиента не сообщает о себе. Экраны просмотра не
показывают кнопок ручного обновления и повтора, индикаторов фонового
перечитывания и технических предупреждений о собственном запросе.
- Временные сбои GET восстанавливаются сами: ограниченный срок ожидания запроса
и не более двух повторов с возрастающими паузами, затем возврат к штатной
работе при появлении результата. Пользователь не инициирует восстановление.
- Состояние источника из `meta` остаётся видимым. Время последнего успешного
результата, признак устаревания, исход последней часовой попытки и неполнота
показываются текстом либо доступно именованным элементом, а не только цветом.
Это свойство данных, а не отчёт о техническом процессе, и оно не превращается
в действие пользователя.
- Доступный результат сохраняется при обновлении и временной ошибке. Неполнота
и подтверждённая пустота остаются различимыми: неизвестная сумма не становится
нулём, незавершённый расчёт не выдаётся за окончательный, незагруженный список
не выдаётся за отсутствие записей.
- Первичное ожидание ограничено по времени и показывает структуру будущего
содержимого. По его истечении экран переходит в спокойную локальную
недоступность вместо бесконечной загрузки и сам заменяет её содержимым после
восстановления. Сбой одного блока не скрывает остальные доступные блоки.
- Ошибки явных действий пользователя сохраняются и остаются видимыми. Решение
касается только чтения; отправка формы, изменение данных и сброс фильтра
по-прежнему сообщают результат, в том числе неуспешный.
## Consequences
Пользователь не может ускорить обновление вручную: нормальным владельцем
обновления остаётся часовой обход из ADR 019, и отсутствие кнопки не меняет его
срок. Если источник недоступен долго, экран показывает прежние данные с
обозначением устаревания, а не приглашение повторить.
Автоматический повтор ограничен: он покрывает короткие сетевые сбои, но не
длительную недоступность. Ошибки доступа, домена и отмены не повторяются,
mutations не повторяются вовсе.
Состояние источника и состояние клиентского чтения описывают разные вещи и
не подменяют друг друга. `Portfolio.isStale` сохраняет смысл возраста снимка;
ошибка клиентского перечитывания его не меняет.
Детали поведения — в
[ожидании и восстановлении интерфейса](../architecture/cross-cutting/ui-resilience.md)
и [свежести данных](../architecture/cross-cutting/data-freshness.md).
Согласованные требования принадлежат workspace-спецификациям
`frontend-user-feedback`, `frontend-data-resilience` и
`frontend-loading-presentation`.
@@ -0,0 +1,56 @@
# 022. Хранимая классификация инструментов T-Bank
**Status:** Accepted. Дополняет [ADR
019](019-hourly-reads-and-online-instrument-reference.md) исключением из
правила «справочные сведения запрашиваются онлайн». Решение утверждено
владельцем в [Issue
WealthLedger/main#48](https://git.personal.ksv741.ru/WealthLedger/main/issues/48).
## Context
ADR 019 установил, что справочные сведения инструментов (detail, lookup,
каталоги) запрашиваются онлайн и не сохраняются как долговременный справочник:
«старые справочные строки не являются источником актуальности». Вкладка
«Концентрация» требует для каждой позиции её сектора и эмитента — бренда
актива по данным T-Bank. Сектор есть только в описаниях отдельных типов
инструментов (`share`, `bond`, `etf`), а эмитент — в описании актива по
`asset_uid` инструмента; из названия, тикера, ISIN или `logoName` его вывести
нельзя. Запрашивать эти поля онлайн при каждом открытии экрана нельзя:
ответ Portfolio не ждёт T-Bank, а разрезы должны считаться по уже сохранённому
снимку.
Существующий metadata-кэш (`TbankInstrument`) не подходит: общий ответ
`GetInstrumentBy` не содержит `sector`, а его `brand` — данные логотипа,
а не `{uid, name}` бренда актива.
## Decision
- Сектор и бренд актива позиции хранятся как последнее известное значение в
глобальной таблице `TbankInstrumentClassification` (провайдер, ключ
инструмента, сектор и время его получения, uid актива и uid/название бренда
с временем получения). Данные публичные, без привязки к пользователю или
подключению; ограждение по connection revision к ним не применяется, публикация
Snapshot ограждается как прежде.
- Каждое поле обновляется в часовом обходе при его первой попытке, начавшейся
не ранее чем через 24 часа после последнего успешного получения этого поля;
пока значение не получено, попытка повторяется в каждом обходе. Сектор и
бренд обновляются независимо.
- Неуспешное получение не мешает публикации Portfolio Snapshot и не влияет на
его свежесть; сохранённое значение остаётся доступным. Отказ token
обрабатывается как отказ token при обходе Portfolio. Ответ «инструмент не
найден» сохраняет прежнее значение и перезапускает отсчёт 24 часов.
- Классификация не входит в `meta.dependencies` Portfolio и не меняет
`isStale` и `lastSuccessfulAt`.
## Consequences
- Это первый долговременный справочник T-Bank в системе: ADR 019 теряет
характер «только онлайн» для этой области и дополняется, а не заменяется.
- Разрезы концентрации считаются по снимку без обращений к T-Bank; число
вызовов растёт ограниченно — не более одной попытки на поле в сутки на
позицию, при первом обходе после выката возможен разовый всплеск, сглаженный
общим лимитером и очередью.
- Значение может быть устаревшим до 24 часов; это приемлемо для группировки
позиций, но классификация не является источником актуальных данных брокера.
- Второй потребитель хранимой классификации — условие пересмотра решения
(выделение независимого процесса обновления, отдельные сроки).
+2
View File
@@ -25,3 +25,5 @@
- [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)
- [021 — Тихое чтение и редкие подтверждения](021-quiet-reading-and-rare-confirmations.md)
- [022 — Хранимая классификация инструментов T-Bank](022-stored-instrument-classification.md)
+15 -8
View File
@@ -140,12 +140,20 @@ membership текущей revision перед каждым финансовым
личные данные. Ротация refresh token остаётся атомарной.
SQLite хранит полный последний portfolio, операции и их подтверждённые
диапазоны, private прогнозы, общие instrument/market sources и intent/staging.
диапазоны, private прогнозы, сохранённые точки истории оценки, общие
instrument/market sources, классификацию инструментов (сектор и бренд актива
как последнее известное значение с временем каждого получения,
`TbankInstrumentClassification`) и intent/staging.
Нормализованные финансовые значения сохраняются decimal-строками. Полнота
отделена от свежести и пагинации. Ответ не ждёт внешних RPC; запрос при
необходимости запускает работу в том же backend process через существующий
лимитер. На startup импорт не запускается; восстановление требует следующего
запроса. Подробности — [модель свежести](cross-cutting/data-freshness.md).
отделена от свежести и пагинации. Ответ не ждёт внешних RPC; обновлением
личных данных владеет часовой обход в том же backend process через
существующий лимитер, недостающие общие источники он же ставит в фоновую
очередь. На startup обход начинает следующую попытку по обычному часовому
сроку; после нового подключения первая попытка начинается сразу.
Классификация — публичные данные без привязки к пользователю и подключению;
её поля обновляются в том же обходе не чаще раза в сутки
([ADR 022](../adr/022-stored-instrument-classification.md)).
Подробности — [модель свежести](cross-cutting/data-freshness.md).
PUT подключения сначала проверяет token у T-Bank, затем одной транзакцией
сохраняет encrypted token, новую revision и проверенный membership.
@@ -195,9 +203,8 @@ access token и вращаемый refresh token. [Политика query-кэш
Авторизация доступа, недопущение token в публичный ответ и атомарность
ротации сессии — отдельные свойства; наличие типизированного клиента
не доказывает их. Известное расхождение регистрации отмечено в
[аутентификации](../domains/authentication/overview.md#регистрация-и-вход),
а действующий формат ошибок описан в [HTTP API](http-api.md#error-contract).
не доказывает их. Действующий формат ошибок описан в
[HTTP API](http-api.md#error-contract).
Поддерживается локальный Compose и ограниченная single-server topology с SQLite.
Origin браузера, адрес API и cookie policy должны быть согласованы.
+10 -3
View File
@@ -8,8 +8,12 @@ T-Bank. Нормальным владельцем обновления служ
простоя выполняется не более одна актуальная попытка, а перекрывающийся срок
пропускается, не ставится в очередь. Общие справочные данные инструментов
запрашиваются онлайн, когда это требуется карточке; финансовый HTTP-ответ не
ждёт T-Bank. Модель принята в
[ADR 019](../../adr/019-hourly-reads-and-online-instrument-reference.md).
ждёт T-Bank. Единственное исключение — сектор и бренд актива позиции, которые
хранятся как последнее известное значение с обновлением не чаще раза в сутки;
свежесть и полнота Portfolio от них не зависят. Модель принята в
[ADR 019](../../adr/019-hourly-reads-and-online-instrument-reference.md),
исключение — в
[ADR 022](../../adr/022-stored-instrument-classification.md).
## Клиентский и серверный снимки
@@ -18,7 +22,10 @@ T-Bank. Нормальным владельцем обновления служ
HTTP-перечитывания в той же границе доступа. Это не серверный fallback и не
состояние часового обхода. SQLite независимо от браузера хранит membership,
последний полный portfolio, исполненные операции, прогнозы, общие сведения об
инструментах, котировки, свечи и календари.
инструментах и классификацию инструментов (сектор и бренд актива как
последнее известное значение, [ADR
022](../../adr/022-stored-instrument-classification.md)), котировки, свечи и
календари.
[Полнота периода](../../glossary.md#полнота-истории-счёта) и свежесть различаются.
Успешно проверенный пустой результат полон и доступен; последняя страница
+26 -10
View File
@@ -16,11 +16,17 @@
пока неизвестно, доступен public или protected маршрут. При загрузке
отложенного маршрута уже доступный каркас остаётся видимым.
Фоновое обновление и действие пользователя сохраняют видимые данные или
элемент управления с компактной индикацией процесса. В частности,
Фоновое чтение не сообщает о себе: оно сохраняет видимые данные без индикации
процесса и без технического предупреждения. В частности,
[клиентский снимок](data-freshness.md#клиентский-и-серверный-снимки) счетов или
портфеля остаётся доступным после ошибки refetch; сообщение и повтор
относятся к обновлению, а не к отсутствию инвестиций.
портфеля остаётся доступным после ошибки refetch, и эта ошибка не означает
отсутствие инвестиций. Действие пользователя сохраняет видимые данные или
элемент управления и сообщает свой результат, включая неуспешный.
Первичное ожидание ограничено по времени. По его истечении область переходит
в спокойную локальную недоступность вместо бесконечной загрузки и сама
заменяет её содержимым после восстановления. Решение принято в
[ADR 021](../../adr/021-quiet-reading-and-rare-confirmations.md).
Серверная полнота не выводится из query lifecycle. Missing показывает
skeleton только отсутствующих секций, partial — подтверждённые строки и
@@ -28,20 +34,30 @@ skeleton только отсутствующих секций, partial — по
готовятся независимо. Только complete empty означает отсутствие операций.
Время источника не заменяется временем получения HTTP-ответа.
Ручное обновление сохраняет показанный результат и applied filters; кнопка
недоступна во время уже запрошенной работы. Ошибка transport отличается от
Экраны просмотра не предлагают ручное обновление или повтор чтения: временные
сбои GET восстанавливаются сами ограниченным числом повторов, сохраняя
показанный результат и applied filters. Ошибка transport отличается от
ошибки source work. Status observation прекращается после terminal outcome
или ухода; само истечение TTL не запускает импорт. Известный access loss
очищает personal view, включая защиту от позднего ответа.
Состояние источника при этом видимо: время последнего успешного результата,
устаревание, исход последней часовой попытки и неполнота показаны текстом либо
доступно именованным элементом рядом с данными, к которым относятся. Это
свойство данных, а не отчёт о техническом процессе, и оно не требует действия.
## Известная ошибка сценария
Ошибки счетов, портфеля и подключения T-Bank остаются локальными: рядом
с затронутыми данными доступны предусмотренные сценарием retry и navigation
actions. Устаревший серверный Portfolio Snapshot показывает сохранённый
портфель с предупреждением. Он не превращается в глобальный fallback.
Ошибки счетов, портфеля и подключения T-Bank остаются локальными: затронутый
блок показывает собственное состояние и не скрывает успешно отображённые
соседние блоки. Устаревший серверный Portfolio Snapshot показывает сохранённый
портфель с обозначением устаревания. Он не превращается в глобальный fallback.
Ошибка источника не означает нулевой баланс или отсутствие операций.
Предусмотренные сценарием navigation actions сохраняются: подтверждённая потеря
доступа предлагает восстановить подключение, а `404` — вернуться к списку
счетов. Это навигация и явные действия пользователя, а не повтор чтения.
## Непойманная ошибка маршрута
Непойманная runtime-ошибка при отображении public или protected route
+13 -5
View File
@@ -12,7 +12,7 @@ Development-команды ниже выполняются из workspace с che
- Docker Engine с Compose plugin **не ниже 2.24.4** (`!override` в development),
доступ к registry и достаточно свободного диска для non-root UID 1000.
Production images `0.2.3` опубликованы для Linux amd64.
Опубликованные images собраны для Linux amd64 (см. README комплекта).
Другую архитектуру проверяют отдельно; multi-platform images не обещаны.
- Nexus Docker hosted repository `docker-hosted`, доступный через
`nexus.personal.ksv741.ru/docker-hosted/`. Docker Bearer Token Realm включён;
@@ -26,7 +26,10 @@ Development-команды ниже выполняются из workspace с che
используется сервером для загрузки образов. Для публикации нужны
browse/read/add/edit на `docker-hosted`; фактически выданный набор прав
настраивается в Nexus. Built-in
workflow token не заменяет эту настройку.
workflow token не заменяет эту настройку. Отдельной read-only учётной записи
сервера нет: `wealthledger-ci` работает и как CI writer, и как server reader,
поэтому её пароль на сервере даёт право публикации в `docker-hosted`. Это
принятое владельцем решение; разделение ролей — возможное усиление.
- На сервере Caddy уже завершает TLS и передаёт весь домен на
`127.0.0.1:8080` (или выбранный frontend port). Отдельного `/api` upstream нет.
DNS, TLS, firewall и provisioning Caddy выполняются вне этого runbook.
@@ -81,7 +84,8 @@ Workflow отказывается перезаписывать существу
Выберите опубликованные version tags, выполните pull и сравните OCI revision
с release commit. Выполните smoke с disposable data/config до первого server
rollout. В `release.env` комплекта хранится пара полных image references, например
`nexus.personal.ksv741.ru/docker-hosted/wealthledger/frontend:0.2.3`. Сохраните versions/revisions
`nexus.personal.ksv741.ru/docker-hosted/wealthledger/frontend:1.1.0` и
`.../backend:2.1.0`. Сохраните versions/revisions
в deployment record. Release tags не должны переназначаться другим images.
## Перенос существующих images из Gitea
@@ -91,7 +95,9 @@ rollout. В `release.env` комплекта хранится пара полн
`REGISTRY_USERNAME`/`REGISTRY_TOKEN` сохраните для отката старого workflow.
Пароли вводятся интерактивно или через `--password-stdin`, не через аргументы.
Скопируйте каждый опубликованный release без пересборки. Например, для `0.2.0`
Прежние images лежат в [Gitea packages](https://git.personal.ksv741.ru/WealthLedger/-/packages)
(`git.personal.ksv741.ru/wealthledger/{frontend,backend}`); новые публикуются
только в Nexus. Скопируйте каждый опубликованный release без пересборки. Например, для `0.2.0`
с установленным Skopeo и доступом чтения Gitea/записи Nexus:
```bash
@@ -114,7 +120,9 @@ artifact повторно не публикуйте; несовпадение т
После копирования сравните digests через `skopeo inspect --raw` и SHA-256,
выполните `docker pull` обоих images пользователем `wealthledger-ci` на сервере приложения,
проверьте OCI revision и container smoke на disposable data.
Только после этого меняйте production image references и запускайте обычную
Серверные шаги (login, pull, smoke) в репозитории не подтверждены и
выполняются оператором. Только после них меняйте
production image references и запускайте обычную
последовательность обновления ниже. Старые Gitea packages и references сохраните:
откат registry возвращает прежние адреса тех же artifacts, не восстанавливает
SQLite и не меняет encryption keys. Не переносите Git release tags и не
+11
View File
@@ -61,6 +61,17 @@ Envelope несовместим с прежними bare-array ответами:
поставляются согласованной парой. Финальный artifact передаётся явно;
локальная генерация и CI frontend читают только собственный snapshot.
## Income analytics
`GET /api/v1/brokerage-accounts/{accountId}/income-analytics` и общий маршрут
`all` возвращают результат только выбранного периода: итоги по исходным
валютам, точные записи выплат, разбиение по инструментам и временные
интервалы. Данных сравнения с предыдущим периодом или годом ранее в ответе
нет — ни в теле, ни среди зависимостей `meta.dependencies`, роль которых
ограничена значением `selected`. Публичную машинную схему задаёт
backend-generated OpenAPI; frontend получает её обновлённый snapshot отдельно.
Точную семантику поведения описывает [доход](../domains/income/overview.md).
## Validation и identity
Backend преобразует и проверяет входные данные на общей HTTP-границе.
+6 -5
View File
@@ -62,8 +62,8 @@
- `409 TBANK_NOT_CONNECTED`: список не запрашивается у T-Bank, экран ведёт в настройки.
- `400 INVALID_TBANK_TOKEN`: сохранённый токен не удаляется, экран ведёт в настройки для замены или удаления.
- `503 TBANK_UNAVAILABLE`: экран предлагает повторить загрузку или открыть настройки.
- Неизвестная ошибка: экран предлагает только повторить загрузку.
- `503 TBANK_UNAVAILABLE`: экран показывает спокойное состояние недоступности; чтение возобновляется автоматически.
- Неизвестная ошибка: то же состояние недоступности без действия повтора.
- Успешный пустой ответ: штатное состояние отсутствия инвестиционных счетов.
Карточка ведёт на `/accounts/:accountId` по всей области и доступна с клавиатуры. Карточки расположены в одну колонку при любой ширине. Карточка показывает название, локализованный тип, крупный валютный итог и вторую валюту при наличии, число остальных валют, дату открытия без времени и видимое действие открытия. Отдельные цветные блоки «Акции» и «Облигации» показывают количество наименований бумаг. Недоступная или пустая сводка отображается локально; отсутствие сумм не скрывает известные количества бумаг, а недоступная сводка не подменяет их нулями. Наведение и видимый клавиатурный фокус подчёркивают переход; настройка уменьшения движения отключает анимацию.
@@ -71,9 +71,10 @@
## Свежесть и границы
Обычное открытие использует query owner и локальный server snapshot.
«Обновить» запрашивает membership и сводки доступных счетов; активная работа
наблюдается без нового импорта. Истечение TTL само не запускает запрос.
Membership имеет пятиминутную свежесть, portfolio — минутную. Время списка
«Обновить» перечитывает сохранённые membership и сводки доступных счетов;
активная работа наблюдается без нового импорта. Истечение TTL само не
запускает запрос: обновлением личных данных владеет часовой обход.
Membership и portfolio source имеют часовую свежесть. Время списка
не подменяет время каждой сводки. Список не заменяет полный
[портфель](../portfolio/overview.md), [журнал](../operations/overview.md)
или историю закрытых счетов. Для общего результата доступен
+13 -7
View File
@@ -11,14 +11,20 @@
Пользователь регистрируется или входит по email и паролю. Регистрация сразу
создаёт первую сессию. Внешние пробелы email удаляются, буквы приводятся
к нижнему регистру. Backend требует пароль не короче 12 символов и не длиннее
72 UTF-8 байтов.
к нижнему регистру.
**Известное расхождение:** сохранённое требование регистрации и проверка
в форме frontend считают нижнюю границу в UTF-8 байтах, а backend — в символах.
Не-ASCII пароль может пройти форму и получить отказ API. Это не принятое
изменение password policy; требуется отдельное согласованное решение
о проверке пароля и подтверждение полного HTTP-потока.
Пароль при регистрации — от 8 до 72 печатных ASCII-символов: латинские
буквы, цифры, спецсимволы и пробел. Кириллица, emoji, другие не-ASCII и
управляющие символы отклоняются. Пароль не обрезается и не нормализуется, а
обязательных классов символов нет. Верхняя граница вытекает из bcrypt, который
учитывает только первые 72 байта: для ASCII символ равен байту, поэтому
длинный пароль не обрезается молча. Frontend и backend проверяют одну и ту же
политику.
При входе проверяется только то, что пароль непустой и не длиннее 72 UTF-8
байтов. Минимум и набор символов не применяются, чтобы пользователь,
зарегистрированный по прежним правилам (в том числе с не-ASCII паролем), мог
войти. Невалидный пароль получает `400` с кодом `VALIDATION_ERROR`.
Access token действует 15 минут и хранится только в памяти браузера.
Refresh token имеет серверный срок 7 дней, заменяется при восстановлении
+14 -29
View File
@@ -4,7 +4,7 @@
купонами и дивидендами за выбранный период». Пользователь открывает
`/accounts/:accountId/income` из обзора счёта или
[общий доход](../portfolio/all-accounts.md) по доступным счетам.
Экран показывает итоги по валютам, сравнение и отдельную карточку каждой
Экран показывает итоги по валютам и отдельную карточку каждой
включённой выплаты. Источником служат [исполненные операции](../operations/overview.md),
а не изменение цены портфеля и не календарь будущих выплат.
@@ -38,11 +38,12 @@
При первой загрузке или новом периоде без сохранённых данных показан
каркас страницы. Пустой результат объясняет отсутствие исполненных купонов и
дивидендов, сохраняя фильтры, налоговое пояснение и сравнения. Ошибка запроса
или нарушение принадлежности выплат даёт локальное состояние с действием «Повторить».
дивидендов, сохраняя фильтры и налоговое пояснение. Ошибка запроса
или нарушение принадлежности выплат даёт локальное состояние недоступности
без действия повтора; чтение восстанавливается автоматически.
При фоновом обновлении того же периода сохранённый ответ и черновик
остаются видимыми: загрузку обозначает индикатор, неуспешное обновление —
предупреждение с повторной попыткой.
остаются видимыми без индикации обновления и технического предупреждения.
Неполнота применённого периода обозначается состоянием самого результата.
На узком экране поля и действия идут вертикально; все карточки выплат
остаются в общем потоке страницы без раскрытия или внутренних областей прокрутки.
@@ -51,32 +52,15 @@
- Backend проверяет доступ локально и читает сохранённые операции. Фоновая загрузка должна завершить все страницы; ошибка страницы или повреждённая цепочка курсоров не подтверждают полноту.
- Только точные типы купона и дивиденда источника формируют результат. Суммы остаются точными десятичными строками в исходной валюте; отрицательные корректировки сохраняют знак. Налоги, комиссии, сделки, переводы, погашения и переводы дивидендов не входят в доход.
- Итоги, сравнения, временные интервалы и разбиение по инструментам не смешивают валюты и не создают общий конвертированный итог. Страница показывает сравнения с предыдущим периодом и годом ранее, когда календарная дата и история счёта позволяют. Неполное сравнение имеет отдельное сообщение, без нулевой базы.
- Итоги, временные интервалы и разбиение по инструментам не смешивают валюты и не создают общий конвертированный итог. Система не загружает другие периоды ради сравнения полученного дохода с выбранным.
- Временные интервалы по-прежнему приходят с backend: дни для 1–45 дней, недели для 46–180 и месяцы для более длинного периода, включая пустые интервалы. Страница дохода не строит из них график или текстовую динамику; ответ API не меняется.
- Раздел «Выплаты» показывает единый список карточек выплат в исходном порядке `entries`: одна карточка на каждую выплату. Внешних групп по инструментам или валютам, итогов и количества выплат инструмента нет. Описание, дата, доступные идентификаторы инструмента и сумма со знаком видны в каждой карточке; валюты по-прежнему разделены в итогах и сравнениях. Дополнительный запрос за составом не нужен.
Сравнение с непосредственно предыдущим периодом использует предыдущий полный
месяц для полного выбранного месяца, иначе — непосредственно предшествующий
интервал той же включительной длительности. Оно не подменяет сравнение годом
ранее. Незагруженное сравнение и ошибка его источника отличаются от
недоступности годового сравнения по календарю или дате открытия счёта.
Каждый раздел сравнения показывает цветные панели без общей белой подложки и
внутренних отступов у внешнего блока. Точные периоды показаны в заголовках двух панелей с русским форматом диапазона
и UTC для календарных дат.
Отдельного заголовка с датами и валютного бейджа нет; валюта остаётся у каждой суммы.
Панель «Разница» сохраняет серверную абсолютную разницу и дополняет итог, купоны
и дивиденды процентом: абсолютная разница / сумма годом ранее × 100.
Это округлённый показатель для отображения, а не пересчёт Money или инвестиционная
доходность. Форматирование сохраняет знак и не более одного десятичного разряда.
При нулевой или отрицательной базе либо непредставимом числовом отношении
процентный бейдж не отображается; абсолютная разница остаётся видимой.
- Раздел «Выплаты» показывает карточки выплат в исходном порядке `entries`. В отдельном счёте каждая выплата — отдельная карточка. В режиме «Все счета» выплаты одного инструмента, дня и точного типа образуют группу, если их две и более ([правила группировки](../operations/overview.md#группировка-в-режиме-все-счета)). Группа стоит на месте первой выплаты; каждая строка счёта показывает название счёта и свою сумму со знаком. Визуальный итог группы — точная сумма по валютам по показанным выплатам; он скрыт, если полнота периода не `complete`, или у выплаты нет суммы, или сумма равна нулю. Это клиентский расчёт и не заменяет серверные итоги аналитики дохода, которые по-прежнему приходят из ответа API и не пересчитываются. Описание, дата, доступные идентификаторы инструмента и сумма со знаком видны в каждой выплате. Дополнительный запрос за составом не нужен.
## Полнота и принадлежность выплат
Доходы читают сохранённые операции и coverage в согласованной транзакции.
Selected, previous и yearAgo имеют независимую готовность. Неполный selected
не получает окончательных итогов; неполное сравнение не создаёт нулевую базу.
Только выбранный период определяет готовность результата. Неполный период
не получает окончательных итогов.
Подтверждённый пустой период отличается от ещё не загруженного. При смене
периода прежний snapshot не показывается под новым названием.
@@ -96,18 +80,19 @@ Backend обеспечивает принадлежность выплат, ва
доверяет типизированному contract, не восстанавливает формулу идентификации
и не выполняет второй consistency validator. Полностью пустой ответ допустим.
Состав и исходный серверный порядок записей и знак сумм
сохраняются, frontend не пересчитывает денежные итоги. Стабильный ID в пределах подключения и счёта определяет одну операцию:
сохраняются; серверные денежные итоги frontend не пересчитывает (визуальный итог группы в режиме «Все счета» отдельный, см. выше). Стабильный ID в пределах подключения и счёта определяет одну операцию:
повторная сверка обновляет её без двойного учёта. Одинаковые ID разных счетов
остаются разными выплатами. Изменение источника логотипа позволяет заново
показать изображение после буквенной заглушки.
## Будущие события и ограничения
На странице дохода нет блоков «Динамика» и «Ближайший прогноз». Она не запрашивает
На странице дохода нет блоков «Динамика» и «Ближайший прогноз», блоков
сравнения периодов и сообщений об их недоступности. Она не запрашивает
`/events` и не зависит от его доступности. Самостоятельная страница
[«Будущие события»](upcoming-events.md) по-прежнему доступна из обзора
выбранного счёта и сохраняет прежнее поведение. Будущие выплаты
не включаются в итоги полученного дохода или сравнения.
не включаются в итоги полученного дохода.
Аналитика читает сохранённую историю операций и не рассчитывает налоги, инвестиционную эффективность, доходность, валютную конвертацию или общий мультивалютный итог.
+26 -7
View File
@@ -39,13 +39,23 @@
## Период и список
Без фильтра период начинается сегодня в UTC и заканчивается через 30 дней
после начала, обе даты включены. `from` и `to` принимают только строгие даты
`YYYY-MM-DD`; без `from` используется текущая дата UTC, без `to` — `from + 30`
календарных дней. Поля «С» и «По» сохраняют выбранные календарные даты в URL,
а «Сбросить» возвращает период по умолчанию.
Без фильтра страница применяет период по умолчанию из семи календарных
дат включительно: сегодняшней и шести следующих календарных дней. API при
отсутствии параметров использует своё окно (от текущей даты UTC до `from + 30`
календарных дней), обе даты включены; `from` и `to` принимают только строгие
даты `YYYY-MM-DD`. Календарь фильтра разрешает выбор сегодняшней и будущих дат
и не позволяет выбрать даты раньше сегодняшней. Прямая ссылка с валидным
прошедшим периодом сохраняет указанные даты без замены; некорректный формат,
несуществующая календарная дата или обратный диапазон нормализуются к периоду
по умолчанию с удалением параметров из URL. Поля «С» и «По» сохраняют
выбранные календарные даты в URL, а «Сбросить» возвращает период по умолчанию.
События упорядочены по календарной дате. У каждой строки видны тип,
События упорядочены по календарной дате. Купоны и дивиденды показываются
единым предметным представлением выплаты с явной пометкой прогноза — тем же,
что у исполненных выплат в доходе и журнале; неизвестная сумма остаётся
«сумма неизвестна» и не превращается в ноль или полученные деньги.
Дата дивиденда обозначена как дата реестра. Offer и погашение сохраняют своё
значение без суммы выплаты. У каждой строки видны тип,
инструмент, дата и доступная сумма в исходной валюте. Список не имеет
пагинации и не конвертирует валюты. Пустой результат означает отсутствие
известных поддерживаемых событий в выбранном окне, а не доказательство
@@ -61,7 +71,16 @@
без замены периода и без запуска личной работы.
Фильтрация на сервере предшествует сортировке и вычислению
`incomeTotalsByCurrency`, включающего только купоны и дивиденды.
Итоги остаются в ответе API; полный экран показывает список без общего итога.
Итоги остаются в ответе API; полный экран показывает список без общего итога списка.
В режиме «Все счета» события одного инструмента, даты, точного типа и `dateKind` образуют
группу, если их две и более, в том числе одного счёта. Ключ дополнительно включает `dateKind`,
поэтому дата реестра дивиденда и иная дата того же инструмента не объединяются. Группа стоит на месте первого
события. Полный список группирует все полученные события; превью обзора сначала берёт пять
событий и группирует только их. Каждая строка счёта остаётся отдельной и показывает название
счёта и свою прогнозную сумму. Визуальный итог группы — точная сумма по валютам; он показывается
только если полнота прогноза `complete` и у каждого события группы известна прогнозная сумма.
Иначе итог скрыт, а строки остаются. Этот итог не равен итогам ответа API и не относится к полученному доходу.
## Получение и отказы
+12 -7
View File
@@ -89,7 +89,11 @@ HTML-источник, общий кэш и поведение при измен
Календарь охватывает пять прошлых лет и следующий год. Будущие купоны
сортируются по дате выплаты, прошедшие и недатированные доступны отдельно.
Показаны сумма на облигацию, номер, тип, длительность периода и дата реестра,
Будущие и прошедшие события купонного графика показываются единым предметным
представлением выплаты с пометкой события по графику — тем же, что у
исполненных выплат и прогноза; исполнение подтверждает только личная история.
Показаны сумма на облигацию, отдельная личная оценка, номер, тип, длительность
периода и дата реестра,
если они известны. Неопределённый будущий купон не заменяется нулём.
Личная оценка доступна только при положительных позициях, известной сумме,
@@ -117,8 +121,8 @@ HTML-источник, общий кэш и поведение при измен
portfolio; они не попадают в общие источники.
BondBy переиспользуется зависимостями выпуска. Discovery принадлежит query,
свежесть — конкретному source/range. Missing/stale зависимости запрашиваются
в фоне через прежний limiter; обычный HTTP-ответ не ждёт брокера.
свежесть — конкретному source/range. Missing/stale зависимости ставятся
в фоновую очередь через прежний limiter; обычный HTTP-ответ не ждёт брокера.
Покрытые завершённые свечи не перечитываются после restart. Открытый хвост
остаётся изменяемым; ручной refresh охватывает показанный период.
@@ -127,7 +131,8 @@ BondBy переиспользуется зависимостями выпуск
выплат. Наблюдение статуса не запускает повторный импорт. Политика источников
и границы — в [модели свежести](../../architecture/cross-cutting/data-freshness.md).
Разделы загружаются независимо, показывают каркас загрузки и локальную повторную попытку.
Разделы загружаются независимо, показывают каркас загрузки и локальное
спокойное состояние недоступности без действия повтора.
Ошибка фонового обновления сохраняет последние данные. Смена подключения
сбрасывает поддерево клиентских запросов облигаций вместе с остальными финансовыми запросами;
выход очищает кэш сессии. Общие график, позиция и личные события
@@ -146,6 +151,6 @@ BondBy переиспользуется зависимостями выпуск
## 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.
Страница облигации, поиск и переход по тикеру обращаются к онлайн-справочнику
брокера; сохранённые quotes, свечи, события, ratings и метки портфеля
сохраняют собственные границы свежести и ошибок.
+20 -13
View File
@@ -42,7 +42,8 @@
время получения списка. Изменение условий не заменяет текущий список до
следующего нажатия «Найти». Повторный поиск получает новый каталог; страницы
одного результата не пересчитываются. Подтверждённый пустой результат отличается
от ошибки источника, для которой интерфейс предлагает повторить поиск.
от ошибки источника: она сообщается рядом с полем поиска, а повторить запрос
пользователь может обычным «Найти» — отдельного действия повтора чтения нет.
Ссылка карточки принадлежит выбранному UID; данные разных режимов не смешиваются.
Прямые ссылки из портфеля сохраняют
@@ -63,8 +64,9 @@
рыночные данные и личная история остаются доступны.
Каждый раздел загружается независимо. Первичная загрузка показывает каркас
раздела, ошибка — локальную повторную попытку. При ошибке фонового обновления
сохраняются предыдущие данные и предупреждение. Цена содержит собственное время
раздела, затянувшаяся недоступность — локальное спокойное состояние без
повторной попытки. При ошибке фонового обновления сохраняются предыдущие
данные без технического предупреждения. Цена содержит собственное время
UTC, которое может быть старше времени получения ответа. Статус торгов не
выводится из свежести цены. Отсутствующее значение не заменяется нулём.
@@ -124,7 +126,11 @@ UID включён в ключ кэша и подпись общего курс
## Дивиденды и финансовые показатели
События компании отделены от личных зачислений. Известные будущие выплаты
События компании отделены от личных зачислений. Будущие и прошедшие события
дивидендного графика показываются единым предметным представлением выплаты
с пометкой «событие по графику» — тем же, что у исполненных выплат и прогноза;
сумма на акцию, отдельная личная оценка и дата реестра сохраняют свои подписи
и не выдаются за личное зачисление. Известные будущие выплаты
определяются по `paymentDate`, при её отсутствии — по `recordDate`; прошедшие
и недатированные события помещены в отдельную историю компании. Отменённые
события исключаются. Личная оценка умножает сумму на акцию на текущее положительное
@@ -155,14 +161,16 @@ TTM означает последние 12 месяцев, MRQ — послед
источники переиспользуются между пользователями, но личные позиции и выплаты
всегда проверяют доступ.
Обычное чтение не ждёт RPC; missing/stale зависимости запрашиваются в фоне
через существующий T-Bank limiter. Минутная свежесть применяется к quotes
и открытому хвосту свечей, суточная — к metadata/company/календарям.
Обычное чтение не ждёт RPC; missing/stale зависимости ставятся в фоновую
очередь через существующий T-Bank limiter. Часовая свежесть применяется
к quotes и открытому хвосту свечей; metadata/company/календари, будучи
сохранёнными, не перечитываются обычным чтением.
Закрытые полные свечные интервалы, включая пустые, сохраняются после restart.
Новый день не делает прежнюю незавершённую свечу полной.
«Обновить» передаёт текущий инструмент, выбранный график и personal-history
scope. Частичные строки видны с предупреждением; неполные личные оценки
Отдельного действия «Обновить» на странице нет: чтение текущего инструмента,
выбранного графика и personal-history scope выполняется автоматически.
Частичные строки видны с обозначением неполноты; неполные личные оценки
не становятся нулями. Статус и `sync=observe` не создают новый импорт.
Смена подключения и известный access loss очищают личное представление;
поздние ответы не возвращают прежние данные. Детали —
@@ -193,7 +201,6 @@ scope. Частичные строки видны с предупреждени
## 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.
Страница акции, поиск и переход по тикеру обращаются к онлайн-справочнику
брокера; сохранённые позиции, quotes, свечи и события остаются независимыми
локальными ресурсами и не подменяются ошибкой справочника.
+25 -5
View File
@@ -13,9 +13,27 @@
Исполненная операция содержит тип события, его категорию, описание,
момент совершения, доступные сведения об инструменте и денежное движение.
Запросы отменённых или ожидающих исполнения поручений не образуют этот журнал.
Суммы остаются точными десятичными строками в исходной валюте; frontend
только форматирует их. Положительное и отрицательное движение сохраняют
знак. Отсутствие `payment` означает «Без движения денег», а не нулевую сумму.
Суммы остаются точными десятичными строками в исходной валюте. Frontend
форматирует их и считает визуальный итог группы по показанным записям
(см. [группировку](#группировка-в-режиме-все-счета)). Положительное и отрицательное
движение сохраняют знак. Отсутствие `payment` означает «Без движения денег», а не нулевую сумму.
## Группировка в режиме «Все счета»
Только в режиме `all` записи журнала и превью обзора, которые относятся к одному
дню экрана, одному инструменту и точному типу операции, объединяются в группу.
Ключом служат день, `instrumentUid` (иначе `figi`) и тип; группа образуется при
двух и более записях, в том числе одного счёта. Группа стоит на месте первой записи.
Каждая запись остаётся отдельной строкой с названием счёта простым текстом и своей суммой.
Одиночный счёт не группируется.
Группировка выполняется после лимита: превью обзора сначала берёт пять записей,
затем группирует только их. Полный журнал группирует страницу, уже загруженную
курсором; группы не переносятся между страницами. Курсор и порядок записей не меняются.
Итог группы — точная сумма по каждой валюте, без конвертации. Он показывается только
если полнота журнала `complete`, у каждой записи группы есть `payment`, и ни одна сумма
не равна нулю. Иначе итог скрыт, а строки счетов остаются.
Категории объединяют разные события для фильтрации: сделка (`trade`),
доход (`income`), налог (`tax`), комиссия (`fee`), перевод (`transfer`)
@@ -84,8 +102,10 @@ Coverage/status без изменения rowset cursor не ломают. Пе
Полный журнал и превью используют одинаковую компактную строку: логотип
или буквенная заглушка, описание, дата, инструмент и денежное движение.
Для купона и дивиденда денежная метка называет точное событие; для прочих
операций — категорию. Она показывается один раз, без повтора рядом с датой.
Исполненные купоны и дивиденды показываются единым предметным представлением
выплаты — тем же, что на странице дохода, в прогнозе и графиках инструментов;
денежная метка называет точное исполненное событие. Для прочих
операций метка называет категорию. Она показывается один раз, без повтора рядом с датой.
Знак и цвет обозначают направление денег; отсутствие движения нейтрально.
Если описание отсутствует, показывается локализованный тип операции.
+10 -7
View File
@@ -53,13 +53,10 @@ Backend публикует статические маршруты под `/api/
- Журнал объединяет операции по убыванию времени, при равном времени использует
порядок идентификаторов счетов и операций. ID
операций разных счетов не считаются дублями. Переводы не схлопываются.
- Доходы рассчитываются из согласованной локальной выборки операций за общие периоды.
Итоги, сравнения, временные интервалы и принадлежность выплат рассчитывает
сервис дохода.
Для сравнения с годом ранее используется текущий состав счетов; новый счёт
добавляет только реально полученные выплаты. При известных датах открытия всех счетов
доступность сравнения определяется самым ранним открытием в этом составе.
Закрытые счета в историческое сравнение не добавляются.
- Доходы собираются из всех страниц операций каждого счёта за выбранный период.
Итоги, временные интервалы и принадлежность выплат рассчитывает
сервис дохода. Данные сравнения периодов не загружаются и не возвращаются;
состав счетов влияет только на фактические выплаты выбранного периода.
- Будущие события сортируются по дате и сохраняют отдельную строку каждого счёта.
Прогноз не включается в реализованные доходы.
@@ -84,6 +81,12 @@ Backend публикует статические маршруты под `/api/
применённые фильтры. Coverage/status без изменения строк не ломают cursor.
Продолжение не зависит от RAM-кэша или перезапуска.
Визуальная группировка строк одного инструмента в общих списках выполняется только
в пределах уже полученного списка: в журнале — на загруженной странице, без переноса группы
на следующую; в полном списке будущих событий и выплатах дохода — по всем полученным строкам
периода. Группировка не меняет порядок, cursor или ответ API. Протокол курсора прежний.
Правила группировки — в [журнале](../operations/overview.md#группировка-в-режиме-все-счета).
Повторная сверка полного показанного периода публикует все счета и интервалы
одной транзакцией; успешное первое окно не смешивается с прежними остальными.
Подробнее — [журнал](../operations/overview.md#получение-и-полнота).
+81
View File
@@ -0,0 +1,81 @@
# Концентрация портфеля
Вкладка «Концентрация» на странице счёта `/accounts/:accountId` показывает,
какие акции, облигации, секторы и эмитенты занимают наибольшую часть текущей
оценки Portfolio. Она отвечает на вопрос «где сконцентрированы деньги»,
который не решают карточки позиций и [структура
активов](overview.md#как-читать-экран). Точный смысл полей и долей — в
[справочнике данных](data-reference.md).
## Вкладка и разрезы
Вкладка есть только у отдельного счёта: в режиме [«Все счета»](all-accounts.md)
её нет. Появление вкладки не меняет вкладку, открытую по умолчанию («Позиции»),
и содержание остальных вкладок. Пока Portfolio загружается, при его ошибке или
штатном пустом составе вкладки нет; при Portfolio хотя бы с одной позицией или
денежным остатком вкладка показывается.
Вкладка содержит четыре разреза и показывает один из них одновременно:
| Разрез | Что ранжирует | Типы позиций |
| --- | --- | --- |
| «Акции» | Пять крупнейших позиций акций | `STOCK` |
| «Облигации» | Пять крупнейших позиций облигаций | `BOND` |
| «Секторы» | Пять крупнейших секторов по данным T-Bank | `STOCK`, `BOND`, `FUND` |
| «Эмитенты» | Пять крупнейших эмитентов (брендов актива) | `STOCK`, `BOND` |
Фонды участвуют только в разрезе «Секторы»: их эмитент — управляющая компания,
а не компания внутри фонда. Позиции типов `CURRENCY`, `FUTURE`, `OPTION`,
`STRUCTURED_NOTE`, `DIGITAL_FINANCIAL_ASSET` и `OTHER` во вкладку не входят.
Позиции без сектора образуют явную группу «Сектор не указан», без бренда —
«Эмитент не указан»; обе группы показываются с видимой долей. Государственные
облигации определяются значением сектора T-Bank `government` с подписью
«Государственный сектор»; других собственных классификаций WealthLedger
не вводит. Название элемента в разрезе эмитентов — название бренда; если у
одного бренда разные названия, показывается название позиции с наибольшей
стоимостью.
## Топ-5 и «Прочее»
В каждом разрезе показаны пять крупнейших элементов по текущей денежной оценке,
каждый с суммой и долей. Рядом показан суммарный показатель «Топ-5 · N %».
Если в разрезе семь и более элементов, все остальные объединены в одну строку
«Прочее» с числом элементов, суммой и долей. При шести и меньшем числе
элементов каждый показан своей строкой. По нажатию на «Прочее» раскрывается
полный перечень остальных элементов, каждый со своей суммой и долей; топ-5
и диаграмма при этом не меняются.
Доли считаются от суммы стоимостей позиций разреза в выбранной валюте и
в сумме дают ровно 100 %; округление — до десятой доли процента, очень малые
доли показываются как «< 0,1 %». Отрицательные и нулевые стоимости, а также
позиции без оценки в разрез не входят. Конвертации валют нет: каждая позиция
входит только в валюту своей оценки.
## Валюта
У вкладки свой список валют — валюты оценок позиций акций, облигаций и фондов,
отсортированные по ISO-коду, — и свой выбор, независимый от «Структуры
портфеля». По умолчанию выбрана первая валюта списка. При одной валюте
переключатель не показывается. Общего итога по нескольким валютам нет.
Выбранные разрез и валюта сохраняются, пока пользователь остаётся на странице
счёта, включая переключение её вкладок, и сбрасываются при новом заходе и при
смене счёта.
## Диаграмма и неполные данные
Рядом с перечнем показана кольцевая диаграмма, согласованная с перечнем;
информация передаётся не только цветом, есть текстовый эквивалент. Если ответ
отмечен как неполный (`completeness: "incomplete"` — часть позиций не имеет
оценки), над разрезом появляется предупреждение «Данные неполные», а под
списком — сноска «Не учтено позиций: N» с числом позиций, не вошедших в разрез.
Пустой разрез (нет позиций с положительной оценкой в выбранной валюте)
показывает текстовое состояние вместо диаграммы.
## Откуда берутся сектор и эмитент
Сектор и эмитент — часть данных Portfolio: их получает backend в часовом
обходе и сохраняет в снимке вместе с остальными полями позиций
([поток загрузки](flows/portfolio-loading.md#обновление-сектора-и-эмитента),
[интеграция T-Bank](../../integrations/tbank.md)). Вкладка считается по уже
загруженному снимку и не обращается к T-Bank.
+5 -1
View File
@@ -32,7 +32,9 @@
| Cash Balance | Суммы из `GetPositions.money`, объединённые по валюте | Заблокированные деньги не прибавляются; торгуемый инструмент `CURRENCY` остаётся позицией |
| `totalsByCurrency` | Стоимости позиций + доступные деньги той же валюты | Не включает невычислимую стоимость; не обещает полную оценку портфеля |
| `lastSuccessfulAt` | Время формирования успешного снимка, UTC | Не является временем каждой котировки; запасной снимок сохраняет исходное время |
| `isStale` | Истёк минутный срок свежести сохранённого portfolio source | Не описывает состояние клиентского кэша или ошибку фонового запроса |
| `isStale` | Истёк часовой срок свежести сохранённого portfolio source | Не описывает состояние клиентского кэша или ошибку фонового запроса |
| `sector` | Сектор инструмента в том виде, как его определяет T-Bank, с обрезанными пробелами | Только для позиций `STOCK`, `BOND` и `FUND`; значение из одних пробел считается отсутствующим. Во всех остальных случаях — `null` |
| `issuer` | Бренд актива инструмента по данным T-Bank: `{ id, name }` | Только для позиций `STOCK`, `BOND` и `FUND`, когда у актива известны uid и название бренда. Во всех остальных случаях — `null`. Не влияет на количество, стоимость и свежесть снимка; используется вкладкой [«Концентрация»](concentration.md) |
Ненулевые денежные остатки одной валюты суммируются. Позиции одинаковых
инструментов в ответе отдельного счёта не объединяются; визуальная группировка
@@ -58,6 +60,8 @@ ISIN, тикер и `logoName` могут быть `null`. `logoName` — имя
или метаданных не меняет количество, суммы и свежесть снимка и не скрывает
финансовые данные. Metadata обновляется независимо; отсутствие имени не задерживает выдачу
финансового снимка и оставляет доступный идентификатор.
`logoName` не равен эмитенту из вкладки «Концентрация»: он берётся из metadata
инструмента, а эмитент — из [классификации инструмента](flows/portfolio-loading.md#обновление-сектора-и-эмитента).
## Структура и доли
+22 -3
View File
@@ -11,9 +11,28 @@
они не ждут и не вызывают T-Bank и не предлагают ручную синхронизацию. Часовой
обход текущего подключения обновляет Portfolio независимо от экрана. Для нового
полного snapshot ему нужны оба финансовых ответа `GetPortfolio` и
`GetPositions`; суммы и позиции публикуются вместе. Metadata инструмента
дополняет представление независимо, с доступным UID/FIGI вместо имени до её
онлайн-загрузки.
`GetPositions`; суммы и позиции публикуются вместе. Metadata инструмента и
классификация (сектор и эмитент) дополняют представление независимо,
с доступным UID/FIGI вместо имени до их загрузки.
## Обновление сектора и эмитента
Часовой обход также обновляет сектор и эмитента позиций типов `share`, `bond`
и `etf`. Значения хранятся как последнее известное ([ADR
022](../../../adr/022-stored-instrument-classification.md)): сектор — как его
определяет T-Bank, эмитент — бренд актива (`uid` и `name`). Каждое поле
обновляется при первом обходе, начавшемся не ранее чем через 24 часа после его
последнего успешного получения; пока значение не получено, попытка повторяется
в каждом обходе. Сектор и эмитент обновляются независимо.
Неуспешное получение не мешает публикации snapshot и не меняет
`lastSuccessfulAt` и `isStale`; сохранённое значение остаётся доступным.
Исключение — отказ token: он обрабатывается так же, как отказ token при
обходе Portfolio. Инструмент ищется по UID, затем по FIGI; ответ «не найдено»
сохраняет прежнее значение и отсчёт 24 часов начинается заново. Позиции без
полученных значений участвуют в разрезах вкладки
[«Концентрация»](../concentration.md) как «Сектор не указан» и
«Эмитент не указан».
Открытый экран выполняет локальное перечитывание не чаще одного раза в
30 минут; retry также повторяет только HTTP GET. `data: null` означает, что
@@ -12,11 +12,12 @@
величины. Убедитесь, что сравниваемые значения относятся к одному составу
счетов и инструменту. Название или тикер сами по себе не доказывают
совпадение выпуска; используйте доступные UID, FIGI и ISIN.
2. **Сопоставьте время.** Проверьте `lastSuccessfulAt`, `isStale` и наличие
предупреждения о клиентском обновлении. Серверный снимок не обещает время
2. **Сопоставьте время.** Проверьте `lastSuccessfulAt`, `isStale` и показанный
исход последней часовой попытки. Серверный снимок не обещает время
каждой котировки, а общий портфель может соединять разные моменты.
Если запрос завершился ошибкой, доступное действие «Повторить» должно
обновить результат или оставить объяснимую ошибку. Перезагрузка backend
Действия «Повторить» на экране нет: временный сбой чтения восстанавливается
автоматически, поэтому расхождение проверяйте по показанному состоянию
источника, а не по результату ручного обновления. Перезагрузка backend
сохраняет последний полный снимок в SQLite, но не создаёт историю стоимости.
3. **Проверьте состав суммы.** Для одной валюты итог складывается из
вычислимых стоимостей позиций и доступных денег. Не добавляйте деньги
+19 -10
View File
@@ -64,6 +64,10 @@ Backend получает данные через серверную
без логотипа и с подписью результата. Отсутствующие показатели скрываются,
а не подменяются нулём или заглушкой.
Рядом с вкладкой «Позиции» на странице отдельного счёта есть вкладка
[«Концентрация»](concentration.md): она показывает, где сконцентрированы
деньги — крупнейшие бумаги, секторы и эмитенты. В режиме «Все счета» её нет.
Существует расхождение: [согласованная спецификация представления позиций](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-представление-карточек-позиций-на-клиенте)
требует доступности всех иных типов в отдельной секции, а текущие frontend
и его проверка исключают `CURRENCY` только из списка карточек. Такие позиции
@@ -79,18 +83,23 @@ Backend получает данные через серверную
не содержат данных и не получают фокус. При обычном фоновом обновлении
сохраняются предыдущие суммы и время успешного получения в UTC.
Серверный `isStale` обозначает истечение минутной свежести снимка.
Клиентское предупреждение означает неудачную попытку обновить уже показанный
ответ. Эти состояния независимы и могут появиться одновременно.
Успешный повторный запрос обновляет суммы и время, снимает клиентскую ошибку;
серверное предупреждение определяется новым `isStale`.
Серверный `isStale` обозначает возраст снимка старше часа: обновлением
владеет часовой обход, а не запрос экрана. Он показывается рядом с суммами
вместе с временем последнего успешного результата и исходом последней часовой
попытки. Неудачная попытка клиента обновить уже показанный ответ о себе не
сообщает: эти состояния независимы, но пользователю видимо только состояние
источника. Успешное автоматическое перечитывание обновляет суммы и время;
обозначение устаревания определяется новым `isStale`.
Правила времени и ошибок приведены в [потоке загрузки](flows/portfolio-loading.md).
В текущем решении нет долговременной истории снимков, графиков стоимости
портфеля, валютной конвертации, учёта виртуальных позиций или заблокированных
средств. Последний полный снимок сохраняется после перезапуска; выполнение
синхронизации рассчитано на один экземпляр backend. Действие «Обновить»
перечитывает зависимости открытого экрана независимо от их свежести.
Отдельного чтения истории стоимости нет, но каждый полный снимок
сохраняет точку оценки по счёту и валюте для будущих поддерживаемых
представлений; публичного графика в текущем решении нет. Нет также
валютной конвертации, учёта виртуальных позиций или заблокированных
средств. Последний полный снимок сохраняется после перезапуска;
обновлением личных данных владеет часовой обход, рассчитанный на один
экземпляр backend. Действие «Обновить» выполняет только локальное
перечитывание открытого экрана и не запускает работу с T-Bank.
Для проверки конкретной суммы используйте
[руководство по расхождениям](how-to/investigate-discrepancy.md).
+40
View File
@@ -119,6 +119,46 @@ Instrument. Она остаётся в `positions` и не объединяет
_Не использовать_: денежный остаток, cash balance.
## Концентрация
Вкладка страницы одного Brokerage Account, показывающая, какие акции,
облигации, секторы и эмитенты занимают наибольшую часть текущей оценки
Portfolio, без валютной конвертации. Отличается от [структуры
портфеля](domains/portfolio/data-reference.md#структура-и-доли): в её разрезах
деньги не входят в знаменатель долей.
_Не использовать_: структура портфеля, диверсификация.
## Разрез
Одна из четырёх группировок вкладки «Концентрация»: «Акции», «Облигации»,
«Секторы», «Эмитенты». Элемент разреза — единица ранжирования; сектор
агрегирует позиции `STOCK`, `BOND` и `FUND`, эмитенты — `STOCK` и `BOND`.
_Не использовать_: фильтр, категория структуры.
## Сектор
Значение сектора инструмента в том виде, как его определяет T-Bank, без
перекодирования и собственной классификации WealthLedger. Заполняется для
позиций `STOCK`, `BOND` и `FUND`; государственные облигации определяются
значением `government` с подписью «Государственный сектор». Позиция без
сектора попадает в явную группу «Сектор не указан».
_Не использовать_: отрасль, собственная классификация приложения.
## Эмитент
В разрезе «Эмитенты» вкладки «Концентрация» — бренд актива по данным T-Bank,
объединяющий акции и облигации одной компании; фонды в разрез не входят.
Название эмитента — название бренда. **Оговорка:** в этом разрезе слово
означает бренд актива T-Bank, а не юридического эмитента ценной бумаги;
[рейтинг выпуска](integrations/nkr.md) не подставляется вместо рейтинга
эмитента и наоборот. Позиция без бренда попадает в явную группу
«Эмитент не указан».
_Не использовать_: юридический эмитент, эмитент рейтинга.
## Instrument
Ценная бумага или иной торгуемый актив T-Bank, на который ссылается Portfolio
+12 -1
View File
@@ -14,8 +14,17 @@ WealthLedger обращается к Invest API на сервере по gRPC ov
| Портфель и денежные остатки | Показать текущий состав инвестиций и итоги по исходным валютам |
| Исполненные операции | Построить журнал и выделить полученные купоны и дивиденды |
| Инструменты и рынок | Имена, идентификаторы, цены, свечи, параметры акций и облигаций |
| Классификация инструментов | Сектор акций, облигаций и фондов и бренд актива для разрезов [концентрации](../domains/portfolio/concentration.md) |
| Купоны и дивиденды | Построить будущие события по текущим позициям и календарь инструмента |
Сектор получается из описаний инструмента (отдельные описания для акций,
облигаций и фондов, поиск по UID, затем по FIGI); эмитент — из описания актива
по `asset_uid` инструмента: его uid и название бренда. Эмитент не выводится из
названия, тикера или ISIN. Классификация хранится как последнее известное
значение с обновлением не чаще раза в сутки ([ADR
022](../adr/022-stored-instrument-classification.md)); все вызовы проходят
через общий лимитер запросов T-Bank.
T-Bank определяет исходные данные и права token. Backend проверяет локальную
сессию, выбирает подключение её пользователя и устанавливает доступ к счёту.
Наличие идентификатора счёта в URL этого доступа не подтверждает.
@@ -41,7 +50,9 @@ Backend передаёт имя файла `logoName` из метаданных
Логотипы используются в портфеле, операциях, будущих событиях, поиске и
страницах инструментов. Отсутствующее имя или ошибка изображения оставляют
буквенную заглушку и не меняют финансовые значения. Правило построения URL
буквенную заглушку и не меняют финансовые значения. Логотип — это metadata
инструмента; он не равен эмитенту из [концентрации](../domains/portfolio/concentration.md),
который берётся из бренда актива. Правило построения URL
принадлежит [форматированию frontend](https://git.personal.ksv741.ru/WealthLedger/frontend/src/commit/9f7e342333b80bfacfd5bc394a2dcd0613d33ff3/src/shared/lib/display.ts).
## Проверка и сохранение подключения
+1
View File
@@ -20,6 +20,7 @@ WealthLedger — локальное приложение для частного
| Найти свой инвестиционный счёт | [Список счетов](domains/accounts/overview.md), их типы и доступные сводки |
| Вести банковские карты | [Ручной учёт](domains/cards/overview.md): независимые балансы, расходы, пополнения, переводы, возвраты и месячные сводки |
| Понять текущий состав инвестиций | [Портфель](domains/portfolio/overview.md): позиции, денежные остатки и итоги по валютам |
| Увидеть, где сконцентрированы деньги | [Концентрация](domains/portfolio/concentration.md): крупнейшие бумаги, секторы и эмитенты счёта |
| Разобрать уже совершённые движения | [Журнал операций](domains/operations/overview.md): исполненные операции с фильтрами и последовательной загрузкой истории |
| Посчитать полученные выплаты | [Пассивный доход](domains/income/overview.md): исполненные купоны и дивиденды за календарный период |
| Посмотреть ожидаемые события | [Будущие выплаты](domains/income/upcoming-events.md): купоны, дивиденды, погашения и оферты по текущим позициям |
+218 -711
View File
File diff suppressed because it is too large Load Diff
+16 -13
View File
@@ -1,9 +1,9 @@
{
"name": "wealth-ledger-docs",
"version": "0.1.4",
"version": "0.1.7",
"private": true,
"engines": {
"node": "24.21.0"
"node": "24.22.1"
},
"scripts": {
"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",
@@ -13,23 +13,26 @@
"commitlint": "commitlint"
},
"devDependencies": {
"@commitlint/cli": "21.2.2",
"@commitlint/config-conventional": "21.2.2",
"@release-it/conventional-changelog": "12.0.0",
"conventional-changelog-conventionalcommits": "10.4.0",
"@commitlint/cli": "21.2.4",
"@commitlint/config-conventional": "21.2.4",
"@release-it/conventional-changelog": "12.0.2",
"conventional-changelog-conventionalcommits": "10.4.1",
"markdownlint-cli": "0.49.1",
"markdownlint-rule-relative-links": "5.1.3",
"release-it": "21.0.2"
"markdownlint-rule-relative-links": "5.1.4",
"release-it": "21.1.1"
},
"overrides": {
"katex": "0.19.0",
"fast-uri": "3.1.9",
"katex": "0.19.1",
"markdownlint-cli@0.49.1": {
"js-yaml": "5.4.2",
"smol-toml": "1.9.0"
"minimatch": "11.0.2",
"smol-toml": "1.9.1"
},
"release-it": {
"basic-ftp": "6.2.1",
"undici": "7.29.1"
}
"basic-ftp": "6.2.3",
"undici": "7.30.1"
},
"markdown-it": "15.0.3"
}
}