chore: codify frontend local verification
This commit is contained in:
@@ -1,37 +1,28 @@
|
|||||||
# Frontend
|
# Frontend
|
||||||
|
|
||||||
## Назначение
|
## Назначение и authority
|
||||||
|
|
||||||
React/Vite-клиент WealthLedger. Функциональные изменения сначала планируются в `../specs/openspec`; контракт API задает backend OpenAPI, а не ручные DTO.
|
React/Vite-клиент WealthLedger. Canonical OpenSpec store — `wealth-ledger-specs` в `../specs/openspec`; OpenSpec commands, читающие или изменяющие change, всегда выполняются с `--store wealth-ledger-specs`. Versioned planning artifacts вне canonical store запрещены, включая `superpowers/plans`; `../references/**` read-only.
|
||||||
|
|
||||||
## Проверка
|
Перед изменением поставленного поведения прочитать [`../docs/architecture/system-overview.md`](../docs/architecture/system-overview.md), а для доменных терминов — [`../docs/architecture/domain-glossary.md`](../docs/architecture/domain-glossary.md). Testing, build-versus-buy и Delivery Map определены в [`../docs/development/engineering-governance.md`](../docs/development/engineering-governance.md). Audit-derived работа начинается с [`../docs/development/audit-remediation.md`](../docs/development/audit-remediation.md).
|
||||||
|
|
||||||
|
## Canonical gate
|
||||||
|
|
||||||
|
Node 22 обязателен. После lockfile install единственный completion gate:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm ci
|
npm ci
|
||||||
npm run verify
|
npm run verify
|
||||||
```
|
```
|
||||||
|
|
||||||
Node 22 обязателен (`.nvmrc`). `npm run openapi:sync` - единственная команда, обращающаяся к `${VITE_API_BASE_URL:-http://localhost:3000}/api/docs-json`; она атомарно обновляет snapshot и generated types. `openapi:generate` и `openapi:check` работают только с committed snapshot.
|
Gate non-mutating и проверяет runtime, OpenAPI snapshot, hygiene, strict TypeScript, Biome, risk-based tests/coverage ratchet, Knip, dependency boundaries, build и bundle budget. `npm run openapi:sync` — отдельная записывающая команда для атомарного обновления snapshot/types; runtime contract обеих сторон сверяется из workspace через `bash specs/scripts/verify-runtime-openapi.sh`.
|
||||||
|
|
||||||
Для read-only сверки backend runtime OpenAPI с committed snapshot под Node 22
|
## Enforceable boundaries
|
||||||
запускать из workspace `bash specs/scripts/verify-runtime-openapi.sh`.
|
|
||||||
|
|
||||||
## Документация для агента
|
- Code style и i18n: [`docs/CONVENTIONS.md`](docs/CONVENTIONS.md), исполняются Biome и TypeScript.
|
||||||
|
- FSD и public API: [`docs/STRUCTURE.md`](docs/STRUCTURE.md), исполняются dependency-cruiser и Knip; направление `app → pages → features → entities → shared`.
|
||||||
|
- HTTP и types: [`docs/API-LAYER.md`](docs/API-LAYER.md); только typed client и generated OpenAPI `paths[...]`, без ручных transport DTO и прямых T-Bank calls.
|
||||||
|
- UI states: [`docs/UI-PATTERN.md`](docs/UI-PATTERN.md); route runtime failures обрабатывает единый route-keyed ErrorBoundary, expected API states остаются локальными.
|
||||||
|
- Тесты: [`docs/TESTING.md`](docs/TESTING.md); новый тест обязателен по risk trigger, а не из-за появления файла или coverage процента.
|
||||||
|
|
||||||
- Перед изменением поставленного поведения или доменных терминов прочитать [`../docs/architecture/system-overview.md`](../docs/architecture/system-overview.md) и [`../docs/architecture/domain-glossary.md`](../docs/architecture/domain-glossary.md).
|
Непроверяемые эстетические предпочтения считаются guidance. Не добавлять Storybook, Playwright, CI, browser MSW worker или mock development mode без утверждённого change.
|
||||||
- Перед изменением API или transport types прочитать [`docs/API-LAYER.md`](docs/API-LAYER.md).
|
|
||||||
- Перед созданием формы, страницы или UI-состояний прочитать [`docs/UI-PATTERN.md`](docs/UI-PATTERN.md).
|
|
||||||
- Перед изменением структуры слайса или импортов прочитать [`docs/STRUCTURE.md`](docs/STRUCTURE.md).
|
|
||||||
- Перед кодом, тестами или quality checks прочитать [`docs/CONVENTIONS.md`](docs/CONVENTIONS.md) и [`docs/TESTING.md`](docs/TESTING.md).
|
|
||||||
- Route-level runtime errors обрабатываются одним native route-keyed ErrorBoundary вокруг `AppRoutes`; expected API states остаются локальными.
|
|
||||||
- Для задачи по Audit ID, продолжения remediation или выбора следующего улучшения сначала прочитать [`../docs/development/audit-remediation.md`](../docs/development/audit-remediation.md); единственный canonical OpenSpec store — `wealth-ledger-specs` в `../specs/openspec`, а OpenSpec commands, читающие или изменяющие change, выполнять с `--store wealth-ledger-specs`.
|
|
||||||
|
|
||||||
## Границы
|
|
||||||
|
|
||||||
- Текущий baseline использует FSD, React Router, i18n, Mantine, React Query и typed API scaffold.
|
|
||||||
- Зависимости FSD идут `app -> pages -> features -> entities -> shared`; слайсы импортируются только через публичный `index.ts`.
|
|
||||||
- HTTP идет только через типизированный клиент; request/response types выводятся из generated OpenAPI `paths[...]`, а не дублируются вручную. UI-строки - только через i18n. Каждый маршрут имеет loading, error и empty состояния.
|
|
||||||
- Соблюдать strict TypeScript: `import type` для типов, без `enum` и `namespace`.
|
|
||||||
- Не добавлять прямые вызовы T-Bank и не переносить Todo-код из `../references/`.
|
|
||||||
- Не добавлять Storybook, Playwright, CI configuration, browser MSW worker или mock development mode.
|
|
||||||
- Не создавать и не коммитить framework-specific planning/spec/task/design artifacts: versioned SDD-артефакты хранятся только в `../specs/openspec`; `../references/**` остаётся read-only исключением.
|
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ npm run dev
|
|||||||
npm run verify
|
npm run verify
|
||||||
```
|
```
|
||||||
|
|
||||||
Команда проверяет committed OpenAPI snapshot, strict TypeScript, Biome, unit
|
Команда сначала отклоняет runtime вне Node 22, затем проверяет committed
|
||||||
tests и coverage, Knip, dependency rules и production build. Для обновления
|
OpenAPI snapshot, repository hygiene, strict TypeScript, Biome, один
|
||||||
OpenAPI artifacts применяется только `npm run openapi:sync`; обычный
|
coverage-backed запуск Vitest, Knip, dependency rules, production build и
|
||||||
`openapi:check` обращается лишь к committed snapshot.
|
bundle budget. Для обновления OpenAPI artifacts применяется только
|
||||||
|
`npm run openapi:sync`; обычный `openapi:check` обращается лишь к committed
|
||||||
|
snapshot.
|
||||||
|
|
||||||
## Документация
|
## Документация
|
||||||
|
|
||||||
@@ -34,8 +36,12 @@ OpenAPI artifacts применяется только `npm run openapi:sync`; о
|
|||||||
- [UI-паттерны](docs/UI-PATTERN.md)
|
- [UI-паттерны](docs/UI-PATTERN.md)
|
||||||
- [Conventions](docs/CONVENTIONS.md) и [тестирование](docs/TESTING.md)
|
- [Conventions](docs/CONVENTIONS.md) и [тестирование](docs/TESTING.md)
|
||||||
- [Обзор поставленной системы](../docs/architecture/system-overview.md)
|
- [Обзор поставленной системы](../docs/architecture/system-overview.md)
|
||||||
|
- [Engineering governance и risk-based testing](../docs/development/engineering-governance.md)
|
||||||
|
- [OpenSpec authority и lifecycle](../docs/development/openspec-authority-and-lifecycle.md)
|
||||||
- [Frontend workflow](../docs/development/frontend-workflow.md)
|
- [Frontend workflow](../docs/development/frontend-workflow.md)
|
||||||
- [Remediation registry](../docs/development/audit-remediation.md)
|
- [Remediation registry](../docs/development/audit-remediation.md)
|
||||||
|
|
||||||
Runtime OpenAPI backend сверяется с frontend snapshot отдельной read-only
|
Runtime OpenAPI backend сверяется с frontend snapshot отдельной read-only
|
||||||
командой из workspace: `bash specs/scripts/verify-runtime-openapi.sh`.
|
командой из workspace: `bash specs/scripts/verify-runtime-openapi.sh`.
|
||||||
|
Полный multi-repository change проверяется из workspace командой
|
||||||
|
`bash specs/scripts/verify-workspace-change.sh <change>`.
|
||||||
|
|||||||
+5
-1
@@ -1,6 +1,10 @@
|
|||||||
# Frontend Documentation
|
# Frontend Documentation
|
||||||
|
|
||||||
Эти документы задают правила AI-разработки и дополняют `AGENTS.md`. Фактические версии зависимостей и scripts всегда определяются конфигурацией проекта.
|
Эти документы задают frontend-local conventions и дополняют `AGENTS.md`.
|
||||||
|
Общая engineering policy находится в
|
||||||
|
[`../../docs/development/engineering-governance.md`](../../docs/development/engineering-governance.md),
|
||||||
|
а фактические версии зависимостей и scripts всегда определяются конфигурацией
|
||||||
|
проекта.
|
||||||
|
|
||||||
- `CONVENTIONS.md` - обязательные правила кода и i18n.
|
- `CONVENTIONS.md` - обязательные правила кода и i18n.
|
||||||
- `API-LAYER.md` - OpenAPI, generated types и typed client.
|
- `API-LAYER.md` - OpenAPI, generated types и typed client.
|
||||||
|
|||||||
+15
-1
@@ -1,9 +1,23 @@
|
|||||||
# Testing
|
# Testing
|
||||||
|
|
||||||
Тесты запускаются `npm run test:run` через Vitest и Testing Library. `npm run test:coverage` создаёт локальный coverage report.
|
Canonical completion gate — `npm run verify`; он запускает Vitest один раз
|
||||||
|
через `npm run test:coverage`. `npm run test:run` остаётся короткой локальной
|
||||||
|
командой без coverage report.
|
||||||
|
|
||||||
|
Выбор нового теста определяется риском поведения, а не фактом изменения файла.
|
||||||
|
Автоматический тест обязателен для security/privacy, денежных расчётов,
|
||||||
|
целостности данных, concurrency, публичного контракта, критического journey и
|
||||||
|
регрессии. DTO без логики, декларативная конфигурация, тонкая orchestration и
|
||||||
|
поведение зависимости отдельного unit test не требуют, пока у них нет
|
||||||
|
собственного branching, transformation, invariant или regression. Полная
|
||||||
|
policy находится в [engineering governance](../../docs/development/engineering-governance.md).
|
||||||
|
|
||||||
MSW запускается только Vitest setup в `src/test/`; handlers покрывают текущий API. Не добавлять service worker, browser mocking или mock development mode. Для transport проверять заголовки и retry через MSW, не через реальный backend.
|
MSW запускается только Vitest setup в `src/test/`; handlers покрывают текущий API. Не добавлять service worker, browser mocking или mock development mode. Для transport проверять заголовки и retry через MSW, не через реальный backend.
|
||||||
|
|
||||||
Проверяйте наблюдаемое поведение, а не детали реализации. UI-тест строится как Arrange, Act, Assert; для интерактивных действий предпочитайте `userEvent`. Форма должна проверять валидацию и отсутствие запроса при невалидных данных; маршруты - редиректы и доступность экрана.
|
Проверяйте наблюдаемое поведение, а не детали реализации. UI-тест строится как Arrange, Act, Assert; для интерактивных действий предпочитайте `userEvent`. Форма должна проверять валидацию и отсутствие запроса при невалидных данных; маршруты - редиректы и доступность экрана.
|
||||||
|
|
||||||
Colocated tests finance views фиксируют выбор loading/error/empty/loaded и доступные recovery actions. Route boundary tests используют test-only throwing route и проверяют безопасную ссылку и reset после navigation.
|
Colocated tests finance views фиксируют выбор loading/error/empty/loaded и доступные recovery actions. Route boundary tests используют test-only throwing route и проверяют безопасную ссылку и reset после navigation.
|
||||||
|
|
||||||
|
Coverage floors остаются anti-regression constraint. Нельзя добавлять тест,
|
||||||
|
который только повторяет декларативную структуру или внутренности зависимости,
|
||||||
|
ради повышения процента.
|
||||||
|
|||||||
+2
-1
@@ -7,6 +7,7 @@
|
|||||||
"node": "22.x"
|
"node": "22.x"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"runtime:check": "node scripts/verify-node-version.mjs",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"typecheck": "tsc -b --noEmit",
|
"typecheck": "tsc -b --noEmit",
|
||||||
"build": "tsc -b && vite build",
|
"build": "tsc -b && vite build",
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
"deps": "node --test scripts/dependency-cruiser-config.test.mjs && depcruise src --config dependency-cruiser.cjs --output-type err-long",
|
"deps": "node --test scripts/dependency-cruiser-config.test.mjs && depcruise src --config dependency-cruiser.cjs --output-type err-long",
|
||||||
"bundle:check": "node --test scripts/bundle-budget.test.mjs && node scripts/bundle-budget.mjs",
|
"bundle:check": "node --test scripts/bundle-budget.test.mjs && node scripts/bundle-budget.mjs",
|
||||||
"bundle:baseline": "npm run build && node scripts/bundle-budget.mjs baseline",
|
"bundle:baseline": "npm run build && node scripts/bundle-budget.mjs baseline",
|
||||||
"verify": "npm run openapi:check && npm run hygiene:check && npm run typecheck && npm run lint && npm run test:run && npm run test:coverage && npm run knip && npm run deps && npm run build && npm run bundle:check",
|
"verify": "npm run runtime:check && npm run openapi:check && npm run hygiene:check && npm run typecheck && npm run lint && npm run test:coverage && npm run knip && npm run deps && npm run build && npm run bundle:check",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { dirname, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const packageJson = JSON.parse(
|
||||||
|
readFileSync(resolve(root, "package.json"), "utf8"),
|
||||||
|
);
|
||||||
|
const nvmVersion = readFileSync(resolve(root, ".nvmrc"), "utf8").trim();
|
||||||
|
const expectedMajor = nvmVersion.replace(/^v/, "").split(".")[0];
|
||||||
|
const expectedEngine = `${expectedMajor}.x`;
|
||||||
|
|
||||||
|
if (packageJson.engines?.node !== expectedEngine) {
|
||||||
|
throw new Error(
|
||||||
|
`Node runtime contracts disagree: .nvmrc=${nvmVersion}, package.json engines.node=${packageJson.engines?.node ?? "missing"}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const actualVersion = process.versions.node;
|
||||||
|
const actualMajor = actualVersion.split(".")[0];
|
||||||
|
if (actualMajor !== expectedMajor) {
|
||||||
|
console.error(
|
||||||
|
`Unsupported Node.js runtime: expected ${expectedEngine}, actual ${actualVersion}. Activate .nvmrc before running repository checks.`,
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Node.js runtime verified: ${actualVersion} (${expectedEngine})`);
|
||||||
Reference in New Issue
Block a user