Files
specs/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/design.md
T
2026-08-14 14:30:20 +03:00

6.2 KiB
Raw Blame History

Context

См. proposal.md для мотивации и specs/app-breadcrumb-navigation/spec.md для контрактов поведения. AppShell является общим layout защищённых маршрутов и уже располагает содержимое над <Outlet />, но находится в shared-слое. Название Brokerage Account доступно через существующий query списка счетов и может отсутствовать при прямом переходе на маршрут счёта.

Goals / Non-Goals

Goals:

  • Показывать единый маршрутный trail над защищённым page content без изменения API.
  • Использовать настоящее название Brokerage Account, когда оно доступно, и безопасный fallback в противном случае.
  • Сохранить понятную навигацию на узких экранах.

Non-Goals:

  • Не добавлять крошки на public и not-found маршруты.
  • Не создавать endpoint отдельного Brokerage Account и не менять cache policy списка счетов.
  • Не заменять существующую боковую или нижнюю навигацию.

Decisions

Route-aware компонент остаётся в app-слое

Добавить app-level компонент, который строит trail из текущего маршрута, его параметра accountId и локализованных строк. AppRoutes передаёт его в shared AppShell как content slot перед <Outlet />.

Это сохраняет FSD-направление зависимостей: shared layout не импортирует entity или feature. Альтернатива с определением маршрутов и загрузкой счета внутри AppShell смешала бы shared-слой с доменными данными.

Название счёта берётся из существующего query списка

Подкомпонент для маршрутов /accounts/:accountId и /accounts/:accountId/operations использует существующий query Brokerage Account и находит запись по accountId. Пока query не вернул соответствующее название, trail показывает «Счёт».

Это поддерживает прямые переходы и повторно использует query cache списка. Альтернатива с передачей имени из каждой страницы дублировала бы route-логику и не покрывала бы loading/error state до отображения page content. Новый API endpoint не нужен: список уже содержит стабильный id и непустое name.

Trail строится из фиксированной карты защищённых маршрутов

Карта определяет Брокерские счета, Настройки, Portfolio счёта и Account Ledger, а также destination URL для предшествующих элементов. Текущий элемент рендерится текстом, остальные - router links. Неизвестные и public routes возвращают отсутствие trail.

Фиксированная карта соответствует текущему небольшому набору маршрутов и исключает разбор URL по сегментам. Автоматическое построение из pathname было бы хрупким для динамического accountId и не предоставляло бы локализованного названия счёта.

Крошки заменяют локальный возврат из Account Ledger

Удалить действие «К счёту» из заголовка Account Ledger: trail уже предоставляет ссылку на Portfolio текущего Brokerage Account.

Это устраняет дублирующий navigation control. Боковая и нижняя навигация остаются без изменений, поскольку ведут к другим разделам приложения.

Адаптация сохраняет последние два элемента

На узком экране компонент передаёт в presentation только ближайшего родителя и текущий элемент; на широком экране показывает полный trail. Стили layout отвечают за перенос и отступ от page content.

Это прямо реализует согласованное поведение для трёхуровневой цепочки. Горизонтальная прокрутка или отдельное меню скрытых элементов добавили бы управление без новых маршрутов и не нужны для текущей глубины.

Risks / Trade-offs

  • [Прямой переход временно показывает обобщённое имя] → отображать «Счёт» до результата существующего query и не раскрывать accountId.
  • [Запрос списка счётов ради названия] → монтировать account-aware подкомпонент только на маршрутах счёта; React Query повторно использует его 60-секундный cache.
  • [Рост route map при новых страницах] → добавлять маршрут и его expected trail в той же app-level карте и соответствующем тесте.

Migration Plan

Изменение не требует миграции данных или API. При rollback удалить slot и app-level компонент; существующие маршруты и page content продолжат работать без крошек.