Files
specs/openspec/changes/archive/2026-08-14-align-frontend-ui-patterns/design.md
T

67 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Контекст
После `align-frontend-foundation` frontend имеет типизированный API layer, aliases и изолированную test infrastructure. Асинхронные страницы всё ещё одновременно получают данные, выбирают состояние и формируют разметку. `AppRoutes` не имеет boundary для непойманных ошибок, а `AppShell` существует только для protected routes.
Причина изменения описана в `proposal.md`; наблюдаемое resilience behavior определено в `specs/frontend-ui-resilience/spec.md`.
## Цели и нецели
**Цели:**
- Изолировать непойманную ошибку любого route в безопасном fallback с восстановлением после навигации.
- Разделить выбор данных и состояния от представления для Brokerage Account list, Portfolio и T-Bank connection.
- Сохранить существующее поведение finance states, auth и navigation.
- Зафиксировать новый UI pattern и resilience behavior тестами и документацией.
**Нецели:**
- Не менять API contract, query keys, cache policies, T-Bank connection semantics и domain terminology.
- Не вводить validation для opaque `accountId`.
- Не переносить auth forms в view-model pattern и не добавлять Storybook или Playwright.
## Решения
### Один native route ErrorBoundary
Boundary реализуется средствами React без новой зависимости и оборачивает `AppRoutes` внутри уже существующих router, auth и query providers. Wrapper получает key текущего route из location и сбрасывает captured error при его изменении. Так один boundary покрывает public и protected routes; boundary внутри `AppShell` отклонён, поскольку не защищает login, register и 404 routes.
Fallback не показывает error details. Он определяет безопасный destination по текущему auth state: authenticated user получает переход к accounts, unauthenticated user — к login. При ошибке protected route AppShell не сохраняется, так как иначе понадобятся разные boundaries или перестройка route layout вне scope.
### Container, view-model и state views для finance data
Accounts page, account portfolio page и T-Bank connection section получают container, который вызывает hooks и рендерит выбранное state view. View-model hook преобразует query and mutation results в props и callbacks конкретного состояния, включая error code and retry action. Loading, Error, Empty и Loaded views получают только presentation props и не выполняют HTTP requests.
Portfolio Loaded view сохраняет stale warning, totals, positions и cash balances. Его Empty view сохраняет heading Brokerage Account и текущее сообщение. Account API-404 остаётся локальным error state; cache miss не получает отдельной validation ветки для `accountId`.
T-Bank connection Loading/Error относятся к status query. Loaded view продолжает владеть формой, modal удаления, pending state и mutation error, чтобы submit/replacement/deletion flow не менялся. Auth forms остаются в текущей структуре, поскольку proposal не включает их в finance UI migration.
### Граница известных ошибок
Known API and domain states выбираются view-model до рендера Loaded view и не throw в route boundary. Это включает отсутствие T-Bank connection, invalid T-Bank token, temporary T-Bank unavailability, empty data и stale Portfolio Snapshot. Existing recovery actions, redirects, logout and refresh behavior сохраняются.
Превращать known failures в глобальный fallback отклонено: оно уничтожит полезные действия recovery и смешает service error с defect рендера.
### Статичные pages, тесты и документация
`NotFoundPageEmpty` удаляется как лишняя wrapper-component; существующий 404 presentation остаётся прямо в static page. Login, register и settings не получают artificial state components.
Tests лежат рядом с container and views. Они проверяют selection Loading/Error/Empty/Loaded, retry/navigation callbacks, stale Portfolio Snapshot, T-Bank error actions и route error recovery. Для route error используются test-only throwing components; production routes не получают тестовых веток.
`frontend/docs/UI-PATTERN.md`, `TESTING.md` и `AGENTS.md` описывают pattern и границы его применения. После реализации `docs/features/` получает краткое фактическое описание fallback и recovery behavior.
## Риски и компромиссы
- [Boundary может поймать ошибку fallback] → Fallback остаётся минимальным, использует только уже существующие auth/navigation providers и не рендерит finance data.
- [Refactor может изменить порядок query states] → Tests фиксируют текущий порядок и known recovery actions до удаления старых компонентов.
- [VM может стать прослойкой без смысла] → VM содержит только state selection and presentation mapping; простая static page не получает VM.
- [Route change не гарантирует исправность нового route] → Boundary сбрасывается на навигации, а новый route снова изолируется, если выбросит ошибку.
## План миграции
1. Добавить route ErrorBoundary и тесты public/protected fallback и navigation recovery.
2. Разделить accounts и portfolio pages на container, VM и colocated state views, сохраняя их tests.
3. Разделить T-Bank connection status presentation от Loaded form and modal, затем проверить mutation behavior.
4. Удалить static state wrapper, обновить documentation и запустить `npm run verify`.
Изменение frontend-local и откатывается возвратом frontend и documentation commits. Backend и persisted data не затрагиваются.