Files
docs/audits/audit-13-08-2026.md
T
2026-08-24 10:33:29 +03:00

26 KiB
Raw Blame History

Аудит качества WealthLedger

Дата: 2026-08-13
Обновление: 2026-08-14 — повторная проверка находок после доработок align-frontend-foundation и align-frontend-ui-patterns. Статус каждой находки помечен: [done] закрыто, [partial] частично, [open] не тронуто.

Статус: снимок текущей рабочей копии; исправления и OpenSpec-артефакты не создавались.

Цель и охват

Проведён тщательный аудит frontend, backend, specs, docs, корневых файлов координации и .opencode. Папка references/ исключена. Оценивались качество кода, архитектура, безопасность, обработка ошибок, целостность данных, производительность, accessibility, качество сценариев тестирования, документация, OpenSpec и артефакты для AI-агентов.

Текущая рабочая копия является источником фактов. История Git использовалась только для контекста жизненного цикла OpenSpec. Проценты и пороги test coverage намеренно не оценивались.

Методика и ограничения

Аудит сопоставляет локальные правила из AGENTS.md, OpenSpec, feature docs, ADR и фактический код. Проверялись критичные цепочки: регистрация и сессии, transport API, подключение T-Bank, счета и портфель, а также путь «спецификация -> реализация -> документация -> инструкция агенту».

Ограничения:

  • Не проводились нагрузочные тесты, анализ production-конфигурации, live-проверки T-Bank, TLS/proxy и multi-instance развёртывания.
  • references/ не анализировалась.
  • В specs присутствуют staged additions/deletions артефактов двух изменений; это нестабильное состояние рабочей копии, а не подтверждённый стабильный релиз.
  • Команда opsx отсутствует в среде, поэтому обязательная lifecycle-проверка opsx-verify не была выполнена.

Карта зрелости

Область Оценка Основание
Код backend Требует приоритетных исправлений Сильные криптография и денежная арифметика, но есть риски ротации и отзыва сессий.
Код frontend Удовлетворительно Типизированный API и UI-состояния устойчивы; A-11/A-12 закрыты, но остаётся production fallback (A-03).
Тестовые сценарии Требует усиления Frontend покрыт (transport + UI resilience); backend concurrent E2E отсутствует.
Документация Требует исправлений Feature docs полезны, но часть устарела; architecture/development пока заглушки.
OpenSpec Удовлетворительно с риском процесса Основные спецификации качественные и валидны, но lifecycle и traceability между репозиториями недостаточны.
Артефакты для AI-агентов Удовлетворительно с риском процесса Границы репозиториев заданы хорошо, но OpenSpec context и multi-repo verification не формализованы.

Приоритетный backlog

Приоритет ID Область Владелец Краткое действие Статус Зависимости
High A-01 Безопасность сессий backend Сделать refresh rotation атомарной. open Prisma conditional update/transaction.
High A-02 Отзыв сессий backend Проверять активность sid либо документировать ограниченную модель отзыва access token. open Решение о DB lookup/cache в guard.
High A-03 Production transport frontend Убрать fallback на localhost для production; использовать явный origin или same-origin /api. open Контракт reverse proxy и env.
High A-04 Документация T-Bank docs Исправить устаревшее ограничение про счета и портфели. open Нет.
High A-05 OpenSpec lifecycle specs Атомарно завершить архивирование либо восстановить активные артефакты. partial Подтверждение намеренного lifecycle.
High A-06 Операционная документация docs Добавить архитектурную карту и workflow разработки/верификации. partial Подтверждение команд и границ от frontend/backend.
Medium A-07 Регистрация backend Преобразовать unique-constraint race в EMAIL_ALREADY_REGISTERED. open Prisma error type/code.
Medium A-08 API errors backend Исправить сериализацию validation errors. open Нет.
Medium A-09 Сессии и cache backend Ввести retention/index для sessions и bounded TTL/LRU cache для portfolio metadata. open Политика retention и лимиты.
Medium A-10 Большие портфели backend Ограничить параллелизм получения metadata ниже лимита очереди клиента. open Целевой latency limit.
Medium A-11 Auth transport frontend Синхронизировать восстановленный token с accessTokenRef. done Нет.
Medium A-12 FSD frontend Перевести внешние импорты слайсов на public API. done Нет.
Medium A-13 Тестовые сценарии frontend/backend Добавить конкурентные auth E2E и behavior-тесты T-Bank UI. partial A-01, A-07; React Query test wrapper.
Medium A-14 ADR и OpenSpec context docs/specs/root Актуализировать ADR, заполнить OpenSpec context и multi-repo evidence. open Согласование общей политики.

