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

13 KiB
Raw Blame History

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, строка 28; HttpExceptionFilter, catch / validationErrors.
  • Convention: Errors, требование.
  • 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, card(active) и write; callers в BankOperationsService.
  • Convention: Data, application boundaries.
  • 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, CategoryManager; consumers — CardsPage и CardPage.
  • Convention: FSD ownership.
  • 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, CardsPage.view, соответствующие CardPage.vm.ts / CardsPage.vm.ts рядом.
  • Convention: 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, items, useLocation, Outlet, nav rendering; public export в shared/ui.
  • Convention: FSD и устройство.
  • 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, AccountsPageError, StocksPage.view, BondsPage.view.
  • Convention: Frontend errors, pattern convergence.
  • 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, call (throw Error); TbankTokenService, translateInvalidToken; InstrumentMetadataService, invalid-token catch.
  • Convention: Errors, Integrations.
  • 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, не переписывая snapshot под новый код.