docs: add broker events and payouts feature docs #35

Merged
ksv741 merged 1 commits from codex/broker-events-and-payouts into main 2026-06-21 21:30:06 +03:00
6 changed files with 490 additions and 0 deletions

View File

@ -28,6 +28,7 @@
- [Отображение брокерского портфеля](../features/broker-portfolio-display/spec.md) - [Отображение брокерского портфеля](../features/broker-portfolio-display/spec.md)
- [x] [Разделы брокерского счёта](../features/broker-account-sections/spec.md) — реализовано - [x] [Разделы брокерского счёта](../features/broker-account-sections/spec.md) — реализовано
- [Информативный обзор брокерских счетов](../features/broker-accounts-overview/spec.md) - [Информативный обзор брокерских счетов](../features/broker-accounts-overview/spec.md)
- [Календарь событий и прогноз будущих выплат брокерского счёта](../features/broker-events-and-payouts/spec.md)
- [Улучшение UI операций](../features/broker-operations-ui-improvements/spec.md) - [Улучшение UI операций](../features/broker-operations-ui-improvements/spec.md)
- [Пагинация и загрузка позиций](../features/broker-positions-pagination-and-loading/spec.md) - [Пагинация и загрузка позиций](../features/broker-positions-pagination-and-loading/spec.md)
- [Исправление deadline и очереди T-Bank](../features/tbank-deadline-queue-fix/spec.md) - [Исправление deadline и очереди T-Bank](../features/tbank-deadline-queue-fix/spec.md)

View File

