Files
docs/audits/2026-08-frontend-repository-audits/frontend-repository-audit-2026-08-28.md
T

19 KiB
Raw Blame History

Repository Audit — frontend

Дата аудита: 2026-08-28. Аудит выполнен только для чтения; этот файл — единственная запись, созданная в рамках работы. Эталонный каталог использовался как ориентир, а не как источник достоверной информации.

Scope and Confidence

Целевой репозиторий: /Users/ksv741/Project/vibe/WealthLedger/frontend
Эталон: /Users/ksv741/Project/vibe/WealthLedger/references/frontend-ai-template

Цель — React 19 / TypeScript / Vite SPA WealthLedger с typed OpenAPI-клиентом, TanStack Query и FSD-направлением зависимостей. Проверены AGENTS.md, README, локальные docs, package и lock-конфигурация, hooks, Biome, dependency-cruiser, Knip, Vitest/Vite/TypeScript-конфигурация, основной app/auth/API путь, entity query hooks, финансовые страницы, настройки T-Bank connection и их тесты. В эталоне проверены эквивалентные scripts, hook, OpenAPI guardrail, тестовая/документационная структура и representative source tree.

Исходное и финальное состояние target: ветка main без tracked или untracked изменений; git diff и staged diff пусты. Эталон — read-only каталог без собственного Git-репозитория, поэтому его рабочее состояние не верифицировалось.

Запущены только заведомо read-only проверки:

  • npm run lint — прошло; Biome проверил 128 файлов, без исправлений.
  • npm run knip — прошло.
  • npm run deps — прошло; dependency-cruiser проверил 136 модулей и 484 зависимости, нарушений нет.

В audit-terminal команда nvm use --silent недоступна, поэтому Node 22 через .nvmrc не был активирован этой оболочкой; version mismatch не диагностировался. Не запускались npm ci, verify, build, coverage-тесты, typecheck и генерация OpenAPI: они могут создавать или обновлять install, coverage, dist, tsbuildinfo либо generated artifacts. Реальный backend, browser E2E и runtime OpenAPI contract также не запускались. Эти ограничения снижают уверенность только в runtime-свойствах, не в трёх статических findings ниже.

Сравнение с эталоном

Эквивалентная обязанность Вердикт Причина
Контроль синхронности OpenAPI source и generated types adopt from reference В эталоне есть небольшой temp-file check, включённый в verify и pre-commit; target хранит такие же два артефакта, но не имеет проверки.
Coverage anti-regression target is already better Target задаёт явные coverage thresholds в Vitest; в эталонной конфигурации их нет.
Storybook, Playwright, browser MSW и mock development mode reference approach is unnecessary Эталон — демонстрационный SPA-шаблон. Target AGENTS.md прямо запрещает эти добавления без approved change, а проверенный scope не показал конкретной проблемы, которую оправдывает весь этот lifecycle.

Executive Summary

Репозиторий находится в хорошем состоянии по типизации, зависимостям, локальному quality gate и навигации для агента. Biome, Knip и dependency-cruiser проходят, а auth, query retry, error states и display-logic имеют целевые тесты.

Два высокоприоритетных пробела делают эту базу менее надёжной, чем обещают её инварианты:

  1. Смена или удаление T-Bank connection оставляет connection-scoped финансовые данные в React Query cache.
  2. Committed OpenAPI snapshot и generated types могут разойтись, а verify всё равно остаться зелёным.

Отдельно, обязательная VM/view и state-view конвенция уже расходится с несколькими production screens. Это создаёт агентам и разработчикам два конкурирующих образца вместо одного канонического.

Priority Findings

Severity Finding Category Action Effort
high F1 — Нет единого invalidation boundary для данных T-Bank connection Architecture / Data correctness change medium
high F2 — Generated OpenAPI type artifact не проверяется на синхронность Tooling / Contract safety add small
medium F3 — Обязательная VM/view конвенция расходится с production code Architecture / AI Readiness change medium

Findings

F1 — Нет единого invalidation boundary для данных T-Bank connection

Category: Architecture / Data correctness
Severity: high
Confidence: high
Action: change
Effort: medium

Observed: Успешные PUT и DELETE T-Bank connection обновляют status и инвалидируют только query списка brokerage accounts. Portfolio, operations, future events, income summary и income analytics продолжают жить в cache по accountId.

