Qadam Roadmap
проектdocs/quality_report.md

Журнал проверок quality_analytic

Обновлён 1 апр. 2026 г., 12:41 · 0 комментариев

Журнал проверок quality_analytic

Паспорт документа

  • Статус документа: living document
  • Актуально на: 28 марта 2026 года
  • Владелец: backend/platform-команда
  • Пересмотр: при изменении workflow агентов, формата quality review или правил append-only логирования
  • Область применения: append-only журнал результатов проверок агента quality_analytic в репозитории qadam-core
  • Связанные документы:

Этот файл является обязательным журналом работы quality_analytic. Каждый новый запуск агента должен дописывать новый блок в конец файла. Сообщение в чат или stdout не заменяет запись в этот журнал.

Контракт записи

  • Добавлять только новый блок в конец файла.
  • Не переписывать и не удалять предыдущие записи.
  • Если дефектов нет, всё равно добавлять запись со статусом ПРИНЯТО.
  • Если область проверки неочевидна, явно писать, что проверялся текущий git diff или working tree.

Формат записи

## Проверка — [дата] | [область проверки]

**Суть проверки:** [1-3 предложения о том, что проверялось и какой контекст изменения]

### Замечания

#### [КРИТИЧНОСТЬ] — [Краткий заголовок]
- **Файл:** `path/to/file.ts` (строка N)
- **Категория:** Корректность | Архитектура | Тесты | Документация | Производительность | Качество
- **Описание:** В чём проблема и почему она важна в данном контексте.
- **Направление исправления:** Какой класс решения нужен без готового кода.

### Общая оценка
[ПРИНЯТО / ТРЕБУЕТ ВНИМАНИЯ / КРИТИЧНО]
Короткий итог по состоянию изменений.

Проверка — 28 марта 2026 года | Инициализация журнала

Суть проверки: Создан явный append-only журнал для quality_analytic, чтобы результаты каждого прогона фиксировались в docs/quality_report.md, а не терялись в чате. Эта запись задаёт контракт, по которому последующие прогоны должны работать.

Замечания

ИНФО — Журнал был пуст и без контракта записи

  • Файл: docs/quality_report.md (строка 1)
  • Категория: Документация
  • Описание: Ранее файл не содержал ни паспорта документа, ни формата записи, ни прямого требования обязательно append-ить результат каждого запуска. В такой конфигурации агент легко ограничивается текстовым ответом в чат.
  • Направление исправления: Держать в файле явный append-only контракт и обязательный шаблон секции для каждого прогона.

Общая оценка

ПРИНЯТО Журнал и формат записи инициализированы; следующие прогоны должны оставлять здесь отдельные записи.

Проверка — 28 марта 2026 года | Текущий working tree: auth, buyer-role, guard quality gate

Суть проверки: Проверен текущий незакоммиченный working tree с фокусом на новый registration/password reset flow, buyer multi-role и auth guard. Дополнительно запущен pnpm test, чтобы проверить реальный статус quality gate, а не опираться только на документацию.

Замечания

КРИТИЧНО — Email reset flow выдаёт боевой reset token прямо в HTTP-ответ

  • Файл: apps/api/src/modules/auth/auth.service.ts (строка 281)
  • Категория: Корректность
  • Описание: forgotPassword() возвращает token: tokenRecord.token для обоих сценариев восстановления, а email-ветка не требует дополнительной верификации перед resetPassword(). В результате любой, кто знает чужой email, может вызвать POST /auth/forgot-password, получить reset token из ответа и сразу завершить POST /auth/reset-password. Это прямой account-takeover. Проблема уже фигурировала в security review и остаётся незакрытой в текущем working tree.
  • Направление исправления: Для email-flow наружу должен уходить только нейтральный ответ и masked identifier, а боевой reset token должен использоваться только во внешней доставке или внутри отдельно подтверждённого server-side state.

ВЫСОКИЙ — Reset token и SMS-код логируются в открытом виде

  • Файл: apps/api/src/modules/auth/auth.service.ts (строка 269)
  • Категория: Качество
  • Описание: Stub transport пишет resetCode и resetToken в структурные логи. Любой доступ к логам даёт рабочий материал для сброса пароля без контроля над email или телефоном пользователя. С учётом Pino/Axiom-контура это превращает обычный observability поток в канал утечки секретов.
  • Направление исправления: Убрать из логов боевые секреты полностью; допустимы только masked identifier, тип канала и технический request metadata без кода и токена.

ВЫСОКИЙ — POST /me/profile обходит ролевое ограничение на добавление buyer-роли

  • Файл: apps/api/src/modules/buyer/buyer.controller.ts (строка 66)
  • Категория: Архитектура
  • Описание: Контроллер buyer больше не проверяет user.type === 'BUYER', а BuyerService.createProfile() не фильтрует тип аккаунта. Из-за этого любой аутентифицированный аккаунт может создать buyer-профиль через POST /me/profile, хотя выделенный multi-role endpoint POST /auth/add-buyer-role явно ограничен seller/seller_staff (apps/api/src/modules/auth/auth.controller.ts, строка 295; docs/product/requirements-api-registration.md, строка 1109). Это ломает границы ролей и позволяет обходить задуманный policy flow.
  • Направление исправления: Вернуть явную ролевую защиту для /me/profile либо централизовать создание buyer-роли в одном проверяемом сценарии и не оставлять параллельный обходной путь.

СРЕДНИЙ — Новый JwtAuthGuard одновременно маскирует доменные причины отказа и держит test gate красным

  • Файл: apps/api/src/common/guards/jwt-auth.guard.ts (строка 39)
  • Категория: Качество
  • Описание: Guard перечитывает аккаунт через AuthService.getMe(), но ACCOUNT_BLOCKED и ACCOUNT_UNDER_REVIEW перехватываются общим catch и превращаются в generic 401 Invalid or expired token, хотя доменный слой различает эти состояния. Параллельно pnpm test сейчас падает на apps/api/src/common/guards/jwt-auth.guard.spec.ts, потому что spec всё ещё ожидает старый синхронный контракт guard без зависимости от AuthService. В итоге ломается и API-контракт для blocked/review аккаунтов, и базовый quality gate репозитория.
  • Направление исправления: Пропускать доменные исключения из getMe() без подмены на generic 401 и синхронно обновить regression tests под async-контракт guard и новую dependency model.

Общая оценка

КРИТИЧНО Текущий working tree нельзя считать готовым к merge: password reset flow сохраняет прямой account-takeover сценарий, role boundaries для buyer размазаны, а auth guard одновременно нарушает доменный контракт и оставляет pnpm test красным.