From a83e26e5ef5d7cae3179a182fb5359a440538177 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 9 Sep 2026 16:23:03 +0300 Subject: [PATCH] docs(ai): add scoped backend conventions --- .ai/CONVENTIONS.md | 24 +++++++++++ .ai/SOURCES.md | 19 +++++++++ .ai/conventions/backend-architecture.md | 53 +++++++++++++++++++++++ .ai/conventions/backend-data.md | 56 +++++++++++++++++++++++++ .ai/conventions/backend-http-api.md | 52 +++++++++++++++++++++++ .ai/conventions/backend-integrations.md | 47 +++++++++++++++++++++ .ai/conventions/backend-testing.md | 46 ++++++++++++++++++++ .ai/conventions/security-auth.md | 51 ++++++++++++++++++++++ AGENTS.md | 48 ++++++++------------- README.md | 17 +++++--- 10 files changed, 377 insertions(+), 36 deletions(-) create mode 100644 .ai/CONVENTIONS.md create mode 100644 .ai/SOURCES.md create mode 100644 .ai/conventions/backend-architecture.md create mode 100644 .ai/conventions/backend-data.md create mode 100644 .ai/conventions/backend-http-api.md create mode 100644 .ai/conventions/backend-integrations.md create mode 100644 .ai/conventions/backend-testing.md create mode 100644 .ai/conventions/security-auth.md diff --git a/.ai/CONVENTIONS.md b/.ai/CONVENTIONS.md new file mode 100644 index 0000000..72e31c6 --- /dev/null +++ b/.ai/CONVENTIONS.md @@ -0,0 +1,24 @@ +# Backend router + +Объединяй triggers из смысла задачи, путей и обнаруженных boundaries. +Читай выбранные guides до решения; якорь допускает чтение только нужного раздела. +Просто backend-файл не требует всех conventions. + +| Решение / сигнал | Читать | +| --- | --- | +| Новый module/provider/service; бизнес-логика; перенос responsibility | [Architecture](conventions/backend-architecture.md) | +| Controller, DTO, route/status, validation/exception, публичная HTTP-семантика | [HTTP API](conventions/backend-http-api.md) | +| Prisma/schema/query/persistence, transaction, migration, atomic write | [Data](conventions/backend-data.md) | +| Тесты или behavior с testing risk | [Testing](conventions/backend-testing.md) | +| JWT, cookie, login/refresh/logout, guard/access, token encryption, sensitive logs | [Security](conventions/security-auth.md) | +| T-Bank/gRPC/proto, upstream retry/rate limit/cache, MoexClient | [Integrations](conventions/backend-integrations.md) | +| Logging/request context без изменения secrets/auth | [Logging](conventions/backend-architecture.md#logging) | +| Новый abstraction/dependency, refactor, неясный scope | [Общий выбор реализации](../../docs/development/engineering-governance.md#выбор-реализации) | +| Изменение request/response/route/status/error shape или Swagger metadata | HTTP API + [общий contract workflow](../../docs/development/runtime-openapi-verification.md) | + +Новый endpoint обычно требует HTTP API + Testing; Architecture/Data/Security +добавляются по новым ответственности, persistence или access rules. +Изменение одного Prisma query без HTTP/auth границы не требует HTTP API/Security. +Auth refresh активирует Security + Data + Testing; HTTP API добавляется, если +меняется controller/HTTP contract. Exact docs/spec sources выбирай через SOURCES. +Повтори routing при расширении diff, включая новые и unstaged файлы. diff --git a/.ai/SOURCES.md b/.ai/SOURCES.md new file mode 100644 index 0000000..35b74d0 --- /dev/null +++ b/.ai/SOURCES.md @@ -0,0 +1,19 @@ +# Источники backend + +| Что нужно установить | Владелец | +| --- | --- | +| Implementation decision и безопасный pattern | [CONVENTIONS](CONVENTIONS.md) | +| HTTP errors, DTO semantics, public wire shape | [docs: HTTP API](../../docs/AI_INDEX.md#http-api); runtime OpenAPI из Nest — единственный editable source | +| Auth/session, account access, token encryption | [docs: Security](../../docs/AI_INDEX.md#security) | +| Prisma schema/data ownership и migration context | [docs: Data](../../docs/AI_INDEX.md#data) | +| T-Bank/gRPC/cache, logging | [docs: Integrations](../../docs/AI_INDEX.md#integrations) | +| Money, account/position/income/cache meanings | [docs: Domain](../../docs/AI_INDEX.md#domain) | +| Поведение конкретной feature | [docs: Features](../../docs/AI_INDEX.md#features) | +| Существующие behavioral requirements при необходимости | [specs index](../../specs/AI_INDEX.md) | +| Versions/scripts и scope автоматических checks | package.json/lockfile, ESLint/TypeScript/Jest/Prisma configs | + +SOURCES — карта, не требование прочитать все ссылки. Code показывает реализацию, +ADR — rationale, docs — текущие факты; старый пример не отменяет контракт. +Исследование предлагает варианты, а actual source разрешает выбор. При missing +или conflicting security/data facts сначала установи источник. Для обычной +работы OpenSpec/SDD не требуется. diff --git a/.ai/conventions/backend-architecture.md b/.ai/conventions/backend-architecture.md new file mode 100644 index 0000000..131a27d --- /dev/null +++ b/.ai/conventions/backend-architecture.md @@ -0,0 +1,53 @@ +# Backend architecture + +## Выбор владельца + +Найди существующий use case, его collaborators и tests до создания module/service. +Сохрани ответственность в текущем module, если новая возможность относится к нему. +Module — граница связного набора providers, а не папка для каждого endpoint. + +| Решение | Owner | +| --- | --- | +| Route, request/response mapping, status/cookie | Controller, [HTTP rules](backend-http-api.md) | +| Business use case, orchestration, domain validation | Feature service | +| Input shape/format | DTO + configured ValidationPipe | +| Атомарность/DB query | Сервис use case через PrismaService, [Data](backend-data.md) | +| Внешний protocol, deadline/retry/limiting | Existing client, [Integrations](backend-integrations.md) | +| Чистое вычисление/mapper без lifecycle и DI | Обычная функция рядом с domain owner | +| Bootstrap/config/global cross-cutting concern | AppModule, config, существующий common owner | + +**Безопасный путь:** расширь текущий owner; выделяй collaborator, когда он скрывает +самостоятельный инвариант или координацию. Не вводи CQRS, generic repository, +interface с одной реализацией или base controller только ради шаблона Nest. +Не превращай common в хранилище бизнес-логики и не переноси frontend модели сюда. + +## Существующие seams + +`TbankConnectionModule` уже объединяет счета, портфель, операции, доходы и события. +Новый связанный use case обычно добавляется в него; создание отдельного module +требует собственной ответственности, не только нового файла. + +- [BrokerageOperationsController](../../src/tbank/brokerage-operations.controller.ts) передаёт user/account/query в service, без финансовых вычислений в controller. +- [TbankAccessService](../../src/tbank/tbank-access.service.ts) владеет connection/account access и generation; новые account use cases используют его вместо копирования guard/decrypt logic. +- [decimal.ts](../../src/tbank/decimal.ts) — пример pure domain helper; Injectable и adapter для арифметики не нужны. + +Наличие guard подтверждает session, но не владение account. При пересечении +access boundary добавь [Security](security-auth.md). Ошибка upstream не должна +обходить общий HTTP filter или превращать чужой account в доступный. + +## Logging + +Единственный logger — nestjs-pino; application events используют существующий +[StructuredLogger](../../src/common/logging/structured-logger.service.ts) и +request context. Выбирай стабильное имя события и разрешённые scalar fields. +Wrapper отбрасывает неизвестные поля, но это не разрешение помещать secret +в `message`/`stack`: review sensitive logging обязателен. +Не добавляй второй logger или сырой request/body/error payload. +Источник rationale — [ADR 008](../../../docs/adr/008-pino-backend-logging.md); +при secrets/user data читай также Security. + +## Проверка + +`npm run typecheck:app`, `npm run lint`, targeted Jest по изменённому use case. +Смысл boundaries проверяется review: backend не имеет отдельного автоматического +FSD/DI architecture checker. Existing tests и build не доказывают правильный owner. diff --git a/.ai/conventions/backend-data.md b/.ai/conventions/backend-data.md new file mode 100644 index 0000000..d446ae0 --- /dev/null +++ b/.ai/conventions/backend-data.md @@ -0,0 +1,56 @@ +# Backend data + +## Ownership и выбор операции + +PrismaService — существующий shared DB provider с lifecycle приложения. +`prisma/schema.prisma` и migrations владеют persistence; `generated/prisma` +создаётся Prisma и не редактируется вручную. Конфигурация URL находится в +`prisma.config.ts`/validated environment; SQLite — текущая локальная база. + +| Ситуация | Решение | +| --- | --- | +| Один query/write конкретного use case | Existing service + PrismaService | +| Несколько записей обязаны выполниться вместе | Database transaction вокруг инварианта | +| Конкурентная смена одного значения | Atomic conditional update/constraint с проверкой результата | +| Независимые reads | Не добавляй transaction ради внешнего вида | +| Общая persistence abstraction | Только при реальной общей ответственности; generic repository для одной Prisma реализации не нужен | + +Выбирай только нужные данные, сохраняй user/account ownership в запросах и +application checks. Предварительный lookup не заменяет unique constraint при race. +Пример: AuthService обрабатывает P2002 и использует conditional `updateMany` +для refresh rotation. Сначала пойми invariant; не копируй его flow в другой use case. + +Transaction не охватывает сетевой T-Bank вызов как будто это одна atomic DB +операция. Планируй порядок и compensation по текущей задаче; не удерживай DB +lock во время retry внешней сети. Access/cache generation semantics — у +[T-Bank source](../../../docs/features/tbank-connection.md#граница-финансового-кэша). + +## Деньги и точность + +Для денежных значений используй existing decimal helpers и строковый wire value, +не JS floating-point арифметику для сумм. Currency — отдельная часть Money; +разные валюты не складываются без явно заданного conversion contract. +Источник: [Money](../../../docs/architecture/domain-glossary.md#money), +пример: [decimal.ts](../../src/tbank/decimal.ts). UI formatting не меняет +backend ownership расчётов и доменную семантику. + +## Schema и migration + +Сначала определи, какие существующие данные/consumers должны сохраниться. +Миграцию проверяй на disposable копии с representative existing data; generated +client обновляй из schema. Не переписывай уже применённую migration ради нового +состояния и не выполняй reset/drop реальной базы как шаг верификации. +Для destructive или compatibility-sensitive изменения подготовь backup/restore, +переход и проверку отката до его применения. SQLite/local MVP не означает disposable data. + +**Безопасный путь:** additive изменение, заполнение/проверка данных и только затем +удаление прежней формы, если задача этого требует. Примеры schema/migrations: +[Prisma source](../../prisma/schema.prisma); исторический rationale — +[ADR 001](../../../docs/adr/001-prisma-sqlite-local-mvp.md), не текущий список таблиц. + +## Проверка + +`npx prisma validate`; после schema change `npx prisma generate` и +`npm run typecheck:app`. Invariants/atomicity/migration safety требуют tests +на соответствующей boundary: mock Prisma не доказывает реальную transaction. +Выбор integration/e2e и известные ограничения — в [Testing](backend-testing.md). diff --git a/.ai/conventions/backend-http-api.md b/.ai/conventions/backend-http-api.md new file mode 100644 index 0000000..8c177ad --- /dev/null +++ b/.ai/conventions/backend-http-api.md @@ -0,0 +1,52 @@ +# Backend HTTP API + +## Выбор boundary + +Сначала определи, меняется wire contract или только реализация существующего +use case. Для route/request/response/status/error shape читай +[HTTP semantics](../../../docs/architecture/http-api.md) и +[общий contract workflow](../../../docs/development/runtime-openapi-verification.md). + +| Проверка | Где выполнять | +| --- | --- | +| Тип/формат/диапазон входа | Runtime DTO class с class-validator/class-transformer | +| Согласованность полей, бизнес-ограничение | Feature service/domain helper | +| Session и identity | Existing guard/strategy | +| Доступ user к конкретному account | Existing access service | +| HTTP envelope/безопасная ошибка | Общий HttpExceptionFilter | + +Controller объявляет contract и делегирует; не обращается напрямую к Prisma/gRPC +ради обхода service. Request identity берётся из verified `request.user`, не из +body/userId, предоставленного клиентом. Access rules активируют Security. + +## DTO и errors + +DTO — runtime class: TS interface не предоставляет validation metadata. +ValidationPipe уже настроен в `configureApp` (`transform`, `whitelist`). +Не обещай rejection неизвестных fields: `forbidNonWhitelisted` не включён. +Для query numbers/arrays выбирай явное преобразование и валидаторы, как в +[operations DTO](../../src/tbank/brokerage-operation.dto.ts). Swagger metadata +описывает те же required/optional/nullable/enum/range значения. + +Используй типизированные response DTO, `ApiOkResponse`/другой фактический status +и существующий `ApiProblemResponses`. При новых ошибках задай публичный stable +`code`; сообщение внутреннего exception не является UI contract. Не возвращай +raw upstream error, Prisma record с secrets или stack. Текущая форма ошибок +описана у HTTP owner; не добавляй поля RFC только потому, что они встречаются в tutorial. + +**Безопасный путь:** используй exception и общий filter, а не локальный +`res.status(...).json(...)`. Исключение — транспортная операция вроде cookie; +следуй существующему auth controller с `passthrough` и явно заданным status. + +## Пример и проверка + +[Operations controller](../../src/tbank/brokerage-operations.controller.ts) +показывает guard, user.sub, DTO query и service delegation. +Для нового field обновляй canonical source и generated artifacts в определённом +направлении; body type frontend не исправляется вручную. + +Проверь happy path и применимые invalid input/access/not-found/domain/upstream +errors на boundary, где они возникают. Unit вызов controller не запускает pipes, +guards или serialization. `npm run test:openapi-contract` проверяет schema parity, +но не поведение invalid request; выбирай соответствующий test по +[Testing](backend-testing.md). Финальный gate не заменяет semantic review ошибок. diff --git a/.ai/conventions/backend-integrations.md b/.ai/conventions/backend-integrations.md new file mode 100644 index 0000000..5b3665e --- /dev/null +++ b/.ai/conventions/backend-integrations.md @@ -0,0 +1,47 @@ +# Backend integrations + +## Выбор boundary + +T-Bank gRPC принадлежит TbankClient; MOEX metadata — MoexClient. Сервисы use case +получают нормализованный результат через эти clients. Frontend не вызывает +T-Bank и не получает credentials/proto client. Reference source — +[ADR 003](../../../docs/adr/003-tbank-server-side-grpc-boundary.md) и +[connection behavior](../../../docs/features/tbank-connection.md). + +Для нового account use case сначала используй TbankAccessService: access, +connection generation и invalid-token translation не дублируются в callers. +Чистый mapper финансового значения остаётся рядом с domain owner. + +## Retry, cache и protocol + +Existing client уже владеет bounded FIFO queue, rate limit, deadline и retry +классификацией. Новый RPC проходит тот же путь; не добавляй вложенный retry loop +в service. Не отключай TLS verification ради окружения: используй документированный +CA mechanism. Точные параметры и ограничения принадлежат +[connection configuration](../../../docs/features/tbank-connection.md#конфигурация-и-ограничения). + +При query/cache change установи key, user/account/generation ownership, +freshness и поведение late response. Старый результат не может обслужить новую +connection generation. Client Cached Snapshot frontend отличается от backend +cache/stale policy; semantics конкретного use case читай через +[feature index](../../../docs/AI_INDEX.md#features). + +Внешний auth failure и временная недоступность имеют разные public codes; +raw gRPC exception не уходит клиенту. Existing translation — в TbankTokenService +и общем HTTP boundary. Для HTTP error change читай HTTP API/Security по trigger. + +Vendor proto хранится в `src/tbank/proto/contracts`; для обновления сверяй +официальный source и влияние на loader/DTO, не редактируй read-only references. +Generated artifacts, если есть, создавай из source, без ручной подгонки вывода. + +## Безопасный путь и проверка + +Сначала добавь нужный operation в существующий client и используй его из +ответственного service. Отдельный abstraction/adapter оправдан новой +ответственностью или несовместимым protocol, не только вторым методом. + +[TbankClient tests](../../src/tbank/tbank.client.spec.ts) — пример controlled +upstream responses. Проверь queue/deadline/retry limit, token translation, +cache isolation и late response для затронутых ветвей. Fixtures синтетические; +реальная сеть, секреты и пользовательские accounts не нужны. +Logging использует [existing logger](backend-architecture.md#logging). diff --git a/.ai/conventions/backend-testing.md b/.ai/conventions/backend-testing.md new file mode 100644 index 0000000..714257d --- /dev/null +++ b/.ai/conventions/backend-testing.md @@ -0,0 +1,46 @@ +# Backend testing + +## Выбор уровня + +Применяй [общие testing risks](../../../docs/development/engineering-governance.md#risk-based-testing). +Тесты должны различать правильное и неправильное наблюдаемое поведение. + +| Что меняется | Проверка | +| --- | --- | +| Pure mapper/decimal/domain branch | Unit со значимыми edge cases | +| Service orchestration/access/retry policy | Jest с mocks внешних boundaries и observable outcome | +| Pipe/guard/cookie/status/HTTP error | Configured Nest HTTP boundary; прямого вызова метода controller недостаточно | +| OpenAPI metadata/wire schema | `test:openapi-contract` + потребительский contract check | +| DB constraint/CAS/transaction/migration | Integration с изолированной реальной DB | +| Только DTO declarations/thin wiring | Existing contract/type/build без искусственного unit test | + +Unit specs colocated в `src/**/*.spec.ts`; HTTP/integration — `test/`. +Мокируй T-Bank, время и нужную DB boundary, а не проверяемую business-функцию. +Не зови реальный внешний account/API. Expected error/code, отсутствие запроса +при недопустимом доступе и сохранение данных важнее private method call count. + +## Случаи и примеры + +- [BrokerageAccountsService tests](../../src/tbank/brokerage-accounts.service.spec.ts): отсутствие connection не вызывает upstream, нормализация и точные суммы. +- [AuthService tests](../../src/auth/auth.service.spec.ts): invalid/expired/superseded token и concurrent rotation; mock race test не является доказательством DB transaction. +- [HTTP filter tests](../../src/common/filters/http-exception.filter.spec.ts): безопасный error envelope. +- [OpenAPI integration](../../test/openapi-contract.e2e-spec.ts): configured app + frontend snapshot, без записи snapshot и без T-Bank. + +При bug сначала воспроизведи именно его исход, затем исправь responsible owner. +Не создавай tests для каждой декларации, logs строки или поведения Prisma/Nest +без собственного инварианта. Coverage не имеет общего threshold. + +## Команды и ограничения + +Итерация: `npm test -- --runInBand `, затем нужный typecheck/lint. +Полный `npm run verify` включает lint, оба typecheck, Jest и build. +`npm run test:openapi-contract` — отдельный required check при wire contract change. + +`npm run test:e2e` существует, но известный Prisma migration blocker описан в +[backend workflow](../../../docs/development/backend-workflow.md) и WL-P2-05 +[registry](../../../docs/development/audit-remediation.md). Скрипт использует +фиксированную `/tmp/wealth-ledger-e2e.db`; не запускай его конкурентно как +независимые DB tests. Для isolation выбери отдельную test DB и runner configuration. +Если задаче нужна HTTP/DB proof, установи применимость blocker и выполни доступную +изолированную проверку. Не объявляй покрытым то, что до tests не запустилось; +сохрани точный failure и оставшуюся проверку. Unit/Swagger success не заменяет e2e. diff --git a/.ai/conventions/security-auth.md b/.ai/conventions/security-auth.md new file mode 100644 index 0000000..d7a9012 --- /dev/null +++ b/.ai/conventions/security-auth.md @@ -0,0 +1,51 @@ +# Security и auth + +Читай при изменении session/token/cookie/guard, account access, encryption или +sensitive logging; обычный data query без этой границы не требует всего документа. + +## Выбор владельца + +Identity/session — AuthService + strategy/guard; cookie transport — AuthController; +account access/connection generation — TbankAccessService; token crypto — +TbankTokenService/TbankCrypto. Расширяй существующую boundary, не добавляй +второй JWT middleware, decrypt helper или refresh coordinator. + +[Authentication](../../../docs/features/authentication.md) и +[ADR 006](../../../docs/adr/006-auth-session-policy.md)/[009](../../../docs/adr/009-concurrent-refresh-rotation-policy.md) +задают session semantics. Access хранится только в памяти frontend; refresh +передаётся httpOnly cookie. Source code конфигурации cookie — +[AuthController](../../src/auth/auth.controller.ts); изменение flags/path требует +проверки browser/HTTP поведения, не только TypeScript. + +Refresh rotation атомарна: один победитель, проигравший/superseded token получает +401, но сам по себе не отзывает session победителя. Не вводи replay history/grace +или иной security contract без текущей задачи. Logout идемпотентен; in-memory +frontend session/cache очищается и при network failure. + +## Trust boundaries + +Verified JWT не доказывает доступ к accountId из URL. Используй user.sub и +existing account access policy; не доверяй userId/token из клиента как authority. +Cross-user, invalid/expired/superseded token и concurrent requests — обязательные +cases для соответствующего изменения. + +T-Bank credentials остаются server-side и хранятся encrypted. Используй +existing AES-256-GCM boundary с validated 32-byte key; не печатай plaintext, +шифротекст, cookie, Authorization или connection generation в logs/errors/API. +[Connection source](../../../docs/features/tbank-connection.md) определяет +cache invalidation при замене/deletion и ограничение key rotation. + +Не передавай Prisma User/Session целиком наружу; выбирай public DTO. Пароль +обрабатывает существующий bcrypt flow. Не копируй требования о нормализации +или длине из tutorial: сверяй runtime DTO, tests и feature source. + +## Безопасный путь и проверка + +При неясной ownership/crypto/session семантике прочитай exact source до edits. +Добавляй проверку на ответственной границе; не скрывай проблему общим catch, +фиктивным success или log. Logger allowlist/redaction не делает произвольный +message безопасным. + +Targeted auth/access/crypto/logging tests + [Testing](backend-testing.md). +Cookie/guard/HTTP changes требуют configured HTTP proof; frontend Bearer/retry +проверяется MSW. Schema parity не доказывает отсутствие утечки secret. diff --git a/AGENTS.md b/AGENTS.md index 5d7950d..2addf59 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,37 +1,23 @@ # Backend -## Назначение и authority +NestJS API; общие правила работы — в root `AGENTS.md`. +До backend-решения прочитай [router](.ai/CONVENTIONS.md) и +[sources](.ai/SOURCES.md), затем только применимые документы/разделы. -NestJS API WealthLedger владеет доменной логикой, данными, конфигурацией и -server-side интеграциями. Workspace layout и reference policy — в root -`AGENTS.md`. Для planning, implementation, validation и завершения читай -[canonical lifecycle](../docs/development/openspec-authority-and-lifecycle.md); -для recovery и выбора relevant evidence — -[context discipline](../docs/development/agent-token-efficiency.md). -Они доступны без optional agent skills или commands. +## Проверка -Для устойчивых backend decisions читать [`../docs/adr/README.md`](../docs/adr/README.md). +Перед Node-командами: `nvm use --silent` по `.nvmrc`. +После lockfile install `npm ci` полный gate — `npm run verify`: +zero-warning ESLint, application/test TypeScript, Jest и build. +`lint:fix`/`format` пишут файлы и запускаются отдельно от доказательства проверки. +`test:cov` — диагностика без общего threshold; scripts принадлежат `package.json`. -## Canonical gate +HTTP contract changes дополнительно проходят общий +[contract workflow](../docs/development/runtime-openapi-verification.md). +Общий e2e имеет известный environment blocker; применимость и маршрут проверки +описаны в [backend testing](.ai/conventions/backend-testing.md). +Generated Prisma client не редактируется вручную. Credentials, авторизация +доступа к счетам и внешние интеграции остаются server-side. -Перед Node-командами активировать `.nvmrc` через `nvm use --silent`; это выбирает -Node 22. Не запускать отдельную проверку версии, кроме диагностики runtime issue. -После lockfile install единственный completion gate: - -```bash -npm ci -npm run verify -``` - -Gate non-mutating и последовательно проверяет ESLint, application/test TypeScript, risk-based Jest suite и build. `npm run lint:fix` и `npm run format` изменяют files и выполняются только явно; `npm run test:cov` — диагностика без общего threshold. `npm run test:e2e` не входит в passing gate до WL-P2-05 trigger из remediation registry. `npm run test:openapi-contract` — отдельный contract gate для изменений обеих сторон API contract. -Актуальные scripts проверять в `package.json`/`npm run`. - -## Enforceable boundaries - -- Style задают `eslint.config.mjs` и TypeScript configs; zero-warning lint и оба typecheck обязательны. -- Публичный HTTP API версионируется как `/api/v1`; generated backend OpenAPI — contract authority для frontend snapshot. -- Frontend не вызывает T-Bank напрямую; credentials, rate limiting и integration resilience остаются server-side. -- Не размещать frontend code, generated client или durable documentation в backend. -- Security, money, data integrity, concurrency, public contracts, critical journeys и regressions требуют risk-based tests. DTO, declarative config и thin scripts не требуют отдельного unit test без собственной logic. - -Непроверяемые предпочтения являются guidance и не заменяют canonical gate. +ESLint/TypeScript не доказывают правильность domain boundaries, security или +денежных вычислений: для них нужны semantic review и risk-based tests. diff --git a/README.md b/README.md index 5fc4467..b805faa 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ NestJS API WealthLedger. Backend владеет auth, SQLite-данными и s ```bash cp .env.example .env +nvm use --silent npm ci npm run start:dev ``` @@ -27,7 +28,7 @@ T-Bank token в `.env`: он вводится пользователем и хр npm run verify ``` -Он сначала отклоняет runtime вне Node 22, затем запускает hygiene, lint, +Он запускает zero-warning lint, application/test typechecks, Jest и build. `npm run lint:fix` — отдельная записывающая команда, `npm run test:cov` — диагностика без общего числового threshold. `npm run test:e2e` пока не является passing gate: Prisma schema @@ -36,19 +37,25 @@ engine останавливает migration до запуска Jest. Точны ## Документация +- [Router conventions](.ai/CONVENTIONS.md) и [источники](.ai/SOURCES.md) +- [Backend architecture](.ai/conventions/backend-architecture.md) +- [HTTP API](.ai/conventions/backend-http-api.md), [data](.ai/conventions/backend-data.md) и [testing](.ai/conventions/backend-testing.md) +- [Security/auth](.ai/conventions/security-auth.md) и [integrations](.ai/conventions/backend-integrations.md) + - [Backend workflow](../docs/development/backend-workflow.md) - [Engineering governance и risk-based testing](../docs/development/engineering-governance.md) -- [OpenSpec authority и lifecycle](../docs/development/openspec-authority-and-lifecycle.md) +- [Карта проектных фактов](../docs/AI_INDEX.md) - [API contract и runtime OpenAPI](../docs/development/runtime-openapi-verification.md) - [Обзор поставленной системы](../docs/architecture/system-overview.md) - [Архитектурные решения](../docs/adr/README.md) - [Remediation registry](../docs/development/audit-remediation.md) -Из workspace runtime OpenAPI можно read-only сверить с frontend snapshot: +Из backend runtime OpenAPI можно read-only сверить с frontend snapshot: ```bash npm run test:openapi-contract ``` -Полный multi-repository change проверяется из workspace через -native OpenSpec validation and the canonical gates of each affected repository. +Разработка идёт напрямую по задаче пользователя. Каждый affected repo проходит +свой verify; при изменении wire contract дополнительно выполняется contract check. +Обязательного OpenSpec/SDD lifecycle нет.