Evidence: src/features/tbank-connection/ui/TbankConnectionSection.tsx:60-79 вызывает invalidateQueries только с brokerageAccountsQueryKey. Все перечисленные data hooks создают самостоятельные account-scoped query keys и оставляют данные видимыми: src/entities/portfolio/api/usePortfolio.ts:12-21, src/entities/broker-operation/api/useBrokerageOperations.ts:35-49, src/entities/brokerage-event/api/useBrokerageEvents.ts:9-19, src/entities/income/api/useIncome.ts:9-41. UI pattern намеренно оставляет Client Cached Snapshot на экране во время background refresh; для замены либо удаления source connection это старое состояние уже не является допустимым snapshot. Тесты settings-сценария проверяют только invalidation account-list: src/features/tbank-connection/ui/TbankConnectionSection.test.tsx:52-98.

Counter-evidence: Logout и неуспешный refresh очищают весь QueryClient в src/features/auth/model/auth.tsx:57-62, а account-list действительно инвалидируется при смене connection. Эта защита не срабатывает, когда пользователь остаётся в той же authenticated session и только заменяет или удаляет connection.

Why it matters: После замены token или отключения connection пользователь может увидеть cache старого portfolio, ledger, events либо income до следующего рефетча. Для финансовых данных это ошибочная принадлежность данных к уже изменившемуся upstream connection; на активном экране она особенно заметна, потому что UI специально отображает cached result при обновлении.

Reference repository: Нет эквивалентного authenticated external-connection domain в todo-template; сравнение неприменимо.

Recommended direction: Ввести один явно названный ownership boundary для всех данных, производных от T-Bank connection, и при replace/delete очищать либо корректно инвалидировать весь этот scope, а не только список счетов. Предпочтение следует отдать удалению snapshot, который больше нельзя показывать. Добавить один интеграционный тест, seed-ящий representative query каждого класса и подтверждающий, что после обоих mutation paths эти данные недоступны для рендера.

F2 — Generated OpenAPI type artifact не проверяется на синхронность

Category: Tooling / Contract safety
Severity: high
Confidence: high
Action: add
Effort: small

Observed: Target хранит committed OpenAPI snapshot и committed generated schema.d.ts, но package scripts и pre-commit не имеют команды, которая пересоздаёт schema во временном месте и сравнивает результат. Поэтому source snapshot можно изменить без regeneration, а TypeScript продолжит проверять устаревший generated contract.

Evidence: package.json:9-25 содержит openapi:generate, но не openapi:check; verify на строке 20 его не вызывает. .husky/pre-commit:1-2 запускает только lint-staged и deps. При этом AGENTS.md:42 утверждает, что openapi:check есть в verify и pre-commit, а docs/CONVENTIONS.md:12-14 называет OpenAPI check обязательным pre-commit step. Поиск по target не нашёл openapi:check. docs/API-LAYER.md:1-5 подтверждает, что snapshot и generated types должны быть committed и обновляться отдельно.

Counter-evidence: Документация предписывает ручной порядок «скопировать snapshot → сгенерировать types», а backend располагает отдельной runtime contract-проверкой. Ни один из этих механизмов не делает локальный frontend gate самодостаточным: ошибка ручной regeneration остаётся незамеченной до более поздней стадии.

Why it matters: Зелёный verify может закрепить stale request/response types после изменения backend contract. Это подрывает заявленную compile-time безопасность API и способно привести к неверно сформированному запросу либо к коду, опирающемуся на устаревшую response shape.

Reference repository: adopt from reference. references/frontend-ai-template/scripts/check-openapi.mjs:1-32 генерирует во временный файл и байтово сравнивает его с committed schema; package.json:13-28 и .husky/pre-commit:1 включают проверку в verify и hook. Это небольшой fitting guardrail, не требующий нового dependency или runtime backend.

Recommended direction: Добавить target-specific offline check для openapi.json → schema.d.ts, подключить его к verify и pre-commit, затем исправить AGENTS.md/README/conventions так, чтобы они описывали фактический gate. Не включать backend fetch или автоматическую генерацию в verify: gate должен оставаться детерминированным и read-only относительно tracked artifacts.

F3 — Обязательная VM/view конвенция расходится с production code

Category: Architecture / AI Readiness
Severity: medium
Confidence: high
Action: change
Effort: medium

Observed: Документация требует, чтобы data-driven finance page была container → VM → view, а top-level states/sections находились в отдельных files. Несколько текущих screens демонстрируют обратное: AccountEventsPage одновременно читает route params, вызывает query hook и объявляет Loading/Error/Empty/Loaded components в одном file; AccountPage и AccountsPage держат четыре top-level state components в одном .view.tsx; AccountIncomePage держит три.

