22 KiB
UX Design
Задача пользователя: в режиме «Все счета» (/accounts/all/...) быстро увидеть, что
несколько записей — это один и тот же факт (один день, одна бумага, один тип), понять
общую сумму и при этом сразу видеть вклад каждого счёта. Нормативное поведение
(ключ группы, состав, порядок, правила итога) задано в proposal.md и трёх spec;
этот документ его не повторяет и не меняет, а только определяет представление.
Допущение: design system — Mantine + @wealthledger/ui по docs/design/overview.md
(семантические роли, направление несут знак и текст, не только цвет).
Requirements Covered
brokerage-account-ledger—Full ledger presents compact rows(MODIFIED, группа в полном журнале)brokerage-account-ledger—Account overview includes recent ledger events(MODIFIED, группа в обзоре)brokerage-account-ledger—User can retrieve an account ledger(MODIFIED, режимall,partial)brokerage-account-ledger—All-accounts ledger groups same-day entries of one instrumentbrokerage-account-ledger—All-accounts ledger group shows each entry and an exact totalbrokerage-account-ledger—All-accounts ledger grouping preserves order and limitsbrokerage-account-upcoming-events—Account page presents an upcoming events list(MODIFIED, прогнозный итог группы)brokerage-account-upcoming-events—All-accounts upcoming events group same-day events of one instrumentbrokerage-account-upcoming-events—All-accounts upcoming event group shows each event and a forecast totalbrokerage-account-upcoming-events—All-accounts upcoming event grouping preserves order and limitsbrokerage-account-income-analytics—Realized income analytics is account-scoped and period-bound(MODIFIED, режимall)brokerage-account-income-analytics—Income payments remain traceable to exact Ledger Entries(MODIFIED, «Выплаты» в режимеall)
User Flows
Цель пользователя — «что и сколько пришло/придёт по бумаге X и с каких счетов».
- Просмотр списка. Пользователь открывает любой из 4 списков в режиме «Все счета» → видит заголовок группы (дата, бумага, тип, итог) → читает строки счетов под ним, раскрывать ничего не нужно.
- Переход к счёту. Из строки группы (журнал, выплаты) пользователь открывает
/accounts/{id}по имени счёта; возврат — кнопкой «Назад» браузера, список и позиция восстанавливаются как сейчас. - Листание журнала. «Назад/Вперёд» меняют страницу; группа собирается заново из показанных записей страницы. Пользователь не получает пометок о неполноте на границе страницы.
- Обзор. На
/accounts/allв блоках «Ближайшие события» и «Последние операции» группа занимает место первой записи; блок по-прежнему содержит не более 5 записей/событий, как сейчас. - Одиночная запись / одиночный счёт. Запись без пары, без Instrument или любой список в режиме одного счёта выглядят как сейчас; пользовательский путь не меняется.
Ветвление по итогу: итог известен → показан в заголовке; итог скрыт (см. UI States) →
пользователь складывает строки сам или смотрит на состояние страницы (partial-Alert).
Information Architecture
Группа — один визуальный блок (рамка Paper withBorder) внутри существующего списка, на
месте первой записи. Состав блока: заголовок + вложенный список строк счетов. Заголовок
повторяет композицию текущей карточки (иконка/логотип | название и метаданные | значение),
строка счёта — компактнее, без логотипа.
Лейблы заголовка: заголовок = «<тип> · <инструмент>» (как в карточках событий/выплат),
метаданные = дата (+ «дата реестра» для дивиденда по реестру), значение = итог,
подпись значения = подпись типа (в событиях — «Прогноз»).
Журнал (/accounts/all/operations, обзор «Последние операции»)
┌──────────────────────────────────────────────────────────┐
│ [logo] Купон · X +300 RUB │ заголовок
│ 12 мая 2026 Купон │
│ ──────────────────────────────────────────────────────── │
│ Брокерский +200 RUB Купон │ строка
│ ИИС +100 RUB Купон │ строка
└──────────────────────────────────────────────────────────┘
Строка: имя счёта слева; справа денежное изменение со знаком и подпись типа
(по Full ledger presents compact rows). Количество и цена в строках группы не показываются (Presentation Decisions, п. 3).
Имя счёта — обычный текст во всех списках, как в текущей метадате строки (withDetails в этих списках не используется).
События (/accounts/all/events, обзор «Ближайшие события»)
┌──────────────────────────────────────────────────────────┐
│ [logo] Дивиденд · X 10 USD │
│ 12 мая 2026 · дата реестра 200 RUB │ итоги по валютам
│ Прогноз │
│ ──────────────────────────────────────────────────────── │
│ Брокерский 10 USD │
│ ИИС Сумма неизвестна│
└──────────────────────────────────────────────────────────┘
Пример выше показывает два разных состояния сразу; на практике итог при строке «Сумма неизвестна» скрыт (см. UI States). Строки счёта в событиях — только текст (ссылки на счёт в текущей карточке события нет).
Выплаты (/accounts/all/income)
┌──────────────────────────────────────────────────────────┐
│ [logo] Купон · X +300 RUB │
│ Исполнено 12 мая 2026 Купон │
│ ──────────────────────────────────────────────────────── │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Брокерский +200 RUB │ │ отдельная карточка
│ └──────────────────────────────────────────────────────┘ │ внутри группы
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ИИС +100 RUB │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
В «Выплатах» spec требует «отдельную сразу видимую карточку» записи внутри группы: вложенные карточки без логотипа и с границей, но визуально легче внешней. Подпись «Исполнено» сохраняет различие факта и прогноза.
Размещение в 4 списках: страница журнала и «Выплаты» — вертикальный стек с зазором sm;
страница событий — тот же стек; блоки обзора — тот же компонент группы без дополнительной
рамки блока. Позиция — по правилам порядка из spec (группа на месте первой записи).
UI States
| Состояние | Представление |
|---|---|
| Одиночная запись | Как сейчас: текущая карточка, без группы и вложенного списка |
| Группа с итогом | Заголовок с итогом +300 RUB (тон по знаку), строки счетов |
| Мультивалютный итог | В заголовке столбец значений: по строке на валюту, +150 RUB над +10 USD; порядок — по первому появлению валюты в записях группы (Presentation Decisions, п. 2); без конвертации и общей суммы |
| Итог скрыт | Значение в заголовке отсутствует; строки счетов видны. Причина: запись без суммы / событие с неизвестной суммой / период partial. Для экранных дикторов — скрытый текст «Итог недоступен» (без различения причин) |
| Нулевой итог | 0 RUB без знака, нейтральный тон; строки с их знаками |
| Offer без сумм | Группа без итога; строки: имя счёта + «Сумма не определена» (существующий текст events.noAmount) |
| Прогноз | Итог и суммы строк в событиях несут подпись «Прогноз» (существующий payout.forecast); тон нейтральный, как у текущей карточки прогноза |
| Строка без денег (ledger) | Нейтральный текст payout.noMoney/«без движения денег» как в одиночной записи; итог группы скрыт |
| Обзор, 5 записей | Не более 5 записей/событий, как сейчас; группа может занимать часть из них, например 2 из 5; кнопка «Все …» ведёт на полную страницу |
| Граница страницы журнала | Группа из показанных записей, без пометки о неполноте и без «ещё N на другой странице» |
| Loading / empty / error / partial-Alert | Не меняются: LoadingSkeleton, StateView, Alert и SourceSyncStatus из существующих страниц; группы строятся только для загруженных данных |
Знак: «+» и «−» всегда в тексте; цвет (positive/negative/neutral) — дополнение.
Visual Package
Решение: reuse + один новый тонкий контейнер. Изображения (PNG/SVG) не создаются: изменение — повторная композиция существующих карточек, а структура и тексты описаны текстовыми макетами выше; отдельный макет дал бы расхождение с живыми компонентами и токенами Mantine.
Переиспользуется:
EntryCard(@wealthledger/ui) — заголовок группы: логотип/инициал,title,metadata(дата),value(итог),valueLabel(тип/«Прогноз»),tone. Отличие: вvalueнужно выводить несколько значений для нескольких валют (сейчас одна строка) и допустить отсутствие значения.LedgerEntryRow/PayoutCard(executed) — единичные записи и карточки внутри группы выплат; в группе опускаются логотип, дата и название инструмента (они в заголовке).BrokerageEventCard/PayoutCard(forecast) — единичные события; текстыevents.type.*,events.noAmount,payout.forecast.- Форматирование:
formatMoney,formatDate,instrumentLogoUrl; текстыledger.noInstrument,payout.noMoney. - Токены:
--wl-color-border,--wl-color-subtle,--wl-color-surface,Paper withBorder.
Новое (предложение, с обоснованием «нужно показать иерархию заголовок → строки»):
- Контейнер группы (рамка, заголовок, вложенный список) и компактная строка счёта
(имя счёта слева, сумма справа, без
Avatar).EntryCardвсегда рисуетAvatar, поэтому для строки счёта нужна его облегчённая форма либо отдельная разметка; выбор — за реализацией. Отступ строк слева — под текстовым блоком заголовка (≈ 40 px аватар +sm), либо без отступа на узкой ширине.
Responsive
- Базовый макет — mobile-first: заголовок — сетка из трёх колонок как
EntryCard(auto | 1fr | auto). - ≥ 768 px: заголовок в одну строку; строки счетов — имя слева, сумма и подпись справа.
- < 576 px (узкий мобильный): колонка значения заголовка переносится под название
(название и метаданные — вверху, итог — следующей строкой справа/слева), мультивалютный итог
— столбцом; название инструмента и имя счёта переносятся (
wrap, безlineClamp), отступ строк слева убирается. Строка счёта: имя счёта сверху, сумма с подписью типа ниже, если вместе не помещаются; длинное имя счёта не обрезается. - Никакого горизонтального скролла; минимальная ширина — 320 px.
- Ввод: touch и мышь; в группе нет новых целей нажатия.
Accessibility
Ориентир — WCAG 2.2 AA.
- Семантика списка. Внешний список —
<ul>; каждая одиночная запись и каждая группа —<li>. Внутри группы-<li>заголовок (обычный блок, не<h*>, чтобы не засорять навигацию по заголовкам страницы) и вложенный<ul>со строками-<li>. Группы в обзоре — внутри уже существующих секций с их заголовками. - Доступное имя группы. Вложенный
<ul>получаетaria-labelвида: «Купон, X, 12 мая 2026, итог +300 RUB» (дата, инструмент, тип, итог, мультивалютный итог — через запятую). При скрытом итоге — «… итог недоступен». Для знаков в озвучке: «плюс 300 рублей», «минус …» — черезaria-labelзначения либо скрытый текст; сам знак в тексте остаётся. - Итог скрыт. Визуально значения нет; в DOM есть
visually-hiddenтекст «Итог недоступен» и он включён в имя группы. Причина скрытияpartialуже объявляется существующимAlert role="status". - Фокус. Заголовок и строки группы не фокусируемы: новых интерактивных элементов нет. Если одиночная карточка содержит ссылку, она остаётся как есть, а порядок Tab совпадает с порядком DOM.
- Не только цвет. Направление передаёт знак «+»/«−» (минус как «−»), подпись типа и слова
«Прогноз»/«Исполнено»; цвет только усиливает. Контраст текста ≥ 4.5:1 (dimmed
gray.6наsubtleпроверить), границы групп ≥ 3:1 не требуются — это декор, смысл не теряется без границы. - Динамика. Смена страницы журнала не перемещает фокус неожиданно; пагинация — как сейчас.
- Масштаб. Текст масштабируется до 200 % без потери информации (перенос строк).
Presentation Decisions
Решения, которые относятся только к представлению и не меняют поведение по specs:
- Видимая причина скрытого итога. Видимого маркера нет. Скринридер получает текст «Итог недоступен». Строки с суммами остаются видны, так что отсутствие итога не выглядит пустотой.
- Несколько валют в заголовке. Каждая валюта на отдельной строке, в порядке первого появления в записях группы.
- Количество и цена в строках сделок. Не показываются, как и в несгруппированном журнале. Specs требуют только счёт и денежное изменение.
- Ссылка на счёт. Сохраняется текущее поведение: имя счёта — текст во всех четырёх списках.
- Подпись «Исполнено» / «Прогноз». Ставится у итога в заголовке. В строках событий подпись остаётся у суммы, как в одиночной карточке.
- Дата реестра. Применяется только к группам прогнозных событий. Исполненные выплаты датируются датой исполнения.
Findings → Specs
Нет. Два пробела, найденных при проектировании, закрыты решением Change Owner и внесены в specs, G2 инвалидирован:
- прогнозный итог скрывается, если полнота прогноза не подтверждена;
- запись с нулевой суммой считается записью без денежного изменения и скрывает итог.