Files
2026-08-14 09:49:55 +03:00

81 lines
12 KiB
Markdown
Raw Permalink 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.
## Контекст
Frontend уже использует React, FSD, generated OpenAPI types и React Query, но получает OpenAPI непосредственно из работающего backend и вручную создаёт query/mutation hooks. Bearer header одновременно добавляется общим HTTP transport и передаётся отдельными вызовами. Локальная проверка состоит из разрозненных команд и не проверяет generated artifact, не изолирует API-тесты и не контролирует границы FSD-слоёв.
Причина изменения описана в `proposal.md`, а контрактные требования — в `specs/api-contract-generation/spec.md`.
## Цели и нецели
**Цели:**
- Сделать настройку frontend, генерацию API-контракта и локальную проверку воспроизводимыми без запущенного backend, кроме явной синхронизации контракта.
- Централизовать типизированную интеграцию React Query и auth transport без изменения существующих пользовательских сценариев и семантики cache.
- Создать чистый, проверяемый и ориентированный на агентов baseline разработки с API mocks только для тестов.
- Зафиксировать реализованный workflow в документации frontend и постоянной документации проекта.
**Нецели:**
- Не мигрируются routes, forms, state-views, view-model и ErrorBoundary; они относятся к `align-frontend-ui-patterns`.
- Не добавляются Storybook, Playwright, browser MSW worker, mock-режим разработки и CI configuration.
- Не меняются владение backend OpenAPI, API routes, authentication protocol и доменная терминология WealthLedger.
## Решения
### Воспроизводимый frontend baseline
Frontend будет объявлять Node 22 через `.nvmrc` и `package.json#engines`. Зависимости будут использовать точные версии, а lockfile будет перегенерирован. Toolchain перейдёт на совместимый baseline template, включая Mantine 9, строгие опции TypeScript, aliases Vite/TypeScript и tooling статического анализа.
Aliases будут одинаково определены в Vite и TypeScript. Существующие cross-slice imports будут использовать публичные API через `index.ts`; файлы внутри slice могут использовать относительные imports. `dependency-cruiser` будет проверять только направление FSD-слоёв, а использование public API останется документированным правилом review.
Точные версии выбраны вместо semver ranges, чтобы установки агентов и разработчиков воспроизводили один dependency graph. Собственный Node version checker отклонён: `.nvmrc` и `engines` сообщают ограничение без дополнительного пути к ошибке.
### Генерация OpenAPI из snapshot
`src/shared/api/spec/` будет хранить committed raw JSON snapshot из backend OpenAPI endpoint, а `src/shared/api/generated/schema.d.ts` останется committed generated artifact. Явная sync-команда получит endpoint, настроенный `VITE_API_BASE_URL`, провалидирует его генерацией и заменит оба artifacts только после успеха всех шагов. Временные файлы не позволят неудачному fetch или generation частично обновить контракт.
`openapi:generate` будет генерировать из committed snapshot. `openapi:check` независимо сгенерирует ожидаемую schema во временную директорию и сравнит её с committed artifact. Команда не обращается к backend, поэтому `verify` остаётся доступным offline.
Генерация напрямую из работающего backend отклонена, потому что обычные локальные проверки станут зависимы от его доступности. Преобразование snapshot в YAML отклонено, потому что сохранение опубликованного JSON исключает ненужную трансформацию.
### Типизированная интеграция queries и auth boundary
Shared OpenAPI client остаётся единственной HTTP entry point. `openapi-react-query` будет получать из него типизированные React Query operations; существующие query keys, `enabled`, stale times, retry policies, invalidations и отображение ошибок сохранятся. API request и response types продолжат выводиться из generated `paths`, а не дублировать DTOs.
Реализация authenticated fetch становится единственным владельцем Bearer header. Она исключает auth endpoints, делает ровно один retry только после `401` с `UNAUTHORIZED` и успешного refresh, а при неудачном refresh очищает session state. Query и mutation calls больше не передают Authorization самостоятельно. Initial session restoration должен обновлять и React state, и token reference, используемый transport; logout и неудачный refresh очищают оба и cache QueryClient.
Ручная передача headers отклонена: она дублирует cross-cutting security concern и может разойтись с поведением transport. Замена refresh semantics на library interceptor отклонена, потому что существующие refresh single-flight и browser lock уже являются корректным product behavior.
### MSW только для тестов и целевые regression tests
MSW будет запускаться только через Vitest setup и handlers для текущего WealthLedger API. Не будут добавлены service worker, команда `dev:mock`, mock build и application mock mode. Поэтому unit и hook tests смогут выполнять успешные и ошибочные API scenarios без backend.
Целевые transport tests проверят Bearer injection, исключение auth endpoints, один refresh/retry для `UNAUTHORIZED`, очистку session после неудачного refresh и авторизацию восстановленной session. Coverage формируется как report, но не получает числовой threshold до стабилизации UI patterns.
Browser mocking отклонён, потому что он создаёт незапрошенный второй application mode. Coverage threshold отклонён, потому что текущий baseline слишком мал для стабильной и содержательной цели.
### Единый локальный quality gate и постоянная документация
`npm run verify` будет запускать OpenAPI drift detection, typecheck, Biome, unit tests, coverage reporting, Knip, dependency-cruiser и production build. Все проверки должны проходить без baseline suppressions или allowlists. Husky устанавливается через `prepare`; pre-commit форматирует staged files и запускает contract и dependency checks, а commit-msg проверяет Conventional Commits.
Frontend `AGENTS.md` остаётся коротким индексом «задача → документ». Его локальные docs описывают API workflow, test setup, structure и conventions. После реализации `docs/development/` получит постоянное cross-repository описание frontend workflow: требуемую Node version, contract synchronization и quality-gate commands. Так знания о реализованном процессе не останутся только в frontend repository.
Запуск полного gate в каждом pre-commit hook отклонён, потому что tests и builds замедляют обычные commits; `verify` остаётся единственным явным полным gate. Storybook и e2e build steps исключены вместе с их tools.
## Риски и компромиссы
- [Обновления Mantine и совместимых зависимостей могут выявить несовместимости исходного кода] → Устранить все type, lint и build errors до принятия нового lockfile.
- [Committed snapshot может отставать от backend] → Backend остаётся источником истины; явный sync обновляет snapshot, а локальная проверка гарантирует только внутреннюю согласованность.
- [Централизация Bearer injection может сломать восстановленные sessions] → Синхронизировать token reference во время initial refresh и покрыть поведение transport tests.
- [Static analyzers могут сообщить о существующем коде] → Исправить код или точно настроить tool до получения зелёного baseline; не скрывать findings временными waivers.
- [Hooks запускаются не во всех окружениях разработчиков] → `npm run verify` остаётся независимо запускаемым и документированным completion gate.
## План миграции
1. Обновить и зафиксировать frontend toolchain, настроить aliases и static-analysis tools, привести текущий исходный код к новым checks.
2. Добавить OpenAPI snapshot, sync/generate/check commands, затем проверить generated artifact из committed snapshot без доступа к backend.
3. Мигрировать API queries и mutations на typed integration, централизовать Bearer handling и добавить transport regression coverage.
4. Добавить MSW только для тестов, coverage reporting, git hooks и единый скрипт `verify`.
5. Обновить frontend agent documentation и `docs/development/` описанием реализованного workflow, затем запустить полный quality gate.
Изменение локально для frontend и может быть отменено откатом его frontend и documentation commits. Backend contract не меняется.