@ -0,0 +1,209 @@
# Broker Events And Payouts Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use
> checkbox (`- [ ]`) syntax for tracking.
**Goal:** Добавить в брокерский счёт T-Bank раздел предстоящих событий и ориентировочный прогноз
будущих выплат по выбранному периоду.
**Architecture:** Backend добавляет отдельный read-only endpoint событий поверх уже существующих
данных T-Bank и MOEX. Слой агрегации строит best-effort список событий по текущим позициям счёта и
summary по будущим денежным потокам. Frontend расширяет shell брокерского счёта новой вкладкой
`События`, отдельной страницей и компактным overview-виджетом ближайших событий.
**Tech Stack:** NestJS 10, Prisma, CacheService, MOEX client, T-Bank module, React 18, React Router
6, TanStack Query 5, TypeScript, Vitest, Testing Library.
---
## Связанные SDD-артефакты
- Epic: `docs/epics/BrokerPortfolio.md`
- Spec: `docs/features/broker-events-and-payouts/spec.md`
- Tasks: `docs/features/broker-events-and-payouts/tasks.md`
## Gate перед реализацией
До начала кода пользователь должен отдельно подтвердить, что:
- текущая spec остаётся источником истины;
- `plan.md` и `tasks.md` согласованы;
- первая версия действительно ограничивается T-Bank-сценарием и оценкой по текущим позициям;
- follow-up по entitlement, налогам и полной купонной сетке остаются вне реализации.
## Архитектурные решения
### Backend endpoint
Новый endpoint:
```text
GET /api/v1/broker/accounts/:accountId/events?from=YYYY-MM-DD&to=YYYY-MM-DD
```
Endpoint возвращает:
- `items` — плоский список событий по текущим позициям счёта;
- `summary` — агрегаты по денежным событиям за период;
- `asOf` — момент построения read model.
### Backend read model
Новый сервис `BrokerEventsService` живёт внутри `TBankModule` и использует:
- `BrokerAccountsService` для проверки счёта;
- `BrokerPortfolioService` или внутренний shared-path для получения текущих позиций;
- `BrokerInstrumentsService` для сопоставления T-Bank instrument metadata;
- `MoexClientService` для дивидендов и bond enrichment;
- `CacheService` для кэширования результата по `accountId + from + to`.
Сервис не записывает события в Prisma и не вводит отдельные таблицы в первой версии.
### Формирование событий
По акциям:
- для каждой позиции, сопоставимой с MOEX share instrument, читаются dividend events;
- в выборку попадают только события, чья `registryCloseDate` лежит в диапазоне;
- `estimatedAmount` рассчитывается как текущий `quantity * payoutPerUnit`, если payout известен.
По облигациям:
- используется уже доступный enrichment-слой MOEX;
- `nextCouponDate` даёт событие `coupon`;
- `matDate` даёт событие `maturity`;
- `offerDate` даёт событие `offer`;
- `couponValue` и `faceValue` используются для оценки `estimatedAmount`, когда они доступны.
### Семантика summary
`summary` агрегирует только денежные события:
- дивиденды;
- купоны;
- погашения.
Оферты остаются в общем списке событий, но не обязаны входить в сумму денежных потоков первой
версии.
### Частичная деградация
Сервис работает по принципу best-effort:
- ошибка по одной бумаге не роняет весь ответ;
- unsupported или несопоставимые позиции пропускаются;
- если сумма события не может быть рассчитана, событие всё равно возвращается без суммы.
## API и типы
### Query contract
Новый query DTO:
```ts
type BrokerEventsQuery = {
from: string;
to: string;
};
```
Обе даты обязательны в первой версии, чтобы не вводить неочевидные дефолты по периоду.
### Response contract
```ts
type BrokerPortfolioEvent = {
id: string;
type: 'dividend' | 'coupon' | 'maturity' | 'offer';
category: 'cashflow' | 'corporate';
eventDate: string;
paymentDate: string | null;
ticker: string | null;
name: string | null;
instrumentUid: string | null;
instrumentType: 'share' | 'bond' | 'other';
quantitySnapshot: number | null;
payoutPerUnit: number | null;
estimatedAmount: number | null;
currency: string | null;
estimateMode: 'current_position';
};
type BrokerEventsSummary = {
eventCount: number;
nearestEventDate: string | null;
totalEstimatedCashflow: number;
dividendsTotal: number;
couponsTotal: number;
principalRepaymentTotal: number;
};
```
## Карта файлов
### Backend
- Create `apps/backend/src/modules/tbank/dto/broker-events-query.dto.ts`
- Create `apps/backend/src/modules/tbank/dto/broker-events-response.dto.ts`
- Modify `apps/backend/src/modules/tbank/dto/broker-envelope.dto.ts`
- Modify `apps/backend/src/modules/tbank/types/broker.types.ts`
- Create `apps/backend/src/modules/tbank/services/broker-events.service.ts`
- Create `apps/backend/src/modules/tbank/services/broker-events.service.spec.ts`
- Modify `apps/backend/src/modules/tbank/tbank.controller.ts`
- Modify `apps/backend/src/modules/tbank/tbank.controller.spec.ts`
- Modify `apps/backend/src/modules/tbank/tbank.module.ts`
### Frontend
- Modify `apps/frontend/src/shared/api/responses.ts`
- Modify `apps/frontend/src/shared/api/index.ts`
- Modify `apps/frontend/src/shared/api/types.ts` through codegen if Swagger changes are published
- Create `apps/frontend/src/entities/broker-event/api/brokerEventApi.ts`
- Create `apps/frontend/src/entities/broker-event/model/useBrokerEvents.ts`
- Create `apps/frontend/src/entities/broker-event/index.ts`
- Create `apps/frontend/src/pages/broker-events/ui/BrokerEventsPage.tsx`
- Create `apps/frontend/src/pages/broker-events/index.ts`
- Create `apps/frontend/src/widgets/broker-events-overview/ui/BrokerEventsOverview.tsx`
- Create `apps/frontend/src/widgets/broker-events-overview/index.ts`
- Modify `apps/frontend/src/widgets/broker-account-layout/ui/BrokerAccountLayout.tsx`
- Modify `apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx`
- Modify `apps/frontend/src/app/routing/AppRoutes.tsx`
### Documentation
- Modify `apps/docs/docs/backend/tbank-invest.md`
- Modify `apps/docs/docs/backend/modules.md` if the public module description changes materially
## Rollout shape
### Overview
Overview получает компактный блок ближайших событий:
- не более 5 событий;
- summary по ближайшим выплатам не обязателен, если он перегружает карточку;
- ссылка ведёт в полный раздел `События`.
### Dedicated page
Страница `События` включает:
- выбор диапазона дат;
- summary cards;
- список событий;
- loading, empty и error states.
## Verification strategy
- Backend unit tests для event mapping, summary и partial failures.
- Backend controller tests для query validation и response shape.
- Frontend hook tests для query lifecycle.
- Frontend page/component tests для фильтра периода, summary и overview-виджета.
- Final verification:
- `npm test -w apps/backend`
- `npm test -w apps/frontend`
- `npm run build -w apps/backend`
- `npm run build -w apps/frontend`
- `npm run build -w apps/docs` если публичные docs менялись
- `npm run codegen -w apps/frontend` если Swagger-контракт обновлён