Находки

High

A-01. Ротация refresh token не атомарна — [open]

  • Доказательство: backend/src/auth/auth.service.ts:75-96,148-166 выполняет read/verify/update в отдельных действиях.
  • Обновление 2026-08-14: код не менялся; риск сохраняется.
  • Риск: два параллельных запроса с одним cookie могут оба пройти проверку и получить access token; итоговый hash зависит от последней записи.
  • Минимальное действие: обновлять с условием по id, refreshTokenHash, активности и сроку жизни; считать нулевое число обновлений отказом.
  • Владелец: backend. Зависимости: Prisma conditional update/transaction.

A-02. Отзыв сессии не прекращает действие уже выданного access JWT — [open]

  • Доказательство: backend/src/auth/jwt.strategy.ts:19-23, backend/src/auth/jwt-auth.guard.ts:4-5, backend/src/auth/auth.service.ts:89-94,114-117 проверяют подпись, срок и тип token, но не состояние sid.
  • Обновление 2026-08-14: backend не менялся; риск сохраняется.
  • Минимальное действие: проверять активный неистёкший sid в guard/strategy либо явно принять и документировать bounded-revocation модель.
  • Владелец: backend. Зависимости: решение о lookup/cache.

A-03. Production fallback направляет bearer token на localhost пользователя — [open]

  • Доказательство: frontend/src/shared/api/config.ts:1-2 использует http://localhost:3000 при отсутствии build-time URL; frontend/src/shared/api/client.ts:54-57 направляет туда bearer-authenticated requests.
  • Обновление 2026-08-14: fallback ?? "http://localhost:3000" перенесён в frontend/src/shared/api/client.ts:6; риск сохраняется.
  • Минимальное действие: требовать явный production API origin либо использовать same-origin /api; завершать build/start при отсутствии допустимой настройки.
  • Владелец: frontend. Зависимости: env и reverse-proxy contract.

A-04. Документация T-Bank противоречит реализованным функциям — [open]

  • Доказательство: docs/features/tbank-connection.md:38-40 откладывает счета и портфели, но docs/features/brokerage-accounts.md:1-55 и docs/features/portfolio-view.md:1-59 описывают их как поставленные.
  • Обновление 2026-08-14: не исправлено.
  • Минимальное действие: оставить в limitations только реально отложенные возможности.
  • Владелец: docs. Зависимости: нет.

A-05. Активные OpenSpec changes находятся в неполном переходном состоянии — [partial]

  • Доказательство: git status в specs показывает staged additions/deletions design.md, delta-spec и tasks.md для add-brokerage-accounts и add-portfolio-view; правила требуют полный набор в specs/AGENTS.md:16-17.
  • Обновление 2026-08-14: align-frontend-foundation и align-frontend-ui-patterns архивированы в archive/ и закоммичены в HEAD, но в индексе остаются 16 staged-записей AD (включая новые изменения); git status не чист, требуется git reset для завершения lifecycle.
  • Минимальное действие: одним коммитом завершить archive/move либо восстановить активные артефакты.
  • Владелец: specs. Зависимости: подтверждение lifecycle.

