330 lines
17 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.

# Финальный HTML Parity брокерского overview — план реализации
> **Для агентных исполнителей:** ОБЯЗАТЕЛЬНЫЙ SUB-SKILL: использовать
> `superpowers:subagent-driven-development` (предпочтительно) или `superpowers:executing-plans` для
> пошагового выполнения. Шаги ведутся чекбоксами `- [ ]`.
**Цель:** привести `/broker/:accountId` к финальному HTML-эталону
`docs/research/frontend-overview-redesign/example.html` без изменения URL-структуры счёта.
**Архитектура:** backend расширяет существующий broker read API минимальными агрегатами и историей
стоимости. Frontend остаётся в FSD-границах `entities/broker-*`, `widgets/broker-dashboard`,
`widgets/broker-account-layout`; dashboard-композиция меняется с промежуточной версии на финальную
HTML parity структуру.
**Технологии:** NestJS, Prisma/T-Bank broker operations read path, Swagger/OpenAPI codegen, React 18,
TanStack Query, TanStack Router, MUI + `@moex-vibe/design-system`, Vitest, Testing Library.
---
## Canonical Research Source
- Использовать как visual source of truth:
`docs/research/frontend-overview-redesign/example.html`.
- Не использовать как source of truth:
`docs/research/2026-06-27-broker-account-redesign.html`, пока файл не синхронизирован с финальным
макетом.
- Production UI не переносит demo-control `Данные / Загрузка`; этот control нужен только HTML-макету.
## Файлы
### Backend
- Modify: `apps/backend/src/modules/tbank/dto/broker-analytics-response.dto.ts` — добавить
`totalFees`, `totalTaxesPaid`.
- Create: `apps/backend/src/modules/tbank/dto/broker-portfolio-history-response.dto.ts` — DTO для
6-месячной истории стоимости.
- Modify: `apps/backend/src/modules/tbank/dto/broker-envelope.dto.ts` — envelope для history endpoint.
- Modify: `apps/backend/src/modules/tbank/dto/broker-operation-query.dto.ts` — query `categories`.
- Modify: `apps/backend/src/modules/tbank/services/broker-analytics.service.ts` — агрегировать fee/tax.
- Create: `apps/backend/src/modules/tbank/services/broker-portfolio-history.service.ts` — read-model
истории стоимости.
- Modify: `apps/backend/src/modules/tbank/services/broker-operations.service.ts` — применять
category-фильтр до ответа.
- Modify: `apps/backend/src/modules/tbank/tbank.controller.ts` — endpoint portfolio history.
- Modify: backend tests рядом с изменёнными сервисами/controller.
### Frontend data
- Modify: `apps/frontend/src/shared/api/index.ts` — экспорт нового `BrokerPortfolioHistory`.
- Create: `apps/frontend/src/entities/broker-account/api/brokerPortfolioHistoryApi.ts`.
- Create: `apps/frontend/src/entities/broker-account/model/useBrokerPortfolioHistory.ts`.
- Modify: `apps/frontend/src/entities/broker-account/index.ts` — экспорт hook/API.
- Modify: `apps/frontend/src/entities/broker-operation/api/brokerOperationApi.ts` — query `categories`.
### Frontend UI
- Modify: `apps/frontend/src/widgets/broker-account-layout/ui/BrokerAccountLayout.tsx` — title yield
рядом с заголовком счёта, без page-header skeleton.
- Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx` — финальный порядок блоков
и источники данных.
- Replace/Remove: `BrokerDashboardHero.tsx` из overview-композиции; файл можно оставить только если
больше используется в тестах/экспортах, но в `/broker/:accountId` он не рендерится.
- Create: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerPortfolioHistoryCard.tsx`.
- Modify: `BrokerDashboardAnalyticsCard.tsx`, `BrokerDashboardAllocationCard.tsx`,
`BrokerDashboardEventsCard.tsx`, `BrokerDashboardSkeleton.tsx`.
- Modify/Create helpers в `apps/frontend/src/widgets/broker-dashboard/lib/` для chart points, latest
event rows, analytics display и visual tones.
- Modify: `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx` и helper unit tests.
### Docs
- Modify: `docs/features/broker-account-overview-html-parity/tasks.md` по факту выполнения.
- Не переписывать `docs/features/broker-dashboard-redesign/*`; старая фича остаётся историей
промежуточной итерации.
## Data Contracts
### Analytics
`BrokerAnalyticsDto` расширяется:
```ts
totalFees: number
totalTaxesPaid: number
```
Расчёт:
- `totalFees` = сумма absolute payment values executed операций категории `fee`;
- `totalTaxesPaid` = сумма absolute payment values executed операций категории `tax`;
- значения возвращаются как положительные агрегаты;
- frontend отображает их со знаком минус и negative tone.
### Portfolio History
Endpoint:
```text
GET /api/v1/broker/accounts/:accountId/portfolio/history?months=6
```
Response data:
```ts
type BrokerPortfolioHistoryData = {
accountId: string
points: Array<{
month: string
label: string
value: BrokerMoneyDto
}>
asOf: string
}
```
Правила v1:
- `months` по умолчанию 6, допустимый диапазон 2-12;
- `points.length === months`;
- `month` в формате `YYYY-MM`;
- `label` — короткое русское имя месяца;
- последняя точка равна текущей `portfolio.totals.portfolio`;
- предыдущие точки могут быть estimated read-model из текущей стоимости и executed операций за период;
- контракт должен позволять позже заменить estimated calculation на persisted snapshots.
### Operation Categories
`BrokerOperationQueryDto` получает:
```ts
categories?: string
```
Правила:
- comma-separated значения из `trade,income,tax,fee,transfer,other`;
- неизвестные категории игнорировать или валидировать с `400`; выбрать один вариант и покрыть тестом;
- filtering выполняется до формирования page response;
- overview `Последние события` запрашивает `categories=income,tax,fee`, `state=OPERATION_STATE_EXECUTED`,
`limit=7`.
## Implementation Tasks
### Task 1: Docs and research alignment
**Files:**
- `docs/features/broker-account-overview-html-parity/spec.md`
- `docs/features/broker-account-overview-html-parity/plan.md`
- `docs/features/broker-account-overview-html-parity/tasks.md`
- Проверить, что docs ссылаются на `docs/research/frontend-overview-redesign/example.html`.
- Проверить, что docs явно запрещают использовать старый dated HTML как canonical reference.
- Зафиксировать финальный порядок блоков и отсутствие production demo-toggle.
### Task 2: Backend analytics contract
**Files:**
- `apps/backend/src/modules/tbank/dto/broker-analytics-response.dto.ts`
- `apps/backend/src/modules/tbank/services/broker-analytics.service.ts`
- `apps/backend/src/modules/tbank/services/broker-analytics.service.spec.ts`
- `apps/backend/src/modules/tbank/tbank.controller.spec.ts`
- Добавить `totalFees`, `totalTaxesPaid` в DTO и тестовый response.
- Расширить analytics service наборами fee/tax типов через существующую категоризацию операций.
- Считать fee/tax только по executed операциям с `payment`.
- Возвращать округление до копеек аналогично текущим analytics агрегатам.
### Task 3: Backend portfolio history endpoint
**Files:**
- `apps/backend/src/modules/tbank/dto/broker-portfolio-history-response.dto.ts`
- `apps/backend/src/modules/tbank/dto/broker-envelope.dto.ts`
- `apps/backend/src/modules/tbank/services/broker-portfolio-history.service.ts`
- `apps/backend/src/modules/tbank/tbank.controller.ts`
- `apps/backend/src/modules/tbank/tbank.controller.spec.ts`
- Добавить DTO для history point и envelope.
- Добавить service, который проверяет account access через `BrokerAccountsService`.
- Получить текущую стоимость через existing portfolio service или общий read path без дублирования T-Bank
вызовов сверх необходимого.
- Вернуть 6 monthly points для default query.
- Покрыть default months, invalid account и shape response тестами.
### Task 4: Backend operation category filtering
**Files:**
- `apps/backend/src/modules/tbank/dto/broker-operation-query.dto.ts`
- `apps/backend/src/modules/tbank/services/broker-operations.service.ts`
- `apps/backend/src/modules/tbank/services/broker-operations.service.spec.ts`
- Добавить `categories` query.
- Применить category filtering к mapped operations page перед отдачей response.
- Если T-Bank page может содержать меньше 7 подходящих операций после фильтрации, documented v1 поведение:
endpoint возвращает подходящие операции из текущей fetched page; full backfill pagination не требуется.
- Покрыть `categories=income,tax,fee` и неизвестную категорию тестом.
### Task 5: OpenAPI and frontend generated types
**Files:**
- `apps/frontend/src/shared/api/types.ts`
- `apps/frontend/src/shared/api/index.ts`
- Запустить backend dev server.
- Выполнить `npm run codegen -w apps/frontend`.
- Не редактировать generated `types.ts` вручную.
- Экспортировать новые frontend aliases из `shared/api/index.ts`.
- Проверить, что generated schemas содержат `totalFees`, `totalTaxesPaid`,
`BrokerPortfolioHistoryDataDto`.
### Task 6: Frontend data hooks
**Files:**
- `apps/frontend/src/entities/broker-account/api/brokerPortfolioHistoryApi.ts`
- `apps/frontend/src/entities/broker-account/model/useBrokerPortfolioHistory.ts`
- `apps/frontend/src/entities/broker-account/index.ts`
- `apps/frontend/src/entities/broker-operation/api/brokerOperationApi.ts`
- Добавить `getBrokerPortfolioHistory(accountId, { months })`.
- Добавить `useBrokerPortfolioHistory(accountId, { months: 6 })` с query key
`['broker', 'portfolio-history', accountId, months]`.
- Добавить `categories` в `BrokerOperationQuery`.
- Не менять существующие hooks detailed вкладок.
### Task 7: Page title yield
**Files:**
- `apps/frontend/src/widgets/broker-account-layout/ui/BrokerAccountLayout.tsx`
- `apps/frontend/src/pages/broker-account/ui/BrokerAccountOverviewPage.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx`
- Перенести compact yield UI рядом с `Брокерский счёт`.
- Убрать отдельный hero KPI из overview.
- Не показывать page-title skeleton в loading state.
- Сохранить доступность: доходность имеет `aria-label="Доходность счёта"` или эквивалент.
### Task 8: Portfolio history card
**Files:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerPortfolioHistoryCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardPortfolioHistory.ts`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardSkeleton.tsx`
- Создать карточку `Стоимость портфеля за 6 месяцев`.
- Нарисовать SVG line/area chart без visible point markers.
- Использовать 6 backend points и подписи месяцев из response.
- Сделать loading chart indicator без skeleton месяцев.
- Обеспечить одинаковую min-height loaded/loading.
- Первая и последняя точки графика должны совпадать с краями области.
### Task 9: Analytics card parity
**Files:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAnalyticsCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx`
- Summary row: `Стоимость портфеля`, `Всего доходов`.
- Detail grid: `Пополнения`, `Выводы`, `Дивиденды`, `Купоны`, `Комиссия`,
`Уплаченные налоги`.
- Удалить `Нетто` и `Всего получено` из overview-card.
- Отображать `totalFees` и `totalTaxesPaid` как negative UI amounts.
- Сохранить skeleton геометрию 2 + 6 карточек.
### Task 10: Allocation card parity
**Files:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAllocationCard.tsx`
- `apps/frontend/src/entities/broker-position/model/brokerAllocation.ts`
- Переименовать карточку в `Структура`.
- Убрать subtitle `Структура портфеля`.
- Показать итоговую стоимость под заголовком.
- Отобразить только строки `Акции`, `Облигации`, `Деньги` для overview parity.
- Сохранить корректное поведение для отсутствующих/нулевых значений.
### Task 11: Latest events card parity
**Files:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardEventsCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardEvents.ts`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.tsx`
- Переключить overview source с `useBrokerEvents` на `useBrokerOperations` с
`categories=income,tax,fee`, `limit=7`.
- Убрать filters toolbar, count badge, footer summary и колонку `Статус`.
- Переименовать карточку в `Последние события`.
- Отсортировать rows новые → старые.
- Инструмент: название сверху жирным, ticker/ISIN снизу серым.
- Тип: бейдж `Дивиденд`, `Купон`, `Погашение`, `Налог`, `Комиссия`.
- Налоговые/комиссионные/отрицательные операции отображать красным.
### Task 12: Tests, build, visual QA
**Files:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx`
- backend specs из предыдущих задач
- `docs/features/broker-account-overview-html-parity/tasks.md`
- Backend targeted tests:
`npm run test -w apps/backend -- src/modules/tbank/services/broker-analytics.service.spec.ts src/modules/tbank/services/broker-operations.service.spec.ts src/modules/tbank/tbank.controller.spec.ts`
- Frontend targeted tests:
`npm run test -w apps/frontend -- --run src/widgets/broker-dashboard`
- Full checks:
`npm run test:frontend`
`npm run lint -w apps/frontend`
`npm run build:frontend`
- Visual QA:
desktop `/broker/:accountId`;
mobile viewport `390x844`;
compare against `docs/research/frontend-overview-redesign/example.html`.
- Update `tasks.md` statuses and notes after verification.
## Risks and Decisions
- History chart v1 uses estimated read-model; exact historical market value requires future snapshots.
- Category filtering after one fetched T-Bank page may underfill latest events; acceptable for v1 unless
testing shows too many empty overview rows.
- The HTML mock uses static values. React must match structure and visual behavior, not literal amounts.
- `Последние события` is intentionally based on executed operations, not calendar events, because the
final HTML shows already happened cashflow rows and removes status/forecast semantics.
## Verification Matrix
- Spec requirements map to tasks 2-11.
- Backend API requirements map to tasks 2-5.
- Frontend order and visual parity map to tasks 7-11.
- Loading stability and mobile overflow are verified in task 12.