View File

@ -0,0 +1,191 @@
# Календарь событий и прогноз будущих выплат брокерского счёта
Дата: 2026-06-21
Статус: согласовано к планированию
Эпик: [Портфель брокера](../../epics/BrokerPortfolio.md)
## Цель
Дать пользователю брокерского счёта T-Bank отдельный раздел, где можно увидеть будущие события по
бумагам счёта и ориентировочный денежный поток по выбранному диапазону дат.
## Пользовательский результат
Пользователь может:
- быстро увидеть ближайшие события по текущему счёту прямо на overview;
- открыть отдельную вкладку `События` внутри счёта;
- выбрать период, например с `2026-06-22` по `2026-07-29`;
- получить список дивидендов, купонов, погашений и оферт, попадающих в этот период;
- увидеть ориентировочную сумму будущих выплат по выбранному диапазону;
- понимать, какие значения являются оценкой по текущим позициям, а не подтверждённым правом на
выплату.
## Область изменений
Фича относится только к брокерским счетам T-Bank и включает:
- новый блок ближайших событий на overview счёта;
- новую вкладку `События` в навигации брокерского счёта;
- фильтр диапазона дат;
- список событий по текущим позициям счёта;
- агрегированный summary по будущим выплатам за выбранный период.
## Требования
### 1. Область первой версии
- Первая версия работает только внутри маршрутов `/broker/:accountId/*`.
- Ручные портфели `PortfolioModule` не входят в область фичи.
- Backend остаётся единственным клиентом T-Bank и MOEX.
- Фича является read-only и не изменяет состав счёта или права пользователя.
### 2. Навигация и точки входа
- На overview брокерского счёта показывается компактный блок ближайших событий.
- Блок overview содержит переход во вкладку `События`.
- У счёта появляется отдельный раздел `События` рядом с существующими разделами `Обзор`, `Акции`,
`Облигации` и `Операции`.
- Переход между разделами не меняет выбранный счёт.
### 3. Типы событий первой версии
Первая версия поддерживает события:
- `dividend` — дивиденд по акции;
- `coupon` — купон по облигации;
- `maturity` — погашение облигации;
- `offer` — оферта по облигации.
По смыслу события делятся на:
- `cashflow` — событие с ожидаемым денежным эффектом;
- `corporate` — важное событие без обязательной денежной оценки в первой версии.
Правила классификации:
- `dividend` относится к `cashflow`;
- `coupon` относится к `cashflow`;
- `maturity` относится к `cashflow`;
- `offer` относится к `corporate`.
### 4. Диапазон дат
- Пользователь задаёт диапазон `from` / `to`.
- Диапазон фильтруется по дате события, а не по дате поступления денег.
- Границы диапазона включительные.
- Если `eventDate` не попадает в диапазон, событие не показывается.
- В первой версии отдельный режим фильтрации по `paymentDate` отсутствует.
### 5. Источники данных
- Для состава счёта используются текущие позиции T-Bank.
- Для акций используются дивидендные данные MOEX.
- Для облигаций используются уже доступные поля MOEX enrichment, включая `nextCouponDate`,
`couponValue`, `matDate`, `offerDate` и `faceValue`.
- Фича не требует отдельного постоянного хранилища событий в первой версии.
### 6. Правила прогноза выплат
- Все денежные суммы первой версии являются оценкой по текущим позициям счёта на момент запроса.
- Фича не восстанавливает историческое владение бумагой на дату отсечки.
- Если состав счёта изменится, прогноз по тем же датам может измениться.
- UI обязан явно показывать, что сумма является estimate или прогнозом.
#### Дивиденды
- Событие строится по `registryCloseDate`.
- Если размер выплаты доступен, ориентировочная сумма считается как количество бумаг в текущем
счёте, умноженное на выплату на единицу.
- Если размер выплаты отсутствует, событие всё равно может быть показано без итоговой суммы.
#### Купоны
- Событие строится по `nextCouponDate`.
- Если размер купона доступен, ориентировочная сумма считается как количество облигаций в текущем
счёте, умноженное на `couponValue`.
- Если размер купона отсутствует, событие показывается без итоговой суммы.
#### Погашение
- Событие строится по `matDate`.
- Если известен `faceValue`, ориентировочная сумма считается как количество облигаций в текущем
счёте, умноженное на номинал.
- Если номинал отсутствует, событие показывается без итоговой суммы.
#### Оферта
- Событие строится по `offerDate`.
- В первой версии оферта считается информационным событием.
- Для оферты не требуется обязательная денежная оценка.
### 7. Overview счёта
- Overview показывает ближайшие 3-5 событий выбранного счёта.
- Для каждого события overview показывает дату, инструмент, тип события и сумму при наличии.
- Если ближайших событий нет, overview показывает спокойное пустое состояние.
- Ошибка загрузки блока событий не должна ломать остальной overview счёта.
### 8. Вкладка `События`
- Вкладка содержит фильтр периода, summary и список событий.
- Список событий показывает:
- дату события;
- тип события;
- инструмент;
- тип инструмента;
- количество бумаг, использованное для расчёта;
- выплату на единицу при наличии;
- итоговую ориентировочную сумму при наличии;
- валюту при наличии.
- Для денежных оценок UI показывает признак `estimate`.
### 9. Summary по периоду
Summary по выбранному периоду показывает:
- количество событий;
- ближайшую дату события;
- общий ориентировочный денежный поток;
- сумму дивидендов;
- сумму купонов;
- сумму погашений.
Оферты не обязаны входить в денежный итог первой версии.
### 10. Ошибки, пустые состояния и частичная деградация
- Ошибка по одному инструменту не должна ломать весь календарь счёта.
- Если по событию недоступна сумма, событие может быть показано без суммы.
- Если в выбранном диапазоне нет событий, пользователь видит пустое состояние, а не ошибку.
- Ошибка вкладки `События` не должна скрывать общую навигацию счёта.
## Ограничения
- Первая версия не покрывает ручные портфели.
- Первая версия не учитывает налоги, комиссии и валютную конвертацию.
- Первая версия не различает в UI `eventDate` и `paymentDate` как отдельные режимы фильтрации.
- Если источник облигаций даёт только ближайший купон, дальний график будущих купонов не
гарантируется.
- Фича не заменяет историческую аналитику операций и не является налоговым расчётом.
## Acceptance Criteria
- На overview брокерского счёта отображается блок ближайших событий.
- В навигации брокерского счёта есть вкладка `События`.
- Пользователь может задать диапазон дат.
- Вкладка показывает только события, дата которых попадает в выбранный диапазон.
- Пользователь видит дивиденды, купоны, погашения и оферты, если они доступны по текущим позициям.
- Summary показывает агрегированный прогноз будущих выплат по диапазону.
- Все денежные суммы явно обозначены как оценочные.
- Пустой диапазон отображается как отдельное пустое состояние.
- Ошибка по одному инструменту не ломает весь ответ.
## Вне области фичи
- точный entitlement-расчёт по историческому владению и датам отсечки;
- поддержка ручных портфелей;
- единый календарь по нескольким доменам портфелей;
- налоги, мультивалютный net cashflow и комиссии;
- iCal/export, уведомления и напоминания;
- отдельный аналитический раздел вне брокерского счёта.

