add: refactor foundation
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-08-14
|
||||
@@ -0,0 +1,80 @@
|
||||
## Контекст
|
||||
|
||||
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 не меняется.
|
||||
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
Текущий WealthLedger frontend имеет базовый React/FSD-стек, но не содержит проверенный агентский workflow из `references/frontend-ai-template`: воспроизводимую среду, единый quality gate, проверку дрейфа OpenAPI и изолированные API-тесты. Это делает работу агентов зависимой от локального backend и ручной дисциплины.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Выравнивается frontend toolchain с проверенным template: Node 22, фиксированные версии зависимостей, strict TypeScript, aliases, Mantine 9 и tooling для статического анализа.
|
||||
- Frontend хранит версионируемый snapshot опубликованного backend OpenAPI, генерирует schema из него и проверяет отсутствие дрейфа generated artifact.
|
||||
- Typed API layer переходит на `openapi-react-query`, сохраняя текущую auth-семантику Bearer token, refresh и retry.
|
||||
- Добавляются MSW handlers только для unit-тестов, единый `verify`, coverage report, git hooks и Conventional Commits.
|
||||
- Документация и `AGENTS.md` расширяются до agent-oriented структуры template, без переноса Todo-домена.
|
||||
- Playwright, Storybook и CI не входят в это изменение.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
<!-- None. -->
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `api-contract-generation`: frontend хранит проверяемый snapshot backend OpenAPI и детерминированно генерирует из него transport types.
|
||||
|
||||
## Impact
|
||||
|
||||
- Затрагивает `frontend` package/configuration, API client, тестовую инфраструктуру, локальную документацию и git hooks.
|
||||
- Backend остаётся источником истины для OpenAPI и используется только командой синхронизации snapshot.
|
||||
- Требует обновления зависимостей и lockfile frontend-репозитория.
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Frontend использует сгенерированный API-клиент
|
||||
Frontend SHALL хранить в репозитории версионируемый snapshot опубликованного OpenAPI-документа и генерировать transport types из этого snapshot. Команда синхронизации MUST получать документ из backend, а затем обновлять snapshot и сгенерированный результат только при успешном завершении всего процесса. Сгенерированный результат MUST храниться в frontend-репозитории.
|
||||
|
||||
#### Scenario: API-контракт синхронизируется
|
||||
- **WHEN** разработчик запускает команду синхронизации при доступном backend с валидным OpenAPI-документом
|
||||
- **THEN** frontend обновляет versioned snapshot и сгенерированные transport types из опубликованного контракта
|
||||
|
||||
#### Scenario: API-контракт изменяется
|
||||
- **WHEN** backend меняет опубликованный API-контракт
|
||||
- **THEN** frontend может синхронизировать snapshot и повторно сгенерировать transport types до интеграции изменения
|
||||
|
||||
#### Scenario: Синхронизация контракта завершается ошибкой
|
||||
- **WHEN** backend недоступен или публикует невалидный OpenAPI-документ
|
||||
- **THEN** команда завершается с ошибкой и существующие snapshot и сгенерированные transport types не изменяются
|
||||
|
||||
### Requirement: Frontend не зависит от OpenAPI во время работы
|
||||
Работающий frontend MUST использовать ранее сгенерированные transport types и MUST NOT требовать доступность Swagger или OpenAPI endpoint во время запуска, выполнения пользовательского сценария или локальной проверки актуальности generated artifact. Доступ к backend OpenAPI endpoint разрешён только команде синхронизации snapshot.
|
||||
|
||||
#### Scenario: OpenAPI endpoint недоступен после сборки frontend
|
||||
- **WHEN** frontend уже собран, а endpoint OpenAPI временно недоступен
|
||||
- **THEN** frontend продолжает использовать сгенерированный код для запросов к API
|
||||
|
||||
#### Scenario: Локальная проверка выполняется без backend
|
||||
- **WHEN** разработчик запускает локальный quality gate без доступного backend
|
||||
- **THEN** проверка актуальности generated artifact использует сохранённый snapshot и не обращается к OpenAPI endpoint
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Frontend обнаруживает дрейф сгенерированного контракта
|
||||
Frontend SHALL проверять, что committed generated transport types соответствуют versioned OpenAPI snapshot, и MUST завершать quality gate с ошибкой при расхождении.
|
||||
|
||||
#### Scenario: Generated artifact устарел
|
||||
- **WHEN** OpenAPI snapshot изменён, а generated transport types не обновлены
|
||||
- **THEN** проверка контракта завершается с ошибкой
|
||||
|
||||
#### Scenario: Generated artifact изменён вручную
|
||||
- **WHEN** generated transport types отличаются от результата генерации из сохранённого snapshot
|
||||
- **THEN** проверка контракта завершается с ошибкой
|
||||
@@ -0,0 +1,26 @@
|
||||
## 1. Воспроизводимый baseline
|
||||
|
||||
- [x] 1.1 Зафиксировать Node 22, exact dependency versions и обновлённый lockfile; обновить совместимые React/Mantine/TypeScript toolchain configuration.
|
||||
- [x] 1.2 Настроить Vite/TypeScript aliases, Knip и `dependency-cruiser`; перевести существующие межслайсовые импорты на public `index.ts` APIs и устранить все findings новых checks.
|
||||
|
||||
## 2. Локальный OpenAPI contract
|
||||
|
||||
- [x] 2.1 Добавить committed raw OpenAPI JSON snapshot и явную атомарную sync-команду, получающую опубликованный backend contract только по запросу разработчика.
|
||||
- [x] 2.2 Генерировать `schema.d.ts` из committed snapshot и добавить offline `openapi:check`, который обнаруживает устаревший или вручную изменённый generated artifact.
|
||||
|
||||
## 3. Типизированный API и тесты
|
||||
|
||||
- [x] 3.1 Подключить `openapi-react-query` к shared typed client и мигрировать текущие API queries и mutations, сохранив cache, retry и UI error semantics.
|
||||
- [x] 3.2 Сделать authenticated fetch единственным владельцем Bearer header; сохранить refresh single-flight/retry semantics и синхронизацию token reference при initial session restoration.
|
||||
- [x] 3.3 Добавить MSW только в Vitest и handlers текущего API; покрыть transport auth invariants и изолированные успешные и ошибочные API scenarios.
|
||||
|
||||
## 4. Единый quality gate
|
||||
|
||||
- [x] 4.1 Добавить coverage report и `npm run verify` с OpenAPI drift, typecheck, Biome, unit tests, coverage, Knip, FSD dependency checks и production build.
|
||||
- [x] 4.2 Настроить Husky, lint-staged и Conventional Commits: быстрый pre-commit для staged formatting, contract/dependency checks и commit-msg validation.
|
||||
|
||||
## 5. Документация и проверка
|
||||
|
||||
- [x] 5.1 Обновить frontend `AGENTS.md` и тематические docs для agent-oriented workflow без UI, Storybook и e2e guidance.
|
||||
- [x] 5.2 Добавить в `docs/development/` постоянную документацию реализованного frontend workflow: Node version, contract sync и quality gate.
|
||||
- [x] 5.3 Выполнить `npm ci` и `npm run verify`; убедиться, что baseline проходит без suppressions и без доступного backend после завершения sync.
|
||||
Reference in New Issue
Block a user