A-06. Архитектурная и development-документация фактически отсутствуют — [partial]

  • Доказательство: docs/architecture/README.md:1-3 и docs/development/README.md:1-3 содержат только заглушки, хотя их назначение закреплено в docs/AGENTS.md:15-17.
  • Обновление 2026-08-14: добавлена docs/development/frontend-workflow.md (Node 22, npm run verify, openapi:sync); docs/architecture/README.md остаётся заглушкой.
  • Минимальное действие: добавить актуальную component/data-flow карту и руководство по setup, generation, verification и выпуску изменений.
  • Владелец: docs. Зависимости: подтверждение команд и границ frontend/backend.

Medium

A-07. Конкурентная регистрация возвращает 500 вместо контрактного 409 — [open]

  • Доказательство: backend/src/auth/auth.service.ts:29-42 делает preflight findUnique, не обрабатывая unique-constraint вокруг create.
  • Риск: один из параллельных запросов с одинаковым email завершится не EMAIL_ALREADY_REGISTERED.
  • Минимальное действие: перехватывать Prisma unique-constraint и возвращать ConflictException.
  • Владелец: backend. Зависимости: Prisma error type/code.

A-08. Формат validation error не соответствует фактическому Nest payload — [open]

  • Доказательство: backend/src/common/filters/http-exception.filter.ts:23-38,58-66 трактует message: string[] как ValidationError[].
  • Риск: публичный VALIDATION_ERROR содержит пустой errors, клиент не получает указания на неверные поля.
  • Минимальное действие: задать exceptionFactory с ValidationError[] или корректно сериализовать строки Nest.
  • Владелец: backend. Зависимости: нет.

A-09. Сессии и portfolio cache не имеют границ роста — [open]

  • Доказательство: backend/src/auth/auth.service.ts:137-165, backend/prisma/schema.prisma:28-39 не очищают sessions и не содержат expiry index; backend/src/tbank/portfolio.service.ts:54-55,67-98,229-273 держит неограниченные process-local maps.
  • Риск: рост SQLite-таблицы и памяти при длительной эксплуатации.
  • Минимальное действие: retention/cleanup сессий и index expiresAt; bounded TTL/LRU с периодической очисткой cache.
  • Владелец: backend. Зависимости: политика retention, лимиты cache.

A-10. Большой портфель может терять metadata из-за burst concurrency — [open]

  • Доказательство: backend/src/tbank/portfolio.service.ts:131-133,229-272 запускает все lookups одновременно, backend/src/tbank/tbank.client.ts:208-209 отклоняет новые вызовы после 50 queued.
  • Риск: часть позиций получает fallback FIGI/Unknown instrument, хотя данные доступны upstream.
  • Минимальное действие: bounded concurrency ниже лимита очереди либо очередь без hard rejection.
  • Владелец: backend. Зависимости: допустимая latency для крупных портфелей.

A-11. Восстановленный access token не синхронизируется с transport ref — [done]

  • Доказательство: frontend/src/features/auth/model/auth.tsx:66-75 обновляет state, но не accessTokenRef.current; :100-110 настраивает shared client только из ref.
  • Обновление 2026-08-14: исправлено. auth.tsx синхронизирует accessTokenRef.current при bootstrap/refresh/login/logout/clear (строки 54,74,87,96,108); transport — единственный владелец Bearer header, покрыт тестами в client.test.ts.
  • Минимальное действие: синхронно обновлять ref при восстановлении token; затем удалить дублирующиеся headers.
  • Владелец: frontend. Зависимости: нет.

A-12. Нарушается FSD public API boundary — [done]

  • Доказательство: frontend/src/app/routes/AppRoutes.tsx:2-9, src/pages/accounts/ui/AccountsPage.tsx:5-10, src/pages/settings/ui/SettingsPage.tsx:4-6, src/features/tbank-connection/ui/TbankConnectionSection.tsx:13-16 импортируют внутренности слайсов вопреки frontend/docs/STRUCTURE.md:11.
  • Обновление 2026-08-14: исправлено. Импорты идут через public index.ts, добавлен dependency-cruiser; npm run deps проходит без нарушений (84 modules).
  • Минимальное действие: экспортировать нужные элементы через index.ts и импортировать только public API.
  • Владелец: frontend. Зависимости: нет.