Evidence: docs/CONVENTIONS.md:12-14 и AGENTS.md:36 описывают правило как обязательное; docs/UI-PATTERN.md описывает владение data/state VM и отдельные state views. Прямой контрпример — src/pages/account-events/ui/AccountEventsPage.tsx:1-116. Остальные representative deviations: src/pages/account/ui/AccountPage.view.tsx:54-147, src/pages/accounts/ui/AccountsPage.view.tsx:42-124 и src/pages/account-income/ui/AccountIncomePage.view.tsx:29-52. Для contrast src/pages/account-operations/ui уже использует VM и отдельные component state views. Lint и dependency check проходят, поскольку правило не имеет machine enforcement.

Counter-evidence: FSD direction, public APIs и circular imports успешно проверяются dependency-cruiser; большинство finance data derivation действительно вынесено в VM. Это ограничивает scope finding до понятности и consistency page-level pattern, а не до общей архитектурной целостности.

Why it matters: Новый агент получает обязательную инструкцию, которую production tree нарушает в нескольких наиболее заметных screens. Это увеличивает navigation cost и делает review субъективным: один и тот же UI change можно «правильно» продолжить по двум несовместимым образцам.

Reference repository: both are acceptable в части принципа, но более мелкая per-state организация эталона подтверждает полезность разделения там, где data/state branches уже самостоятельны. Переносить его Storybook/e2e scaffolding или создавать новый page framework не требуется.

Recommended direction: Выбрать один честный canonical pattern: привести существующие named pages к заявленной VM/state-view границе там, где branches самостоятельны, либо сузить документацию, прямо разрешив компактные colocated views для небольших screens. После выбора оставить FSD проверки как есть; новый dependency или тяжёлый linter ради одного file-layout правила не оправдан.

Missing Practices

  • F1: отсутствует connection-scoped cache ownership и test, проверяющий его очистку при trust-boundary change.
  • F2: отсутствует детерминированная offline-проверка committed OpenAPI source и generated type artifact.

Over-engineering / Simplification Opportunities

Материальной production over-engineering проблемы не найдено. Компоненты LoadingSkeleton и StateView повторно используют доступные state regions; query/auth seams обслуживают реальные trust и concurrency requirements. Самая выгодная simplification — не добавлять параллельные способы описания page architecture: закрыть F3 одним каноническим соглашением.

AI Readiness

Оценка: хорошая, с одним существенным navigation risk. AGENTS.md кратко направляет к специализированной документации, scripts узнаваемы, FSD-boundary gate и generated-code exclusion ясны. F2 делает API change небезопасным несмотря на эти подсказки, а F3 заставляет агент выбирать между текстовыми правилами и существующим кодом. Устранение этих двух findings улучшит predictability без расширения toolchain.

What Is Already Good

  • Строгая TypeScript-конфигурация, exact dependency versions, package-lock, Biome, Husky/commitlint и Node 22 intent хорошо определяют baseline.
  • Dependency-cruiser проверяет FSD direction, отсутствие circular imports и public slice API; текущий graph проходит (136 modules, 484 dependencies).
  • API transport отделён в shared typed client, auth request исключены из Bearer attachment, refresh имеет single-flight путь и tests на retry/failure.
  • Query hooks задают явные staleTime и retry policy; UI/tests покрывают cached snapshot, refresh error, route boundary, portfolio display и operation filtering.
  • Target coverage thresholds — более практичный anti-regression guard, чем эталонный template без порогов.

Do now

  1. Закрыть F1: сделать T-Bank connection change полноценной границей очистки data cache и добавить regression test.
  2. Закрыть F2: добавить offline OpenAPI synchronization check в verify/pre-commit, затем синхронизировать документацию.

Do next

  1. Закрыть F3: согласовать page-level VM/state-view rule с production tree и обновить только выбранный source of truth.

Consider later

Переоценить browser-level critical journeys только при approved change, который меняет соответствующий пользовательский риск; текущая статическая evidence не оправдывает широкий test-stack перенос из template.

Do not add

  • Storybook, Playwright, browser MSW worker или mock development mode только потому, что они есть в эталоне.
  • CI/CD, deployment tooling или cloud configuration: system scope остаётся локальным.
  • Ещё один FSD/framework linter для VM/view file layout: сначала нужно устранить противоречие F3, а текущий dependency-cruiser уже покрывает доказанные dependency risks.