# Обзор системы 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).