codex/broker-dashboard-redesign #49

Merged
ksv741 merged 19 commits from codex/broker-dashboard-redesign into main 2026-06-27 16:55:04 +03:00
4 changed files with 1411 additions and 4 deletions
Showing only changes of commit ae207b0cb3 - Show all commits

View File

@ -8,6 +8,9 @@
**Технологии:** React 18, TanStack Router, TanStack Query, MUI через `@moex-vibe/design-system`, MUI X DateCalendar community (`@mui/x-date-pickers`) с Day.js, Vitest, Testing Library.
**HTML parity update:** согласованный визуальный эталон находится в `docs/research/2026-06-27-broker-account-redesign.html`.
Следующая итерация переносит его детали в реальную страницу без изменения backend-контрактов.
---
## Область реализации
@ -31,6 +34,8 @@
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.test.ts` — unit-тесты income helpers.
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFilters.ts` — пресеты дат, validate и mapping income types.
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardFormatters.ts` — локальные formatter/helpers для fallback и event labels.
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts` — локальные helpers визуальной семантики dashboard: tone сумм, tone типов, отображение инструмента, символ валюты.
- Create/Modify: `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts` — unit-тесты визуальных helpers.
- Modify: `apps/frontend/package.json` — добавить community-пакет `@mui/x-date-pickers`, если зависимость ещё не подключена; `@mui/x-date-pickers-pro` не добавлять.
- Modify: `docs/features/broker-dashboard-redesign/tasks.md` — фиксация статусов выполнения.
@ -93,6 +98,32 @@
- Ошибки `events`, `income`, `analytics` локальны соответствующим карточкам.
- Пустые данные показываются отдельными сообщениями, а не нулевыми значениями.
### 7. HTML parity visual layer
- Реальная страница `/broker/:accountId` должна визуально соответствовать `docs/research/2026-06-27-broker-account-redesign.html`,
но использовать существующие React-компоненты и FSD-границы.
- Не менять backend и OpenAPI: блок `Доходы` остаётся на текущем endpoint операций и текущем наборе
income-типов. Отрицательный tone должен поддерживаться для строк, которые уже отображаются или будут
отображаться без расширения контракта.
- Ввести локальные helpers в `widgets/broker-dashboard/lib/dashboardVisual.ts`:
`moneyTone(value, source?) -> 'positive' | 'negative' | 'planned' | 'neutral'`,
`eventTypeTone(type)`, `incomeTypeTone(typeLabel)`, `formatDashboardCurrency(moneyOrValue)`,
`instrumentDisplay({ ticker, name, description })`.
- `formatDashboardCurrency` для RUB должен выводить `₽`. Для неизвестных валют использовать код валюты.
- `instrumentDisplay` должен возвращать основную строку и опциональную подпись: для событий приоритет
`ticker/isin` как main и `name` как subtitle; для операций приоритет `ticker` как main и
`name/description` как subtitle. Если ticker отсутствует, main берётся из name/description, subtitle не
дублируется.
- `BrokerDashboardCard` должен поддержать компактный заголовок карточки уровня HTML-прототипа, не
используя крупный `Heading size="title"`.
- `BrokerDashboardDateFilter` должен использовать иконку раскрытия вместо текстового символа и сохранять
единый toolbar-паттерн для `События` и `Доходы`.
- Таблицы `События` и `Доходы` должны иметь `thead`, type badges, двухстрочный инструмент при наличии
названия и semantic amount colors.
- `BrokerDashboardAnalyticsCard` должен окрашивать KPI-карточки по смыслу и показывать RUB через `₽`.
- Skeleton таблиц событий и доходов должен использовать один компонент/паттерн и различаться только
числом колонок.
## Задачи
### Задача 1: Базовые helpers и локальные dashboard-patterns
@ -184,6 +215,79 @@
- [ ] Проверить вручную mobile layout `/broker/2084014113` на viewport `390x844`.
- [ ] После завершения обновить `docs/features/broker-dashboard-redesign/tasks.md` и выполнить `graphify update .`.
### Задача 7: Visual helpers для HTML parity
**Файлы:**
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.ts`
- `apps/frontend/src/widgets/broker-dashboard/lib/dashboardIncome.test.ts`
- [ ] Добавить `moneyTone`, который возвращает `negative` для отрицательных значений, `positive` для
положительных фактических значений, `planned` для прогнозных/нефактических значений и `neutral` для
нуля/недоступного значения.
- [ ] Добавить `formatDashboardCurrency`, который для `RUB` выводит `₽`, а для неизвестной валюты
оставляет код валюты.
- [ ] Добавить `instrumentDisplay` с приоритетами main/subtitle из технического решения 7.
- [ ] Добавить type tone helpers для event types и income labels.
- [ ] Расширить `DashboardIncomeRow`: хранить `instrumentMain` и `instrumentSubtitle`, сохранив
совместимость через существующий `instrument` только если это нужно текущим тестам.
- [ ] Покрыть helpers unit-тестами: RUB symbol, unknown currency fallback, negative/positive/planned
tones, event/income type tones, отсутствие дублирования subtitle.
### Задача 8: Hero, карточка и toolbar parity
**Файлы:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardHero.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardDateFilter.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx`
- [ ] Применить semantic color к hero: отрицательная доходность красная, положительная зелёная,
дневное изменение окрашивается по знаку, `Всего доходов` зелёный при значении больше нуля.
- [ ] Сделать заголовки dashboard-card компактными, соответствующими HTML-прототипу.
- [ ] Собрать filters area карточек в единый toolbar: слева типы, справа поле периода и действие.
- [ ] Заменить текстовую стрелку раскрытия периода на иконку: использовать уже подключённые
`CalendarTodayRounded` и `ExpandMoreRounded` из `@mui/icons-material`, без добавления новой icon
dependency.
- [ ] Обновить component tests: проверять отсутствие текста `RUB` для RUB-значений, отсутствие символа
`v` в period button и наличие accessible name у управления периодом.
### Задача 9: Таблицы событий и доходов как в HTML
**Файлы:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardEventsCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardIncomeCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardTableSkeleton.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx`
- [ ] Добавить `thead` в обе dashboard-таблицы с колонками из спецификации.
- [ ] В колонке инструмента выводить main и subtitle из `instrumentDisplay`.
- [ ] Заменить текстовые типы на компактные бейджи с tone из visual helpers.
- [ ] Окрашивать суммы через `moneyTone`: поступления зелёным, списания красным, прогноз/ожидание серым.
- [ ] Окрашивать статусные бейджи: `Поступило` зелёный, прогноз/ожидание серый.
- [ ] Сохранить горизонтальный scroll только внутри таблицы на mobile, без общего page overflow.
- [ ] Обновить skeleton так, чтобы `События` и `Доходы` использовали один визуальный паттерн строк.
- [ ] Обновить tests на наличие type badges, subtitle инструмента, semantic amount classes и skeleton.
### Задача 10: Analytics parity и визуальная проверка
**Файлы:**
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboardAnalyticsCard.tsx`
- `apps/frontend/src/widgets/broker-dashboard/ui/BrokerDashboard.test.tsx`
- `docs/features/broker-dashboard-redesign/tasks.md`
- [ ] Отображать RUB как `₽` во всех analytics KPI.
- [ ] Окрашивать analytics cards: positive для пополнений/дивидендов/купонов/всего получено,
negative для выводов и отрицательного нетто, neutral для нулевых/недоступных значений.
- [ ] Обновить component tests для analytics: `₽` вместо `RUB`, positive/negative tone cards.
- [ ] Прогнать `rtk npm run test:frontend -- --run src/widgets/broker-dashboard`.
- [ ] Прогнать `rtk npm run test:frontend`.
- [ ] Прогнать `rtk npm run lint -w apps/frontend && rtk npm run build:frontend`.
- [ ] Проверить `/broker/2084014113` вручную на desktop и mobile `390x844` против
`docs/research/2026-06-27-broker-account-redesign.html`.
- [ ] После проверки обновить `docs/features/broker-dashboard-redesign/tasks.md`.
## Проверка покрытия спецификации
- Общая композиция и горизонтальная навигация: задачи 2 и 6.
@ -193,3 +297,5 @@
- Community DateCalendar range control, weekly default range и skeleton loading tables: задачи 3, 4 и 6.
- Аналитика и аллокация с горизонтальными барами: задача 5.
- Ошибки, empty states, тесты и ручная верификация: задача 6.
- HTML parity: visual helpers — задача 7, hero/card/toolbar — задача 8, dashboard tables — задача 9,
analytics — задача 10.

