From 462212c95eecc42ccdc0161091baa140046b4f3c Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Mon, 22 Jun 2026 22:15:51 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20update=20apps/docs=20=E2=80=94=20fix=20?= =?UTF-8?q?inconsistencies,=20add=20broker=20events=20diagrams?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/docs/docs/backend/api.md | 13 +++++++++ apps/docs/docs/backend/overview.md | 4 ++- apps/docs/docs/backend/tbank-invest.md | 37 ++++++++++++++++++++++++++ apps/docs/docs/development/commands.md | 14 ++++++++++ apps/docs/docs/development/testing.md | 22 +++++++++++++++ apps/docs/docs/frontend/components.md | 21 ++++++++++----- apps/docs/docs/frontend/hooks.md | 2 ++ apps/docs/docs/frontend/overview.md | 32 +++++++++------------- apps/docs/docs/frontend/routes.md | 32 ++++++++++++++++++++++ apps/docs/docs/infrastructure/ci.md | 36 +++++++++++-------------- apps/docs/sidebars.ts | 5 ++++ 11 files changed, 171 insertions(+), 47 deletions(-) diff --git a/apps/docs/docs/backend/api.md b/apps/docs/docs/backend/api.md index 6945f10..cd1d285 100644 --- a/apps/docs/docs/backend/api.md +++ b/apps/docs/docs/backend/api.md @@ -392,3 +392,16 @@ `DELETE` endpoints возвращают `{ data: null, meta }`, что отражено в OpenAPI schema и frontend codegen types. + +## Broker (T-Bank Invest) + +Все broker endpoints защищены JWT и возвращают envelope `{ data, meta }`. + +| Endpoint | Method | Описание | +|---|---|---| +| `/api/v1/broker/accounts` | GET | Список брокерских счетов и ИИС | +| `/api/v1/broker/accounts/:accountId/portfolio` | GET | Портфель счёта: позиции, cash, метаданные | +| `/api/v1/broker/accounts/:accountId/events` | GET | События и будущие выплаты (дивиденды, купоны) с фильтром по датам | +| `/api/v1/broker/accounts/:accountId/operations` | GET | История операций (cursor pagination) | +| `/api/v1/broker/accounts/:accountId/operations/refresh` | POST | Принудительная синхронизация операций из T-Bank | +| `/api/v1/broker/accounts/:accountId/positions` | GET | Позиции счёта (с пагинацией) | diff --git a/apps/docs/docs/backend/overview.md b/apps/docs/docs/backend/overview.md index 2702eec..c1d9925 100644 --- a/apps/docs/docs/backend/overview.md +++ b/apps/docs/docs/backend/overview.md @@ -48,5 +48,7 @@ apps/backend/src/ ├── securities/ ├── shares/ ├── bonds/ - └── candles/ + ├── candles/ + ├── portfolio/ + └── tbank/ ``` diff --git a/apps/docs/docs/backend/tbank-invest.md b/apps/docs/docs/backend/tbank-invest.md index 794b1fb..c9bdb26 100644 --- a/apps/docs/docs/backend/tbank-invest.md +++ b/apps/docs/docs/backend/tbank-invest.md @@ -40,9 +40,44 @@ root CA, которым локальная сеть или proxy подписы |---|---| | `GET /api/v1/broker/accounts` | Открытые брокерские счета и ИИС | | `GET /api/v1/broker/accounts/:accountId/portfolio` | Итоги портфеля, позиции, деньги и заблокированные деньги | +| `GET /api/v1/broker/accounts/:accountId/events` | Будущие события (дивиденды, купоны, погашения, оферты) и прошедшие фактические выплаты с фильтром по датам и типам | | `GET /api/v1/broker/accounts/:accountId/operations` | История операций с cursor pagination | | `POST /api/v1/broker/accounts/:accountId/operations/sync` | Синхронизация истории операций в локальные Prisma-таблицы | +## Поток данных для `/events` + +Endpoint `/events` агрегирует будущие события и прошедшие выплаты из нескольких источников: + +```mermaid +sequenceDiagram + actor User + participant Frontend + participant Backend + participant TBank as T-Bank gRPC + participant MOEX as MOEX ISS (cache) + + User->>Frontend: Открывает вкладку «События» + Frontend->>Backend: GET /broker/accounts/:id/events?from=X&to=Y&types=Z + Backend->>TBank: GetPositions (текущие позиции счёта) + TBank-->>Backend: positions[] + loop Для каждой позиции + Backend->>MOEX: Получить график купонов / дивидендов + MOEX-->>Backend: futureEvents[] + end + Backend->>TBank: GetOperationsByCursor (фактические выплаты за период) + TBank-->>Backend: pastPayouts[] + Note over Backend: Агрегация + фильтр по from/to/types + Backend-->>Frontend: { events[], summary } + Frontend->>User: Отображает таблицу событий и сумму выплат +``` + +- **Будущие события** — строятся на лету по текущим позициям счёта и MOEX-метаданным (график купонов, даты дивидендов). Не записываются в БД. +- **Прошедшие выплаты** — извлекаются из истории операций T-Bank за указанный период. +- **Summary** — агрегированная оценка будущих выплат (не является гарантированной суммой). +- Кешируется через `CACHE_TBANK_EVENTS_TTL`. + +Типы событий: `dividend`, `coupon`, `maturity`, `offer`. Первые три относятся к `cashflow`, `offer` — к `corporate`. + ## Методы T-Bank | Задача | Метод T-Bank | @@ -51,6 +86,7 @@ root CA, которым локальная сеть или proxy подписы | Итоги портфеля | `OperationsService/GetPortfolio` | | Деньги и settled-позиции | `OperationsService/GetPositions` | | История операций | `OperationsService/GetOperationsByCursor` | +| События и выплаты | Агрегация из позиций счёта + фактических операций | | Метаданные инструментов | `InstrumentsService/GetInstrumentBy` | ## Кеширование и синхронизация @@ -62,6 +98,7 @@ Direct-read endpoints используют короткий in-memory cache, ч - портфель: `CACHE_TBANK_PORTFOLIO_TTL` - позиции: `CACHE_TBANK_POSITIONS_TTL` - страницы операций: `CACHE_TBANK_OPERATIONS_TTL` +- события и прогноз выплат: `CACHE_TBANK_EVENTS_TTL` - метаданные инструментов: `CACHE_TBANK_INSTRUMENT_TTL` Для долговременной истории операций есть отдельные таблицы Prisma: diff --git a/apps/docs/docs/development/commands.md b/apps/docs/docs/development/commands.md index 1d66501..da8fc43 100644 --- a/apps/docs/docs/development/commands.md +++ b/apps/docs/docs/development/commands.md @@ -7,11 +7,16 @@ | `npm run dev:backend` | Запуск NestJS в режиме watch на :3000 | | `npm run dev:frontend` | Vite dev-сервер на `:5173`, проксирует `/api` на backend | | `npm run dev:docs` | Docusaurus dev-сервер документации | +| `npm run dev:design-system` | Storybook dev-сервер дизайн-системы | | `npm run build:backend` | `nest build` | | `npm run build:frontend` | `tsc -b && vite build` | | `npm run build:docs` | `docusaurus build` | +| `npm run build:design-system` | TypeScript build дизайн-системы | +| `npm run build:storybook` | Production build Storybook | | `npm run test:backend` | Offline backend unit tests через Vitest | | `npm run test:frontend` | Frontend tests через Vitest + Testing Library | +| `npm run test:design-system` | Design system tests через Vitest | +| `npm run test:storybook` | Storybook browser tests (Playwright) | | `npm run lint` | ESLint для backend и frontend | | `npm run format` | Prettier для всех `*.{ts,tsx}` | | `npm run format:check` | Проверка Prettier для всех `*.{ts,tsx}` | @@ -39,6 +44,15 @@ | `npm run lint -w apps/frontend` | ESLint для `src/**/*.{ts,tsx}` | | `npm run test -w apps/frontend` | Frontend Vitest suite | +## Design system workspace + +| Команда | Описание | +|---|---| +| `npm run dev -w packages/design-system` | Storybook dev-server | +| `npm run build -w packages/design-system` | TypeScript build | +| `npm run build:storybook -w packages/design-system` | Production build Storybook | +| `npm run test -w packages/design-system` | Vitest suite | + ## Docs workspace | Команда | Описание | diff --git a/apps/docs/docs/development/testing.md b/apps/docs/docs/development/testing.md index 0b5e1d9..7c8906d 100644 --- a/apps/docs/docs/development/testing.md +++ b/apps/docs/docs/development/testing.md @@ -51,6 +51,28 @@ npm run test -w apps/frontend Тесты покрывают API-клиент, auth context, hooks, базовые pages и shared components. +## Тесты design system + +Фреймворк: **Vitest** + **React Testing Library** + **Accessibility check**. + +Запуск: + +```bash +npm run test:design-system +# или +npm run test -w packages/design-system +``` + +Тесты покрывают компоненты дизайн-системы: Button, DataTable, Select, Skeleton, Money и др. + +## Storybook browser tests + +Интерактивные тесты Storybook через Playwright. + +```bash +npm run test:storybook +``` + ## Live MOEX integration tests Live MOEX checks вынесены из default backend suite. diff --git a/apps/docs/docs/frontend/components.md b/apps/docs/docs/frontend/components.md index c043ae0..d04a767 100644 --- a/apps/docs/docs/frontend/components.md +++ b/apps/docs/docs/frontend/components.md @@ -1,7 +1,7 @@ # Компоненты -Published docs ниже перечисляют primary entrypoints. Legacy файлы в `components/` сохранены как -тонкие re-export shim'ы для coexistence со старыми импортами. +Published docs ниже перечисляют primary entrypoints. Все legacy-файлы в `components/` удалены, +компоненты используют FSD-структуру. ## Layout (`app/layouts/AppLayout.tsx`, legacy shim: `components/Layout.tsx`) @@ -19,7 +19,7 @@ Published docs ниже перечисляют primary entrypoints. Legacy фа - При клике на результат переходит на `/stocks/:secid` или `/bonds/:secid` - Закрывается при клике вне компонента -Legacy path `components/SearchBar.tsx` остаётся shim-файлом и не является primary entrypoint. +Legacy path `components/SearchBar.tsx` удалён. ## PriceChart (`widgets/price-chart/ui/PriceChart.tsx`, public API: `widgets/price-chart`) @@ -30,7 +30,7 @@ Legacy path `components/SearchBar.tsx` остаётся shim-файлом и н - Цвета: зелёный для роста, красный для падения - Адаптивная ширина (resize listener) -Legacy path `components/PriceChart.tsx` остаётся shim-файлом. +Legacy path `components/PriceChart.tsx` удалён. ## StockDetails (`widgets/stock-details/ui/StockDetails.tsx`, public API: `widgets/stock-details`) @@ -39,7 +39,7 @@ Legacy path `components/PriceChart.tsx` остаётся shim-файлом. - Принимает `ShareResponse` - Отображает: название, тикер, ISIN, цена, изменение (%), open/high/low, объём, капитализация, уровень листинга -Legacy path `components/StockDetails.tsx` остаётся shim-файлом. +Legacy path `components/StockDetails.tsx` удалён. ## BondDetails (`widgets/bond-details/ui/BondDetails.tsx`, public API: `widgets/bond-details`) @@ -48,7 +48,7 @@ Legacy path `components/StockDetails.tsx` остаётся shim-файлом. - Принимает `BondResponse` - Отображает: название, ISIN, цена (в % от номинала), номинал, дата погашения, купон (сумма/%), период купона, НКД, доходность к погашению, дюрация, тип -Legacy path `components/BondDetails.tsx` остаётся shim-файлом. +Legacy path `components/BondDetails.tsx` удалён. ## DividendsTable (`widgets/dividends-table/ui/DividendsTable.tsx`, public API: `widgets/dividends-table`) @@ -57,3 +57,12 @@ Legacy path `components/BondDetails.tsx` остаётся shim-файлом. - Принимает готовый список дивидендов через props - Рендерит payout-историю без собственных query-вызовов - Используется page-layer как prop-driven widget + +## BrokerEventsOverview (`widgets/broker-events-overview/ui/BrokerEventsOverview.tsx`, public API: `widgets/broker-events-overview`) + +Обзор ближайших событий и будущих выплат брокерского счёта. + +- Принимает `accountId` +- Показывает до 5 ближайших событий (дивиденды, купоны) +- Ссылка на полную страницу событий +- Состояния: загрузка, ошибка, пустой список diff --git a/apps/docs/docs/frontend/hooks.md b/apps/docs/docs/frontend/hooks.md index f09ef4d..52fd35f 100644 --- a/apps/docs/docs/frontend/hooks.md +++ b/apps/docs/docs/frontend/hooks.md @@ -10,6 +10,7 @@ | `useStockDividends(secid)` | `['stockDividends', secid]` | 86400s | Дивиденды акции | | `useBond(secid)` | `['bond', secid]` | 900s | Спецификация облигации | | `useBondCandles(secid, interval, from, till)` | `['bondCandles', secid, interval, from, till]` | 3600s | Свечи облигации | +| `useBrokerEvents(accountId, { from, to, types })` | `['broker', 'events', accountId, from, to, types]` | 300s | Будущие события и прошедшие выплаты брокерского счёта | ## Public API @@ -20,6 +21,7 @@ - broker-account hooks: `entities/broker-account/index.ts` - broker-position hooks: `entities/broker-position/index.ts` - broker-operation hooks: `entities/broker-operation/index.ts` +- broker-event hooks: `entities/broker-event/index.ts` - session hooks: `entities/session/index.ts` ## Конфигурация Query diff --git a/apps/docs/docs/frontend/overview.md b/apps/docs/docs/frontend/overview.md index 46db3ab..78a54db 100644 --- a/apps/docs/docs/frontend/overview.md +++ b/apps/docs/docs/frontend/overview.md @@ -14,8 +14,8 @@ React SPA, собранная с Vite. ## Структура исходников -Published-структура ниже описывает primary FSD entrypoints. Исторические каталоги `api/`, `context/`, -`hooks/`, `components/` ещё присутствуют в кодовой базе для ещё не мигрированных доменов. +Published-структура ниже описывает primary FSD entrypoints. Исторические каталоги полностью +мигрированы. ``` apps/frontend/src/ @@ -34,6 +34,8 @@ apps/frontend/src/ │ └── layouts/ │ ├── AppLayout.tsx # Шапка + │ └── index.ts +├── features/ # FSD features +│ └── screener/ # Скринер ценных бумаг (api, model, ui) ├── shared/ │ ├── api/ # shared API client, response types, generated OpenAPI types │ └── ui/ # shared UI primitives without domain logic @@ -55,6 +57,7 @@ apps/frontend/src/ │ ├── broker-account-card/ # Карточка брокерского счёта │ ├── broker-accounts-summary/ # Сводка брокерских счетов │ ├── broker-allocation-chart/ # График распределения +│ ├── broker-events-overview/ # Ближайшие события (обзор) │ ├── broker-operations-table/ # Таблица операций │ ├── portfolio-card/ # Карточка портфеля │ ├── portfolio-form/ # Форма портфеля @@ -73,14 +76,9 @@ apps/frontend/src/ │ ├── screener/ # Скринер (не мигрирован) │ ├── broker-accounts/ # FSD: page entrypoint │ ├── broker-account/ # FSD: page entrypoint +│ ├── broker-events/ # FSD: page entrypoint │ ├── broker-positions/ # FSD: page entrypoint │ └── broker-operations/ # FSD: page entrypoint -├── api/ -│ └── screener.ts # Screener API helpers (не мигрирован) -├── hooks/ -│ └── useScreener.ts # Screener hook (не мигрирован) -├── components/ -│ └── screener/ # Screener UI (не мигрирован) ├── test/ │ ├── factories.ts # Фабрики тестовых данных │ ├── handlers.ts # MSW handlers @@ -116,6 +114,7 @@ apps/frontend/src/ | `broker-account` | API брокерских счетов | useBrokerAccounts, useBrokerAccountPortfolios | BrokerAccountLayout | | `broker-position` | API брокерских позиций | useBrokerPositions | — | | `broker-operation` | API брокерских операций | useBrokerOperations | — | +| `broker-event` | API брокерских событий и выплат | useBrokerEvents | — | Каждая сущность имеет barrel-файл `index.ts`, реэкспортирующий публичное API. @@ -135,17 +134,10 @@ apps/frontend/src/ - `pages/home`, `pages/stock`, `pages/bond` — FSD page entrypoints для market pages - `pages/broker-*` — FSD page entrypoints для брокерского домена -- Временно не мигрированы: `portfolios/`, `screener/`, `LoginPage.tsx`, `RegisterPage.tsx`, `ProfilePage.tsx` +- `pages/portfolios/` — FSD page entrypoints для портфелей +- `pages/screener/` — FSD page entrypoint для скринера +- `pages/LoginPage.tsx`, `RegisterPage.tsx`, `ProfilePage.tsx` — auth страницы, используют FSD-imports из `entities/session` -### Не мигрировано +### features -Скринер остаётся в исторической структуре: - -- `api/screener.ts` — API-вызовы -- `hooks/useScreener.ts` — логика с URLSearchParams -- `components/screener/` — FilterPanel, FilterPanelBond, FilterPanelShare, ScreenerTable -- `pages/screener/ScreenerPage.tsx` — страница - -Страницы аутентификации (`LoginPage`, `RegisterPage`, `ProfilePage`) — плоские, но используют FSD-импорты из `entities/session`. - -ESLint-правила на границы импортов FSD пока не введены. +- `features/screener/` — скринер: FilterPanel, FilterPanelBond, FilterPanelShare, ScreenerTable, useScreener hook diff --git a/apps/docs/docs/frontend/routes.md b/apps/docs/docs/frontend/routes.md index fb5fe9d..cd4f5ee 100644 --- a/apps/docs/docs/frontend/routes.md +++ b/apps/docs/docs/frontend/routes.md @@ -15,6 +15,7 @@ Source of truth для маршрутов: `apps/frontend/src/app/routing/AppRou | `/portfolios/:id` | `PortfolioDetailPage` | Protected | Детальная страница портфеля | | `/broker` | `BrokerAccountsPage` from `pages/broker-accounts` | Protected | Список брокерских счетов | | `/broker/:accountId` | `BrokerAccountLayout` + nested pages | Protected | Детальная область брокерского счёта | +| `/broker/:accountId/events` | `BrokerEventsPage` from `pages/broker-events` | Protected | Календарь событий и выплат | Все page entrypoints живут в FSD-слоях: @@ -25,6 +26,7 @@ Source of truth для маршрутов: `apps/frontend/src/app/routing/AppRou - `pages/broker-account` - `pages/broker-positions` - `pages/broker-operations` +- `pages/broker-events` Все страницы обёрнуты в `AppLayout`, который содержит: @@ -87,7 +89,37 @@ Source of truth для маршрутов: `apps/frontend/src/app/routing/AppRou } /> } /> } /> + } /> ``` + +## Композиция страницы событий + +Страница `/broker/:accountId/events` собирается из FSD-слоёв: + +```mermaid +flowchart TB + BrokerEventsPage["pages/broker-events
BrokerEventsPage"] + useBrokerEvents["entities/broker-event
useBrokerEvents"] + BrokerEventApi["entities/broker-event/api
brokerEventApi"] + BrokerEventsOverview["widgets/broker-events-overview
BrokerEventsOverview"] + DS["@moex-vibe/design-system
DatePicker, Select, Button
DataTable, Metric, LoadingState"] + + BrokerEventsPage --> useBrokerEvents + BrokerEventsPage --> BrokerEventsOverview + BrokerEventsPage --> DS + + useBrokerEvents --> BrokerEventApi + + subgraph Overview["Обзор на dashboard счёта"] + BrokerAccountOverview["pages/broker-account
BrokerAccountOverviewPage"] + BrokerAccountOverview --> BrokerEventsOverview + end +``` + +- `BrokerEventsPage` — entrypoint страницы: фильтр по датам/типам, таблица событий, summary +- `BrokerEventsOverview` — компактный блок 5 ближайших событий (используется на overview счёта) +- `useBrokerEvents` — TanStack Query hook с ключом `['broker', 'events', accountId, from, to, types]` +``` diff --git a/apps/docs/docs/infrastructure/ci.md b/apps/docs/docs/infrastructure/ci.md index 80a8723..af48e19 100644 --- a/apps/docs/docs/infrastructure/ci.md +++ b/apps/docs/docs/infrastructure/ci.md @@ -18,25 +18,21 @@ env: ## Jobs -### lint +Единый job `ci` выполняет последовательно: -- `actions/checkout@v4` -- `actions/setup-node@v4` (Node 20) -- `npm ci` -- `npm run lint` (ESLint для бэкенда) -- `npx prettier --check "**/*.{ts,tsx}"` (проверка форматирования) +1. **Checkout** — `actions/checkout@v4` +2. **Setup Node** — `actions/setup-node@v4` (Node 20) +3. **Install** — `npm ci` +4. **Lint** — `npm run lint` +5. **Format check** — `npm run format:check` +6. **Test backend** — `npm run test:backend` +7. **Test frontend** — `npm run test:frontend` +8. **Test design system** — `npm run test:design-system` +9. **Test Storybook (browser)** — `npm run test:storybook` +10. **Build backend** — `npm run build:backend` +11. **Build frontend** — `npm run build:frontend` +12. **Build design system** — `npm run build:design-system` +13. **Build Storybook** — `npm run build:storybook` +14. **Build docs** — `npm run build:docs` -### test - -- `actions/checkout@v4` -- `actions/setup-node@v4` (Node 20) -- `npm ci` -- `npm run test:backend` (vitest) - -### build - -- `actions/checkout@v4` -- `actions/setup-node@v4` (Node 20) -- `npm ci` -- `npm run build:backend` (nest build) -- `npm run build:frontend` (tsc -b && vite build) +При failure Storybook build артефакты загружаются для диагностики. diff --git a/apps/docs/sidebars.ts b/apps/docs/sidebars.ts index 001d74c..b2f0197 100644 --- a/apps/docs/sidebars.ts +++ b/apps/docs/sidebars.ts @@ -78,6 +78,11 @@ const sidebars: SidebarsConfig = { 'adr/ADR-009-portfolio-domain', 'adr/ADR-010-backend-price-computation', 'adr/ADR-011-tbank-invest-grpc', + 'adr/ADR-012-frontend-broker-account-aggregation', + 'adr/ADR-013-frontend-fsd-broker-pilot', + 'adr/ADR-014-frontend-fsd-market-pages', + 'adr/ADR-015-frontend-libraries-modernization', + 'adr/ADR-016-design-system', ], }, ],