Files
docs/architecture/system-overview.md
T

170 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Обзор системы
WealthLedger — локальное приложение для частного инвестора: оно связывает
состав портфеля, операции, полученный доход и будущие выплаты по счетам T-Bank.
Обзор объясняет систему сверху вниз. Детали сценариев и ответственность подсистем находятся
в [карте возможностей](../features/README.md).
## Поставленные возможности
- [Аутентификация](../features/authentication.md): access/refresh-сессии и
защищённые маршруты.
- [Подключение T-Bank](../features/tbank-connection.md): один зашифрованный
token на User.
- [Брокерские счета](../features/brokerage-accounts.md),
[Portfolio](../features/portfolio-view.md),
[Account Ledger](../features/brokerage-account-ledger.md),
[Пассивный доход](../features/brokerage-account-income-analytics.md) и
[Future Cash Events](../features/brokerage-account-upcoming-events.md).
- [Frontend UI resilience](../features/frontend-ui-resilience.md): явные
loading, error, empty и cached-snapshot состояния; initial и частичные
loading-состояния показывают structural skeleton, а уже доступный контекст
остаётся видимым при фоновом обновлении или действии пользователя.
- [Все счета](../features/all-accounts.md): общий портфель, журнал, доходы
и будущие выплаты с сохранением принадлежности к счетам.
- [Акции](../features/stock-detail.md) и [облигации](../features/bond-detail.md):
поиск, рыночные данные, личная позиция и события конкретного инструмента.
Термины этих возможностей определяет [глоссарий домена](domain-glossary.md), а
причины ключевых технических решений — [ADR](../adr/README.md).
## Контекст системы
```mermaid
flowchart LR
U[Частный инвестор] -->|Смотрит инвестиции| W[WealthLedger]
W -->|Счета, позиции, операции и рынок| T[T-Bank Invest API]
W -->|Публичные данные облигаций| M[MOEX ISS]
W -->|Рейтинги выпусков| N[Реестр НКР]
W -->|Изображения логотипов| C[T-Bank Brands CDN]
```
T-Bank — источник личных брокерских данных и рынка. MOEX дополняет будущие
события и показатели облигаций, НКР — рейтинг конкретного выпуска. Публичный
рейтинг или календарь выпуска не подтверждает личное зачисление инвестору.
Отсутствие записи и недоступность источника имеют разный смысл; детали —
[Bond detail](../features/bond-detail.md).
## Исполняемые части
На уровне C4 containers здесь два приложения и локальная база. Каталоги
`docs` и `specs` не являются runtime-компонентами.
```mermaid
flowchart LR
subgraph Browser[Браузер пользователя]
F[React SPA]
end
subgraph Local[Локальное окружение]
B[NestJS API]
D[(SQLite)]
B -->|Prisma: identity, sessions, connection| D
end
F -->|HTTP JSON, Bearer и auth cookie| B
B -->|gRPC over TLS, token пользователя| T[T-Bank Invest]
B -->|HTTPS, публичные данные| M[MOEX ISS]
B -->|HTTPS, публичный HTML| N[НКР]
F -->|HTTPS, изображения| C[Brands CDN]
```
- **Frontend** владеет представлением, навигацией и клиентским query cache.
Access token существует в памяти; refresh-cookie обслуживает browser.
- **Backend** владеет identity, проверкой доступа, credentials брокера,
нормализацией, денежными расчётами и upstream-кэшем.
- **SQLite** хранит локального User, sessions и зашифрованное подключение.
- **Интеграции backend** обращаются к T-Bank, MOEX и НКР, сохраняя различия
личных данных брокера и публичных данных выпуска. Браузер получает
изображения логотипов непосредственно из публичного CDN.
Frontend связывает пользовательские экраны навигацией. Backend объединяет
аутентификацию, подключение брокера и инвестиционные сценарии через публичный API.
Согласование адресов и origin — [локальный запуск](../development/local-workspace.md).
## Хранимые данные
Локальная база содержит идентичность пользователя и hash пароля, состояние
его сессий со сроком действия, признаком отзыва и hash текущего refresh token,
а также одно зашифрованное подключение T-Bank с временем подключения.
Сессии и подключение принадлежат конкретному пользователю; plaintext пароля
или broker token не является сохраняемым представлением credentials.
Изменения связанных локальных данных требуют сохранения их целостности.
Ротация сессии атомарно заменяет текущий refresh token: конкурентные запросы
не могут оба выиграть. Сетевой вызов брокера и изменение локальной базы не
образуют одну общую транзакцию. Финансовые наблюдения хранятся в ограниченном
кэше, а не как долговременная история брокерских данных.
## Локальные границы
- Финансовые API-запросы frontend проходят backend; browser не получает
T-Bank credential или gRPC client. Загрузка публичных логотипов — отдельный поток.
- Backend — NestJS API `/api/v1`, владеющий auth, SQLite-данными и T-Bank
gRPC boundary.
- OpenAPI backend — единственный контракт frontend; committed client
генерируется штатным workflow.
- Поставка остаётся локальной: deployment, Docker, CI/CD и облачные сервисы не
входят в текущие границы.
- Portfolio Snapshot, summary списка Brokerage Account, Future Cash Events и
Ledger pages существуют как read-only наблюдения текущего T-Bank connection;
система не хранит историю портфеля, будущих событий или брокерских счетов как
долговременные агрегаты. Summary списка сохраняет исходные валюты без FX-
агрегации и может быть локально недоступна для отдельного счета.
## Предметная модель
Локальный [User](domain-glossary.md#user) владеет
[Session](domain-glossary.md#session) и одним
[T-Bank connection](domain-glossary.md#t-bank-connection). Через подключение
backend устанавливает доступ к [Brokerage Accounts](domain-glossary.md#brokerage-account).
Идентификатор счёта из URL сам по себе не подтверждает этот доступ.
[Portfolio](domain-glossary.md#portfolio) отвечает на вопрос «что есть сейчас»,
[Account Ledger](domain-glossary.md#account-ledger) — «что исполнено»,
[Realized Income](domain-glossary.md#realized-income-analytics) — «какие выплаты
уже получены», будущие события — «что ожидается». Эти представления нельзя
подменять друг другом. [Money](domain-glossary.md#money) сохраняет исходную
валюту и точность; неизвестное значение отличается от нуля.
Режим [«Все счета»](../features/all-accounts.md) агрегирует доступный состав,
сохраняя происхождение строк; он не создаёт новый брокерский счёт. Обновление
подключения меняет границу финансовых кэшей; перезапуск backend не восстанавливает
прежние in-memory snapshots и cursor continuations из SQLite.
## Поток auth/session
Вход создаёт локальную сессию; последующие запросы используют access token.
После перезагрузки SPA восстанавливает сессию через refresh-cookie. Схема,
конкурентная ротация, logout и ограничения собраны у одного owner:
[Authentication](../features/authentication.md).
## Поток инвестиционных данных
```mermaid
sequenceDiagram
participant U as User
participant F as Frontend
participant B as Backend
participant D as SQLite
participant T as T-Bank gRPC
U->>F: Открывает счета или Portfolio
F->>B: GET /api/v1/brokerage-accounts/* (Bearer)
B->>D: Читает подключение текущего User
B->>T: Проверяет доступ к счёту
B->>T: Запрос через server-side gRPC boundary
T-->>B: Upstream-данные
B-->>F: Нормализованные данные или Problem Details
F-->>U: Экран с данными или локальным состоянием ошибки
```
Схема показывает запрос, которому нужны upstream-данные. Повторные чтения могут
обслуживаться кэшем по правилам конкретной feature. Проверку connection/account
выполняет backend: запрос связывается с пользователем, его текущим подключением
и доступными через него счетами, включая выдачу данных из кэша.
Внешняя ошибка не становится нулевым балансом; допустимость stale snapshot и
локальное восстановление описывает соответствующий сценарий.
Причины server-side границы, шифрования и retry policy —
[ADR 003](../adr/003-tbank-server-side-grpc-boundary.md),
[ADR 004](../adr/004-encrypted-per-user-tbank-token.md) и
[ADR 005](../adr/005-tbank-upstream-resilience.md).