chore: codify frontend local verification

This commit is contained in:
2026-08-24 19:55:28 +03:00
parent 1fc269adec
commit 11be786943
6 changed files with 75 additions and 31 deletions
+15 -24
View File
@@ -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 исключением.
+10 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
}, },
+28
View File
@@ -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})`);