Files
main/.ai/migrations/conventions-v1/audit.md
T
ksv741 4a78dd640d
Workspace security / security (pull_request) Successful in 6s
Workspace verify / verify (pull_request) Successful in 20s
Conventional commits / commits (pull_request) Successful in 10s
Workspace security / security (push) Successful in 5s
Workspace verify / verify (push) Successful in 19s
docs: align inventory with simplified conventions
2026-09-15 05:58:30 +03:00

178 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Conventions v1: semantic audit
Дата: 2026-09-15. Read-only audit production code; conventions изменены отдельно.
Snapshot: root `2567a755569e6ef6ba12063b62f202fe52884ce7`, frontend
`0244acf429c525b23117f165bbe52ef5403eefd3`, backend
`660b250ecd05e38784690b9a9adb381764c0ca7c`. На старте worktrees чистые.
## Scope и метод
Прочитаны existing AGENTS/.ai, manifests, TypeScript/Biome/ESLint, dependency
rules, test/Storybook setup и OpenAPI flow. Проверены representative paths:
auth/refresh, bank cards/operations/summary, portfolio/income page VM, account
errors, instrument search и T-Bank/MOEX/NCR boundaries. `rg` использован для
callers, HTTP/Prisma/domain imports, raw fetch/SQL, logging, error strings и
state patterns. Точечная executable reproduction проверяет ValidationPipe → filter.
Это reviewed inventory подтверждённых findings, не полный автоматический
счётчик всех файлов. P0 — явное архитектурное нарушение / высокий риск;
P1 — неверная ответственность / существенная inconsistency;
P2 — cleanup / naming / менее важная consistency issue.
Confidence: High / Medium / Low. P0 по проверенной области не выявлены;
это не security certification.
| Severity | Findings |
| --- | --- |
| P0 | 0 |
| P1 | 4 |
| P2 | 3 |
## BE-001 — Validation теряет ошибки полей
- **Location:** [configureApp](../../../backend/src/main.ts), строка 28;
[HttpExceptionFilter](../../../backend/src/common/filters/http-exception.filter.ts),
`catch` / `validationErrors`.
- **Convention:** [Errors](../../../backend/.ai/conventions/error-handling.md),
[требование](../../../specs/openspec/specs/user-authentication/spec.md#requirement-стандартные-ответы-об-ошибках).
- **Current state:** стандартный ValidationPipe формирует `message: string[]`;
filter трактует его как `ValidationError[]`, возвращая пустой `errors`.
- **Expected state:** invalid request → 400 / VALIDATION_ERROR с применимыми
`{ pointer, detail }`; вложенные поля обрабатываются согласно контракту.
- **Severity:** P1. **Confidence:** High.
- **Reason:** публичный контракт теряет field details; типовой filter unit test
и OpenAPI schema parity не проходят реальную validation pipeline.
- **Suggested migration:** отдельный behavior fix в Auth/API validation slice:
согласовать output pipe с filter; доказать через configured HTTP request.
Не добавлять новый validation framework.
## BE-002 — Repository решает business eligibility и HTTP outcome
- **Location:** [BankCardsRepository](../../../backend/src/modules/banking/bank-cards/infrastructure/bank-cards.repository.ts),
`card(active)` и `write`; callers в
[BankOperationsService](../../../backend/src/modules/banking/bank-cards/application/bank-operations.service.ts).
- **Convention:** [Data](../../../backend/.ai/conventions/data.md),
[application boundaries](../../../backend/.ai/architecture.md#ответственность-и-направление-зависимостей).
- **Current state:** repository импортирует application `conflict/missing`,
решает запрет archived card и переводит общий P2002 в DuplicateCategory.
- **Expected state:** repository владеет owner-filtered reads, transaction/retry
и техническим DB outcome; application/domain определяет eligibility/public error.
- **Severity:** P1. **Confidence:** High.
- **Reason:** storage helper знает business policy нескольких callers;
P2002 не всегда означает duplicate category. Утечка доступа не утверждается.
- **Suggested migration:** Cards/Operations slice: перенести policy и mapping
к ответственным сценариям, сохранив lookup/check/write внутри той же transaction,
retry budget, idempotency, CAS и действующие public codes.
## FE-001 — Самостоятельные банковские действия находятся в entity UI
- **Location:** [BankCardForm](../../../frontend/src/entities/bank-card/ui/BankCardForm.tsx),
[CategoryManager](../../../frontend/src/entities/bank-card/ui/CategoryManager.tsx);
consumers — CardsPage и CardPage.
- **Convention:** [FSD ownership](../../../frontend/.ai/architecture.md#выбор-владельца).
- **Current state:** entity UI координирует создание/редактирование карты,
idempotency intent, submit, version adoption, создание/редактирование категорий.
- **Expected state:** самостоятельные пользовательские workflows имеют feature
owner; entity сохраняет модели, queries и presentation понятия карты/категории.
- **Severity:** P1. **Confidence:** High.
- **Reason:** это полноценные reused capabilities с собственным lifecycle,
а не вывод о слое из наличия одной кнопки или mutation.
- **Suggested migration:** по одному действию в Cards slice; presentation fields
сохранять/reuse, не перемещать всю entity и все её hooks механически.
## FE-002 — Views банковских страниц владеют query state selection
- **Location:** [CardPage.view](../../../frontend/src/pages/card/ui/CardPage.view.tsx),
[CardsPage.view](../../../frontend/src/pages/cards/ui/CardsPage.view.tsx),
соответствующие `CardPage.vm.ts` / `CardsPage.vm.ts` рядом.
- **Convention:** [Container/VM/view](../../../frontend/.ai/conventions/ui.md#container-vm-и-view).
- **Current state:** VM отдаёт query objects; views выбирают initial/cached/error
states через `data/isLoading/isError/isPlaceholderData` и вызывают `refetch`.
- **Expected state:** VM выбирает presentation states и retry callbacks,
views отображают данные/действия. DOM scroll/focus остаются UI responsibility.
- **Severity:** P1. **Confidence:** High.
- **Reason:** presentation зависит от query lifecycle и принимает решения,
которые existing account-income pattern уже размещает в VM.
- **Suggested migration:** Cards slice, сначала один экран: перенести state
selection без изменения loading/cached/recovery, URL pagination и scroll anchor.
Не строить generic state machine для всех страниц.
## FE-003 — Application navigation находится в shared UI
- **Location:** [AppShell](../../../frontend/src/shared/ui/AppShell.tsx),
`items`, `useLocation`, `Outlet`, nav rendering; public export в shared/ui.
- **Convention:** [FSD и устройство](../../../frontend/.ai/architecture.md).
- **Current state:** shared owner содержит конкретные `/accounts`, `/cards`,
`/stocks`, `/bonds`, `/settings` и application navigation.
- **Expected state:** navigation/composition принадлежит app; shared сохраняет
только действительно общие presentation primitives при текущей потребности.
- **Severity:** P2. **Confidence:** High.
- **Reason:** известное legacy placement уже отмечалось старым convention;
dependency graph не доказывает отсутствие business meaning в shared.
- **Suggested migration:** отдельный navigation slice вместе с app callers и CSS,
без новой оболочки над Mantine и без переразметки пользовательского UI.
## FE-004 — Connection recovery классифицируется повторно
- **Location:** [AccountPageError](../../../frontend/src/pages/account/ui/components/AccountPageError.view.tsx),
[AccountsPageError](../../../frontend/src/pages/accounts/ui/components/AccountsPageError.view.tsx),
[StocksPage.view](../../../frontend/src/pages/stocks/ui/StocksPage.view.tsx),
[BondsPage.view](../../../frontend/src/pages/bonds/ui/BondsPage.view.tsx).
- **Convention:** [Frontend errors](../../../frontend/.ai/conventions/data.md#errors),
[pattern convergence](../../conventions/code-health.md#search--reuse--converge).
- **Current state:** несколько owners повторяют `TBANK_NOT_CONNECTED` /
`INVALID_TBANK_TOKEN` comparisons; presentation/retry actions различаются.
- **Expected state:** общая классификация принадлежит одному допустимому owner,
локальный текст/actions остаются у сценария; unknown code сохраняет fallback.
- **Severity:** P2. **Confidence:** High.
- **Reason:** повторяется техническое decision rule. Различный UI сам по себе
не нарушение; generated `code: string` не разрешает выдумывать закрытый enum.
- **Suggested migration:** Accounts/Portfolio, затем Instruments/Settings:
унифицировать только classification с сохранением всех текущих recovery paths.
## BE-003 — Invalid-token protocol основан на Error.message
- **Location:** [TbankClient](../../../backend/src/integrations/tbank/tbank.client.ts),
`call` (throw Error); [TbankTokenService](../../../backend/src/integrations/tbank/tbank-token.service.ts),
`translateInvalidToken`; [InstrumentMetadataService](../../../backend/src/integrations/tbank/instrument-metadata.service.ts),
invalid-token catch.
- **Convention:** [Errors](../../../backend/.ai/conventions/error-handling.md),
[Integrations](../../../backend/.ai/conventions/integrations.md).
- **Current state:** low-level client бросает `Error('INVALID_TBANK_TOKEN')`,
два consumers сравнивают строку сообщения для выбора recovery/HTTP mapping.
- **Expected state:** один явный local typed/code outcome на integration boundary,
public HTTP translation остаётся у существующего owner.
- **Severity:** P2. **Confidence:** High.
- **Reason:** изменение диагностического текста ломает machine behavior;
raw provider exception сейчас уже скрыт, подтверждённой утечки нет.
- **Suggested migration:** Instruments/Settings integration slice; заменить
marker и всех consumers одной связной правкой, сохранив auth/unavailable
distinction и wire codes. Общий enterprise error framework не нужен.
## Что не признано нарушением
- Page-local components account/income/events и их flat views допустимы.
Размер файла, `map` или handler сами по себе не определяют feature/entity.
- Прямые Prisma queries связных auth/banking/connection services допускаются
existing data convention; standalone use cases уже используют repository.
- URL-applied values и editable draft dates — разные состояния; синхронизация
draft после navigation не равна лишнему server-state cache.
- Повторы `filter(Boolean).join(" · ")` формируют display metadata, а не CSS
classes; это не основание устанавливать `clsx`.
- `ProblemDetailsDto.code: string` и typed wire literals — ограничение принятого
генератора, не основание создавать ручную копию backend enum.
- Stories показывают synthetic presentation; отсутствие story/test у каждого
component не считается finding. По выполненным поискам не найдены raw fetch
вне shared/api, production console или raw SQL; это не доказательство полноты.
## Evidence BE-001
Из backend после `nvm use --silent`: одноразовый `node -r ts-node/register`
загрузил actual CredentialsDto, ValidationPipe и HttpExceptionFilter.
Input `{ email: 'bad', password: 'x' }` → exception `message: string[]` →
`{ status: 400, code: 'VALIDATION_ERROR', errors: [] }` (assert PASS).
DB/порты/внешняя сеть не использовались. Это proof пары pipe/filter;
исправление всё равно требует configured HTTP regression test.
Immutable baseline этого анализа; статусы закрытия и evidence будущих работ
вести в [plan](plan.md), не переписывая snapshot под новый код.