View File

@ -0,0 +1,78 @@
# Календарь событий и прогноз будущих выплат брокерского счёта — задачи
Статус: запланировано
Связанные документы:
- [Epic](../../epics/BrokerPortfolio.md)
- [Spec](spec.md)
- [Plan](plan.md)
## 1. Подготовка и gate
- [ ] Получить отдельное подтверждение `spec.md`, `plan.md` и `tasks.md` перед началом кода.
- [ ] Подтвердить, что первая версия ограничена T-Bank-сценарием и расчётом по текущим позициям.
- [ ] Зафиксировать, что follow-up по historical entitlement, налогам и полной купонной сетке не
входят в первую реализацию.
## 2. Backend contract
- [ ] Добавить новый broker endpoint событий с обязательными параметрами `from` и `to`.
- [ ] Описать Swagger DTO для query, response item, summary и envelope.
- [ ] Синхронизировать backend internal types для списка событий и summary.
## 3. Backend aggregation
- [ ] Добавить `BrokerEventsService` в `TBankModule`.
- [ ] Собрать текущие позиции счёта через существующий backend path без frontend-композиции.
- [ ] Построить dividend events по MOEX dividend data.
- [ ] Построить coupon, maturity и offer events по MOEX bond enrichment.
- [ ] Рассчитывать `estimatedAmount` только там, где для этого достаточно данных.
- [ ] Реализовать best-effort деградацию по отдельным инструментам.
- [ ] Добавить кэширование результата по `accountId + from + to`.
## 4. Backend tests
- [ ] Покрыть дивиденды, купоны, погашения и оферты unit-тестами.
- [ ] Проверить включительные границы диапазона дат.
- [ ] Проверить partial-failure сценарий, где один инструмент не ломает весь ответ.
- [ ] Проверить controller response shape и валидацию query.
## 5. Frontend data layer
- [ ] Добавить entity/hook для чтения broker events.
- [ ] Добавить handwritten response types для событий и summary.
- [ ] Обновить generated frontend API types, если меняется опубликованный Swagger-контракт.
## 6. Интерфейс overview
- [ ] Добавить overview-виджет ближайших событий для выбранного счёта.
- [ ] Показать не более 5 ближайших событий.
- [ ] Добавить ссылку на полную вкладку `События`.
- [ ] Реализовать loading, empty и local error state без поломки overview.
## 7. Вкладка `События`
- [ ] Добавить новый раздел `События` в `BrokerAccountLayout`.
- [ ] Добавить маршрут `/broker/:accountId/events`.
- [ ] Реализовать выбор диапазона дат.
- [ ] Реализовать summary по выбранному периоду.
- [ ] Реализовать список событий с признаком `estimate`.
- [ ] Разделить денежные и неденежные события на уровне представления.
## 8. Frontend tests
- [ ] Покрыть hook событий тестами query lifecycle.
- [ ] Покрыть overview-виджет сценариями loading, empty, error и success.
- [ ] Покрыть страницу `События` сменой диапазона, отображением summary и пустым состоянием.
- [ ] Проверить наличие новой вкладки в навигации счёта.
## 9. Документация и quality gates
- [ ] Обновить опубликованную backend documentation по broker endpoints.
- [ ] Прогнать backend tests.
- [ ] Прогнать frontend tests.
- [ ] Прогнать backend build.
- [ ] Прогнать frontend build.
- [ ] Прогнать docs build, если менялась опубликованная документация.
- [ ] Отметить roadmap и связанные SDD-статусы только после полной проверки реализации.

