# Редизайн обзора брокерского счёта в инвестиционный дашборд Дата: 2026-06-26 (обновлено 2026-06-27) Статус: согласовано к планированию Эпик: [Портфель брокера](../../epics/BrokerPortfolio.md) ## Контекст Текущий маршрут `/broker/:accountId` показывает корректный overview выбранного брокерского счёта, но визуально остаётся вертикальным набором отдельных блоков: сводка, аллокация, карточки активов, ближайшие события и последние операции. Пользователь подготовил прототип `temp.html`, где тот же домен представлен как более плотный инвестиционный дашборд с hero KPI, компактными таблицами и аналитическими карточками. После обсуждения выбран вариант A: страница `/broker/:accountId` должна стать единым дашбордом, используя структуру и плотность прототипа, но сохраняя текущую светлую тему и компоненты `@moex-vibe/design-system`. Тёмная тема из прототипа не переносится в первую версию. При этом двухколоночная desktop-композиция прототипа сознательно не переносится: и на desktop, и на mobile блоки dashboard идут по одному на строке в фиксированном порядке. ## Цель Сделать 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-иерархия и компактность таблиц ориентируются на `temp.html`. - Дизайн использует компоненты и токены `@moex-vibe/design-system` там, где они применимы. - Если DS-компонент слишком ограничен, допускается точечно расширить DS API или создать локальный dashboard-pattern в frontend, но не добавлять доменную брокерскую логику в DS. ### 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-ячейки с выравниванием от верхнего края. ### 4. Блок `События` - Блок использует существующий источник `useBrokerEvents(accountId, query)`. - По умолчанию применяется период `сегодня - 7 дней` / `сегодня` и типы `dividend,coupon,maturity,offer`, как в существующей вкладке событий. - Блок содержит кликабельные chip-фильтры типов событий: `Дивиденды`, `Купоны`, `Погашения`, `Оферты`. - Пользователь может выбрать несколько типов событий. - Если пользователь снимает все типы событий, запрос не выполняется, а блок показывает валидационное сообщение. - Изменение chip-фильтров типов событий применяется сразу и возвращает локальную пагинацию на первую страницу. - Блок содержит фильтр периода `from` / `to`. - По умолчанию применяется недельный период `сегодня - 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 событий, блок показывает локальную пагинацию по страницам. - Смена применённых фильтров возвращает пагинацию блока на первую страницу. - Таблица показывает дату, инструмент, тип, сумму и статус. - Сумма для `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-пагинацию блока на первую страницу. - Таблица показывает дату, инструмент, тип и сумму. - Блок показывает итог по отображаемым доходным операциям. - Блок содержит ссылку на подробную вкладку `/broker/:accountId/operations`. - Если текущий endpoint операций не позволяет корректно получить доходные операции без изменения backend-контракта, первая реализация должна явно зафиксировать это в `plan.md` перед изменением API. ### 6. Блок `Аналитика доходности` - Блок использует существующий endpoint `/api/v1/broker/accounts/:accountId/analytics`. - Отображаются: пополнения, выводы, нетто вложено, дивиденды, купоны, всего получено, доходность. - При отсутствии analytics data блок показывает спокойное пустое состояние. - Ошибка analytics не ломает остальные блоки. ### 7. Блок `Аллокация` - Используется существующий расчёт `buildBrokerAllocation`. - Вместо donut-диаграммы используется горизонтальный bar chart: каждый сектор — полоса с процентом, подписью и суммой. - Сверху блока показывается итоговая стоимость портфеля. - Каждая полоса содержит: название сектора, долю в процентах, сумму в валюте. - Цвета полос соответствуют существующей палитре аллокации (акции, облигации, ETF, деньги, прочие). - Отрицательные значения отображаются текстом без полосы. - Текст подписей контрастный и читаемый на всех цветах фона. - Информация остаётся понятной без различения цветов. ### 8. Загрузка, ошибки и пустые состояния - Первичная загрузка portfolio показывает dashboard skeleton соответствующей формы. - Ошибка portfolio показывает ошибку overview, потому что без portfolio dashboard не имеет основного контекста. - Загрузка событий и доходов внутри карточек показывает 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 не создаёт перекоса. - Блок `События` использует существующие events data и показывает дату, инструмент, тип, сумму и статус. - Блок `События` поддерживает multi-select chip-фильтр типов и локальную пагинацию по 10 событий. - Блок `События` по умолчанию запрашивает период `сегодня - 7 дней` / `сегодня` и использует одно поле периода с popover-календарём на базе community `DateCalendar`. - Блок `Доходы` показывает доходные операции дивидендов и купонов и итог по отображаемым строкам. - Блок `Доходы` поддерживает multi-select chip-фильтр типов и cursor-пагинацию по 10 операций. - Блок `Доходы` по умолчанию запрашивает период `сегодня - 7 дней` / `сегодня` и использует одно поле периода с popover-календарём на базе community `DateCalendar`. - В шапке управления периодом не отображается слово `Фильтр`, а действие применения периода не называется `Показать`. - Загрузка событий и доходов отображается skeleton-таблицей. - Блок `Аналитика доходности` показывает данные существующего analytics endpoint. - Блок `Аллокация` показывает горизонтальные бары секторов с названием, долей и суммой, а также итоговую стоимость портфеля. - Ошибка одного вторичного блока не скрывает остальные блоки dashboard. - Существующие detailed вкладки остаются доступны из навигации счёта. - Первая версия не содержит график истории стоимости портфеля и не добавляет API для него. - Дизайн использует светлую DS-тему, а не тёмную тему из `temp.html`. ## Вне области фичи - график стоимости портфеля по датам; - новые исторические снапшоты стоимости; - dark mode; - изменение backend-расчётов доходности; - налоговая аналитика; - экспорт dashboard; - объединение нескольких брокерских счетов в один dashboard.