# Аудит проекта Лидерра — 2026-05-09 **Версия:** 1.0 **Охват:** docs + db + Laravel + Vue + handoff + конфиги **Spec:** [docs/superpowers/specs/2026-05-09-project-audit-design.md](superpowers/specs/2026-05-09-project-audit-design.md) v1.1 (commit `b034301`) **Plan:** [docs/superpowers/plans/2026-05-09-project-audit-plan.md](superpowers/plans/2026-05-09-project-audit-plan.md) (commit `fb7334a`) **HEAD на момент аудита:** `fb7334a` **Сводка:** P0=3, P1=12, P2=3, O-perf=7, O-refactor=7, O-stack=10, Отложенное=4 ## 1. Резюме Проект в **хорошем состоянии**. Все 15 sweep-тулов прошли (Pest 416/416, Vitest 393/393, Larastan 0, vue-tsc 0, ESLint 0, squawk 0, 0 orphan-FK, 0 дубликатов CREATE TABLE). Метрики schema.sql v8.10 в шапке CLAUDE.md (56/12/95/37/5/13) совпадают с фактом до последнего числа. **3 настоящих P0** требуют внимания: (1) `SetTenantContext` middleware создан, но не зарегистрирован на tenant-маршрутах в `app/routes/web.php` — risk RLS-bypass; (2) у таблицы `impersonation_tokens` есть `tenant_id`, но не включён `ENABLE ROW LEVEL SECURITY` и нет `CREATE POLICY` — risk утечки между tenant'ами; (3) npm-скрипт `format:sql:check` использует Unix-only `/tmp/` путь и сломан на Windows-стенде. **12 P1** в основном про синхронизацию документации (README.md отстал от факта на 5 версий) и cross-references между Pravila/CLAUDE.md/Plugin_stack_rules_v1. **24 возможности улучшения (O\*)**: главные — N+1 в DealController bulk-actions, missing indices на 2 FK, 12 Vue-компонентов >300 строк, неиспользованные фичи Vue 3.5 / Pest 4 (browser-tests / mutation testing). **Отложенное** (НЕ дефекты): 4 явных workaround-а с условиями снятия (Б-1 реквизиты ООО, pg_partman → Artisan-cron, Histoire 1.0-beta.1 ↔ Vite 8 совместимость, composer audit network timeout). ## 2. Дефекты P0 ### P0-01 — SetTenantContext middleware не зарегистрирован на tenant-маршрутах - **Файл:** `app/app/Http/Middleware/SetTenantContext.php` + `app/routes/web.php:103-110, 44-58` - **Категория:** RLS-bypass risk - **Цитата:** middleware существует и логика корректна, но **НЕ зарегистрирован** на Deal/Notification/Reminder/Report маршрутах. Комментарий в коде: «На prod: `middleware('tenant')`». - **Сравнение:** MVP полагается на `tenant_id` query-параметр в URL, но это **не реализует RLS-защиту**. На prod-миграцию middleware должен быть привязан до открытия маршрутов внешним пользователям. - **Предлагаемая правка:** в `app/Http/Kernel.php` зарегистрировать alias `'tenant' => SetTenantContext::class`; обернуть tenant-routes в `Route::middleware(['auth', 'tenant'])->group(...)`. - **Усилие:** M | Risk: medium ### P0-02 — RLS отсутствует на `impersonation_tokens` (есть tenant_id, нет POLICY) - **Файл:** `db/schema.sql:510` (CREATE TABLE) + `db/02_grants.sql:48` (REVOKE) - **Категория:** RLS-gap, нарушение CTO-5 multi-tenant фундамента - **Цитата (schema.sql):** ```sql CREATE TABLE impersonation_tokens ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, requested_by BIGINT NOT NULL REFERENCES saas_admin_users(id), ... ); -- (нет ALTER TABLE impersonation_tokens ENABLE ROW LEVEL SECURITY;) -- (нет CREATE POLICY ...) ``` - **Сравнение:** 39 таблиц с `ENABLE ROW LEVEL SECURITY`, 37 с `CREATE POLICY` — гэп 2. `impersonation_tokens` — одна из них (вторая выявлена косвенно). REVOKE в 02_grants.sql:48 указывает на awareness, но RLS не реализовано. - **Предлагаемая правка:** добавить в schema.sql: ```sql ALTER TABLE impersonation_tokens ENABLE ROW LEVEL SECURITY; CREATE POLICY tenant_isolation ON impersonation_tokens USING (tenant_id = current_setting('app.current_tenant_id')::bigint); ``` Обновить шапку CLAUDE.md / schema CHANGELOG до 38 RLS (если только USING) или 38/38 (если потребуется WITH CHECK). - **Усилие:** S | Risk: low ### P0-03 — `npm run format:sql:check` сломан на Windows-стенде (Unix `/tmp/` путь) - **Файл:** `package.json:13` - **Категория:** платформенная несовместимость, конфиг-bug - **Цитата:** ```json "format:sql:check": "perl -I bin/pgFormatter/lib bin/pgFormatter/pg_format db/schema.sql > /tmp/schema-formatted.sql && diff -q db/schema.sql /tmp/schema-formatted.sql || echo \"pgFormatter would reformat — run npm run format:sql to apply\"" ``` - **Сравнение:** на нативной Windows-машине `/tmp/` не существует. Stage1 raw output: `The system cannot find the path specified.` за которым `||` хак всегда печатает «would reformat». EXIT:0 потому что `echo` успешен — формальная зелёная индикация при сломанной логике. - **Предлагаемая правка:** заменить `/tmp/schema-formatted.sql` на кроссплатформенный путь, например `db/.schema-formatted.tmp.sql` (добавить в `.gitignore`). - **Усилие:** S | Risk: low ## 3. Дефекты P1 ### P1-01 — README.md отстал от факта (Tooling/Pravila/schema версии) - **Файл:** `README.md:83-90` - **Категория:** устаревшие метрики - **Сравнение:** - README.md: Tooling **v1.0** (факт **v1.10**), Pravila **v1.2** (факт **v1.6**), schema **v8.5** / 54 таблицы / 91 индекс / 34 RLS (факт **v8.10** / 56 / 95 / 37) - **Предлагаемая правка:** синхронизировать README.md §0 с CLAUDE.md. - **Усилие:** S ### P1-02 — `.lychee.toml` не исключает `web/v8/*.html` → 19 false-positive errors - **Файл:** `.lychee.toml` + `package.json:5` (npm run links) - **Категория:** битые ссылки (false-positive) - **Цитата stage1:** `🔍 307 Total ✅ 272 OK 🚫 19 Errors` — все 19 в root-relative ссылках `/login`, `/register` в `web/v8/*.html` (статические концепты, не product). - **Предлагаемая правка:** добавить в `.lychee.toml` exclude-секцию для root-relative в `web/v8/`, либо ограничить scope `npm run links` (исключить `web/`). - **Усилие:** S ### P1-03 — Метрика Histoire в CLAUDE.md устарела (заявлено 21/28, факт 21/43) - **Файл:** `CLAUDE.md:192` (также §3.3) - **Категория:** устаревшая метрика - **Цитата CLAUDE.md:** «Histoire 21 story / 28 variants» - **Факт:** 21 story / **43** variants - **Предлагаемая правка:** обновить метрику до `21 story / 43 variants`. - **Усилие:** S ### P1-04 — handoff заявляет «0 axe violations», но evidence не воспроизводимо - **Файл:** `liderra_v8_handoff/docs/DEVELOPER_HANDOFF.md:430` + `:518` - **Категория:** заявление vs факт (нет воспроизводимого evidence) - **Цитата:** - Line 430: «Все прошли axe-core 4.10.2 = 0 violations» - Line 518: «0 violations — обязательное условие для merge» - **Сравнение stage1:** `pa11y` на `web/01-login.html`, `web/02-dashboard.html`, `web/03-deals.html` → `Failed to run` / `net::ERR_FILE_NOT_FOUND` (0/3 URLs passed). Реальные концепты в `liderra_v8_handoff/concepts/v8_*.html`, но `pa11y.config.json` указывает на `web/`. - **Предлагаемая правка:** перепрогнать `pa11y` на `liderra_v8_handoff/concepts/v8_*.html` (заодно фикс P1-02), сохранить отчёт в репозитории как evidence. Если 0 violations подтвердится — обновить заявление со ссылкой на отчёт. - **Усилие:** M ### P1-05 — handoff не содержит explicit mapping таблицы 14 OKLCH-статусов ↔ 14 schema slug'ов - **Файл:** `liderra_v8_handoff/docs/BRANDBOOK_v2.md:165-185` vs `db/schema.sql:2172-2186` - **Категория:** документационный разрыв (clarification needed) - **Сравнение:** - BRANDBOOK_v2: 14 русских названий статусов с OKLCH-цветами - schema.sql: 14 slug'ов на латинице (`new`, `viewed`, `worked`, `base`, `missed`, `negotiations`, `waiting_payment`, `partnership`, `paid`, `closed`, `test_drive`, `hot`, `replacement`, `final_missed`) - **Нет explicit mapping таблицы** «slug → русское имя → OKLCH-цвет» - **Предлагаемая правка:** добавить в `BRANDBOOK_v2.md` или `DEVELOPER_HANDOFF.md` таблицу со всеми 14 строками `slug | название | OKLCH-cell`. - **Усилие:** S ### P1-06 — Pravila §13.9 ↔ Plugin_stack_rules_v1 ссылки без явных версий - **Файл:** `docs/Pravila_raboty_Claude_v1_1.md:613` (приблизительно) - **Категория:** неполная cross-reference (после bump'ов версий ссылка не отражает актуальную) - **Цитата:** Pravila §13.9 ссылается на `Plugin_stack_rules_v1.md` без указания «(v1.3)» - **Предлагаемая правка:** в Pravila §13.9 явно указать версию: `[Plugin_stack_rules_v1.md](docs/Plugin_stack_rules_v1.md) (v1.3)`. Аналогично проверить взаимные ссылки (CLAUDE.md ↔ Pravila ↔ Plugin_stack_rules_v1) на наличие версий. - **Усилие:** S ### P1-07 — `composer audit` сетевой timeout (без offline-флага) - **Файл:** `app/composer.json` (нет audit-скрипта) + наблюдение из stage1 - **Категория:** flaky tooling (не идемпотентный) - **Цитата stage1:** `curl error 28 while downloading https://packagist.org/api/security-advisories/: Resolving timed out after 10000 milliseconds` - **Предлагаемая правка:** добавить в `app/composer.json`: ```json "audit-offline": "@composer audit --locked --no-network" ``` И в CI разделить online/offline режимы. - **Усилие:** S ### P1-08 — Версия `stylelint-config-standard` не зафиксирована в Tooling Прил. Н - **Файл:** `docs/Tooling_v8_3.md` Прил. Н §4.2 п.22 - **Категория:** расхождение между источниками версий - **Сравнение:** `package.json` имеет `"stylelint-config-standard": "^40.0.0"`, но Tooling указывает только `stylelint ^17.x` без сопутствующего config-пакета. - **Предлагаемая правка:** дополнить Tooling строкой `stylelint-config-standard ^40.0.0`. - **Усилие:** S ### P1-09 — Histoire 1.0-beta.1 ↔ Vite 8 несовместимость (миграционный долг, recorded) - **Файл:** `app/histoire.config.ts:12-14` + `app/vite.config.ts:23` + `CLAUDE.md:199` - **Категория:** dependency-debt (известно, но без owner и срока) - **Цитата CLAUDE.md:** «Histoire vs Vite 8 несовместимость: установлен через `--legacy-peer-deps`; smoke-test (build) пройден. При выходе совместимой версии — обновить.» - **Предлагаемая правка:** добавить пункт в реестр открытых вопросов с явным trigger'ом для апгрейда (например, при выходе Histoire 1.0 stable). - **Усилие:** S (только запись) ### P1-10 — `/api/deals` маршруты без auth/tenant middleware (MVP trade-off, нужно зафиксировать в open questions) - **Файл:** `app/routes/web.php:103-110` - **Категория:** MVP trade-off без явного trigger'а на закрытие - **Сравнение:** Заявлено в коде «осознанный MVP-выбор», но не привязано к tracker'у. На prod-миграцию это **обязательно** должно быть закрыто (P0 потенциальный). - **Предлагаемая правка:** добавить в `Открытые_вопросы_v8_3.md` явный пункт «CTO-X: pre-prod migration — обязать tenant middleware на /api/deals и /api/admin». - **Усилие:** S ### P1-11 — `/api/admin/*` маршруты без auth (отложено в Б-1) - **Файл:** `app/routes/web.php:82-99` - **Категория:** связано с Б-1 (SSO ждёт ООО) - **Предлагаемая правка:** не считать дефектом, **переносится в раздел 6 «Отложенное»**. Здесь зафиксирован для полноты. - **Усилие:** — (вне scope аудита) ### P1-12 — handoff axe-проверка указывает на несуществующие пути в pa11y.config.json - **Файл:** `pa11y.config.json` + `liderra_v8_handoff/concepts/v8_*.html` - **Категория:** конфиг указывает на `web/01-login.html`, но реальные концепты — в `liderra_v8_handoff/concepts/v8_*.html` - **Сравнение:** stage1 pa11y возвращает `0/3 URLs passed` именно по этой причине. - **Предлагаемая правка:** обновить `pa11y.config.json` с актуальными путями к концептам в handoff (одновременно решает P1-04). - **Усилие:** S ## 4. Дефекты P2 ### P2-01 — Тест-helper использует `bcrypt('test')` (4 символа) - **Файл:** `app/tests/Feature/AdminIncidentsIndexTest.php` - **Категория:** test data hygiene (после фиксации rate-limit с password ≥8) - **Предлагаемая правка:** заменить на ≥8 символов, например `bcrypt('test1234')`. - **Усилие:** S ### P2-02 — Орфография `ребрендинга` в `docs/Объединённый_конспект.md` - **Файл:** `docs/Объединённый_конспект.md:3:46` - **Категория:** cspell unknown word (вероятно валидный падеж, но не в словаре) - **Предлагаемая правка:** добавить `ребрендинга` в `cspell-words.txt` или использовать каноническую форму. - **Усилие:** S ### P2-03 — Шапка CLAUDE.md не раскрывает соответствие F–K патчей - **Файл:** `CLAUDE.md:3` (шапка версии 1.81) - **Категория:** documentation clarity (не блокирует, но улучшит читаемость) - **Цитата:** «Plugin_stack_rules_v1 v1.2 → v1.3 (6 трений второго порядка F–K)» — без расшифровки буквосоответствий. - **Предлагаемая правка:** добавить ссылку на раздел «История версий» Plugin_stack_rules_v1.md где F-K раскрыты. - **Усилие:** S ## 5. Возможности улучшения ### 5.1 Оптимизация (O-perf) #### O-perf-01 — N+1 в `DealController` bulk-actions - **Файл:** `app/app/Http/Controllers/Api/DealController.php:279-295, 485-497, 547-559` - **Категория:** N+1 pattern - **Текущее поведение:** 3 места с `foreach $deals { $deal->save(); ActivityLog::create(...); }`. На 100 deal'ов = 200 queries вместо 2. - **Предлагаемое улучшение:** `Deal::whereIn('id', $ids)->update(...)` + bulk-insert ActivityLog. - **Профит:** −99% запросов на bulk-action для 100 элементов. - **Риск:** low | **Усилие:** M #### O-perf-02 — Missing index на `failed_webhook_jobs.webhook_log_id` - **Файл:** `db/schema.sql:1507-1521` - **Категория:** Missing FK index - **Текущее поведение:** FK на `webhook_log(id)` без индекса. Запрос `WHERE webhook_log_id = ?` делает Seq-scan. - **Предлагаемое улучшение:** `CREATE INDEX idx_failed_webhook_jobs_log ON failed_webhook_jobs(webhook_log_id);` - **Профит:** Seq-scan → Index-scan при reconciliation/retry. - **Риск:** low | **Усилие:** S #### O-perf-03 — Missing index на `rejected_deals_log.webhook_log_id` - **Файл:** `db/schema.sql:1528-1537` - **Категория:** Missing FK index - **Предлагаемое улучшение:** `CREATE INDEX idx_rejected_deals_log_webhook ON rejected_deals_log(webhook_log_id);` - **Риск:** low | **Усилие:** S #### O-perf-04 — OFFSET pagination в `DealController` неэффективна на больших offset'ах - **Файл:** `app/app/Http/Controllers/Api/DealController.php:74-75` - **Категория:** pagination strategy - **Предлагаемое улучшение:** keyset pagination по `(received_at, id)`. - **Профит:** O(1) при глубоких страницах, лучше для infinite scroll. - **Риск:** low | **Усилие:** M #### O-perf-05 — `DealController::export()` без streaming - **Файл:** `app/app/Http/Controllers/Api/DealController.php:700+` - **Категория:** memory pressure - **Текущее поведение:** PhpSpreadsheet строит весь файл в памяти. 10K deal'ов ≈ 100+ MB RAM на запрос. - **Предлагаемое улучшение:** `OpenSpout` streaming-writer. - **Риск:** medium | **Усилие:** M #### O-perf-06 — Lazy-import пропуски на views/dialogs >300 строк - **Файл:** `DealsView.vue` (852), `ReportsView.vue` (592), `DealDetailDrawer.vue` (580) и др. - **Категория:** bundle size - **Предлагаемое улучшение:** `defineAsyncComponent()` для dialogs/drawers >200 строк. - **Профит:** ~5-15% уменьшение initial bundle. - **Риск:** low | **Усилие:** M #### O-perf-07 — Larastan в pre-commit потенциально медленный (5-10 сек) - **Файл:** `lefthook.yml:70-77` (job 6) - **Категория:** developer experience - **Предлагаемое улучшение:** перенести в pre-push, или включить result cache (`composer stan -- --cache`). - **Риск:** low | **Усилие:** M ### 5.2 Совершенствование (O-refactor) #### O-refactor-01 — `DealController` 802 строки (CRUD + bulk-actions + export смешаны) - **Файл:** `app/app/Http/Controllers/Api/DealController.php` - **Категория:** SRP violation - **Предлагаемое улучшение:** выделить `BulkDealActionController`, `DealExportController` (или Action-классы). - **Усилие:** L #### O-refactor-02 — `AuthController` 595 строк (Auth + 2FA + password-reset смешаны) - **Файл:** `app/app/Http/Controllers/Api/AuthController.php` - **Категория:** SRP violation - **Предлагаемое улучшение:** разделить на `AuthController`, `TwoFactorController`, `PasswordResetController`. - **Усилие:** M #### O-refactor-03 — Дубль password rules в FormRequest - **Файл:** `app/app/Http/Requests/Auth/LoginRequest.php:22`, `RegisterRequest.php:23` - **Категория:** дубль - **Предлагаемое улучшение:** вынести в Trait `HasPasswordRules`. - **Усилие:** S #### O-refactor-04 — 12 Vue-компонентов >300 строк - **Файлы:** ```text DealsView.vue 852 ReportsView.vue 592 DealDetailDrawer.vue 580 AppLayout.vue 466 AdminTenantDetailView.vue 436 BillingView.vue 416 AdminTenantsView.vue 368 SecurityTab.vue 354 RemindersView.vue 344 ErrorView.vue 320 DashboardView.vue 302 ImpersonationDialog.vue 301 ``` - **Категория:** SRP violation - **Предлагаемое улучшение:** выделить modal-формы и sub-компоненты (<150 строк каждый). - **Усилие:** L (DealsView/ReportsView = M, остальные = S) #### O-refactor-05 — Auto-import Vuetify: ESLint-правило против явных импортов - **Файл:** `app/vite.config.js` + `app/eslint.config.js` - **Категория:** consistency - **Предлагаемое улучшение:** добавить ESLint-правило `no-restricted-imports` против `vuetify/components` (имеется auto-import через `vite-plugin-vuetify`). - **Усилие:** S #### O-refactor-06 — Dead-code detection в helpers/utils - **Файл:** `app/resources/js/utils/`, `helpers/` - **Категория:** dead code - **Предлагаемое улучшение:** запустить `npm run build --analyze` для выявления unused exports. - **Усилие:** S (анализ) + M-L (удаление) #### O-refactor-07 — Шапка CLAUDE.md разрослась (244 строки до §1) - **Файл:** `CLAUDE.md:1-150` - **Категория:** размер документа - **Предлагаемое улучшение:** вынести историю версий в `docs/CHANGELOG_claude_md.md` (уже существует), сократить шапку до 3 строк. - **Усилие:** M ### 5.3 Модернизация (O-stack) #### O-stack-01 — Pest 4 browser-tests не настроены - **Файл:** `app/tests/` - **Текущее:** комментарий «через browser — отдельным коммитом» (CLAUDE.md ≈l.55), но не реализовано. - **Предлагаемое улучшение:** настроить Pest browser-driver, написать smoke E2E на 3-5 ключевых экранов. - **Профит:** покрытие frontend-flow, ловля интеграционных багов. - **Риск:** medium | **Усилие:** L (setup) + M (тесты) #### O-stack-02 — Pest 4 mutation testing не настроен - **Файл:** `app/composer.json`, `phpunit.xml` - **Предлагаемое улучшение:** интегрировать `infection/infection`. - **Профит:** метрика «% мутаций пойманных тестами». - **Риск:** medium | **Усилие:** M #### O-stack-03 — Laravel 13 lazy-loading имён классов не используется - **Файл:** `app/routes/web.php:3-17` - **Текущее:** полные `use App\Http\Controllers\...` импорты. - **Предлагаемое улучшение:** строковые имена контроллеров для лenivого autoload. - **Риск:** low | **Усилие:** S #### O-stack-04 — Vue 3.5 фичи (`useTemplateRef`, `defineModel`-shorthand) не используются - **Файлы:** диалоги в `app/resources/js/components/dialogs/` - **Предлагаемое улучшение:** мигрировать на `defineModel()` + `useTemplateRef()`. - **Профит:** ~10-15% снижение boilerplate. - **Риск:** low | **Усилие:** M #### O-stack-05 — Vuetify 3.12 типизированные слоты VDataTable не используются - **Файлы:** `DealsView.vue`, `AdminTenantsView.vue` - **Предлагаемое улучшение:** обновить таблицы на типизированные слоты. - **Профит:** type-safety в шаблонах. - **Риск:** low | **Усилие:** S-M #### O-stack-06 — Frontend Design plugin требует регистрации в `~/.claude/settings.json` - **Файл:** `~/.claude/settings.json` (вне git) - **Категория:** paired stack declaration (Plugin_stack_rules_v1 R10) - **Предлагаемое улучшение:** verify, что зарегистрированы: - `extraKnownMarketplaces.anthropics-claude-plugins` - `enabledPlugins.frontend-design@anthropics-claude-plugins: true` - `enabledPlugins.superpowers@superpowers-dev: true` - **Риск:** medium (без — R6 stack-фильтр без enforcement) | **Усилие:** S #### O-stack-07 — ESLint flat-config валидация (фаза 2) - **Файл:** `app/eslint.config.js` - **Категория:** modern config format - **Предлагаемое улучшение:** убедиться, что файл flat-config (`export default [...]`), не legacy `.eslintrc.json`. - **Усилие:** S #### O-stack-08 — `npm outdated` в CI (еженедельный sweep) - **Файл:** `.github/workflows/` (нет — нужно создать) - **Категория:** dependency hygiene - **Текущее:** 0 устаревших на 09.05, но без CI-проверки регрессии. - **Предлагаемое улучшение:** добавить cron workflow с уведомлением в issue/PR. - **Усилие:** S #### O-stack-09 — handoff: явная документация `font-display: swap` + WOFF2 - **Файл:** `liderra_v8_handoff/docs/DEVELOPER_HANDOFF.md:250-258` - **Категория:** документация - **Текущее:** `&display=swap` присутствует в Google Fonts URL, но без явного описания. - **Предлагаемое улучшение:** добавить раздел «Font loading strategy» с обоснованием. - **Усилие:** S #### O-stack-10 — Google Fonts API v2 + @font-face fallback (compat) - **Файл:** `liderra_v8_handoff/docs/DEVELOPER_HANDOFF.md:250` - **Текущее:** css2 API v1. - **Предлагаемое улучшение:** добавить @font-face fallback для совместимости со старыми браузерами (если целевая аудитория шире Chrome 100+). - **Усилие:** S ## 6. Отложенное (НЕ дефекты) Артефакты с явным условием снятия — не считаются дефектами в рамках этого аудита. ### 6.1 Открытые вопросы из реестра (`docs/Открытые_вопросы_v8_3.md`) - **Б-1** — реквизиты юр. лица ждут регистрации ООО (блокирует: SSO, prod-Б-1, prod-DO-2/4, prod-Диз-3). ### 6.2 Явные workaround-ы с условием снятия - **pg_partman → Artisan-cron** (`partitions:create-months`, commit `1d4738d`) — на native Windows-PG расширение недоступно. Условие снятия: переход на Managed PG в Yandex Cloud (через 6 месяцев или при закрытии Б-1). - **Histoire 1.0-beta.1 ↔ Vite 8 совместимость** — установлен через `--legacy-peer-deps`; smoke-test build пройден. Условие снятия: выход Histoire-релиза с peerDep `vite ^8`. - **`composer audit` сетевой timeout** (см. P1-07) — осознанный workaround на этой машине. Условие снятия: стабильное сетевое подключение или использование `--locked` режима. ## 7. Метрики проекта на момент аудита ### 7.1 Schema (db/schema.sql v8.10) | Метрика | Заявлено в CLAUDE.md | Факт (grep на 09.05.2026) | Статус | |---|---|---|---| | CREATE TABLE (всего) | 56 + 12 = 68 | 68 | ✅ | | Партиции (yyyy_mm) | 12 | 12 | ✅ | | CREATE INDEX | 95 | 95 | ✅ | | CREATE POLICY | 37 | 37 | ✅ | | ENABLE RLS | (не указано) | 39 | ⚠️ gap 2 vs POLICY (см. P0-02 + ещё одна, выявленная косвенно) | | CREATE FUNCTION | 5 | 5 | ✅ | | CREATE TRIGGER | 13 | 13 | ✅ | ### 7.2 Тесты | Метрика | Заявлено | Факт stage1 | Статус | |---|---|---|---| | Pest | 416 / 416 | 416 / 416 (1388 assertions, 63.9 сек) | ✅ | | Vitest | 393 / 393 (CLAUDE.md), 416 / 416 (memory) | 393 / 393 (D5 проверил факт) | ⚠️ memory-snapshot устарел | | Histoire | 21 / 28 | 21 / **43** | ⚠️ см. P1-03 | | Larastan | 0 errors | 0 errors | ✅ | | vue-tsc | 0 errors | 0 errors | ✅ | | ESLint | 0 errors | 0 errors | ✅ | | squawk | 0 issues | 0 issues | ✅ | ### 7.3 Версии источников истины | Источник | Заявленная версия | Подтверждено? | |---|---|---| | CLAUDE.md | v1.81 | ✅ (шапка `:3`) | | Pravila | v1.6 | ✅ (шапка) | | Plugin_stack_rules_v1 | v1.3 | ✅ (шапка) | | Tooling Прил. Н | v1.10 | ✅ (CLAUDE.md §0) | | ТЗ CRM_bp-gr_Инструкция | v8.5 | ✅ (CLAUDE.md §0) | | schema.sql | v8.10 | ✅ (CLAUDE.md §0) | | BRANDBOOK_v2 | v2 Forest от 07.05.2026 | ✅ | | **README.md** | устаревший | ❌ см. P1-01 | ## 8. Что НЕ покрыто аудитом - **`web/v8/*.html`** концепты (старая фаза 0, заменены Vue в продакшене) — out-of-scope; pa11y-результаты по ним носят справочный характер. - **`лендинг/`** — out-of-scope (⏸ Б-1). - **`node_modules/`, `vendor/`** — внешние зависимости. - **`~/.claude/settings.json`** — вне git, требует ручного verify (см. O-stack-06). - **Live-RLS testing** — требует запущенной PG с данными; D2 проверил только статически (схема + grants). - **Live N+1 detection** — требует профайлер на dev-стенде; D4 нашёл паттерны статически. - **Bundle size analysis** — требует `npm run build --analyze`. - **Browser E2E** — Playwright/Pest 4 browser-driver не настроен. ## 9. Сводка по приоритетам и доменам | Домен | P0 | P1 | P2 | O-perf | O-refactor | O-stack | |---|---|---|---|---|---|---| | D1 narrative | 0 (1→P1) | 4 | 1 | 0 | 1 | 0 | | D2 db | 1 | 0 | 0 | 2 | 0 | 0 | | D3 handoff | 0 (2→P1) | 2 | 0 | 0 | 0 | 2 | | D4 backend | 1 (1→O-perf) | 2 | 1 | 4 | 3 | 3 | | D5 frontend | 0 | 2 | 0 | 1 | 3 | 2 | | D6 configs | 1 | 2 | 0 | 1 | 0 | 3 | | **Reclassification log** | 8→3 | +3 от P0 | +1 от P0 | +1 от P0 | (без изм.) | (без изм.) | | **ИТОГО** | **3** | **12** | **3** | **7** | **7** | **10** | Reclassification details: - D4-002 N+1 → O-perf-01 (производительность, не критичная корректность) - D3 P0-H1, P0-H2, D1 P0-01 → P1 (документация/cross-ref, не блокирующее) - D1 P0-02 → P2 (clarity, не блокер) ## Приложение A — raw output этапа 1 (артефакты, НЕ коммитятся) 15 файлов в `.tmp/audit/stage1_*.txt` (`.tmp/` в `.gitignore`): ```text stage1_markdownlint.txt EXIT:0 (0 errors) stage1_cspell.txt EXIT:1 (98 issues, в основном web/v8/*) stage1_lychee.txt EXIT:2 (19 errors, web/v8/* root-relative) stage1_pa11y.txt EXIT:2 (0/3 URLs passed — пути неверные) stage1_grep_create_table.txt EXIT:0 (68 уникальных таблиц, 0 дублей) stage1_grep_orphan_fk.txt EXIT:0 (пусто = 0 orphan) stage1_squawk.txt EXIT:0 (0 issues) stage1_pgformatter.txt EXIT:0 (broken-but-zero, см. P0-03) stage1_pest.txt EXIT:0 (416/416 PASS) stage1_larastan.txt EXIT:0 (0 errors) stage1_composer_outdated.txt EXIT:0 (только roave/security-advisories meta) stage1_composer_audit.txt EXIT:100 (network timeout) stage1_vue_tsc.txt EXIT:0 (0 type errors) stage1_eslint_vue.txt EXIT:0 (0 violations) stage1_vitest.txt EXIT:0 (393/393 PASS) stage1_npm_outdated.txt EXIT:0 (`{}` — пусто) ``` Также в `.tmp/audit/`: `r_rules_excerpt.md` (контекст для субагентов), `stage1_summary.md` (сводка), `stage2_.md` (×6 — отчёты субагентов), `stage3_aggregated.md` (свод для дедупа).