View File

@ -281,6 +281,14 @@ cash flow, бюджеты, аналитика, прогнозы и автома
- Исследовать учёт количества бумаг на дату фиксации, валют, налогов, комиссий, оферт и изменений - Исследовать учёт количества бумаг на дату фиксации, валют, налогов, комиссий, оферт и изменений
состава портфеля. состава портфеля.
- Календарь событий должен стать источником событий, а аналитика выплат — их денежным представлением. - Календарь событий должен стать источником событий, а аналитика выплат — их денежным представлением.
- Для broker-first версии закрепить follow-up на точный расчёт entitlement по истории операций, а не
только по текущим позициям счёта.
- Исследовать раздельную семантику `eventDate` и `paymentDate`, чтобы будущий фильтр периода мог
переключаться между датой события и датой поступления денег.
- Проверить, можно ли получить полный график купонов, амортизаций и частичных погашений, а не
только ближайшие доступные bond events.
- Отдельно продумать мультивалютность, налоги и net cashflow, чтобы будущие выплаты не выглядели
как гарантированная сумма к зачислению.
## Портфельная аналитика ## Портфельная аналитика

View File

@ -12,6 +12,9 @@ Roadmap отражает порядок продуктовой работы, н
- [x] [Разделы брокерского счёта](features/broker-account-sections/spec.md) — реализовано. - [x] [Разделы брокерского счёта](features/broker-account-sections/spec.md) — реализовано.
- [x] [Информативный обзор брокерских счетов](features/broker-accounts-overview/spec.md) — реализовано. - [x] [Информативный обзор брокерских счетов](features/broker-accounts-overview/spec.md) — реализовано.
- [ ] [Календарь событий и прогноз будущих выплат брокерского счёта](features/broker-events-and-payouts/spec.md)
— отдельная вкладка событий и прогноз будущих выплат по выбранному диапазону дат для T-Bank
счёта.
## Следующие этапы для активной фичи ## Следующие этапы для активной фичи