3 Commits
Author SHA1 Message Date
ksv741 34b483018b chore(release): 0.1.1
Conventional commits / commits (pull_request) Successful in 12s
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-09-16 11:35:55 +03:00
ksv741 cead9dc176 docs: document container deployment and recovery
Docs security / security (pull_request) Successful in 6s
Docs verify / verify (pull_request) Successful in 11s
Conventional commits / commits (pull_request) Successful in 11s
Docs security / security (push) Successful in 7s
Docs verify / verify (push) Successful in 10s
2026-09-16 09:41:58 +03:00
ksv741 97069d6f6d docs: make documentation checks self-contained
Docs security / security (pull_request) Successful in 6s
Docs verify / verify (pull_request) Successful in 11s
Conventional commits / commits (pull_request) Successful in 16s
Docs security / security (push) Successful in 9s
Docs verify / verify (push) Successful in 10s
2026-09-15 20:45:40 +03:00
34 changed files with 461 additions and 122 deletions
-6
View File
@@ -1,6 +0,0 @@
{
"main": "2567a755569e6ef6ba12063b62f202fe52884ce7",
"frontend": "0244acf429c525b23117f165bbe52ef5403eefd3",
"backend": "660b250ecd05e38784690b9a9adb381764c0ca7c",
"specs": "9e227a563dda67620f0ad78228aa8a4c18bf35a0"
}
+3 -29
View File
@@ -8,39 +8,13 @@ on:
jobs:
verify:
runs-on: ubuntu-latest
defaults:
run:
working-directory: workspace/docs
steps:
- uses: https://github.com/actions/checkout@v4
with:
path: workspace/docs
- name: Checkout compatible peer revisions
env:
SOURCE_BRANCH: ${{ github.head_ref || github.ref_name }}
TARGET_BRANCH: ${{ github.base_ref || github.ref_name }}
run: |
set -eu
for repo in main frontend backend specs; do
ref=develop
case "$SOURCE_BRANCH:$TARGET_BRANCH" in
release/*:*|*:main)
ref=$(jq -er --arg repo "$repo" '.[$repo]' .ci/refs.json)
printf '%s\n' "$ref" | grep -Eq '^[0-9a-f]{40}$'
;;
esac
target="../$repo"
if [ "$repo" = main ]; then target=..; fi
git init "$target"
git -C "$target" remote add origin "https://git.personal.ksv741.ru/WealthLedger/$repo.git"
git -C "$target" fetch --depth 1 origin "$ref"
git -C "$target" checkout --detach FETCH_HEAD
git -C "$target" rev-parse HEAD
done
git rev-parse HEAD
- name: Record checked revision
run: git rev-parse HEAD
- uses: https://github.com/actions/setup-node@v4
with:
node-version-file: workspace/docs/.nvmrc
node-version-file: .nvmrc
- run: npm ci
- name: Check Markdown and relative links
run: npm run verify
+6 -4
View File
@@ -4,8 +4,10 @@
затем только затронутую тему. Docs объясняет систему; требования принадлежат
основным спецификациям, реализация и coding conventions — соседним репозиториям.
Проверь существенные факты адресно по спецификациям, ADR и реализации с учётом
веток и незакоммиченных изменений. Расхождение обозначь, не выбирая источник
Проверь существенные факты по локальным тематическим страницам и ADR;
внешние источники используй как справочные свидетельства, когда они доступны.
Недостающие факты отмечай явно; инструкции и проверки не требуют других checkout.
Расхождение обозначь, не выбирая источник
победителем автоматически. Перенос сохраняет полезное содержание и входящие
ссылки. Docs описывает текущее устройство системы; история поставок остаётся в Git.
Отчёты аудитов и исследований в docs не размещаются. Подтверждённые решения
@@ -19,6 +21,6 @@
## Ветки и релизы
Работа — в отдельной ветке от `develop`, затем PR в `develop`; в `main` напрямую
не пушить. Release/hotfix и синхронизация веток — по [root README](../README.md#релизы-и-ветки).
не пушить. Release/hotfix и синхронизация веток — по [README](README.md#релизы).
Commits и заголовки PR — Conventional Commits; для спецификаций допустим `spec:`.
Перед подготовкой релиза прочитай root README; версии вручную не повышать.
Перед подготовкой релиза прочитай местный README; версии вручную не повышать.
+7
View File
@@ -1,5 +1,12 @@
# Changelog
## [0.1.1](https://git.personal.ksv741.ru/WealthLedger/docs/compare/v0.1.0...v0.1.1) (2026-09-16)
### Documentation
* document container deployment and recovery ([cead9dc](https://git.personal.ksv741.ru/WealthLedger/docs/commit/cead9dc1765700b7e10f9567e38f6d68d4ec9656))
* make documentation checks self-contained ([97069d6](https://git.personal.ksv741.ru/WealthLedger/docs/commit/97069d6f6d0719d6fcee30b1ce8adbda41bd3a6d))
## 0.1.0 (2026-09-14)
### Features
+13 -15
View File
@@ -8,13 +8,13 @@ Docs даёт самостоятельное понимание продукта
| Вид знания | Где поддерживается |
| --- | --- |
| Согласованное проверяемое поведение: требования и сценарии | [Основные спецификации](../specs/AI_INDEX.md) в `specs/openspec/specs/` |
| Согласованное проверяемое поведение: требования и сценарии | [Основные спецификации](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/AI_INDEX.md) в `specs/openspec/specs/` |
| Предложения изменений, их проектирование и задачи | OpenSpec changes в существующем Store `wealth-ledger-specs`, `specs/openspec/changes/` |
| Понимание системы, областей и взаимодействий | Тематические страницы docs |
| Принятые решения и подтверждённые причины | Единственный журнал [docs/adr](adr/README.md) |
| Конкретная реализация и технические контракты | Код, тесты, схемы, конфигурация; публичный OpenAPI формирует backend |
| Размещение кода, conventions, команды разработки и проверки | Локальные инструкции frontend/backend |
| Выбор репозитория и типа знания | Корневой [AGENTS](../AGENTS.md) |
| Работа над docs | Локальные [AGENTS](AGENTS.md) и этот документ |
История аудитов и проверок остаётся в Git, Issues и PR. `CHANGELOG.md`
генерируется release-it из commits; вручную дублировать его на тематических страницах не нужно.
@@ -86,9 +86,11 @@ Docs объясняет смысл контракта, не вводя неза
Нужные точные значения сопровождай определяющим источником, чтобы не создать
конкурирующую норму. Паспорта страниц, Evidence-секции и номера строк не требуются.
Внутри docs используем относительные Markdown-ссылки. Между репозиториями —
относительный путь через соседний корень, например `../specs/AI_INDEX.md` из README.
Проверяй регистр, файл и якорь в фактическом workspace. Перенос требует исправить
Внутри docs используем относительные Markdown-ссылки. Внешние репозитории —
необязательные справочные веб-ссылки на опубликованный источник. Основной текст
и инструкции должны быть понятны без открытия этих ссылок. Проверяй локальные
файлы/якоря; для удалённых источников не обещай проверку их доступности CI.
Перенос требует исправить
входящие ссылки активных Markdown-документов; исторические архивы и dated audits
сохраняют адреса своего времени. Короткий указатель оставляем только при реальной
необходимости совместимости, без второй копии содержания.
@@ -153,8 +155,7 @@ npm run verify
Существующий gate запускает Markdown lint с проверкой относительных ссылок
и якорей, затем `git diff --check`. Он охватывает новые Markdown-файлы;
обычный diff их не показывает, поэтому отдельно просмотри untracked-содержание.
При изменениях соседних репозиториев выполни там `git diff --check` и проверь
затронутые ссылки. Markdown-only правки не требуют тестов всего приложения.
Markdown-only правки не требуют тестов приложения или соседнего checkout.
Правило relative-links не проверяет внешние URL и HTML-ссылки. Mermaid-рендер
в gate не входит; используй доступный локальный рендерер без отправки материалов
@@ -169,13 +170,10 @@ npm run verify
### CI и обновления зависимостей
`.gitea/workflows/verify.yml` запускает этот gate на push и PR с Node
из `.nvmrc` и установкой через `npm ci`. Checkout docs размещается внутри
workspace из `WealthLedger/main`, рядом с frontend, backend и specs. Соседние
репозитории для разработки берутся из `develop`; для `main`, PR в `main`
и `release/*` — из полных SHA в `.ci/refs.json`. SHA всех пяти участников
сохраняются в логе.
Ошибка checkout, Markdown или относительной ссылки завершает job с FAIL.
Это проверка ссылок на выбранные revisions, без Mermaid-render и semantic review.
из `.nvmrc` и установкой через `npm ci`. Скачивается только docs;
его SHA сохраняется в логе. Ошибка checkout, Markdown или внутренней ссылки
завершает job с FAIL. Внешние веб-ссылки — справочные; CI не проверяет их
доступность, Mermaid-render или semantic correctness.
`security.yml` при push, PR и ежедневно проверяет всю Git-историю через
Gitleaks 8.30.1 с redacted-выводом и все npm dependencies через
@@ -187,4 +185,4 @@ Renovate объединяет minor/patch updates; major требует согл
Dependency Dashboard, automerge не включён. Required checks включаются
отдельно в Gitea; workflow сам по себе не запрещает merge.
Версии и ветки: [процесс релиза](../README.md#релизы-и-ветки).
Версии и ветки: [процесс релиза](README.md#релизы).
+39 -2
View File
@@ -47,15 +47,16 @@ WealthLedger помогает частному инвестору понимат
| Понять ошибку или старые данные | [Состояния интерфейса](architecture/cross-cutting/ui-resilience.md), [свежесть данных](architecture/cross-cutting/data-freshness.md) |
| Понять визуальные роли и состояния | [Визуальные принципы](design/overview.md) |
| Узнать причину архитектурного решения | [Журнал ADR](adr/README.md) |
| Запустить, обновить или восстановить приложение | [Контейнерная поставка](architecture/deployment.md) |
## Границы знаний
[Основные спецификации](../specs/AI_INDEX.md) сохраняют согласованное проверяемое
[Основные спецификации](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/AI_INDEX.md) сохраняют согласованное проверяемое
поведение, а OpenSpec changes — предложения, дизайн и задачи изменений.
Фактический Store находится в `specs/openspec/`, основные требования — в
`specs/openspec/specs/`. Docs объясняет систему; код, тесты, схемы и конфигурация
задают конкретный механизм, а [ADR](adr/README.md) сохраняют принятые решения.
Локальные инструкции [frontend](../frontend/AGENTS.md) и [backend](../backend/AGENTS.md)
Локальные инструкции [frontend](https://git.personal.ksv741.ru/WealthLedger/frontend/src/commit/9f7e342333b80bfacfd5bc394a2dcd0613d33ff3/AGENTS.md) и [backend](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/AGENTS.md)
описывают изменение реализации и её проверки.
Эти источники дополняют друг друга. Найденный незавершённый change не доказывает
@@ -67,3 +68,39 @@ WealthLedger помогает частному инвестору понимат
Правила изменения текста, диаграмм, ссылок и проверки docs-impact находятся
в [CONTRIBUTING](CONTRIBUTING.md).
## Релизы
Репозиторий выпускается независимо. `develop` — интеграция, `main` — принятые
релизы. Работа: `codex/<task>` от актуального `develop`, PR в `develop`.
Обычные PR допускают squash; release и обратная синхронизация сохраняют историю.
Commits и PR titles — Conventional Commits, включая `spec:`. Версии вручную не повышай.
1. Получи `main`, `develop` и теги: `git fetch origin --tags`. Убедись, что
`develop` содержит последний релиз. Создай `release/<name>` от проверенного
`develop`; `nvm use --silent`, `npm ci`. Hotfix начинается от `main` в
`release/hotfix-<name>` и проходит тот же процесс.
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 и версией
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 исправь и проверь
существующий кандидат без повторного повышения версии.
`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*` защищены.
Workflow сам не включает эти настройки. Отдельное review approval для одного
владельца не требуется. Npm publishing, deploy и Gitea Releases не включены.
+3
View File
@@ -2,6 +2,9 @@
**Status:** Accepted, baseline decision
Deployment boundary расширена [ADR 015](015-single-server-sqlite-deployment.md)
для одного сервера и одного backend process. Ниже сохранён исходный контекст.
## Context
MVP нужен воспроизводимый локальный доступ к данным без инфраструктуры развёртывания. Доменные таблицы и миграции на baseline отсутствуют.
@@ -0,0 +1,47 @@
# 015. SQLite в ограниченном single-server deployment
**Status:** Accepted
## Context
[ADR 001](001-prisma-sqlite-local-mvp.md) ограничивал SQLite локальным MVP.
Контейнерная поставка требует постоянного хранилища на одном сервере,
но не требует высокой доступности или нескольких экземпляров API.
Пользователи, сессии, зашифрованные подключения и банковская история уже
хранятся в SQLite. Кэши, limiter и generation подключений локальны процессу.
## Decision
Разрешён один backend process на одном Docker host с SQLite в постоянном
host directory. Development использует отдельный named volume. SQLite
остаётся embedded library без сетевого порта. Это расширяет deployment
boundary ADR 001; его исторический контекст сохраняется.
Prisma migrations выполняются отдельным одноразовым service из того же image,
что и backend. Перед изменением схемы backend останавливается, всё data
directory копируется вместе с возможными WAL/SHM files. Ключ шифрования
сохраняется отдельно. Неуспешная migration блокирует запуск новой версии.
Откат image требует совместимости с текущей схемой и не восстанавливает
старую базу. Restore требует отдельного решения о потере данных после backup.
Frontend и backend имеют независимые версии; production фиксирует version tags.
Краткий простой допустим.
## Alternatives
PostgreSQL потребовал бы миграции данных и отдельного database lifecycle;
текущие требования этого не оправдывают. Kubernetes, replicas и blue-green
не устраняют ограничения process-local состояния и не входят в решение.
## Consequences
Сервер не обещает HA или zero-downtime. Один backend instance — обязательное
ограничение, а не рекомендуемая настройка масштабирования. Нужны контроль
свободного места, согласованные backups и проверяемое восстановление.
Решение пересматривается при необходимости нескольких replicas, другом
availability target, заметном write contention или потребности в отдельном
database service. Добавление реплик до такого решения недопустимо.
Топология описана в [архитектуре](../architecture/containers.md#контейнерная-поставка),
операции — в [runbook](../architecture/deployment.md).
+1
View File
@@ -19,3 +19,4 @@
- [009 — Concurrent refresh rotation policy](009-concurrent-refresh-rotation-policy.md)
- [013 — НКР как первый источник кредитных рейтингов облигаций](013-nkr-bond-credit-ratings.md)
- [014 — Актуальная OpenAPI-схема как вход frontend](014-trusted-openapi-input.md)
- [015 — SQLite в ограниченном single-server deployment](015-single-server-sqlite-deployment.md)
+1
View File
@@ -16,6 +16,7 @@
| Как обрабатываются ошибки и ожидание? | [HTTP API и ошибки](http-api.md), [состояния интерфейса](cross-cutting/ui-resilience.md) |
| Как связать ошибку с обработкой запроса? | [Наблюдаемость](http-api.md#наблюдаемость) |
| Как устроено подтверждённое локальное окружение? | [Container](containers.md#представление-container), [качество и ограничения](containers.md#качество-и-ограничения) |
| Как запустить, обновить или восстановить приложение? | [Развёртывание](deployment.md) |
| Что означают предметные термины? | [Глоссарий](../glossary.md) |
Эта карта покрывает вопросы архитектуры там, где о них есть подтверждённое
+46 -7
View File
@@ -27,11 +27,50 @@ flowchart LR
F -->|"HTTPS; изображения без авторизации"| C
```
SPA выполняется в браузере пользователя. Backend — отдельное локальное
SPA выполняется в браузере пользователя. Backend — отдельное
приложение; SQLite используется внутри его процесса через библиотеку и файл
базы. Между API и SQLite нет сетевого database server. Граница системы на
схеме показывает принадлежность частей, а не их размещение на одном узле.
## Контейнерная поставка
Deployment view для одного сервера. Caddy принадлежит серверу; Compose
содержит два постоянных application containers и одноразовую migration.
```mermaid
flowchart LR
Browser["Браузер · React SPA"] -->|HTTPS| Caddy["Серверный Caddy · TLS"]
subgraph Host["Один Docker host"]
Caddy -->|"HTTP · 127.0.0.1:8080"| Frontend["frontend · nginx · SPA + /api/"]
Frontend -->|"HTTP /api/v1 · internal network"| Backend["backend · NestJS · один process"]
Migration["migration · Prisma · one-shot"] -->|"До старта backend"| Data[("Host directory · SQLite + WAL")]
Backend -->|"Чтение и запись /data"| Data
Secrets["Restricted environment · ключи вне images"] --> Backend
end
```
Только frontend публикует host port, привязанный к loopback. Backend не
публикует порт, но имеет исходящий доступ к внешним API. nginx сохраняет
`/api/` prefix, forwarding headers и request ID; Docker DNS разрешается
повторно после backend recreation. HTML требует revalidation, hashed assets
имеют immutable cache. Caddy не содержит отдельного маршрута к API.
Development заменяет nginx на Vite с HMR, backend — на Nest watch, а host data
path — на отдельный named volume. Browser origin остаётся единым. Linux
node_modules не монтируются с хоста. Production SPA собирается с relative API
base; production cookies остаются Secure, публичный origin использует HTTPS.
Компоненты имеют независимые images и версии. Production фиксирует image
version tags; migration использует тот же backend image. Успех migration предшествует
backend healthcheck на существующем auth route; frontend ждёт healthy backend.
Runtime работает non-root, SQLite сохраняется вне image, ключ шифрования и JWT
secret поступают из restricted environment и сохраняются между обновлениями.
Ограничение SQLite расширено в [ADR 015](../adr/015-single-server-sqlite-deployment.md).
[Runbook](deployment.md) описывает установку, independent
updates, backup, rollback и explicit restore. Он также перечисляет внешние
prerequisites: локальный smoke не подтверждает registry/server rollout.
## Ответственность частей
| Часть | Ответственность |
@@ -106,10 +145,10 @@ credentials не являются сохраняемым представлен
## Сохранение и восстановление данных
Резервная копия SQLite должна быть согласованной: для работающей базы
используется SQLite backup API с учётом WAL. Несогласованное копирование
файлов базы и WAL не сохраняет целостный снимок. Восстановление проверяется
на отдельной копии. Ключ шифрования подключения хранится отдельно от базы;
Поддерживаемая процедура останавливает backend и копирует весь data directory
с возможными WAL/SHM files до migration. Копирование отдельных файлов
работающей базы не сохраняет целостный снимок; для live backup потребовался бы
SQLite backup API. Восстановление проверяется на отдельной копии. Ключ шифрования подключения хранится отдельно от базы;
его потеря делает сохранённый T-Bank token нечитаемым.
Откат приложения требует совместимости предыдущей версии с сохранённой
@@ -150,12 +189,12 @@ access token и вращаемый refresh token. [Политика query-кэш
отмечены в [аутентификации](../domains/authentication/overview.md#регистрация-и-вход)
и [HTTP API](http-api.md#error-contract).
Подтверждённая топология — локальная SPA и локальный API с файлом SQLite.
Поддерживается локальный Compose и ограниченная single-server topology с SQLite.
Origin браузера, адрес API и cookie policy должны быть согласованы.
`localhost` и `127.0.0.1` задают разные browser-границы для cookie и CORS.
Локальный HTTP поддерживается в development-режиме backend; в остальных
режимах refresh-cookie имеет Secure flag и требует защищённого соединения.
Наличие локального запуска не задаёт production-топологию или гарантии SLA.
Single-server deployment не задаёт гарантий HA или zero-downtime.
Кэши и лимитер T-Bank действуют на экземпляр backend. Ротация ключа шифрования
подключений и согласование изменений подключения между распределёнными
+4 -4
View File
@@ -65,8 +65,8 @@ Client Cached Snapshot прежнего подключения больше не
Пользовательский сценарий описан в [интеграции T-Bank](../../integrations/tbank.md).
Согласованные правила frontend находятся в workspace-спецификациях
[query coherence](../../../specs/openspec/specs/frontend-query-coherence/spec.md)
и [data resilience](../../../specs/openspec/specs/frontend-data-resilience/spec.md);
[query coherence](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/frontend-query-coherence/spec.md)
и [data resilience](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/frontend-data-resilience/spec.md);
серверные правила — в
[portfolio](../../../specs/openspec/specs/portfolio-view/spec.md) и
[ledger](../../../specs/openspec/specs/brokerage-account-ledger/spec.md).
[portfolio](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md) и
[ledger](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-ledger/spec.md).
+3 -3
View File
@@ -44,6 +44,6 @@ actions. Устаревший серверный Portfolio Snapshot показы
[аутентификации](../../domains/authentication/overview.md).
Согласованное поведение раскрыто в workspace-спецификациях
[UI resilience](../../../specs/openspec/specs/frontend-ui-resilience/spec.md),
[loading presentation](../../../specs/openspec/specs/frontend-loading-presentation/spec.md)
и [data resilience](../../../specs/openspec/specs/frontend-data-resilience/spec.md).
[UI resilience](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/frontend-ui-resilience/spec.md),
[loading presentation](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/frontend-loading-presentation/spec.md)
и [data resilience](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/frontend-data-resilience/spec.md).
+227
View File
@@ -0,0 +1,227 @@
# Контейнерная поставка
Runbook для одного Docker host, одного backend и краткого простоя.
[Топология](containers.md#контейнерная-поставка) и
[ADR 015](../adr/015-single-server-sqlite-deployment.md) объясняют границы.
Команды выполняются из checkout `WealthLedger/main`, содержащего `compose.yaml`.
Development дополнительно требует checkout `frontend/` и `backend/`.
## Предпосылки
- Docker Engine с Compose plugin **не ниже 2.24.4** (`!override` в development),
доступ к registry и достаточно свободного диска для non-root UID 1000.
Локально проверены Engine 29.8.0, Compose 5.5.1, Linux arm64.
Другую архитектуру проверяют отдельно; multi-platform images не обещаны.
- Gitea Container Registry; проверяемая версия сервера — 1.27.3.
Runner label — `ubuntu-latest`, runner должен иметь Docker CLI, buildx и daemon.
Наличие label само по себе не доказывает Docker capability.
- В Actions каждого component repo нужны `REGISTRY_USERNAME` и
`REGISTRY_TOKEN` отдельной identity с package write permission. Server
использует другую identity только с package read permission. Built-in
workflow token не заменяет эту настройку.
- На сервере Caddy уже завершает TLS и передаёт весь домен на
`127.0.0.1:8080` (или выбранный frontend port). Отдельного `/api` upstream нет.
DNS, TLS, firewall и provisioning Caddy выполняются вне этого runbook.
Реальная публикация и server pull-only login требуют отдельной проверки
на вашей инфраструктуре. Локальные images не доказывают registry permissions.
## Development
Из workspace с исходниками обоих компонентов:
```bash
docker version
docker compose version
docker compose --env-file .env.development.example \
-f compose.yaml -f compose.development.yaml config --quiet
docker compose --env-file .env.development.example \
-f compose.yaml -f compose.development.yaml up -d --build --wait --wait-timeout 180
```
Откройте `http://localhost:5173`. Vite отдаёт HMR и проксирует `/api/` без
rewrite; Nest работает в watch mode. Монтируются только source/public,
`node_modules` и generated files остаются в container filesystem. `.env`
с хоста не копируется. После изменения manifest, lockfile, tsconfig или Vite
config пересоберите соответствующий image. `up --build` обновляет Linux
dependencies без stale named volume для `node_modules`.
Для другого порта скопируйте `.env.development.example` в игнорируемый
`.env.development` и согласованно поменяйте `FRONTEND_PORT`/`FRONTEND_ORIGIN`.
Пример содержит только вымышленные local secrets; server secrets сюда не входят.
Поля image/data directory нужны для интерполяции base Compose, но полностью
заменяются development override. В итоговом config нет production data path.
Project `wealthledger-dev` хранит SQLite в `development-data`. Обычные
`restart` и `down` сохраняют его. Не применяйте `down -v` к данным, которые
хотите сохранить. Не используйте production project name для development.
## Публикация компонентных images
Штатный release process каждого repo создаёт защищённый `vX.Y.Z` после
проверенного release commit. `image.yml` проверяет tag против package/lock
version, затем выполняет `npm ci`, `npm run verify`; backend дополнительно
выполняет `npm run test:e2e`. У каждого image OCI version/revision labels.
Images публикуются как `git.personal.ksv741.ru/wealthledger/frontend:X.Y.Z`
и `.../backend:X.Y.Z`. `latest` не создаётся.
Workflow отказывается перезаписывать существующие release tags;
защита release tags и запрет параллельных publishers обязательны. Если одна
публикация уже состоялась, не удаляйте tag для повторного запуска: проверьте
опубликованный image и завершите проверку существующего artifact отдельно.
Выберите опубликованные version tags, выполните pull и сравните OCI revision
с release commit. Выполните smoke с disposable data/config до первого server
rollout. В production env хранится пара полных image references, например
`git.personal.ksv741.ru/wealthledger/frontend:0.1.0`. Сохраните versions/revisions
в deployment record. Release tags не должны переназначаться другим images.
## Первая установка
Создайте restricted environment file и data directory:
```bash
sudo install -d -m 0700 /srv/wealthledger
sudo install -d -m 0700 -o 1000 -g 1000 /srv/wealthledger/data
sudo install -m 0600 .env.compose.example /srv/wealthledger/production.env
```
Дальнейшие команды выполняет оператор, имеющий доступ к environment file,
backup directory и Docker. Заполните env локальным защищённым редактором:
полные ссылки `FRONTEND_IMAGE` и `BACKEND_IMAGE` с опубликованными version tags,
публичный HTTPS origin и абсолютный data path. Версии в примере — образец
формата; перед запуском выберите реально опубликованные releases.
Пустые required значения блокируют config; некорректные secrets блокируют backend.
Не выводите полный rendered config с настоящими secrets в журналы.
Для новой базы создайте JWT secret длиной хотя бы 32 символа и отдельный
32-byte encryption key в base64 (`openssl rand -hex 32` и
`openssl rand -base64 32` в защищённом терминале). Сохраните ключ отдельно
от data backup. Для существующей установки перенесите прежние JWT secret
и encryption key, а согласованную копию **всего** data directory — при
остановленном прежнем backend. Файл должен называться `wealthledger.db`;
если переименовываете, согласуйте также WAL/SHM companion names до старта.
Не запускайте старый и новый backend на одной базе одновременно.
Войдите в registry server identity без помещения token в командную строку:
```bash
docker login git.personal.ksv741.ru --username SERVER_PULL_USER
export COMPOSE_FILE=compose.yaml
export COMPOSE_PROJECT_NAME=wealthledger
export COMPOSE_ENV_FILES=/srv/wealthledger/production.env
docker compose config --quiet
docker compose pull frontend backend migration
docker compose up -d --wait --wait-timeout 120
docker compose ps -a
```
Migration и backend используют один image и один data mount.
Migration должна завершиться с кодом 0; иначе backend не запускается.
Readiness принимает 401 от существующего `/api/v1/auth/me` без credentials.
Frontend становится healthy после backend. Backend host port отсутствует.
Runtime non-root; root filesystem read-only, nginx temp files находятся в tmpfs.
Проверьте SPA deep link, регистрацию/вход, refresh, существующие карты,
чтение старого зашифрованного подключения и один финансовый запрос.
Production refresh-cookie имеет Secure flag: проверяйте через HTTPS Caddy;
loopback HTTP curl без browser cookie jar не доказывает browser session.
При локальном smoke используйте disposable credentials и явную передачу cookie.
Направляйте Caddy на новый deployment только после успешной проверки.
Прежний runtime удаляйте только после проверки новой установки.
## Backup при остановленном backend
До backend update проверьте совместимость новой версии с текущим frontend
и схемой, а обратной версии — с новой схемой. При неизвестной совместимости
не обещайте image rollback. В выбранном rollout отсутствуют параллельные API.
Ниже data path соответствует примеру env; при другом path замените его.
Сохраните текущую пару image references/revisions и отдельно — ключи.
```bash
docker compose stop backend
docker compose ps -a backend
install -d -m 0700 /srv/wealthledger/backups
BACKUP_DIRECTORY="/srv/wealthledger/backups/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -m 0700 "$BACKUP_DIRECTORY"
cp -a /srv/wealthledger/data "$BACKUP_DIRECTORY/data"
```
Перед копированием убедитесь, что backend остановлен, migration не выполняется
и никто другой не пишет в каталог. Успех `cp` обязателен перед продолжением.
Не копируйте отдельный `.db` из работающего приложения. Проверяйте backup
на отдельной копии: migration status, `PRAGMA integrity_check`, auth, карты
и расшифровка тестового подключения исходным ключом. Backup без проверяемого
ключа недостаточен для восстановления подключения.
## Независимое обновление frontend
После проверки API compatibility замените только `FRONTEND_IMAGE` в env:
```bash
docker compose pull frontend
docker compose up -d --no-deps --wait --wait-timeout 120 frontend
```
Backend container и SQLite не пересоздаются. Входная точка кратко недоступна.
Проверьте deep link, login/refresh и новую OCI revision. Старым browser tabs
может понадобиться reload: старые hashed chunks не сохраняются между images.
## Независимое обновление backend
Выполните stopped-backend backup выше. Замените только `BACKEND_IMAGE` в env.
Последовательность не продолжается после failed migration:
```bash
docker compose pull backend migration
docker compose up --no-deps --force-recreate --abort-on-container-exit \
--exit-code-from migration migration &&
docker compose up -d --no-deps --wait --wait-timeout 120 backend
```
Frontend не пересоздаётся; nginx повторно разрешает backend DNS. Во время
перерыва возможен 502. При failure оставьте backend остановленным, сохраните
диагностику migration и выберите совместимый image либо отдельный restore.
Не используйте `migrate reset` или автоматический `resolve` как recovery.
Проверьте migration status, health, login/refresh, карты и расшифровку подключения.
После успешного smoke запишите фактически установленную пару image references.
## Откат image
Для frontend верните предыдущий совместимый version tag и повторите frontend update.
Для backend сначала остановите процесс и подтвердите совместимость старого
image с **текущей** схемой. Верните предыдущий image reference и запустите только backend:
```bash
docker compose pull backend
docker compose up -d --no-deps --wait --wait-timeout 120 backend
```
Данные и encryption key не заменяются. Migration service здесь намеренно
не запускается: старые migrations не являются down-migrations. Прочитайте
новые записи, сделанные после backup, и проверьте auth/cards/connection.
При несовместимости оставьте приложение остановленным до решения о recovery.
## Explicit restore
Это отдельное решение оператора, **не часть image rollback**. Оператор выбирает
backup timestamp и явно принимает потерю всех изменений после него, включая
сессии, карты и подключения. Сначала воспроизведите restore на isolated project
с отдельным data path/port и совместимым image; не используйте production data
как fixture. Убедитесь в наличии соответствующего encryption key.
После отдельного решения остановите backend и убедитесь, что migration не
работает. Сохраните нынешний каталог под новым именем, ничего не удаляя:
```bash
docker compose stop backend
mv /srv/wealthledger/data /srv/wealthledger/data-before-restore-TIMESTAMP
cp -a /srv/wealthledger/backups/CHOSEN_TIMESTAMP/data /srv/wealthledger/data
```
Проверьте owner 1000:1000, permissions, выбранный compatible image и исходный
ключ. Запустите backend командой rollback с `--no-deps`, затем выполните smoke.
Сверьте наличие записей до backup и отсутствие известных записей потерянного
интервала. Сохраните прежний каталог для расследования. При необходимости
новой migration сначала выполните обычную backup/update последовательность.
+11 -2
View File
@@ -8,6 +8,15 @@ Backend генерирует OpenAPI из собственного публич
схемы находятся вне frontend. Это разделение принято в
[ADR 002](../adr/002-nest-generated-openapi-contract.md) и
[ADR 014](../adr/014-trusted-openapi-input.md).
Backend командой `npm run openapi:generate` создаёт `openapi.json` без запуска
сервера и не хранит результат в Git. Contract test сравнивает вывод генератора
с Nest runtime schema настроенного приложения. Frontend хранит полученный
artifact у себя и проверяет соответствие generated types этой копии. CI не
скачивает соседние репозитории и не сравнивает их текущие revisions. Обновление
входного artifact потребителя выполняется отдельно с review; совместимость
развёрнутых версий не доказывается одним зелёным локальным CI.
API имеет prefix `/api/v1`; Swagger публикуется для локальной разработки по
environment policy, а не используется frontend в runtime.
@@ -36,7 +45,7 @@ message/stack. Типичный ответ:
HTTP-ответа после всех стадий обработки запроса.
**Известное расхождение:** согласованная
[спецификация аутентификации](../../specs/openspec/specs/user-authentication/spec.md#requirement-стандартные-ответы-об-ошибках)
[спецификация аутентификации](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/user-authentication/spec.md#requirement-стандартные-ответы-об-ошибках)
требует `pointer` и `detail` для невалидных полей. В текущей конфигурации
валидация формирует строковые сообщения, а фильтр ожидает структурированные
ошибки полей; поэтому корректность деталей `errors` не подтверждена.
@@ -74,5 +83,5 @@ client request ID. Это позволяет сопоставить публич
Выбор logger и граница ответственности описаны в
[ADR 008](../adr/008-pino-backend-logging.md); согласованное поведение — в
workspace-спецификации
[Structured logging](../../specs/openspec/specs/backend-structured-logging/spec.md).
[Structured logging](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/backend-structured-logging/spec.md).
Сборщик, срок хранения журналов и alerting не определяются приложением.
+1 -1
View File
@@ -44,4 +44,4 @@
и [банковских картах](../domains/cards/overview.md).
Согласованная общая основа описана в
[спецификации дизайн-системы](../../specs/openspec/specs/frontend-design-system/spec.md).
[спецификации дизайн-системы](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/frontend-design-system/spec.md).
+1 -1
View File
@@ -93,7 +93,7 @@ sequenceDiagram
[журнал операций](../operations/overview.md) или историю закрытых счетов.
Для совокупного результата доступен [режим «Все счета»](../portfolio/all-accounts.md).
Согласованное поведение описывает [спецификация счетов](../../../specs/openspec/specs/brokerage-accounts/spec.md).
Согласованное поведение описывает [спецификация счетов](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-accounts/spec.md).
Её раздел об экране пока требует одноколоночного списка и не описывает
счётчики акций и облигаций. Текущая реализация и её проверки используют
две колонки на широком экране и показывают эти счётчики. Расхождение требует
+2 -2
View File
@@ -23,7 +23,7 @@
Access token действует 15 минут и хранится только в памяти браузера.
Refresh token имеет серверный срок 7 дней, заменяется при восстановлении
сессии и передаётся в cookie `refresh_token` с `httpOnly` и `SameSite=Lax`.
Сроки определены в [спецификации сессий](../../../specs/openspec/specs/user-authentication/spec.md#requirement-access-и-refresh-сессии)
Сроки определены в [спецификации сессий](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/user-authentication/spec.md#requirement-access-и-refresh-сессии)
и [ADR 006](../../adr/006-auth-session-policy.md).
После перезагрузки SPA получает новый access token через refresh-cookie.
@@ -117,6 +117,6 @@ Backend проверяет учётные данные и tokens, хранит
и проверку атомарности с реальной изолированной базой.
Согласованное поведение находится в workspace-спецификации
[User authentication](../../../specs/openspec/specs/user-authentication/spec.md).
[User authentication](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/user-authentication/spec.md).
Правила начального ожидания — в
[состояниях интерфейса](../../architecture/cross-cutting/ui-resilience.md).
+1 -1
View File
@@ -140,6 +140,6 @@ JavaScript Number. Отдельный ввод ограничен signed64: на
сохраняет новую финансовую историю и при откате приложения. Устройство хранения
описано в [контейнерах](../../architecture/containers.md#хранимые-данные-и-границы-доступа).
Согласованный контракт банковского учёта находится в
[manual-bank-cards](../../../specs/openspec/changes/add-manual-bank-cards/specs/manual-bank-cards/spec.md).
[manual-bank-cards](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/changes/add-manual-bank-cards/specs/manual-bank-cards/spec.md).
Автоматическая загрузка банковских данных, кредитные карты, другие валюты,
бюджеты и общий баланс банковских денег с инвестициями в эту версию не входят.
+2 -2
View File
@@ -59,7 +59,7 @@
для полного месяца это предыдущий полный месяц, иначе — непосредственно
предшествующий интервал той же включительной длительности. Текущая страница
его не показывает. Это расходится с
[основным требованием сравнений](../../../specs/openspec/specs/brokerage-account-income-analytics/spec.md#requirement-period-comparisons-preserve-calendar-and-currency-meaning),
[основным требованием сравнений](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-income-analytics/spec.md#requirement-period-comparisons-preserve-calendar-and-currency-meaning),
которое описывает оба сравнения. Требуется отдельно согласовать этот разрыв;
здесь сохранено различие между ответом API и фактическим экраном.
@@ -104,7 +104,7 @@ Frontend проверяет принадлежность выплат по по
Аналитика только читает данные, не хранит историю операций и не рассчитывает налоги, инвестиционную эффективность, доходность, валютную конвертацию или общий мультивалютный итог.
Основное проверяемое поведение — в [спецификации дохода](../../../specs/openspec/specs/brokerage-account-income-analytics/spec.md),
Основное проверяемое поведение — в [спецификации дохода](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-income-analytics/spec.md),
точная форма ответа — в [HTTP API](../../architecture/http-api.md).
Не следует использовать календарь будущих событий для восстановления
состава уже полученного дохода.
+2 -2
View File
@@ -29,7 +29,7 @@
Суммы рассчитаны по количеству на `calculatedAt`. Они не учитывают будущие
сделки, право владения на дату реестра и персональный налоговый расчёт.
Есть неразрешённое ограничение интерпретации:
[основная спецификация](../../../specs/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-forecasts-preserve-event-meaning-and-uncertainty)
[основная спецификация](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-forecasts-preserve-event-meaning-and-uncertainty)
и текущая подсказка экрана называют прогноз суммой «до налогов», но для
дивиденда реализация только умножает `dividend_net` на количество.
Налоговый смысл этого поля не подтверждён локальными материалами; на
@@ -61,7 +61,7 @@ API принимает необязательные `from` и `to` в форма
Итоги остаются в ответе API; полный экран показывает список без общего итога.
Текущие controller, сервис и экран поддерживают выбор периода, тогда как
[основная спецификация](../../../specs/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-account-page-presents-an-upcoming-events-list)
[основная спецификация](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-account-page-presents-an-upcoming-events-list)
описывает фиксированные 30 дней и экран без фильтров. Документация отражает
реализованный выбор периода, не изменяя это несогласованное требование.
+6 -6
View File
@@ -132,13 +132,13 @@ HTML-источник, общий кэш и поведение при измен
выход очищает кэш сессии. Общие график, позиция и личные события
имеют общее представление на страницах акций и облигаций.
Основные спецификации [портфеля](../../../specs/openspec/specs/portfolio-view/spec.md)
и [журнала](../../../specs/openspec/specs/brokerage-account-ledger/spec.md)
Основные спецификации [портфеля](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md)
и [журнала](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-ledger/spec.md)
описывают исходные финансовые понятия. Отдельная основная спецификация
страницы облигации в текущем OpenSpec Store не найдена; условия вычислений
подтверждены [каталогом](../../../backend/src/modules/investments/instruments/bonds/application/bond-catalog.service.ts),
[рыночными данными](../../../backend/src/modules/investments/instruments/bonds/application/bond-market.service.ts),
[выплатами](../../../backend/src/modules/investments/instruments/bonds/application/bond-income.service.ts)
и [проверками](../../../backend/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-catalog.service.ts),
[рыночными данными](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/bonds/application/bond-market.service.ts),
[выплатами](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/bonds/application/bond-income.service.ts)
и [проверками](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/instruments/bonds/application/bond.spec.ts).
Границы источников описаны в [разделе интеграций](../../integrations/README.md),
сходное разделение рыночных и личных данных — в [акциях](stocks.md).
+5 -5
View File
@@ -169,11 +169,11 @@ TTM означает последние 12 месяцев, MRQ — послед
История открытых счетов не обещает полную историю владения, включая закрытые
счета, переводы и универсальные корпоративные события.
Основные спецификации [портфеля](../../../specs/openspec/specs/portfolio-view/spec.md)
и [журнала](../../../specs/openspec/specs/brokerage-account-ledger/spec.md)
Основные спецификации [портфеля](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md)
и [журнала](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-ledger/spec.md)
задают исходные финансовые понятия. Отдельная основная спецификация страницы
акции в текущем OpenSpec Store не найдена; описанные механизмы проверяются
по [каталогу](../../../backend/src/modules/investments/instruments/stocks/application/stock-catalog.service.ts),
[рыночным данным](../../../backend/src/modules/investments/instruments/stocks/application/stock-market.service.ts),
[выплатам](../../../backend/src/modules/investments/instruments/stocks/application/stock-income.service.ts) и [проверкам](../../../backend/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-catalog.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).
Сопоставление с облигациями — на [странице облигаций](bonds.md).
+1 -1
View File
@@ -112,6 +112,6 @@ Backend хранит не более 100 страниц в памяти проц
и `TBANK_UNAVAILABLE` сохраняют [общую семантику API](../../architecture/http-api.md).
Пустой успешный ответ означает отсутствие подходящих операций, а не сбой.
Согласованное поведение описано в [спецификации журнала](../../../specs/openspec/specs/brokerage-account-ledger/spec.md).
Согласованное поведение описано в [спецификации журнала](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-ledger/spec.md).
Фильтр конкретной бумаги и общий режим расширяют исходное описание отдельного
счёта; их механизм раскрыт на страницах инструментов и общего портфеля.
+5 -5
View File
@@ -109,11 +109,11 @@ Backend публикует статические маршруты под `/api/
работать с отдельными счетами. При откате сначала возвращается клиент.
Этот механизм не требует изменения схемы SQLite и миграции финансовых данных.
Основные спецификации [портфеля](../../../specs/openspec/specs/portfolio-view/spec.md),
[операций](../../../specs/openspec/specs/brokerage-account-ledger/spec.md),
[дохода](../../../specs/openspec/specs/brokerage-account-income-analytics/spec.md)
и [событий](../../../specs/openspec/specs/brokerage-account-upcoming-events/spec.md)
Основные спецификации [портфеля](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md),
[операций](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-ledger/spec.md),
[дохода](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-income-analytics/spec.md)
и [событий](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-upcoming-events/spec.md)
описывают отдельный счёт. Общий режим подтверждён действующими маршрутизаторами,
сервисами и [проверками агрегации](../../../backend/src/modules/investments/all-accounts.spec.ts),
сервисами и [проверками агрегации](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/all-accounts.spec.ts),
но не выделен в самостоятельную основную спецификацию. Не следует считать
описание общего режима изменением требований к отдельному счёту.
+2 -2
View File
@@ -90,8 +90,8 @@ frontend показывает до сотых. Положительное зна
поэтому ограничение долей действует на все валюты. В общем портфеле проверка
отрицательных денег выполняется по остаткам счетов до взаимозачёта.
Нормативные основы: [нормализованный состав](../../../specs/openspec/specs/portfolio-view/spec.md#requirement-нормализованный-состав-portfolio)
и [точные значения и валютные агрегаты](../../../specs/openspec/specs/portfolio-view/spec.md#requirement-точные-значения-и-валютные-агрегаты).
Нормативные основы: [нормализованный состав](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-нормализованный-состав-portfolio)
и [точные значения и валютные агрегаты](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-точные-значения-и-валютные-агрегаты).
Структура и общий режим подтверждены реализацией и её проверками;
отдельных требований к ним в основной спецификации портфеля пока нет.
Поля транспорта следует сверять с [HTTP API](../../architecture/http-api.md),
+5 -5
View File
@@ -79,9 +79,9 @@ sequenceDiagram
| Метаданные инструмента | Успешный поиск или подтверждённое отсутствие | Свежими считаются 24 часа; общий кэш на 500 ключей UID/FIGI, ошибки не сохраняются |
Это параметры текущей реализации, а не самостоятельная политика этого
документа: [снимки](../../../../backend/src/modules/investments/portfolio/application/portfolio.service.ts),
[метаданные](../../../../backend/src/integrations/tbank/instrument-metadata.service.ts) и
[клиентский запрос](../../../../frontend/src/entities/portfolio/api/usePortfolio.ts).
документа: [снимки](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/portfolio/application/portfolio.service.ts),
[метаданные](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/integrations/tbank/instrument-metadata.service.ts) и
[клиентский запрос](https://git.personal.ksv741.ru/WealthLedger/frontend/src/commit/9f7e342333b80bfacfd5bc394a2dcd0613d33ff3/src/entities/portfolio/api/usePortfolio.ts).
Пять минут — предельный возраст успешного снимка, а не дополнительные
пять минут после окончания свежих 30 секунд. Запасной ответ сохраняет
@@ -152,7 +152,7 @@ Frontend отображает название и остальные сведе
источника; его увеличение не является гарантированным исправлением
ограничения самого T-Bank.
Проверяемые правила: [свежесть и запасной снимок](../../../../specs/openspec/specs/portfolio-view/spec.md#requirement-свежесть-и-fallback-полного-portfolio-snapshot),
[клиентские состояния](../../../../specs/openspec/specs/portfolio-view/spec.md#requirement-состояния-и-ошибки-portfolio-на-клиенте).
Проверяемые правила: [свежесть и запасной снимок](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-свежесть-и-fallback-полного-portfolio-snapshot),
[клиентские состояния](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-состояния-и-ошибки-portfolio-на-клиенте).
Для расследования конкретного значения используйте
[порядок диагностики](../how-to/investigate-discrepancy.md).
@@ -37,16 +37,16 @@
теряет цифры, валюту или показатель, исследуйте frontend.
Если исходные безопасные данные и нормализованный ответ расходятся,
исследуйте backend. Если не совпадают ожидаемое и описанное поведение,
сначала сопоставьте [спецификацию портфеля](../../../../specs/openspec/specs/portfolio-view/spec.md)
сначала сопоставьте [спецификацию портфеля](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md)
и ограничения [потока загрузки](../flows/portfolio-loading.md).
Исправление документации само по себе не разрешает конфликт требований
и реализации.
Для адресной проверки исходников владельцами служат
[сервис снимков](../../../../backend/src/modules/investments/portfolio/application/portfolio.service.ts),
[валютные итоги](../../../../backend/src/modules/investments/portfolio/infrastructure/tbank-portfolio.mapper.ts),
[структура](../../../../backend/src/modules/investments/portfolio/domain/portfolio-structure.ts) и
[подготовка экрана](../../../../frontend/src/pages/account/ui/AccountPage.vm.ts).
[сервис снимков](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/portfolio/application/portfolio.service.ts),
[валютные итоги](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/portfolio/infrastructure/tbank-portfolio.mapper.ts),
[структура](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/modules/investments/portfolio/domain/portfolio-structure.ts) и
[подготовка экрана](https://git.personal.ksv741.ru/WealthLedger/frontend/src/commit/9f7e342333b80bfacfd5bc394a2dcd0613d33ff3/src/pages/account/ui/AccountPage.vm.ts).
Это точки продолжения расследования; смысл вычислений изложен выше.
Разбор завершён, когда различие объяснено составом, временем или определением
+2 -2
View File
@@ -64,7 +64,7 @@ SQLite не хранит сам портфель: backend получает да
без логотипа и с подписью результата. Отсутствующие показатели скрываются,
а не подменяются нулём или заглушкой.
Существует расхождение: [согласованная спецификация представления позиций](../../../specs/openspec/specs/portfolio-view/spec.md#requirement-представление-карточек-позиций-на-клиенте)
Существует расхождение: [согласованная спецификация представления позиций](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md#requirement-представление-карточек-позиций-на-клиенте)
требует доступности всех иных типов в отдельной секции, а текущие frontend
и его проверка исключают `CURRENCY` только из списка карточек. Такие позиции
остаются в ответе, валютных итогах, структуре и знаменателе долей остальных
@@ -95,5 +95,5 @@ SQLite не хранит сам портфель: backend получает да
Для проверки конкретной суммы используйте
[руководство по расхождениям](how-to/investigate-discrepancy.md).
Проверяемое поведение отдельного счёта описано в
[спецификации портфеля](../../../specs/openspec/specs/portfolio-view/spec.md);
[спецификации портфеля](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/portfolio-view/spec.md);
точную форму HTTP-ответа задаёт [OpenAPI backend](../../architecture/http-api.md).
+2 -2
View File
@@ -48,6 +48,6 @@ HTTP-запрос ограничен таймаутом. Сеть, неуспе
Наличие успешного HTTP-ответа не гарантирует котировку без задержки.
Условия обработки источника в прогнозе закреплены в
[спецификации будущих событий](../../specs/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-upcoming-events-use-complete-source-results).
[спецификации будущих событий](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/brokerage-account-upcoming-events/spec.md#requirement-upcoming-events-use-complete-source-results).
Точный механизм транспорта, разбора и сопоставления реализован в
[клиенте MOEX](../../backend/src/integrations/moex/moex.client.ts).
[клиенте MOEX](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/integrations/moex/moex.client.ts).
+1 -1
View File
@@ -36,7 +36,7 @@ ISIN, даты и ссылки на выпуск. Изменение табли
После ошибки новая загрузка ограничена минутным интервалом; внутри одного
HTTP-запроса повторных попыток нет. Обновление запускается следующим обращением
после истечения кэша, без фонового задания. Точный механизм и сроки принадлежат
[клиенту НКР](../../backend/src/integrations/ncr/ncr-ratings.client.ts).
[клиенту НКР](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/integrations/ncr/ncr-ratings.client.ts).
При отказе реестра показатели облигации отмечают недоступность рейтинга,
сохраняя остальные доступные показатели. Готовый ответ метрик имеет
+4 -4
View File
@@ -36,7 +36,7 @@ Backend передаёт имя файла `logoName` из метаданных
Логотипы используются в портфеле, операциях, будущих событиях, поиске и
страницах инструментов. Отсутствующее имя или ошибка изображения оставляют
буквенную заглушку и не меняют финансовые значения. Правило построения URL
принадлежит [форматированию frontend](../../frontend/src/shared/lib/display.ts).
принадлежит [форматированию frontend](https://git.personal.ksv741.ru/WealthLedger/frontend/src/commit/9f7e342333b80bfacfd5bc394a2dcd0613d33ff3/src/shared/lib/display.ts).
## Проверка и сохранение подключения
@@ -96,7 +96,7 @@ sequenceDiagram
для последующих запросов. Оно не описывает отзыв token на стороне T-Bank.
Согласованное поведение сохранено в workspace-спецификации
[T-Bank connection](../../specs/openspec/specs/tbank-connection/spec.md).
[T-Bank connection](https://git.personal.ksv741.ru/WealthLedger/specs/src/commit/9e227a563dda67620f0ad78228aa8a4c18bf35a0/openspec/specs/tbank-connection/spec.md).
Точные endpoints и формы ответов определяет backend OpenAPI;
[HTTP API](../architecture/http-api.md) описывает общую границу.
@@ -126,7 +126,7 @@ Backend хранит token в шифротексте AES-256-GCM с новым n
| `TBANK_CA_CERT_PATH` | Необязательный путь к доверенному корневому CA в PEM для сетей с TLS-инспекцией; проверка TLS сохраняется |
Параметры окружения определяет backend
[validateEnv](../../backend/src/config/env.validation.ts) (workspace-ссылка).
[validateEnv](https://git.personal.ksv741.ru/WealthLedger/backend/src/commit/016782657acfd35ff3fd755462007938fac35156/src/config/env.validation.ts) (справочный источник).
Общий FIFO-лимитер ограничивает поток RPC и не допускает более 50
ожидающих. Для `UNAVAILABLE`, `DEADLINE_EXCEEDED` и `RESOURCE_EXHAUSTED`
обычный RPC допускает один повтор через секунду. Deadline каждой попытки — 15 секунд,
@@ -139,7 +139,7 @@ Backend хранит token в шифротексте AES-256-GCM с новым n
отсутствие инструмента, а не временный сбой. Остальные RPC при полной
очереди завершаются сразу.
Параметры попыток принадлежат
[T-Bank client](../../backend/src/integrations/tbank/tbank.client.ts) (workspace-ссылка);
[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).
Большое число ранее неизвестных инструментов требует отдельных запросов
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "wealth-ledger-docs",
"version": "0.1.0",
"version": "0.1.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wealth-ledger-docs",
"version": "0.1.0",
"version": "0.1.1",
"devDependencies": {
"@commitlint/cli": "21.2.2",
"@commitlint/config-conventional": "21.2.2",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "wealth-ledger-docs",
"version": "0.1.0",
"version": "0.1.1",
"private": true,
"engines": {
"node": "24.21.0"