Compare commits
2 Commits
6c768ef6a9
...
7b1d649853
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b1d649853 | |||
| 723250f0b2 |
@ -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)
|
||||||
|
|||||||
209
docs/features/broker-events-and-payouts/plan.md
Normal file
209
docs/features/broker-events-and-payouts/plan.md
Normal 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-контракт обновлён
|
||||||
191
docs/features/broker-events-and-payouts/spec.md
Normal file
191
docs/features/broker-events-and-payouts/spec.md
Normal 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, уведомления и напоминания;
|
||||||
|
- отдельный аналитический раздел вне брокерского счёта.
|
||||||
78
docs/features/broker-events-and-payouts/tasks.md
Normal file
78
docs/features/broker-events-and-payouts/tasks.md
Normal 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-статусы только после полной проверки реализации.
|
||||||
89
docs/features/table-migration/plan.md
Normal file
89
docs/features/table-migration/plan.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Миграция таблиц на дизайн-систему — 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:** Перевести legacy-таблицы frontend на единый дизайн-системный слой без изменения бизнес-логики
|
||||||
|
и без отказа от `TanStack Table`.
|
||||||
|
|
||||||
|
**Architecture:** `packages/design-system/src/components/DataTable` становится общим UI-каркасом для
|
||||||
|
таблиц, а приложение продолжает владеть `TanStack Table` instance, колонками и доменными cell renderers.
|
||||||
|
Вся предметная логика остаётся в `apps/frontend`, а дизайн-система забирает только переиспользуемую
|
||||||
|
табличную оболочку и связанные presentation-состояния.
|
||||||
|
|
||||||
|
**Tech Stack:** React 18, TanStack Table, `@moex-vibe/design-system`, Vitest, Testing Library.
|
||||||
|
|
||||||
|
**Связанные документы:**
|
||||||
|
|
||||||
|
- Spec: `docs/features/table-migration/spec.md`
|
||||||
|
- DS foundation: `docs/features/design-system-foundation/spec.md`
|
||||||
|
- DS migration precedent: `docs/features/broker-account-sections-ds-migration/spec.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task 1: Уточнить API `DataTable`
|
||||||
|
|
||||||
|
Подготовить минимальное расширение API `DataTable`, которое покрывает реальные кейсы существующих таблиц.
|
||||||
|
|
||||||
|
- Проверить текущий `DataTable` в `packages/design-system/src/components/DataTable/DataTable.tsx`.
|
||||||
|
- Зафиксировать минимально необходимую поддержку:
|
||||||
|
- `table` / table model from `TanStack Table`;
|
||||||
|
- empty state;
|
||||||
|
- loading state / skeleton mode;
|
||||||
|
- row actions column or slot;
|
||||||
|
- controlled pagination / pagination slot;
|
||||||
|
- cell alignment.
|
||||||
|
- Не добавлять API, которое не подтверждено текущими 4 таблицами.
|
||||||
|
- Не добавлять MUI table-компоненты в код приложения.
|
||||||
|
|
||||||
|
## Task 2: Мигрировать `DividendsTable`
|
||||||
|
|
||||||
|
Сделать `DividendsTable` первым и самым простым потребителем общего DS-слоя.
|
||||||
|
|
||||||
|
- Перевести сырой HTML table на `DataTable`.
|
||||||
|
- Сохранить текущие колонки и форматирование.
|
||||||
|
- Убедиться, что пустое состояние и базовый layout совпадают по смыслу с текущим экраном.
|
||||||
|
|
||||||
|
## Task 3: Мигрировать `ScreenerTable`
|
||||||
|
|
||||||
|
Перевести табличную оболочку `ScreenerTable` на `DataTable`, сохранив текущее поведение.
|
||||||
|
|
||||||
|
- Оставить sorting и pagination под контролем существующей логики.
|
||||||
|
- Сохранить кастомные ячейки и действия над строками.
|
||||||
|
- Не менять query/data-flow скринера.
|
||||||
|
|
||||||
|
## Task 4: Мигрировать `SharePositionTable`
|
||||||
|
|
||||||
|
Заменить локальную табличную разметку на `DataTable`, не вынося доменную логику в DS.
|
||||||
|
|
||||||
|
- Сохранить row/cell renderers в приложении.
|
||||||
|
- Сохранить update/delete actions.
|
||||||
|
- Не менять вычисления и форматтеры, если это не требуется для миграции UI.
|
||||||
|
|
||||||
|
## Task 5: Мигрировать `BondPositionTable`
|
||||||
|
|
||||||
|
Перевести наиболее сложную таблицу позиций облигаций на DS-каркас.
|
||||||
|
|
||||||
|
- Сохранить предметно-специфичные bond columns и rendering.
|
||||||
|
- Сохранить все row actions.
|
||||||
|
- Не менять финансовую логику, сортировку и представление данных сверх UI-слоя.
|
||||||
|
|
||||||
|
## Task 6: Очистка legacy-слоя и документация
|
||||||
|
|
||||||
|
После миграции проверить связанные legacy-компоненты и документацию.
|
||||||
|
|
||||||
|
- Проверить судьбу `apps/frontend/src/shared/ui/Table/*` и `TableSkeleton`.
|
||||||
|
- Удалить или сократить helper-код, если он остаётся без потребителей.
|
||||||
|
- Обновить `apps/docs/docs/design-system/components.md` и `apps/docs/docs/frontend/styling.md`:
|
||||||
|
- явно зафиксировать, что `DataTable` построен на `TanStack Table`;
|
||||||
|
- отразить ожидаемый способ миграции legacy-таблиц.
|
||||||
|
|
||||||
|
## Task 7: Верификация
|
||||||
|
|
||||||
|
Подтвердить, что миграция не сломала текущие контракты frontend.
|
||||||
|
|
||||||
|
- Запустить frontend-тесты для затронутых областей.
|
||||||
|
- Запустить lint для frontend и design-system.
|
||||||
|
- Запустить build frontend и design-system.
|
||||||
|
- Проверить, что во frontend не появились новые запрещённые MUI table imports.
|
||||||
70
docs/features/table-migration/spec.md
Normal file
70
docs/features/table-migration/spec.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# Миграция таблиц на дизайн-систему
|
||||||
|
|
||||||
|
Дата: 2026-06-21
|
||||||
|
Статус: запланировано
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
Во frontend уже есть дизайн-система `@moex-vibe/design-system` и компонент `DataTable`, но часть экранов
|
||||||
|
по-прежнему использует legacy-таблицы на сыром HTML и локальных helper-компонентах. Основные зоны
|
||||||
|
миграции: `DividendsTable`, `ScreenerTable`, `SharePositionTable`, `BondPositionTable`, а также связанные
|
||||||
|
legacy-элементы вроде `shared/ui/Table` и `TableSkeleton`.
|
||||||
|
|
||||||
|
При этом сложные таблицы проекта должны и дальше опираться на `TanStack Table` как на источник
|
||||||
|
модели данных, сортировки и состояния. Цель фичи — не заменить `TanStack Table`, а стандартизировать
|
||||||
|
табличный UI через единый дизайн-системный слой.
|
||||||
|
|
||||||
|
## Связанные фичи
|
||||||
|
|
||||||
|
- Базовая фича дизайн-системы: `docs/features/design-system-foundation/spec.md`
|
||||||
|
- Связанная DS-миграция: `docs/features/broker-account-sections-ds-migration/spec.md`
|
||||||
|
- Frontend styling docs: `apps/docs/docs/frontend/styling.md`
|
||||||
|
- DS docs: `apps/docs/docs/design-system/components.md`
|
||||||
|
|
||||||
|
## Цель
|
||||||
|
|
||||||
|
Перевести legacy-таблицы frontend на единый дизайн-системный табличный слой, построенный поверх
|
||||||
|
`TanStack Table`, без изменения бизнес-логики, API-контрактов и доменной модели данных.
|
||||||
|
|
||||||
|
## In scope
|
||||||
|
|
||||||
|
- Уточнить и при необходимости расширить API `DataTable` в `@moex-vibe/design-system` под реальные
|
||||||
|
сценарии проекта.
|
||||||
|
- Мигрировать существующие таблицы frontend на `DataTable`.
|
||||||
|
- Сохранить текущие сценарии сортировки, пагинации, кастомных ячеек и row actions.
|
||||||
|
- Унифицировать loading / empty / error presentation вокруг дизайн-системных компонентов.
|
||||||
|
- Сократить использование legacy table helpers в `apps/frontend/src/shared/ui`.
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
|
||||||
|
- Изменение бизнес-логики портфелей, скринера, дивидендов, акций и облигаций.
|
||||||
|
- Перенос предметно-специфичных row/cell-компонентов в дизайн-систему.
|
||||||
|
- Изменение backend API, query-keys, маршрутизации или структуры доменных данных.
|
||||||
|
- Замена `TanStack Table` на другой табличный движок.
|
||||||
|
- Полная миграция всех форм и page sections вне областей, напрямую затронутых таблицами.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- `DataTable` должен оставаться обёрткой над `TanStack Table`, а не отдельной несовместимой таблицей.
|
||||||
|
- Табличный слой должен поддерживать:
|
||||||
|
- sortable columns;
|
||||||
|
- выравнивание ячеек;
|
||||||
|
- custom cell renderers;
|
||||||
|
- empty state;
|
||||||
|
- loading state / skeleton state;
|
||||||
|
- row actions;
|
||||||
|
- controlled pagination или pagination slot.
|
||||||
|
- Доменные таблицы должны сохранять собственные описания колонок и кастомный рендеринг ячеек.
|
||||||
|
- В приложении нельзя добавлять новые legacy table helpers взамен миграции на DS.
|
||||||
|
- Во frontend не должны появляться новые прямые MUI table-компоненты.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- `DividendsTable`, `ScreenerTable`, `SharePositionTable` и `BondPositionTable` используют
|
||||||
|
дизайн-системный табличный слой.
|
||||||
|
- Сортировка, пагинация и действия над строками работают так же, как до миграции.
|
||||||
|
- `DataTable` документирован как компонент на базе `TanStack Table`.
|
||||||
|
- Legacy table helpers не расширяются; после миграции их количество сокращается или они удаляются,
|
||||||
|
если остаются без потребителей.
|
||||||
|
- Изменение не требует корректировки backend-контрактов.
|
||||||
|
- Для затронутых пакетов проходят тесты, lint и build.
|
||||||
55
docs/features/table-migration/tasks.md
Normal file
55
docs/features/table-migration/tasks.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Миграция таблиц на дизайн-систему — Tasks
|
||||||
|
|
||||||
|
Дата: 2026-06-21
|
||||||
|
Статус: запланировано
|
||||||
|
|
||||||
|
Связанные документы:
|
||||||
|
|
||||||
|
- [Spec](spec.md)
|
||||||
|
- [Plan](plan.md)
|
||||||
|
|
||||||
|
## Task 1: Уточнить API `DataTable`
|
||||||
|
|
||||||
|
- [ ] Проверить текущее API `DataTable`
|
||||||
|
- [ ] Зафиксировать минимальный список поддерживаемых сценариев из существующих таблиц
|
||||||
|
- [ ] Подготовить изменения API только под подтверждённые кейсы
|
||||||
|
- [ ] Убедиться, что `TanStack Table` остаётся source of truth
|
||||||
|
|
||||||
|
## Task 2: Мигрировать `DividendsTable`
|
||||||
|
|
||||||
|
- [ ] Перевести HTML table на `DataTable`
|
||||||
|
- [ ] Сохранить текущие колонки и форматирование
|
||||||
|
- [ ] Проверить empty/loading presentation
|
||||||
|
|
||||||
|
## Task 3: Мигрировать `ScreenerTable`
|
||||||
|
|
||||||
|
- [ ] Перевести табличную оболочку на `DataTable`
|
||||||
|
- [ ] Сохранить сортировку и пагинацию
|
||||||
|
- [ ] Сохранить row actions и кастомные ячейки
|
||||||
|
|
||||||
|
## Task 4: Мигрировать `SharePositionTable`
|
||||||
|
|
||||||
|
- [ ] Перевести таблицу на `DataTable`
|
||||||
|
- [ ] Сохранить доменные row/cell renderers в приложении
|
||||||
|
- [ ] Сохранить update/delete сценарии
|
||||||
|
|
||||||
|
## Task 5: Мигрировать `BondPositionTable`
|
||||||
|
|
||||||
|
- [ ] Перевести таблицу на `DataTable`
|
||||||
|
- [ ] Сохранить bond-specific rendering и действия
|
||||||
|
- [ ] Не менять предметную финансовую логику
|
||||||
|
|
||||||
|
## Task 6: Очистка legacy и документация
|
||||||
|
|
||||||
|
- [ ] Проверить использование `shared/ui/Table`
|
||||||
|
- [ ] Проверить использование `TableSkeleton`
|
||||||
|
- [ ] Обновить docs по `DataTable` и `TanStack Table`
|
||||||
|
- [ ] Удалить legacy helper'ы, если они больше не нужны
|
||||||
|
|
||||||
|
## Task 7: Верификация
|
||||||
|
|
||||||
|
- [ ] Запустить frontend tests
|
||||||
|
- [ ] Запустить frontend lint
|
||||||
|
- [ ] Запустить design-system lint/tests при необходимости
|
||||||
|
- [ ] Запустить frontend и design-system build
|
||||||
|
- [ ] Проверить отсутствие новых запрещённых MUI table imports
|
||||||
@ -186,6 +186,11 @@ cash flow, бюджеты, аналитика, прогнозы и автома
|
|||||||
- Определить, нужна ли дизайн-система только внутри monorepo или как отдельный npm-пакет.
|
- Определить, нужна ли дизайн-система только внутри monorepo или как отдельный npm-пакет.
|
||||||
- Предусмотреть accessibility, визуальные regression-тесты и каталог компонентов (например,
|
- Предусмотреть accessibility, визуальные regression-тесты и каталог компонентов (например,
|
||||||
Storybook) как темы исследования.
|
Storybook) как темы исследования.
|
||||||
|
- Подготовить отдельную migration-фичу для перевода legacy-таблиц на дизайн-системный `DataTable`,
|
||||||
|
построенный поверх `TanStack Table`, без переноса доменной логики таблиц в DS.
|
||||||
|
- Для миграции таблиц использовать поэтапный порядок: `DividendsTable` → `ScreenerTable` →
|
||||||
|
`SharePositionTable` → `BondPositionTable`, сначала уточнив минимальный API `DataTable` на основе
|
||||||
|
реальных кейсов.
|
||||||
|
|
||||||
### Исследовать Backend-Driven UI
|
### Исследовать Backend-Driven UI
|
||||||
|
|
||||||
@ -276,6 +281,14 @@ cash flow, бюджеты, аналитика, прогнозы и автома
|
|||||||
- Исследовать учёт количества бумаг на дату фиксации, валют, налогов, комиссий, оферт и изменений
|
- Исследовать учёт количества бумаг на дату фиксации, валют, налогов, комиссий, оферт и изменений
|
||||||
состава портфеля.
|
состава портфеля.
|
||||||
- Календарь событий должен стать источником событий, а аналитика выплат — их денежным представлением.
|
- Календарь событий должен стать источником событий, а аналитика выплат — их денежным представлением.
|
||||||
|
- Для broker-first версии закрепить follow-up на точный расчёт entitlement по истории операций, а не
|
||||||
|
только по текущим позициям счёта.
|
||||||
|
- Исследовать раздельную семантику `eventDate` и `paymentDate`, чтобы будущий фильтр периода мог
|
||||||
|
переключаться между датой события и датой поступления денег.
|
||||||
|
- Проверить, можно ли получить полный график купонов, амортизаций и частичных погашений, а не
|
||||||
|
только ближайшие доступные bond events.
|
||||||
|
- Отдельно продумать мультивалютность, налоги и net cashflow, чтобы будущие выплаты не выглядели
|
||||||
|
как гарантированная сумма к зачислению.
|
||||||
|
|
||||||
## Портфельная аналитика
|
## Портфельная аналитика
|
||||||
|
|
||||||
|
|||||||
@ -12,9 +12,17 @@ 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
|
||||||
|
счёта.
|
||||||
|
|
||||||
## Следующие этапы для активной фичи
|
## Следующие этапы для активной фичи
|
||||||
|
|
||||||
1. [x] Проверить и утвердить `spec.md` для планирования.
|
1. [x] Проверить и утвердить `spec.md` для планирования.
|
||||||
2. [x] Проверить и утвердить подготовленные `plan.md` и `tasks.md`.
|
2. [x] Проверить и утвердить подготовленные `plan.md` и `tasks.md`.
|
||||||
3. [x] Получить отдельное подтверждение пользователя перед началом реализации.
|
3. [x] Получить отдельное подтверждение пользователя перед началом реализации.
|
||||||
|
|
||||||
|
## Кандидаты следующих фич
|
||||||
|
|
||||||
|
- [ ] [Миграция таблиц на дизайн-систему](features/table-migration/spec.md) — перевести legacy-таблицы
|
||||||
|
frontend на `DataTable` поверх `TanStack Table` без изменения бизнес-логики.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user