diff --git a/AGENTS.md b/AGENTS.md index eba6be7..28f262a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,37 +1,28 @@ # 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 npm ci 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 -запускать из workspace `bash specs/scripts/verify-runtime-openapi.sh`. +## Enforceable boundaries -## Документация для агента +- 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). -- Перед изменением 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 исключением. +Непроверяемые эстетические предпочтения считаются guidance. Не добавлять Storybook, Playwright, CI, browser MSW worker или mock development mode без утверждённого change. diff --git a/README.md b/README.md index 6df7074..db5088c 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,12 @@ npm run dev npm run verify ``` -Команда проверяет committed OpenAPI snapshot, strict TypeScript, Biome, unit -tests и coverage, Knip, dependency rules и production build. Для обновления -OpenAPI artifacts применяется только `npm run openapi:sync`; обычный -`openapi:check` обращается лишь к committed snapshot. +Команда сначала отклоняет runtime вне Node 22, затем проверяет committed +OpenAPI snapshot, repository hygiene, strict TypeScript, Biome, один +coverage-backed запуск Vitest, Knip, dependency rules, production build и +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) - [Conventions](docs/CONVENTIONS.md) и [тестирование](docs/TESTING.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) - [Remediation registry](../docs/development/audit-remediation.md) Runtime OpenAPI backend сверяется с frontend snapshot отдельной read-only командой из workspace: `bash specs/scripts/verify-runtime-openapi.sh`. +Полный multi-repository change проверяется из workspace командой +`bash specs/scripts/verify-workspace-change.sh `. diff --git a/docs/README.md b/docs/README.md index 52f95c3..7047f79 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,10 @@ # 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. - `API-LAYER.md` - OpenAPI, generated types и typed client. diff --git a/docs/TESTING.md b/docs/TESTING.md index d3d6d94..5d83b11 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -1,9 +1,23 @@ # 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. Проверяйте наблюдаемое поведение, а не детали реализации. UI-тест строится как Arrange, Act, Assert; для интерактивных действий предпочитайте `userEvent`. Форма должна проверять валидацию и отсутствие запроса при невалидных данных; маршруты - редиректы и доступность экрана. Colocated tests finance views фиксируют выбор loading/error/empty/loaded и доступные recovery actions. Route boundary tests используют test-only throwing route и проверяют безопасную ссылку и reset после navigation. + +Coverage floors остаются anti-regression constraint. Нельзя добавлять тест, +который только повторяет декларативную структуру или внутренности зависимости, +ради повышения процента. diff --git a/package.json b/package.json index 91a657c..a8f35fa 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "node": "22.x" }, "scripts": { + "runtime:check": "node scripts/verify-node-version.mjs", "dev": "vite", "typecheck": "tsc -b --noEmit", "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", "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", - "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", "preview": "vite preview" }, diff --git a/scripts/verify-node-version.mjs b/scripts/verify-node-version.mjs new file mode 100644 index 0000000..8b35138 --- /dev/null +++ b/scripts/verify-node-version.mjs @@ -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})`);