8 Commits
Author SHA1 Message Date
ksv741 a45d3e77b9 docs: document hourly investment reads
Docs security / security (push) Successful in 8s
Docs verify / verify (push) Successful in 13s
Conventional commits / commits (pull_request) Successful in 12s
Docs security / security (pull_request) Successful in 8s
Docs verify / verify (pull_request) Successful in 14s
2026-10-09 19:56:40 +03:00
ksv741 3a272681c5 docs: clarify card summary totals 2026-10-09 16:04:56 +03:00
ksv741 e0bceea936 docs: document hourly sync history
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 13s
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (pull_request) Successful in 7s
Docs verify / verify (pull_request) Successful in 13s
2026-10-09 09:05:08 +03:00
ksv741 9a9b0409cc chore(release): 0.1.3
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (pull_request) Successful in 10s
Docs verify / verify (pull_request) Successful in 12s
Docs security / security (push) Successful in 9s
Docs verify / verify (push) Successful in 12s
2026-10-07 18:13:58 +03:00
ksv741 256d49b045 fix(deps): refresh docs security baseline
Conventional commits / commits (pull_request) Successful in 12s
Docs security / security (pull_request) Successful in 7s
Docs verify / verify (pull_request) Successful in 14s
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 16s
2026-10-07 15:36:47 +03:00
ksv741 9477e688d1 fix(deps): remove vulnerable docs tooling
Docs security / security (push) Successful in 19s
Docs verify / verify (push) Successful in 13s
Replace CLI2's unpatched braces dependency with markdownlint-cli.

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

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