A-13. Критичные сценарии не защищены тестами — [partial]

  • Доказательство: backend/test/app.e2e-spec.ts:36-85 не тестирует параллельные refresh/registration; frontend/src/features/tbank-connection/ui/TbankConnectionSection.tsx:27-169 не имеет focused tests.
  • Обновление 2026-08-14: frontend-часть закрыта — transport-тесты (client.test.ts), RouteErrorBoundary.test.tsx, AccountPage.test.tsx, TbankConnectionSection.view.test.tsx; vitest run 30/30. Backend-часть (concurrent auth E2E) не добавлена — backend не менялся.
  • Минимальное действие: добавить concurrent E2E для auth и behavior tests для replace/delete/error/pending/invalidation UI.
  • Владелец: backend и frontend. Зависимости: A-01, A-07; React Query test wrapper.

A-14. Контекст и verification evidence не адаптированы к multi-repo SDD — [open]

  • Доказательство: specs/openspec/config.yaml:1-20 оставлен примером; .opencode/skills/openspec-verify-change/SKILL.md:70-115 не требует evidence matrix по frontend, backend, docs; архивные tasks, например specs/openspec/changes/archive/2026-08-13-add-portfolio-view/tasks.md:13-15,23-32, не содержат commit SHA и результаты проверок.
  • Обновление 2026-08-14: не менялось; config.yaml всё ещё пример.
  • Минимальное действие: задать OpenSpec context/rules и completion record: репозиторий, SHA, версия/ревизия контракта, дата и результат проверок.
  • Владелец: specs и root. Зависимости: соглашение frontend/backend/docs.

Low

A-15. ADR отражают план, а не реализованное состояние — [open]

  • Доказательство: docs/adr/003-tbank-server-side-grpc-boundary.md:19-21, 004-encrypted-per-user-tbank-token.md:13-15, 006-auth-session-policy.md:13-15 описывают будущую реализацию; feature docs фиксируют поставленные функции.
  • Риск: читатель не отличит accepted decision от delivery status.
  • Минимальное действие: дополнить consequences статусом реализации и ссылкой на feature doc; обновить конфликтующий policy в docs/adr/007-react-query-fetch-policy.md:9-15.
  • Владелец: docs. Зависимости: согласование frontend/backend policy.

A-16. Локальные frontend guides не имеют явного статуса в общей документации — [open]

  • Доказательство: frontend/AGENTS.md:19-24 требует читать пять внутренних документов, а корневой AGENTS.md:17,23 описывает только durable docs.
  • Риск: агенту неясно, какая документация авторитетна и как поддерживать локальные convention guides.
  • Минимальное действие: отметить их как frontend-local conventions и связать с development index.
  • Владелец: root. Зависимости: согласование frontend/docs.

A-17. Небольшие UX/i18n несоответствия — [open]

  • Доказательство: frontend/src/features/auth/ui/AuthForm.tsx:84-99 не содержит autoComplete; src/entities/brokerage-account/ui/BrokerageAccountList.tsx:33-38, src/entities/portfolio/model/display.ts:20-25, src/features/tbank-connection/ui/TbankConnectionSection.tsx:99-104 жёстко используют ru-RU при наличии i18n.
  • Риск: хуже работа password manager и некорректный формат дат при добавлении другой локали.
  • Минимальное действие: добавить semantic autocomplete и использовать текущий язык i18n в formatters.
  • Владелец: frontend. Зависимости: решение о дополнительных локалях для второй части.

