6.2 KiB
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 продолжат работать без крошек.