# Редизайн обзора брокерского счёта в инвестиционный дашборд
Дата: 2026-06-26 (обновлено 2026-06-27, HTML parity)
Статус: согласовано к планированию
Эпик: [Портфель брокера](../../epics/BrokerPortfolio.md)
## Контекст
Текущий маршрут `/broker/:accountId` показывает корректный overview выбранного брокерского счёта, но
визуально остаётся вертикальным набором отдельных блоков: сводка, аллокация, карточки активов,
ближайшие события и последние операции. Пользователь подготовил прототип `temp.html`, где тот же домен
представлен как более плотный инвестиционный дашборд с hero KPI, компактными таблицами и аналитическими
карточками.
После обсуждения выбран вариант A: страница `/broker/:accountId` должна стать единым дашбордом,
используя структуру и плотность прототипа, но сохраняя текущую светлую тему и компоненты
`@moex-vibe/design-system`. Тёмная тема из прототипа не переносится в первую версию. При этом
двухколоночная desktop-композиция прототипа сознательно не переносится: и на desktop, и на mobile блоки
dashboard идут по одному на строке в фиксированном порядке.
После интерактивной дизайн-итерации согласован статический эталон
`docs/research/2026-06-27-broker-account-redesign.html`. Реальная React-страница должна визуально соответствовать этому HTML:
компактные заголовки карточек, единая шапка таблиц, бейджи типов, подписи инструментов, семантические
цвета денежных значений и единый skeleton таблиц.
## Цель
Сделать overview брокерского счёта быстрым обзором состояния портфеля, будущих/прошедших событий,
полученных доходов, аналитики доходности и аллокации без перехода по вкладкам.
## Пользовательский результат
Пользователь может на `/broker/:accountId`:
- сразу увидеть стоимость портфеля, доходность и сумму полученных доходов;
- увидеть ближайшие события по счёту в компактной таблице;
- увидеть последние доходные операции по дивидендам и купонам и итог по ним;
- оценить вложения, полученные выплаты и доходность по существующей аналитике;
- увидеть структуру портфеля через горизонтальные полосы аллокации и подписи к ним;
- перейти в существующие подробные вкладки `Акции`, `Облигации`, `Операции`, `События` и `Аналитика`
для drill-down сценариев.
## Область изменений
Фича относится только к frontend-маршруту `/broker/:accountId` и связанным frontend-компонентам
брокерского overview.
В область входят:
- новая dashboard-композиция для `BrokerAccountOverviewPage`;
- переиспользуемые frontend-паттерны для dashboard card, KPI, compact table и filter chips;
- адаптация существующих брокерских widgets под новую компоновку, если это нужно для читаемости;
- точечные доработки `@moex-vibe/design-system`, если существующие компоненты блокируют корректное
использование текущей светлой DS-темы;
- тесты новой композиции и ключевых представлений.
## Требования
### 1. Общая композиция
- `/broker/:accountId` остаётся overview выбранного брокерского счёта.
- Overview визуально становится dashboard-страницей, а не вертикальным списком независимых секций.
- Существующая навигация счёта отображается горизонтальными вкладками над контентом, чтобы не занимать
левую колонку и оставить больше пространства для таблиц dashboard.
- На desktop и mobile блоки dashboard отображаются по одному блоку на строке: hero KPI, `События`,
`Доходы`, `Аналитика доходности`, `Аллокация`.
- Существующая навигация счёта сохраняет ссылки на `Обзор`, `Акции`, `Облигации`, `Операции`,
`События`, `Аналитика`.
- На мобильном viewport сохраняется тот же порядок блоков в одну колонку.
### 2. Визуальный стиль
- Используется текущая светлая DS-тема MoexVibe.
- Не добавляется dark mode и не переносится тёмная палитра `temp.html`.
- Визуальная плотность, структура карточек, KPI-иерархия и компактность таблиц ориентируются на
`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
Hero показывает:
- название счёта или fallback `Брокерский счёт`;
- стоимость портфеля из `portfolio.totals.portfolio`;
- доходность из существующих данных: приоритет `broker analytics.totalReturnPercent`, если загружена,
иначе `portfolio.yields.expectedPercent`, если доступна;
- дневное изменение из `portfolio.yields.daily` и `portfolio.yields.dailyPercent`, если доступно;
- всего полученных доходов из `broker analytics.totalReceived`, если аналитика загружена;
- спокойный fallback `—` для недоступных значений.
- Все Metric-блоки имеют одинаковую высоту в grid-ряду, даже если у некоторых есть supportingText. Поддерживающий текст остаётся внутри Metric, но все Metrics растягиваются на полную высоту grid-ячейки с выравниванием от верхнего края.
- Доходность в hero имеет цветовую семантику: положительная — зелёная, отрицательная — красная,
недоступная/нулевая — нейтральная.
- Дневное изменение в supporting text hero тоже окрашивается по знаку значения.
- `Всего доходов` окрашивается как положительный финансовый показатель, если значение больше нуля.
### 4. Блок `События`
- Блок использует существующий источник `useBrokerEvents(accountId, query)`.
- По умолчанию применяется период `сегодня - 7 дней` / `сегодня + 7 дней` и типы
`dividend,coupon,maturity,offer`, как в существующей вкладке событий.
- Блок содержит кликабельные chip-фильтры типов событий: `Дивиденды`, `Купоны`, `Погашения`, `Оферты`.
- Пользователь может выбрать несколько типов событий.
- Если пользователь снимает все типы событий, запрос не выполняется, а блок показывает
валидационное сообщение.
- Изменение chip-фильтров типов событий применяется сразу и возвращает локальную пагинацию на первую
страницу.
- Блок содержит фильтр периода `from` / `to`.
- По умолчанию применяется недельный период `сегодня - 7 дней` / `сегодня + 7 дней`, чтобы обзор
сразу показывал ближайшие будущие события.
- Изменение черновых фильтров не запускает запрос до применения периода пользователем.
- В пользовательском тексте шапки периода не используется слово `Фильтр`; UI должен считываться как
управление периодом за счёт иконки календаря, применённого диапазона, пресетов и affordance раскрытия.
- Блок содержит быстрые пресеты периода `7д`, `30д`, `90д`, `1г`, `Всё`, действие `Сбросить` и
основное действие применения периода с более понятным текстом, чем `Показать`.
- Период отображается как одно визуальное поле/кнопка с диапазоном, например `19 июн – 26 июн`.
- По клику на поле периода открывается popover с community-компонентом MUI `DateCalendar` из
`@mui/x-date-pickers` и ручной логикой выбора начала/конца периода.
- `DateRangePicker` и пакет `@mui/x-date-pickers-pro` не используются.
- Native `` не используется.
- Применённые фильтры dashboard не обязаны синхронизироваться с URL; URL-синхронизация остаётся
обязанностью подробной вкладки `События`.
- В dashboard отображается не более 10 событий на странице.
- Если в выбранном диапазоне больше 10 событий, блок показывает локальную пагинацию по страницам.
- Смена применённых фильтров возвращает пагинацию блока на первую страницу.
- Таблица показывает дату, инструмент, тип, сумму и статус.
- Таблица содержит компактную строку заголовков колонок.
- В колонке `Инструмент` показывается тикер/ISIN и дополнительная строка с названием инструмента, если
оно доступно из `event.name`; если названия нет, дополнительная строка не занимает место.
- В колонке `Тип` значения отображаются небольшими бейджами с разными тонами для купона, дивиденда,
погашения и оферты.
- Сумма для `actual` берётся из `actualAmount`, сумма для `forecast` берётся из `estimatedAmount`.
- Фактические поступления визуально отмечаются как `Поступило`.
- Прогнозные суммы помечаются как оценочные.
- Суммы окрашиваются по смыслу: фактическое положительное поступление зелёным, отрицательное списание
красным, прогноз/план серым. Цвет не является единственным носителем смысла: прогнозные строки также
имеют статусный текст.
- Статус отображается компактным бейджем. `Поступило` использует зелёный тон, прогноз/ожидание —
нейтральный серый тон.
- Блок содержит ссылку на подробную вкладку `/broker/:accountId/events`.
- Ошибка загрузки событий не ломает остальной dashboard.
### 5. Блок `Доходы`
- Блок показывает последние доходные операции по дивидендам и купонам из существующего endpoint
операций.
- В первую версию входят операции с типами дивидендов и купонов, которые уже используются в backend
analytics: `OPERATION_TYPE_DIVIDEND`, `OPERATION_TYPE_DIV_EXT`, `OPERATION_TYPE_COUPON`.
- Блок содержит кликабельные chip-фильтры типов доходов: `Дивиденды`, `Купоны`.
- Пользователь может выбрать один или оба типа доходов.
- Если пользователь снимает все типы доходов, запрос не выполняется, а блок показывает
валидационное сообщение.
- Изменение chip-фильтров типов доходов применяется сразу и сбрасывает cursor-пагинацию.
- Блок содержит фильтр периода `from` / `to`.
- По умолчанию применяется недельный период `сегодня - 7 дней` / `сегодня`, чтобы dashboard не загружал
слишком много операций при первом открытии.
- Изменение черновых фильтров не запускает запрос до применения периода пользователем.
- В пользовательском тексте шапки периода не используется слово `Фильтр`; UI должен считываться как
управление периодом за счёт иконки календаря, применённого диапазона, пресетов и affordance раскрытия.
- Блок содержит быстрые пресеты периода `7д`, `30д`, `90д`, `1г`, `Всё`, действие `Сбросить` и
основное действие применения периода с более понятным текстом, чем `Показать`.
- Период отображается как одно визуальное поле/кнопка с диапазоном, например `19 июн – 26 июн`.
- По клику на поле периода открывается popover с community-компонентом MUI `DateCalendar` из
`@mui/x-date-pickers` и ручной логикой выбора начала/конца периода.
- `DateRangePicker` и пакет `@mui/x-date-pickers-pro` не используются.
- Native `` не используется.
- Применённые фильтры dashboard не обязаны синхронизироваться с URL; URL-синхронизация остаётся
обязанностью подробных разделов.
- Для блока используется 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 не ломает остальные блоки.
### 7. Блок `Аллокация`
- Используется существующий расчёт `buildBrokerAllocation`.
- Вместо donut-диаграммы используется горизонтальный bar chart: каждый сектор — полоса с процентом,
подписью и суммой.
- Сверху блока показывается итоговая стоимость портфеля.
- Каждая полоса содержит: название сектора, долю в процентах, сумму в валюте.
- Цвета полос соответствуют существующей палитре аллокации (акции, облигации, ETF, деньги, прочие).
- Отрицательные значения отображаются текстом без полосы.
- Текст подписей контрастный и читаемый на всех цветах фона.
- Информация остаётся понятной без различения цветов.
### 8. Загрузка, ошибки и пустые состояния
- Первичная загрузка portfolio показывает dashboard skeleton соответствующей формы.
- Ошибка portfolio показывает ошибку overview, потому что без portfolio dashboard не имеет основного
контекста.
- Загрузка событий и доходов внутри карточек показывает skeleton таблицы соответствующей структуры, а не
только текстовую строку загрузки.
- Skeleton таблиц событий и доходов должен иметь единый визуальный паттерн: строки соответствуют
геометрии таблицы, колонка инструмента шире остальных, для `Доходы` используется тот же паттерн без
лишней колонки статуса.
- Ошибка событий, доходов или analytics отображается внутри соответствующей карточки.
- Пустые события, пустые доходы и пустая analytics имеют отдельные понятные сообщения.
- Недоступные отдельные значения отображаются как `—`, не подменяются нулём.
## Ограничения
- Backend остаётся единственным клиентом T-Bank и MOEX.
- В первой версии не добавляется график истории стоимости портфеля.
- В первой версии не добавляется backend storage/API для снапшотов стоимости портфеля.
- Тёмная тема и переключатель темы не входят в область фичи.
- Не меняются правила расчёта доходности, событий, операций и аллокации.
- Не удаляются существующие detailed вкладки счёта.
- Не изменяется URL-структура `/broker/:accountId/*`.
## Backlog
Идея `Broker portfolio value history` вынесена в `docs/inbox.md` и `docs/roadmap.md`: хранить снапшоты
стоимости брокерского счёта и позже заменить отсутствие графика полноценным блоком `Стоимость портфеля`.
## Acceptance Criteria
- `/broker/:accountId` показывает dashboard-композицию: hero KPI, `События`, `Доходы`,
`Аналитика доходности`, `Аллокация`.
- Навигация счёта отображается горизонтальными вкладками над dashboard-контентом.
- На desktop и mobile блоки `События`, `Доходы`, `Аналитика доходности`, `Аллокация` расположены по
одному блоку на строке.
- На мобильном viewport dashboard читаемо перестраивается в одну колонку.
- Hero показывает стоимость портфеля, доходность или fallback, дневное изменение или fallback, всего
доходов или fallback.
- Все Metric-блоки hero имеют одинаковую высоту; supportingText не создаёт перекоса.
- Hero KPI использует цветовую семантику для доходности, дневного изменения и всего полученных доходов.
- Блок `События` использует существующие events data и показывает дату, инструмент, тип, сумму и статус.
- В таблице `События` инструмент отображается двумя строками при наличии названия, тип отображается
бейджем, сумма и статус имеют семантические цвета.
- Блок `События` поддерживает multi-select chip-фильтр типов и локальную пагинацию по 10 событий.
- Блок `События` по умолчанию запрашивает период `сегодня - 7 дней` / `сегодня + 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.
- Существующие detailed вкладки остаются доступны из навигации счёта.
- Первая версия не содержит график истории стоимости портфеля и не добавляет API для него.
- Дизайн использует светлую DS-тему, а не тёмную тему из `temp.html`.
## Вне области фичи
- график стоимости портфеля по датам;
- новые исторические снапшоты стоимости;
- dark mode;
- изменение backend-расчётов доходности;
- налоговая аналитика;
- экспорт dashboard;
- объединение нескольких брокерских счетов в один dashboard.