A-18. Непоследовательное оформление основной OpenSpec — [open]

  • Доказательство: specs/openspec/specs/user-authentication/spec.md:1-5 начинается с ## Purpose, в отличие от остальных спецификаций, например specs/openspec/specs/tbank-connection/spec.md:1-7.
  • Риск: небольшая навигационная и tooling-неоднозначность.
  • Минимальное действие: добавить # user-authentication Specification.
  • Владелец: specs. Зависимости: нет.

Подтверждённые сильные стороны

  • T-Bank tokens шифруются AES-256-GCM с уникальным nonce и authentication tag: backend/src/tbank/tbank.crypto.ts:16-43.
  • Tokens валидируются до сохранения и не возвращаются connection status API: backend/src/tbank/tbank-connection.service.ts:34-61, backend/src/tbank/tbank-connection.controller.ts:35-55.
  • JWT algorithm закреплён, а для неизвестного пользователя используется dummy bcrypt hash: backend/src/auth/jwt.strategy.ts:11-16, backend/src/auth/auth.service.ts:50-58.
  • Денежная арифметика использует bigint, не floating point: backend/src/tbank/decimal.ts:1-44.
  • Frontend использует централизованный типизированный OpenAPI client, не хранит token в persistent storage, а маршруты и страницы имеют loading/error/empty patterns.
  • Основные OpenSpec scenario-based, охватывают ошибки, cache и безопасность; feature docs содержат пользовательские потоки, API, ограничения и Mermaid diagrams.
  • Корневые и локальные AGENTS.md ясно фиксируют независимые репозитории и SDD intent.

Результаты воспроизводимых проверок

Проверки выполнены 2026-08-13 без запуска test:cov и без анализа процентов покрытия. Повторные проверки frontend — 2026-08-14.

Область Команда Результат
frontend ./node_modules/.bin/biome check . Успешно: 64 файла, замечаний нет.
frontend ./node_modules/.bin/tsc -b --noEmit Успешно.
frontend ./node_modules/.bin/vitest run Успешно: 8 files, 25 tests.
frontend ./node_modules/.bin/tsc -b && ./node_modules/.bin/vite build Успешно; Vite предупреждает о JS chunk 582.99 kB (176.19 kB gzip) после minification.
frontend ! rg -i todo src --glob '*.{ts,tsx}' Успешно: TODO не найдено.
backend rtk lint "{src,apps,libs,test}/**/*.ts" Успешно: ESLint без замечаний.
backend npm test Успешно: 8 suites, 22 tests.
backend rtk npm run build Успешно: Prisma generate и Nest build.
specs npx openspec validate --all --strict Успешно: 7 specs, 0 failures.
specs opsx validate --all --strict Не выполнено: opsx: command not found.

Повторные проверки 2026-08-14

Область Команда Результат
frontend npm run typecheck Успешно.
frontend ./node_modules/.bin/biome check . Успешно: 81 файл, замечаний нет.
frontend npm run openapi:check Успешно: generated artifact соответствует committed snapshot.
frontend npm run deps Успешно: dependency-cruiser, 84 modules, нарушений нет.
frontend npm run knip Успешно.
frontend vitest run Успешно: 30 tests (11 files).
specs npx openspec validate --all --strict Успешно: 8 specs (добавлен frontend-ui-resilience), 0 failures.
specs git status Грязный: 16 staged-записей AD в openspec/changes/ — ожидает git reset.

Рекомендуемый порядок исправлений

  1. Создать одну security-focused change для A-01, A-02, A-03 и A-07; добавить связанные concurrent tests из A-13 (backend-часть). Это единственный незакрытый High-блок.
  2. Завершить lifecycle A-05: выполнить git reset в specs, чтобы убрать 16 staged-записей AD и вернуть воспроизводимый OpenSpec store.
  3. Исправить A-04, A-06, A-14 и A-15 одним documentation/process change, включив multi-repo evidence matrix.
  4. Выполнить A-08, A-09 и A-10 отдельными backend-изменениями.
  5. Завершить Low-улучшения (A-16, A-17, A-18) после согласования локалей и статуса локальных руководств.