View File

@ -1,6 +1,6 @@
# Редизайн обзора брокерского счёта в инвестиционный дашборд
Дата: 2026-06-26 (обновлено 2026-06-27)
Дата: 2026-06-26 (обновлено 2026-06-27, HTML parity)
Статус: согласовано к планированию
Эпик: [Портфель брокера](../../epics/BrokerPortfolio.md)
@ -18,6 +18,11 @@
двухколоночная desktop-композиция прототипа сознательно не переносится: и на desktop, и на mobile блоки
dashboard идут по одному на строке в фиксированном порядке.
После интерактивной дизайн-итерации согласован статический эталон
`docs/research/2026-06-27-broker-account-redesign.html`. Реальная React-страница должна визуально соответствовать этому HTML:
компактные заголовки карточек, единая шапка таблиц, бейджи типов, подписи инструментов, семантические
цвета денежных значений и единый skeleton таблиц.
## Цель
Сделать overview брокерского счёта быстрым обзором состояния портфеля, будущих/прошедших событий,
@ -68,10 +73,17 @@ dashboard идут по одному на строке в фиксированн
- Используется текущая светлая DS-тема MoexVibe.
- Не добавляется dark mode и не переносится тёмная палитра `temp.html`.
- Визуальная плотность, структура карточек, KPI-иерархия и компактность таблиц ориентируются на
`temp.html`.
`docs/research/2026-06-27-broker-account-redesign.html`.
- Дизайн использует компоненты и токены `@moex-vibe/design-system` там, где они применимы.
- Если DS-компонент слишком ограничен, допускается точечно расширить DS API или создать локальный
dashboard-pattern в frontend, но не добавлять доменную брокерскую логику в DS.
- Заголовки dashboard-карточек не должны использовать page-level размер `Heading size="title"`;
визуально они должны соответствовать компактному card heading из HTML-прототипа.
- В карточках `События` и `Доходы` фильтры должны быть собраны в единый toolbar: группа типов, единое
поле периода с иконкой календаря и chevron-иконкой, действие обновления/применения периода.
- В поле периода не используется текстовый символ `v`; раскрытие обозначается иконкой.
- Валюта в dashboard отображается символом `₽`, а не строкой `RUB`, кроме случаев, где backend вернул
другую валюту и formatter проекта не знает её символ.
### 3. Hero KPI
@ -85,6 +97,10 @@ Hero показывает:
- всего полученных доходов из `broker analytics.totalReceived`, если аналитика загружена;
- спокойный fallback `—` для недоступных значений.
- Все Metric-блоки имеют одинаковую высоту в grid-ряду, даже если у некоторых есть supportingText. Поддерживающий текст остаётся внутри Metric, но все Metrics растягиваются на полную высоту grid-ячейки с выравниванием от верхнего края.
- Доходность в hero имеет цветовую семантику: положительная — зелёная, отрицательная — красная,
недоступная/нулевая — нейтральная.
- Дневное изменение в supporting text hero тоже окрашивается по знаку значения.
- `Всего доходов` окрашивается как положительный финансовый показатель, если значение больше нуля.
### 4. Блок `События`
@ -115,9 +131,19 @@ Hero показывает:
- Если в выбранном диапазоне больше 10 событий, блок показывает локальную пагинацию по страницам.
- Смена применённых фильтров возвращает пагинацию блока на первую страницу.
- Таблица показывает дату, инструмент, тип, сумму и статус.
- Таблица содержит компактную строку заголовков колонок.
- В колонке `Инструмент` показывается тикер/ISIN и дополнительная строка с названием инструмента, если
оно доступно из `event.name`; если названия нет, дополнительная строка не занимает место.
- В колонке `Тип` значения отображаются небольшими бейджами с разными тонами для купона, дивиденда,
погашения и оферты.
- Сумма для `actual` берётся из `actualAmount`, сумма для `forecast` берётся из `estimatedAmount`.
- Фактические поступления визуально отмечаются как `Поступило`.
- Прогнозные суммы помечаются как оценочные.
- Суммы окрашиваются по смыслу: фактическое положительное поступление зелёным, отрицательное списание
красным, прогноз/план серым. Цвет не является единственным носителем смысла: прогнозные строки также
имеют статусный текст.
- Статус отображается компактным бейджем. `Поступило` использует зелёный тон, прогноз/ожидание —
нейтральный серый тон.
- Блок содержит ссылку на подробную вкладку `/broker/:accountId/events`.
- Ошибка загрузки событий не ломает остальной dashboard.
@ -150,15 +176,27 @@ Hero показывает:
- Для блока используется cursor-пагинация existing operations endpoint с размером страницы 10.
- Смена применённых фильтров сбрасывает cursor-пагинацию блока на первую страницу.
- Таблица показывает дату, инструмент, тип и сумму.
- Таблица содержит компактную строку заголовков колонок.
- В колонке `Инструмент` показывается тикер и дополнительная строка с названием операции/инструмента,
если оно доступно из `operation.name` или `operation.description`.
- В колонке `Тип` значения отображаются небольшими бейджами.
- Суммы окрашиваются по знаку: положительные поступления зелёным, отрицательные списания красным,
плановые/нефактические значения серым, если такие строки отображаются в блоке.
- Блок показывает итог по отображаемым доходным операциям.
- Блок содержит ссылку на подробную вкладку `/broker/:accountId/operations`.
- Если текущий endpoint операций не позволяет корректно получить доходные операции без изменения
backend-контракта, первая реализация должна явно зафиксировать это в `plan.md` перед изменением API.
- В этой итерации блок `Доходы` не расширяется до полной истории комиссий/налогов; цветовая семантика
отрицательных сумм должна быть готова для отображаемых строк, но API-контракт не меняется.
### 6. Блок `Аналитика доходности`
- Блок использует существующий endpoint `/api/v1/broker/accounts/:accountId/analytics`.
- Отображаются: пополнения, выводы, нетто вложено, дивиденды, купоны, всего получено, доходность.
- Денежные значения analytics отображаются с символом валюты `₽` для RUB.
- Карточки analytics используют цветовую семантику: положительные потоки и полученные доходы —
зелёный тон, отрицательные выводы и отрицательное нетто — красный тон, нейтральные/нулевые значения —
нейтральный тон.
- При отсутствии analytics data блок показывает спокойное пустое состояние.
- Ошибка analytics не ломает остальные блоки.
@ -181,6 +219,9 @@ Hero показывает:
контекста.
- Загрузка событий и доходов внутри карточек показывает skeleton таблицы соответствующей структуры, а не
только текстовую строку загрузки.
- Skeleton таблиц событий и доходов должен иметь единый визуальный паттерн: строки соответствуют
геометрии таблицы, колонка инструмента шире остальных, для `Доходы` используется тот же паттерн без
лишней колонки статуса.
- Ошибка событий, доходов или analytics отображается внутри соответствующей карточки.
- Пустые события, пустые доходы и пустая analytics имеют отдельные понятные сообщения.
- Недоступные отдельные значения отображаются как `—`, не подменяются нулём.
@ -211,18 +252,27 @@ Hero показывает:
- Hero показывает стоимость портфеля, доходность или fallback, дневное изменение или fallback, всего
доходов или fallback.
- Все Metric-блоки hero имеют одинаковую высоту; supportingText не создаёт перекоса.
- Hero KPI использует цветовую семантику для доходности, дневного изменения и всего полученных доходов.
- Блок `События` использует существующие events data и показывает дату, инструмент, тип, сумму и статус.
- В таблице `События` инструмент отображается двумя строками при наличии названия, тип отображается
бейджем, сумма и статус имеют семантические цвета.
- Блок `События` поддерживает multi-select chip-фильтр типов и локальную пагинацию по 10 событий.
- Блок `События` по умолчанию запрашивает период `сегодня - 7 дней` / `сегодня` и использует одно поле
периода с popover-календарём на базе community `DateCalendar`.
- Блок `Доходы` показывает доходные операции дивидендов и купонов и итог по отображаемым строкам.
- В таблице `Доходы` инструмент отображается двумя строками при наличии названия, тип отображается
бейджем, сумма имеет семантический цвет.
- Блок `Доходы` поддерживает multi-select chip-фильтр типов и cursor-пагинацию по 10 операций.
- Блок `Доходы` по умолчанию запрашивает период `сегодня - 7 дней` / `сегодня` и использует одно поле
периода с popover-календарём на базе community `DateCalendar`.
- В шапке управления периодом не отображается слово `Фильтр`, а действие применения периода не называется
`Показать`.
- Шапки фильтров `События` и `Доходы` визуально соответствуют единому toolbar из
`docs/research/2026-06-27-broker-account-redesign.html`.
- Поле периода использует chevron-иконку, а не текстовый символ `v`.
- Загрузка событий и доходов отображается skeleton-таблицей.
- Блок `Аналитика доходности` показывает данные существующего analytics endpoint.
- Блок `Аналитика доходности` отображает RUB как `₽` и использует цветовую семантику карточек.
- Блок `Аллокация` показывает горизонтальные бары секторов с названием, долей и суммой, а также
итоговую стоимость портфеля.
- Ошибка одного вторичного блока не скрывает остальные блоки dashboard.

