diff --git a/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/.openspec.yaml b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/.openspec.yaml new file mode 100644 index 0000000..4af8641 --- /dev/null +++ b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-08-14 diff --git a/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/design.md b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/design.md new file mode 100644 index 0000000..f12f8cf --- /dev/null +++ b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/design.md @@ -0,0 +1,57 @@ +## Context + +См. `proposal.md` для мотивации и `specs/app-breadcrumb-navigation/spec.md` для контрактов поведения. `AppShell` является общим layout защищённых маршрутов и уже располагает содержимое над ``, но находится в 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 перед ``. + +Это сохраняет 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 продолжат работать без крошек. diff --git a/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/proposal.md b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/proposal.md new file mode 100644 index 0000000..1a0bced --- /dev/null +++ b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/proposal.md @@ -0,0 +1,25 @@ +## Why + +Пользователь теряет быстрый путь к списку Brokerage Account и к Portfolio при переходе к Account Ledger. Нужна единая навигационная цепочка в защищённой части приложения. + +## What Changes + +- Добавить хлебные крошки над содержимым каждого защищённого маршрута. +- Отразить иерархию `Брокерские счета → <название счёта> → Операции` и отдельный маршрут «Настройки». +- Сделать только предшествующие крошки ссылками; текущую страницу показывать текстом. +- Сохранять текущую страницу и ближайшего родителя на узких экранах; при недоступном названии Brokerage Account показывать «Счёт». +- Удалить из Account Ledger избыточное локальное действие возврата к счёту. + +## Capabilities + +### New Capabilities +- `app-breadcrumb-navigation`: единая и адаптивная навигация по защищённым маршрутам приложения. + +### Modified Capabilities + +_Нет._ + +## Impact + +- Затрагивает shared layout и локализованные UI-строки frontend. +- Не изменяет backend API, данные Brokerage Account или зависимости. diff --git a/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/specs/app-breadcrumb-navigation/spec.md b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/specs/app-breadcrumb-navigation/spec.md new file mode 100644 index 0000000..abddbfc --- /dev/null +++ b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/specs/app-breadcrumb-navigation/spec.md @@ -0,0 +1,42 @@ +## Purpose + +Позволяет User быстро переходить по иерархии защищённых инвестиционных маршрутов через хлебные крошки над содержимым страницы. + +## ADDED Requirements + +### Requirement: Хлебные крошки доступны на защищённых маршрутах +Клиент SHALL показывать хлебные крошки над содержимым на защищённых маршрутах `/accounts`, `/accounts/:accountId`, `/accounts/:accountId/operations` и `/settings`. Клиент MUST NOT показывать хлебные крошки на public-маршрутах и странице несуществующего маршрута. + +#### Scenario: User открывает список Brokerage Account +- **WHEN** авторизованный User открывает `/accounts` +- **THEN** клиент показывает единственную текущую крошку «Брокерские счета» над содержимым списка + +#### Scenario: User открывает Settings +- **WHEN** авторизованный User открывает `/settings` +- **THEN** клиент показывает единственную текущую крошку «Настройки» над содержимым страницы + +### Requirement: Цепочка крошек отражает иерархию Brokerage Account +На `/accounts/:accountId` клиент SHALL показывать «Брокерские счета → <название счёта>». На `/accounts/:accountId/operations` клиент SHALL показывать «Брокерские счета → <название счёта> → Операции». Если название Brokerage Account недоступно, клиент MUST показывать «Счёт» вместо технического идентификатора. + +#### Scenario: User открывает Portfolio счёта с доступным названием +- **WHEN** авторизованный User открывает `/accounts/:accountId` и название Brokerage Account доступно +- **THEN** клиент показывает его название как текущую крошку после ссылки «Брокерские счета» + +#### Scenario: User открывает Account Ledger +- **WHEN** авторизованный User открывает `/accounts/:accountId/operations` и название Brokerage Account доступно +- **THEN** клиент показывает ссылку на список, ссылку на Portfolio этого счёта и текущую крошку «Операции» в указанном порядке без отдельного локального действия возврата к счёту + +#### Scenario: Название Brokerage Account недоступно +- **WHEN** клиент не получил название Brokerage Account для защищённого маршрута счёта +- **THEN** клиент показывает «Счёт» и не показывает `accountId` + +### Requirement: Крошки предоставляют доступную адаптивную навигацию +Клиент SHALL делать ссылками только крошки, предшествующие текущей странице; текущая крошка MUST быть обычным текстом. На узком экране клиент MUST скрывать промежуточные крошки, сохраняя ближайшую родительскую крошку и текущую страницу. + +#### Scenario: User выбирает предшествующую крошку +- **WHEN** User выбирает крошку, предшествующую текущей странице +- **THEN** клиент переходит по маршруту этой крошки + +#### Scenario: Крошки показаны на узком экране +- **WHEN** цепочка содержит более двух элементов и User открывает её на узком экране +- **THEN** клиент сохраняет видимыми ближайшую родительскую крошку и текущую страницу, скрывая более дальние промежуточные крошки diff --git a/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/tasks.md b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/tasks.md new file mode 100644 index 0000000..b4ad9ec --- /dev/null +++ b/openspec/changes/archive/2026-08-14-add-app-breadcrumbs/tasks.md @@ -0,0 +1,16 @@ +## 1. Навигация по маршрутам + +- [x] 1.1 Добавить app-level компонент хлебных крошек, зависящий от маршрута: он строит локализованную цепочку для каждого protected route и не отображается на public или неизвестных маршрутах. +- [x] 1.2 Получать название Brokerage Account через существующий query списка счетов на маршрутах счёта, используя локализованный fallback `Счёт`. +- [x] 1.3 Добавить content slot в `AppShell` и отрисовать компонент крошек над outlet защищённого маршрута, не добавляя entity-зависимости в shared. +- [x] 1.4 Удалить из Account Ledger локальное действие «К счету», которое дублирует ссылку крошек на Portfolio. + +## 2. Отображение и тесты + +- [x] 2.1 Добавить локализованные строки крошек и адаптивные стили, сохраняющие ближайшую родительскую и текущую крошку на узком экране. +- [x] 2.2 Добавить component или route-тесты для цепочек protected route, назначений ссылок, текста текущей крошки, fallback названия счёта и отсутствия крошек на public и неизвестных маршрутах. + +## 3. Проверка + +- [x] 3.1 Выполнить `npm run verify` в `frontend`. +- [x] 3.2 Выполнить `openspec validate add-app-breadcrumbs --type change --store wealth-ledger-specs` в `specs`. diff --git a/openspec/specs/app-breadcrumb-navigation/spec.md b/openspec/specs/app-breadcrumb-navigation/spec.md new file mode 100644 index 0000000..e4ef17f --- /dev/null +++ b/openspec/specs/app-breadcrumb-navigation/spec.md @@ -0,0 +1,44 @@ +# app-breadcrumb-navigation Specification + +## Purpose + +Позволяет User быстро переходить по иерархии защищённых инвестиционных маршрутов через хлебные крошки над содержимым страницы. + +## Requirements + +### Requirement: Хлебные крошки доступны на защищённых маршрутах +Клиент SHALL показывать хлебные крошки над содержимым на защищённых маршрутах `/accounts`, `/accounts/:accountId`, `/accounts/:accountId/operations` и `/settings`. Клиент MUST NOT показывать хлебные крошки на public-маршрутах и странице несуществующего маршрута. + +#### Scenario: User открывает список Brokerage Account +- **WHEN** авторизованный User открывает `/accounts` +- **THEN** клиент показывает единственную текущую крошку «Брокерские счета» над содержимым списка + +#### Scenario: User открывает Settings +- **WHEN** авторизованный User открывает `/settings` +- **THEN** клиент показывает единственную текущую крошку «Настройки» над содержимым страницы + +### Requirement: Цепочка крошек отражает иерархию Brokerage Account +На `/accounts/:accountId` клиент SHALL показывать «Брокерские счета → <название счёта>». На `/accounts/:accountId/operations` клиент SHALL показывать «Брокерские счета → <название счёта> → Операции». Если название Brokerage Account недоступно, клиент MUST показывать «Счёт» вместо технического идентификатора. + +#### Scenario: User открывает Portfolio счёта с доступным названием +- **WHEN** авторизованный User открывает `/accounts/:accountId` и название Brokerage Account доступно +- **THEN** клиент показывает его название как текущую крошку после ссылки «Брокерские счета» + +#### Scenario: User открывает Account Ledger +- **WHEN** авторизованный User открывает `/accounts/:accountId/operations` и название Brokerage Account доступно +- **THEN** клиент показывает ссылку на список, ссылку на Portfolio этого счёта и текущую крошку «Операции» в указанном порядке без отдельного локального действия возврата к счёту + +#### Scenario: Название Brokerage Account недоступно +- **WHEN** клиент не получил название Brokerage Account для защищённого маршрута счёта +- **THEN** клиент показывает «Счёт» и не показывает `accountId` + +### Requirement: Крошки предоставляют доступную адаптивную навигацию +Клиент SHALL делать ссылками только крошки, предшествующие текущей странице; текущая крошка MUST быть обычным текстом. На узком экране клиент MUST скрывать промежуточные крошки, сохраняя ближайшую родительскую крошку и текущую страницу. + +#### Scenario: User выбирает предшествующую крошку +- **WHEN** User выбирает крошку, предшествующую текущей странице +- **THEN** клиент переходит по маршруту этой крошки + +#### Scenario: Крошки показаны на узком экране +- **WHEN** цепочка содержит более двух элементов и User открывает её на узком экране +- **THEN** клиент сохраняет видимыми ближайшую родительскую крошку и текущую страницу, скрывая более дальние промежуточные крошки