16 KiB
Финальный редизайн обзора брокерского счёта по HTML-эталону
Дата: 2026-06-27 Статус: спецификация подготовлена Эпик: Портфель брокера
Контекст
Маршрут /broker/:accountId уже был переведён на dashboard-композицию в рамках
docs/features/broker-dashboard-redesign, но эта итерация отражает промежуточный вариант:
Hero → События → Доходы → Аналитика доходности → Аллокация.
После интерактивной дизайн-итерации пользователь согласовал финальный HTML-эталон в
docs/research/frontend-overview-redesign/example.html. Именно этот файл является canonical visual
reference для текущей фичи. Файл docs/research/2026-06-27-broker-account-redesign.html содержит более
раннюю версию и не должен использоваться как источник истины, пока не будет синхронизирован.
Финальный экран должен выглядеть как HTML-эталон, но работать на реальных данных приложения, существующих FSD-границах, backend API и текущей светлой теме MoexVibe.
Цель
Переделать обзор брокерского счёта /broker/:accountId так, чтобы production React-страница визуально
и поведенчески соответствовала финальному HTML-эталону:
Заголовок счёта → Стоимость портфеля за 6 месяцев → Аналитика доходности → Структура → Последние события.
Пользовательский результат
Пользователь на /broker/:accountId может:
- сразу увидеть название счёта, текущую доходность и дневное изменение;
- увидеть график стоимости портфеля за последние 6 месяцев;
- увидеть ключевые показатели доходности, включая комиссии и уплаченные налоги;
- увидеть структуру портфеля в компактном bar-chart виде;
- увидеть последние уже произошедшие события/денежные операции по счёту;
- перейти в подробные вкладки
Акции,Облигации,Операции,События,Аналитика.
Область изменений
Входит в scope:
- frontend-маршрут
/broker/:accountIdи виджетыwidgets/broker-dashboard; - layout заголовка счёта в
widgets/broker-account-layout; - backend read endpoints брокерского домена, необходимые для честного отображения HTML parity;
- OpenAPI/codegen для новых или расширенных DTO;
- тесты backend/frontend и визуальная проверка desktop/mobile.
Не входит в scope:
- редизайн подробных вкладок
Акции,Облигации,Операции,События,Аналитика; - dark mode;
- demo-переключатель
Данные / Загрузкаиз HTML-эталона; - полноценное хранилище исторических снапшотов портфеля;
- изменение URL-структуры
/broker/:accountId/*.
Требования
1. Общая композиция
/broker/:accountIdостаётся overview выбранного брокерского счёта.- Страница использует порядок блоков из HTML-эталона:
Заголовок счёта,Стоимость портфеля за 6 месяцев,Аналитика доходности,Структура,Последние события. - Отдельный hero KPI-блок удаляется из overview-композиции.
- Блок
Доходыудаляется из overview-композиции. Подробные доходные операции остаются доступны через вкладкуОперации. - Существующая навигация счёта остаётся горизонтальными вкладками над dashboard-контентом.
- На desktop и mobile блоки идут одной колонкой в одинаковом порядке.
- Production UI не содержит demo-toggle
Данные / Загрузка.
2. Заголовок счёта
- Заголовок показывает название счёта или fallback
Брокерский счёт. - Справа от заголовка, визуально меньшим блоком, показывается доходность счёта:
Доходность, значение процента и supporting textЗа день: .... - Доходность берётся из
analytics.totalReturnPercent, если доступна, иначе изportfolio.yields.expectedPercent, иначе отображается—. - Дневное изменение берётся из
portfolio.yields.daily, иначе отображается—. - Отрицательная доходность окрашивается красным, положительная зелёным, недоступная нейтральным.
- В loading-состоянии заголовок не показывает skeleton-полосы. Layout должен сохранять стабильную высоту и не прыгать после загрузки.
3. Стоимость портфеля за 6 месяцев
- Первый dashboard-блок называется
Стоимость портфеля за 6 месяцев. - Карточка использует зелёный градиентный фон и тонкую зелёную рамку как в HTML-эталоне.
- В карточке отображаются:
- label
Текущая стоимость; - текущая стоимость портфеля из
portfolio.totals.portfolio; - плавный line/area chart по 6 месячным точкам.
- label
- График показывает ровно 6 подписей месяцев и 6 значений, соответствующих этим месяцам.
- Первая точка линии начинается у левого края области графика, последняя — у правого края.
- Visible point markers не отображаются; линия плавная.
- Подписи месяцев не выходят за границы карточки.
- Loading-состояние графика использует chart-like indicator без skeleton-подписей месяцев.
- Высота карточки в loading и loaded состояниях должна совпадать.
4. Аналитика доходности
- Блок называется
Аналитика доходности. - Верхний summary-row содержит только:
Стоимость портфеля;Всего доходов.
- Detail-grid содержит ровно:
Пополнения;Выводы;Дивиденды;Купоны;Комиссия;Уплаченные налоги.
- Поля
НеттоиВсего полученоне отображаются в overview-карточке. - RUB отображается как
₽, а неRUB. - Положительные финансовые значения окрашиваются зелёным, отрицательные/уменьшающие баланс — красным.
КомиссияиУплаченные налогиотображаются как отрицательные UI-суммы, даже если backend хранит агрегат абсолютным положительным числом.- Loading-состояние использует skeleton-карточки той же геометрии, чтобы интерфейс не прыгал.
5. Структура
- Блок называется
Структура. - Под заголовком показывается итоговая стоимость портфеля.
- Под итогом отображаются горизонтальные бары:
Акции;Облигации;Деньги.
- Каждая строка показывает название сектора, сумму и процент.
- Цвета соответствуют HTML-эталону: акции — синий, облигации — янтарный, деньги — фиолетовый.
- Если значение сектора отсутствует или равно нулю, строка остаётся читаемой и не ломает layout.
- Общая карточка не содержит subtitle
Структура портфеля.
6. Последние события
- Блок называется
Последние события. - Блок показывает только уже произошедшие записи, которые меняют или отражают денежный поток счёта.
- Источник данных — executed broker operations с категориями
income,tax,fee. - Записи сортируются от новых к старым.
- В overview показывается не более 7 последних записей.
- Таблица содержит колонки:
Дата;Инструмент;Тип;Сумма.
- Колонка
Статусне отображается. - Toolbar фильтров, count badge и footer summary не отображаются в overview-карточке.
- В колонке
Инструментназвание отображается сверху жирным, ticker/ISIN снизу серым. - Для операций без названия основная строка берётся из ticker/figi/description без дублирования в subtitle.
- Тип операции отображается бейджем:
Дивиденд,Купон,Погашение,Налог,Комиссияили безопасный fallback. - Всё, что уменьшает баланс, отображается красным: сумма, типовой бейдж и tone строки/значения.
- Для налоговых операций в колонке
Типдолжен быть бейджНалог, а не исходный income/coupon label. - Блок содержит ссылку
Все событияна подробную вкладку/broker/:accountId/eventsили согласованный detailed cashflow route, если реализация выделит его отдельно. - Ошибка загрузки последних событий не ломает остальные блоки.
7. Backend API
BrokerAnalyticsDtoрасширяется полями:totalFees: number;totalTaxesPaid: number.
totalFeesсчитается из executed broker operations категорииfee.totalTaxesPaidсчитается из executed broker operations категорииtax.- Оба агрегата возвращаются абсолютными положительными числами; frontend отвечает за знак отображения.
- Добавляется endpoint:
GET /api/v1/broker/accounts/:accountId/portfolio/history?months=6. - Endpoint возвращает envelope с данными:
accountId: string;points: Array<{ month: string; label: string; value: BrokerMoneyDto }>;asOf: string.
monthимеет форматYYYY-MM.labelсодержит короткое русское имя месяца для оси.points.lengthравен запрошенномуmonths, по умолчанию 6.- Для v1 допускается estimated read-model из текущей стоимости портфеля и executed operations. Shape контракта должен позволять позже заменить расчёт на реальные snapshots без изменения frontend.
BrokerOperationQueryDtoрасширяется фильтромcategories?: string.categoriesпринимает comma-separated категории из существующего набора:trade,income,tax,fee,transfer,other.GET /broker/accounts/:accountId/operationsприменяетcategoriesдо пагинации/лимита, чтобы overview не фильтровал неполную страницу на клиенте.
8. Загрузка, ошибки и пустые состояния
- Ошибка portfolio остаётся page-level ошибкой.
- Ошибка analytics, history или latest events отображается только внутри соответствующей карточки.
- Недоступные значения отображаются как
—, не подменяются нулём. - Loading-состояния должны сохранять высоты карточек и не вызывать layout shift.
- На mobile не должно быть общего горизонтального overflow. Горизонтальный scroll допустим только внутри таблицы, если без него невозможно сохранить читаемость.
Acceptance Criteria
/broker/:accountIdотображает блоки в порядке:Стоимость портфеля за 6 месяцев,Аналитика доходности,Структура,Последние события.- Верхняя строка страницы показывает
Брокерский счёти доходность рядом с ним, без отдельного hero. - Production UI не показывает demo-toggle
Данные / Загрузка. - График стоимости имеет 6 подписей месяцев и 6 точек данных; линия начинается слева и заканчивается справа.
- Loading графика не содержит skeleton-подписей месяцев и имеет ту же высоту, что loaded состояние.
- Analytics overview показывает
КомиссияиУплаченные налоги, не показываетНеттоиВсего получено. Структурапоказывает итоговую стоимость и барыАкции,Облигации,Деньги.Последние событияпоказывает только произошедшие записи, отсортированные новые → старые.- Таблица
Последние событияне содержит toolbar, count badge, footer summary и колонкуСтатус. - Операции налогов/комиссий и другие списания отображаются красным.
- Backend Swagger содержит новые analytics fields, portfolio history endpoint и
categoriesquery. - Frontend generated types обновлены через codegen.
- Desktop и mobile визуально соответствуют
docs/research/frontend-overview-redesign/example.html.