View File

@ -1,7 +1,7 @@
# Редизайн обзора брокерского счёта в инвестиционный дашборд — задачи
Дата: 2026-06-26
Статус: в реализации
Дата: 2026-06-26 (обновлено 2026-06-27)
Статус: в реализации, итерация HTML parity
## Документация и pre-flight
@ -51,6 +51,26 @@
- [ ] Проверить desktop layout `/broker/2084014113`.
- [ ] Проверить mobile layout `/broker/2084014113`.
## Итерация HTML parity
- [x] Согласовать статический визуальный эталон `docs/research/2026-06-27-broker-account-redesign.html`.
- [x] Обновить `spec.md` под HTML parity: компактные заголовки, единый toolbar, бейджи, цвета, подписи инструментов, `₽`.
- [x] Обновить `plan.md` под перенос HTML parity в React-компоненты.
- [ ] Добавить `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.ts` с helpers для money tone, type tone, currency symbol и instrument display.
- [ ] Добавить `apps/frontend/src/widgets/broker-dashboard/lib/dashboardVisual.test.ts`.
- [ ] Расширить income helpers так, чтобы строки доходов могли отдавать main/subtitle инструмента без дублирования текста.
- [ ] Обновить `BrokerDashboardHero`: semantic colors для доходности, дневного изменения и всего полученных доходов.
- [ ] Обновить `BrokerDashboardCard`: компактный card heading вместо крупного page-level heading.
- [ ] Обновить `BrokerDashboardDateFilter`: единый toolbar-паттерн и chevron-иконка вместо текстового `v`.
- [ ] Обновить `BrokerDashboardEventsCard`: `thead`, двухстрочный инструмент, type badges, semantic amount colors, status badges.
- [ ] Обновить `BrokerDashboardIncomeCard`: `thead`, двухстрочный инструмент, type badges, semantic amount colors.
- [ ] Обновить `BrokerDashboardTableSkeleton`: общий skeleton-паттерн для событий и доходов с корректной геометрией колонок.
- [ ] Обновить `BrokerDashboardAnalyticsCard`: `₽` для RUB и positive/negative tone карточек.
- [ ] Обновить component tests dashboard под HTML parity.
- [ ] Проверить, что блок `Доходы` не расширяет backend/API и остаётся в рамках текущих income-типов.
- [ ] Проверить desktop layout `/broker/2084014113` против `docs/research/2026-06-27-broker-account-redesign.html`.
- [ ] Проверить mobile layout `/broker/2084014113` на viewport `390x844` против `docs/research/2026-06-27-broker-account-redesign.html`.
## Definition of Done
- [x] `rtk npm run test:frontend` проходит.
@ -60,3 +80,14 @@
- [ ] Dashboard соответствует acceptance criteria из `spec.md`.
- [x] Существующие вкладки `Акции`, `Облигации`, `Операции`, `События`, `Аналитика` остаются доступны.
- [x] `graphify update .` выполнен после code changes.
## Definition of Done для HTML parity
- [ ] `rtk npm run test:frontend -- --run src/widgets/broker-dashboard` проходит.
- [ ] `rtk npm run test:frontend` проходит после HTML parity изменений.
- [ ] `rtk npm run lint -w apps/frontend` проходит после HTML parity изменений.
- [ ] `rtk npm run build:frontend` проходит после HTML parity изменений.
- [ ] На `/broker/2084014113` заголовки карточек, toolbar таблиц, бейджи типов, подписи инструментов,
цвета сумм, analytics colors и skeleton визуально соответствуют `docs/research/2026-06-27-broker-account-redesign.html`.
- [ ] Нет общего горизонтального overflow на mobile; горизонтальный scroll допускается только внутри таблиц.
- [ ] `docs/features/broker-dashboard-redesign/tasks.md` обновлён по факту выполнения.

File diff suppressed because it is too large Load Diff