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

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

- Статус документа: living document
- Актуально на: 28 марта 2026 года
- Владелец: backend/platform-команда
- Пересмотр: при изменении workflow агентов, формата quality review или правил append-only логирования
- Область применения: append-only журнал результатов проверок агента `quality_analytic` в репозитории `qadam-core`
- Связанные документы:
  - [Инженерные принципы](./governance/engineering-principles.md)
  - [Стандарт документации](./governance/documentation-standard.md)
  - [Project Instructions](../AGENTS.md)

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

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

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

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

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

**Суть проверки:** [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` красным.
