diff --git a/cspell-words.txt b/cspell-words.txt index c27c65f0..7fd2e757 100644 --- a/cspell-words.txt +++ b/cspell-words.txt @@ -691,3 +691,6 @@ BYTEA trg SPE gethostbyname +KDV +коммита +коммитов diff --git a/docs/Объединённый_конспект.md b/docs/Объединённый_конспект.md index 2d42d8c8..a6422c63 100644 --- a/docs/Объединённый_конспект.md +++ b/docs/Объединённый_конспект.md @@ -1359,3 +1359,150 @@ OPEN-И-12 ⏸ Где хранить контакты эскалации (P1, *Часть VII добавлена 05.05.2026 (поздний вечер) по итогам сессии аудита связности архива и выпуска патча v8.3.1.* *Часть VIII добавлена 05.05.2026 (поздний вечер, итерация 2) по итогам сессии закрытия бэклога 🟡-расхождений + закрытия Биз-10 переоткрытого + синхронизации narrative до v8.3.1 + устранения унаследованной арифметической ошибки сводки §0 в Прил. Е v1.8 → выпуск патча v8.3.2.* + +--- + +# ЧАСТЬ IX. v8.3.3 + v8.4 ФИНАЛ + МИГРАЦИЯ + АУДИТ C → v8.5 (06–07.05.2026) + +> Часть IX добавлена 07.05.2026 (вечер) по итогам двух дней работы: финализации v8.4, миграции проекта на Server 2022, проведения аудита C двумя read-only агентами, закрытия 27 решений в реестре v1.12 и реализации v8.5 (schema + narrative + Прил. И + кросс-ссылки). + +## 1. Хронология (06–07.05.2026) + +| Дата | Этап | Артефакты | +|---|---|---| +| 06.05.2026 (день) | **v8.3.3** — добавлен Прил. Н (реестр 28 инструментов в 4 фазах), создан корневой `CLAUDE.md`. Pravila_raboty_Claude → v1.2. Открытые_вопросы → v1.9 | 3 правки в файлах, 0 архитектурных изменений | +| 06.05.2026 (вечер) | **v8.4 финализация** — переписаны все 13 разделов плана v8.4 (§1, §5, §7, §8, §9, §12, §14, §17, §18.4, §19.10, §22, §23.10, §26). Главный narrative переименован `_v8_3.md` → `_v8_4.md`. Schema → v8.4 (+`outbound_webhook_subscriptions/deliveries`, +2 RLS, +5 индексов). Метрики: 51/81/31 → 53/86/33 | 2 коммита (`c8db9a2` + `4321251`); реестр → v1.10 | +| 06.05.2026 → 07.05.2026 | **Миграция на Server 2022** — заказчик сменил рабочую машину (Windows 10 KDV → Windows Server 2022 Administrator). Пересоздан node_modules, восстановлена git-история через GitHub API (после ошибочного force-push). 25 коммитов восстановлены, +`185e663` (gitignore для orphan-папок старой машины) | Перенос проекта без `.git`, восстановление через `POST /git/refs` + `git fetch` + `PATCH refs/heads/main` | +| 07.05.2026 (день) | **Аудит C** — два read-only general-purpose агента (C-1 архитектура HubSpot/Pipedrive comparison, C-2 security STRIDE). Найдено 27 новых открытых вопросов: 8 P0 + 12 P1 + 7 P2. Раздел 13 в реестре v1.11. Закрытий нет (правило §2.2) | Коммит `4d65d6a` | +| 07.05.2026 (вечер) | **Реализация v8.5** — заказчик решил «A везде» по всем 27. 3 коммита: `aabf827` реестр v1.12, `038a884` schema v8.5, `4ffc19a` narrative v8.5 + README архива + Прил. И Часть Г + кросс-ссылки | Состояние архива: 17 файлов в `docs/` + 2 в `db/` + CLAUDE.md + README.md | + +## 2. v8.4 — финал narrative (06.05.2026) + +Завершение плана v8.4, начатого в v8.3+. Все 13 разделов плана переписаны: + +- **§1** — конкурентные преимущества vs оригинал (7 differentiator'ов: outbound webhook, аудит мутаций, Kanban DnD, real-time push, кастомизация дашборда, REST API, security-стек). +- **§5** — формат ingress (webhook/manual/CSV), 3 чекбокса click-wrap при регистрации. +- **§7** — синхронизация с фактическим schema.sql v8.4 (53 таблицы, 86 индексов, 33 RLS). +- **§8** — кастомизация статусов через `tenant_status_overrides` + Redis-кеш. +- **§9** — `EffectiveLimitCalculator` + `project_suppliers` + soft-delete TTL 180 дней. +- **§12** — расширенная аналитика, конверсия проектов (паритет с `/admin/visit/rt-stat`). +- **§14** — полный аудит мутаций (vs оригинал, который логирует только смену статуса/комментарий/звонок). +- **§17** — Тихие часы (паритет с оригиналом, на уровне тенанта). +- **§18.4** — security-differentiator (7 функций безопасности vs оригинал). +- **§19.10** — outbound webhook (10 подразделов: формат, HMAC SHA-256, retry-логика 7 попыток до 24ч, SSRF-защита). +- **§22** — расширенный CSP, защита от prompt injection в DOM, антипаттерны оригинала + code review checklist. +- **§23.10** — админка SaaS (10 подсекций включая «Желаемое × факт сегодня», workflow ПДн). +- **§26** — UX/Frontend. + +## 3. Миграция на Server 2022 (06–07.05.2026) + +**Заказчик сменил рабочую машину.** Старый путь `c:\Users\KDV\Projects\lidpotok` (Win10) → `c:\моя\проекты\портал crm\Документация` (Server 2022 Administrator). Проект скопирован **без `.git`**. + +**Установлено через Chocolatey 2.7.1** (winget на Server 2022 нет): git 2.54.0, Node.js 24.15.0 + npm 11.12.1, PHP 8.3.31 NTS x64, Composer 2.9.7. `node_modules` пересоздан `npm ci` (443 пакета, 54 сек). + +**История git восстановлена через GitHub Git DB API.** В процессе была допущена критическая ошибка: при первом 404 от fine-grained PAT (Repository access не настроен) Claude ошибочно сделал `git push --force` поверх `4d65d6a`, уничтожив 24 коммита. Восстановлено через `POST /git/refs` (объекты на GitHub живут 30+ дней) + `git fetch` + `PATCH refs/heads/main` обратно на `4d65d6a`. Итого 25 коммитов на main + `185e663` (правка `.gitignore` для исключения orphan-папок). + +**Урок зафиксирован в `feedback_environment.md`:** **404 от fine-grained PAT ≠ удалённый репо** — это Repository access не настроен. Никогда не делать force-push, не убедившись через 2-й независимый источник (curl с другим токеном, веб-интерфейс). + +## 4. Аудит C (07.05.2026, день) + +**Два независимых параллельных read-only агента:** + +- **C-1 архитектурный** (general-purpose, ~100K токенов, 22 tool uses) — чтение narrative + schema + brandbook + реестр; сравнение с лучшими практиками HubSpot / Pipedrive / AmoCRM / Kommo / RetailCRM для pay-per-lead-РФ-сегмента. +- **C-2 security** (general-purpose, ~149K токенов, 21 tool use) — STRIDE для 4 потоков (логин админа, inbound webhook, биллинг, экспорт) + 5 осей (RLS-дыры, secret rotation, audit-логи, DDoS, PII). + +**Найдено 27 новых вопросов с вариантами A/B/C** в `Открытые_вопросы_v8_3.md` v1.11 раздел 13: + +- **Бизнес/продукт (8):** Биз-17 (автораспределение), Биз-18 (TTFR-SLA), Биз-19 (антифрод дублей) — все P0; Биз-20..22 — P1; Биз-23/24 — P2. +- **CTO (4):** CTO-13 (SET LOCAL+PgBouncer тест) — P0; CTO-14..16 — P1. +- **OPEN-И (14):** OPEN-И-13/14/15/16 — P0; OPEN-И-17..21 — P1; OPEN-И-22..26 — P2. +- **Юрист (1):** Ю-9 — P1. + +**Что хорошо покрыто (из C-2):** 34/34 RLS, CSP без `unsafe-inline`, HMAC SHA-256+timestamp+replay, SSRF-фильтр, impersonation Ю-1, atomic billing, processing_restricted, four-eyes >50К ₽. Выпадает только DNS-rebinding (P1 OPEN-И-18). + +**Закрытий нет** в этом коммите — по правилу §2.2. + +## 5. Реализация v8.5 (07.05.2026, вечер) + +**Решение заказчика:** «A везде» по всем 27 (рекомендованные варианты, минимально-достаточный baseline для pay-per-lead-сегмента + 152-ФЗ). + +**Три коммита одной сессией:** + +### 5.1. `aabf827` — реестр v1.11 → v1.12 + +- §13.10 «Закрытия аудита C — 27 решений» с тремя подразделами (P0/P1/P2). Каждое решение → ✅ + variant A + импакт на schema/narrative. +- Сводка §0: 32 ⏸ → 5 ⏸ (1 P0 = Б-1; 4 P1 ждут Б-1 или у Claude; 0 P2). 67/77 ✅ из 77 продуктовых. +- §13.10.4 «Итоговый импакт» — прогноз метрик schema v8.5. + +### 5.2. `038a884` — schema.sql v8.4 → v8.5 + +| Параметр | v8.4 | v8.5 | Δ | +|---|---|---|---| +| Логических таблиц | 53 | **54** | +1 (`project_user_assignments`, CTO-16) | +| Индексов | 86 | **91** | +5 | +| RLS-политик | 34 | **35** | +1 + WITH CHECK на 2 | +| ENABLE RLS | 34 | **35** | +1 | +| Ролей БД | 3 | **4** | +1 (`crm_audit_writer`) | +| Триггеров | 0 | **12** | +12 | +| Функций | 0 | **4** | +4 | +| Колонок | — | +26 | (см. CHANGELOG_schema §Y.2) | + +**Ключевые DDL-изменения:** + +- **OPEN-И-15** (append-only audit hash chain): `log_hash BYTEA` на 5 audit-таблицах (`auth_log`, `activity_log`, `pd_processing_log`, `saas_admin_audit_log`, `balance_transactions`); 10 триггеров (5×2 = BEFORE INSERT для `audit_chain_hash()` + BEFORE UPDATE/DELETE для `audit_block_mutation()`); функция `audit_chain_hash()` через `digest(prev_hash || NEW::text, 'sha256')`; новая роль `crm_audit_writer` (только INSERT); REVOKE UPDATE/DELETE на этих 5 таблицах от других ролей. +- **OPEN-И-14** (RLS WITH CHECK + REVOKE): WITH CHECK добавлен к политикам `tenant_isolation` на `deal_tag_pivot` и `saas_invoice_items`; REVOKE ALL на 6 saas-таблицах от `crm_app_user`. +- **Биз-19** (антифрод дублей): `deals.duplicate_of_id BIGINT` (без FK — партиционированная); индекс `(duplicate_of_id) WHERE NOT NULL`. +- **CTO-14** (UTM): 4 × VARCHAR(100) на `deals` + индекс `(tenant_id, utm_source) WHERE NOT NULL`. +- **CTO-16** (skill-based routing): новая таблица `project_user_assignments(project_id, user_id, skills JSONB)` + RLS через JOIN на `projects.tenant_id`. +- **Биз-22** (lead scoring без ML): `suppliers.quality_score`, `deals.time_in_form_seconds/lead_score`, триггер `calc_lead_score()` BEFORE INSERT/UPDATE. +- **OPEN-И-13** (SSO): `saas_admin_users.sso_provider/is_break_glass`. +- **CTO-15+Ю-9** (two-person impersonation): `impersonation_tokens.second_approver_id/second_approval_at`. +- **OPEN-И-17/19** (TTL secrets): ALTER `api_keys.expires_at SET NOT NULL DEFAULT NOW()+365d`; `tenants.api_key_limit INT DEFAULT 5 CHECK (1..10)`. +- **OPEN-И-26** (call_recording задел Post-MVP): закомментированный DDL `call_recordings(...)` 10 строк в секции 17. + +**CHANGELOG_schema.md** — новая запись Y (v8.4 → v8.5) с детальным разбором всех изменений по 10 подразделам. + +### 5.3. `4ffc19a` — narrative v8.4 → v8.5 + +- Файл переименован `CRM_bp-gr_Инструкция_v8_4.md` → `_v8_5.md`. README архива тоже переименован (v8_4 → v8_5). +- Шапка обновлена + блок «Что нового в v8.5» (~60 пунктов решений с привязкой к секциям). +- **8 новых in-place подразделов:** + - §10.8 «Антифрод+routing+scoring+regions+escalation» — Биз-17/19/22/23, CTO-16, OPEN-И-25/26 (~150 строк). + - §12.5.5 — TTFR-SLA (Биз-18) + UTM-когорты (CTO-14). + - §14.8 — append-only audit hash chain (OPEN-И-15) + report_jobs export trigger (OPEN-И-20). + - §17.9 — Telegram-канал (Биз-20), эскалация-нотификации (OPEN-И-25), late waiting_payment alert (Биз-24). + - §19.10.11–12 — DNS-rebinding pin-IP (OPEN-И-18), `marketing.conversion` event (Биз-21). + - §22.13 — SSO+SET LOCAL+Sentry+anti-DDoS+TTL+two-person+audit-chain (~250 строк, самый большой подраздел). + - §23.10.11 — break-glass dashboard, two-person UI, 152-ФЗ ст.21 hard-block UI. + - §7.1 — метрики schema обновлены под v8.5. +- **Прил. И → v0.3 (новая Часть Г)** — 9 операционных процедур: Г.1 RLS smoke-test (CTO-13, BLOCKER для фазы 1), Г.2 cron `audit:verify-chain` (OPEN-И-15), Г.3 `secrets:notify-expiring` (OPEN-И-17), Г.4 anti-DDoS компоненты, Г.5 per-tenant DEK + crypto-shred (OPEN-И-22), Г.6 `pg_anonymizer` для staging (OPEN-И-24), Г.7 Yandex 360 SSO setup (OPEN-И-13), Г.8 cron `leads:escalate-stale` (OPEN-И-25), Г.9 cron `payments:notify-stale` (Биз-24). +- Кросс-ссылки обновлены в `CLAUDE.md`, `README.md`, `web/index.html`, `db/schema.sql` шапке. + +## 6. Метрики двух дней + +- **5 коммитов** на main за 06–07.05.2026: `c8db9a2` (v8.4 финал), `4321251` (README архива v8.4), `185e663` (gitignore migration), `4d65d6a` (audit C), `aabf827` (реестр v1.12), `038a884` (schema v8.5), `4ffc19a` (narrative v8.5) + восстановленные после force-push. +- **27 продуктовых решений закрыто** (8 P0 + 12 P1 + 7 P2). +- **+1 таблица, +26 колонок, +5 индексов, +12 триггеров, +4 функции, +1 роль, +2 WITH CHECK, +6 REVOKE.** +- **+~700 строк narrative** (8 новых подразделов + Часть Г Runbook + 2 шапки). +- **markdownlint+cspell чистые** на каждом коммите. +- **0 orphan-FK, 0 дубликатов CREATE TABLE, метрики совпадают с grep'ами** (self-review §8 CLAUDE.md). + +## 7. Что осталось после v8.5 + +1. **HTML-прототипы 04..08** (Диз-1, у Claude). Перед стартом — уточнить с заказчиком возможное переоткрытие Диз-2 («дизайн не нравится» 06.05). +2. **Б-1** ждём — единственный реальный P0-блокер от заказчика. От него: Диз-3, DO-2, DO-4, OPEN-З-*. +3. **Триггер фазы 1 архитектурно разблокирован.** Финальный gate — RLS smoke-test (CTO-13) в спринте 1 (Прил. И §Г.1, BLOCKER без прохождения). +4. **ER-диаграммы Прил. Б+В** под v8.5 — обновлено в этой же сессии (см. отдельную правку файла). +5. **Ротация утёкшего PAT** — `github_pat_11...` (утёк в чат 07.05 при восстановлении истории) ротирован 07.05 при push'е v8.5-коммитов. + +## 8. Уроки сессии + +1. **«A везде» — допустимый fast-track при качественном предварительном ранжировании.** Аудит C ранжировал варианты A как минимально-достаточные; «A везде» прошло без переоткрытий потому что агенты сделали homework. Если бы варианты A были компромиссными — fast-track мог бы загнать решения в рискованную зону. +2. **Schema-CHANGELOG записи Y/Z/A/B по обратной хронологии — рабочий паттерн.** При каждом bump'е новая запись в начало; старые остаются неизменными. Реалистично читается. +3. **«Что нового в vX.Y» блок в шапке narrative — критичная навигация.** При v8.5 добавлено 8 подразделов в разные секции — без сводного блока в шапке невозможно найти что изменилось без grep'а. +4. **Три коммита вместо одного — правильно.** Реестр (декларация решений) → schema (DDL) → narrative (документация) — три разных уровня абстракции, ревью по очереди легче, rollback каждого слоя возможен независимо. +5. **Триггеры audit-append-only + отдельная роль = реальная защита.** Один слой (только триггеры) — admin может сделать `ALTER TABLE … DISABLE TRIGGER` (если есть права). Один слой (только REVOKE на роль) — другая роль может писать с правами. Двойной слой = и admin не отключит триггер на чужой роли, и роль `crm_audit_writer` не имеет UPDATE/DELETE. + +--- + +*Часть IX добавлена 07.05.2026 (вечер) по итогам двух дней работы 06–07.05.2026: финализация v8.4 (13/13 разделов плана) + миграция проекта на Server 2022 + аудит C двумя read-only агентами (27 новых вопросов) + реализация v8.5 (3 коммита: реестр v1.12, schema v8.5 с +1 таблицей/+26 колонками/+12 триггерами/+4 функциями/+1 ролью, narrative v8.5 с 8 новыми подразделами + Прил. И Часть Г).* diff --git a/docs/Приложение_Б_В_БД_диаграммы_v8_3.md b/docs/Приложение_Б_В_БД_диаграммы_v8_3.md index 791dcc17..521af2fd 100644 --- a/docs/Приложение_Б_В_БД_диаграммы_v8_3.md +++ b/docs/Приложение_Б_В_БД_диаграммы_v8_3.md @@ -7,14 +7,92 @@ - **Часть Б** — ER-диаграмма (Mermaid `erDiagram` × 6 доменов + flowchart-карта + текстовый справочник 81 FK + рейтинг таблиц + дельта к v8.0). - **Часть В** — State machine диаграммы (Mermaid `stateDiagram-v2` × 4: `saas_transactions`, `tariff_subscriptions`, `report_jobs`, `refund_requests`). -**Источник фактов для обеих частей:** `db/schema.sql` (актуальная — v8.4: 53 логических таблицы + 12 партиций, 86 индексов, 34 RLS-политики на 34 защищённых таблицах). При расхождении ER/state machines с этой версией — приоритет за `schema.sql`. +**Источник фактов для обеих частей:** `db/schema.sql` (актуальная — **v8.5**: 54 логических таблицы + 12 партиций, 91 индекс, 35 RLS-политик с WITH CHECK на 2, 35 ENABLE RLS, 4 роли, 12 триггеров, 4 функции). При расхождении ER/state machines с этой версией — приоритет за `schema.sql`. **Замечания по версионированию:** -- ER-диаграмма (Часть Б) исходно от v8.1 (`ER_диаграмма_v8_1.md`). Изменения схемы v8.2 (`suppliers`, `project_suppliers`, расширение `projects`, `project_limit_adjustments`), v8.3 (переписанная `reminders`, capabilities у `suppliers`, `tenants.desired_daily_numbers`) и v8.4 (`outbound_webhook_subscriptions`, `outbound_webhook_deliveries`, RLS на `deal_tag_pivot`) **не отражены в ER-диаграммах** — перерисовка отложена до спринта 0/1, когда схема стабилизируется. До этого момента читать ER + сверяться с актуальной `db/schema.sql` v8.4 и `Прил_М_Analiz_originala_v8_3.md` §3.1, §3.5. -- State machines (Часть В) от v8.1 — изменений в state machines между v8.1 и v8.4 не было. +- ER-диаграмма (Часть Б) исходно от v8.1 (`ER_диаграмма_v8_1.md`). Изменения схемы v8.2/v8.3/v8.4/v8.5 **не отражены в Mermaid-диаграммах** — перерисовка отложена до спринта 0/1, когда схема стабилизируется. До этого момента — **читать ER + сверяться с актуальной `db/schema.sql` v8.5 + блоком «Дельта v8.2 → v8.5» ниже** + `db/CHANGELOG_schema.md` (записи Y, Z, A, B) + `Прил_М_Analiz_originala_v8_3.md` §3.1, §3.5. +- State machines (Часть В) от v8.1 — изменений в state machines между v8.1 и v8.5 не было (один новый workflow v8.5 — pending-state у `impersonation_tokens` для two-person approval — описан текстом в narrative §22.13.7 без отдельной диаграммы; добавление в Часть В возможно в спринте 1). -**Связано:** `db/schema.sql` v8.4, `db/CHANGELOG_schema.md` (запись Z), `Прил_М_Analiz_originala_v8_3.md` v1.1 §3. +**Связано:** `db/schema.sql` v8.5, `db/CHANGELOG_schema.md` (записи Y=v8.5, Z=v8.4), `Прил_М_Analiz_originala_v8_3.md` v1.1 §3, `CRM_bp-gr_Инструкция_v8_5.md` §7.1. + +--- + +## Дельта v8.2 → v8.5 (не перерисовано в Mermaid, читать вместе с диаграммами v8.1 ниже) + +Поскольку Mermaid-диаграммы фиксируют срез v8.1 (47 таблиц, 81 FK), для актуальной картины их нужно дополнять перечнем изменений v8.2..v8.5. Ниже — компактная сводка, что нужно мысленно добавить к диаграммам. + +### v8.2 (04.05.2026) — реселлерская модель + 152-ФЗ + +**Новые таблицы (+5):** `suppliers` (B1/B2/B3), `project_suppliers` (M2M), `project_limit_adjustments`, `pd_subject_requests`, `incidents_log`. **Новые колонки в существующих:** `users.notification_preferences JSONB` (8×3), `tenants.chargeback_unrecovered_rub`, `pd_subject_requests.processing_restricted` (OPEN-Д-1 152-ФЗ ст.21), `refund_requests.source`. **+`projects` 6 полей:** `daily_limit_target`, `effective_daily_limit_today`, `region_mask`, `region_mode`, `delivery_days_mask`, и др. + +### v8.3 (05.05.2026) — аудит партий 12–15 + +**Переписана `reminders`:** `created_by` (вместо `user_id`), `assignee_id NULL`, `completed_at` (вместо `is_done`). **Удалены `deals.reminder_text/reminder_at/idx_deals_reminder`** — множественные напоминания через таблицу `reminders`. **+`suppliers` 5 capabilities:** `channel`, `supports_sender_name/keyword/csv_upload/domains_list`. **+`tenants.desired_daily_numbers`** (Биз-16, сигнал саппорту). + +### v8.4 (06.05.2026) — outbound webhook + +**Новые таблицы (+2):** `outbound_webhook_subscriptions`, `outbound_webhook_deliveries`. **+RLS-политика для `deal_tag_pivot`** (hotfix через JOIN на `deal_tags.tenant_id`). **Метрики:** 51→53 табл, 81→86 инд, 31→34 RLS на 34 защищённых таблицах. + +### v8.5 (07.05.2026) — реализация 27 решений аудита C + +**Новые таблицы (+1):** + +- **`project_user_assignments(project_id, user_id, skills JSONB, is_active)`** (CTO-16) — пул менеджеров проекта для `assignment_strategy IN ('round_robin','least_loaded')` Post-MVP. RLS через JOIN на `projects.tenant_id` (USING + WITH CHECK). PK = `(project_id, user_id)`. Индекс `idx_project_user_assignments_user(user_id) WHERE is_active`. + +**Новые колонки (+26):** + +| Таблица | Колонки | Источник | +|---|---|---| +| `suppliers` | `quality_score NUMERIC(3,2) DEFAULT 1.00` | Биз-22 | +| `saas_admin_users` | `sso_provider VARCHAR(32) DEFAULT 'yandex360'`, `is_break_glass BOOLEAN` | OPEN-И-13 | +| `impersonation_tokens` | `second_approver_id BIGINT REFERENCES saas_admin_users(id)`, `second_approval_at TIMESTAMPTZ` | CTO-15 + Ю-9 | +| `tenants` | `api_key_limit INT DEFAULT 5 CHECK (1..10)`, `telegram_bot_token TEXT` | OPEN-И-19, Биз-20 | +| `projects` | `assignment_strategy VARCHAR(32) DEFAULT 'manual'`, `ttfr_target_minutes INT DEFAULT 15` | Биз-17, Биз-18 | +| `users` | `telegram_user_id BIGINT` | Биз-20 | +| `deals` | `assigned_at TIMESTAMPTZ`, `escalated_count INT DEFAULT 0`, `duplicate_of_id BIGINT` (без FK), `utm_source/utm_medium/utm_campaign/utm_content VARCHAR(100)`, `region_code VARCHAR(8)`, `city VARCHAR(100)`, `time_in_form_seconds INT`, `lead_score NUMERIC(5,2)` | OPEN-И-25, Биз-19, CTO-14, Биз-23, Биз-22 | +| `auth_log`, `activity_log`, `pd_processing_log`, `saas_admin_audit_log`, `balance_transactions` | `log_hash BYTEA` | OPEN-И-15 | + +**ALTER (1):** `api_keys.expires_at SET NOT NULL DEFAULT NOW() + INTERVAL '365 days'` (OPEN-И-17 + OPEN-И-19; миграция backfill всем NULL-ключам). + +**Новые индексы (+5):** `(tenant_id, utm_source) WHERE NOT NULL`, `(tenant_id, region_code) WHERE NOT NULL`, `(duplicate_of_id) WHERE NOT NULL`, `(tenant_id, assigned_at) WHERE status NOT IN ('closed','rejected')`, `idx_project_user_assignments_user(user_id) WHERE is_active`. + +**Новые политики RLS (+1):** `tenant_isolation` на `project_user_assignments` через JOIN на `projects.tenant_id` (USING + WITH CHECK). + +**WITH CHECK добавлен к существующим политикам (+2):** `tenant_isolation` на `deal_tag_pivot` (через `deal_tags.tenant_id`) и `saas_invoice_items` (через `saas_invoices.tenant_id`). До v8.5 защита была только на USING — INSERT мог пройти при `tag_id`/`invoice_id` чужого тенанта. + +**REVOKE ALL от `crm_app_user` (+6 таблиц):** `saas_admin_users`, `saas_admin_sessions`, `saas_admin_audit_log`, `incidents_log`, `pd_subject_requests`, `impersonation_tokens` (defense-in-depth, OPEN-И-14). + +**Новые роли (+1):** + +- **`crm_audit_writer`** — INSERT-only на 5 audit-таблицах. UPDATE/DELETE заблокированы и триггерами, и REVOKE'ом. Application пишет в audit под этой ролью через temporary `SET ROLE`. + +**Новые функции (+4):** + +- **`audit_chain_hash() RETURNS TRIGGER`** (OPEN-И-15) — заполняет `NEW.log_hash = sha256(prev_hash || NEW::text)` перед INSERT в audit-таблицы. +- **`audit_block_mutation() RETURNS TRIGGER`** (OPEN-И-15) — `RAISE EXCEPTION` при UPDATE/DELETE. +- **`report_jobs_log_export() RETURNS TRIGGER`** (OPEN-И-20) — auto-INSERT в `pd_processing_log` action='exported' при создании `report_jobs`. +- **`calc_lead_score() RETURNS TRIGGER`** (Биз-22) — `lead_score = supplier.quality_score × (time_in_form_seconds / 60)`, clamped в `[0, 99.99]`. + +**Новые триггеры (+12):** + +- **5 пар** на audit-таблицах (`auth_log`, `activity_log`, `pd_processing_log`, `saas_admin_audit_log`, `balance_transactions`): `BEFORE INSERT` (hash chain) + `BEFORE UPDATE OR DELETE` (block mutation) = 10 триггеров. +- **1 на `report_jobs`:** `AFTER INSERT` → `pd_processing_log`. +- **1 на `deals`:** `BEFORE INSERT OR UPDATE OF time_in_form_seconds, project_id` → расчёт `lead_score`. + +**Закомментированный задел Post-MVP:** + +- **`call_recordings(tenant_id, deal_id, call_started_at, duration_sec, direction, recording_path, transcript)`** (OPEN-И-26) — задел под Биз-12 (телефония + транскрипция), 10 строк закомментированного DDL в `db/schema.sql` секция 17. Активация — однострочный uncomment + миграция при первом клиентском запросе Post-MVP. + +**Метрики schema v8.5:** 54 таблицы + 12 партиций, 91 индекс, 35 RLS-политик (из них 2 с WITH CHECK обновлены), 35 ENABLE RLS, **4 роли** (crm_app_user / crm_admin_user / crm_migrator / crm_audit_writer), **12 триггеров**, **4 функции**. + +**Новые межсущностные связи v8.5 (для будущей перерисовки ER):** + +- `project_user_assignments → projects (project_id)` + `→ users (user_id)` ON DELETE CASCADE (новая M2M). +- `impersonation_tokens.second_approver_id → saas_admin_users(id)` (новая FK). +- `deals.duplicate_of_id` (self-reference, **без FK** — партиционированная таблица). + +> **Полный DDL v8.5** — `db/schema.sql`. **Полный CHANGELOG v8.4 → v8.5** — `db/CHANGELOG_schema.md` запись Y. **Narrative-обоснование v8.5** — `CRM_bp-gr_Инструкция_v8_5.md` блок «Что нового в v8.5» + §10.8/§12.5.5/§14.8/§17.9/§19.10.11–12/§22.13/§23.10.11. **Operational runbook v8.5** — `Runbook_ekspluatatsii_v8_2.md` Часть Г (9 процедур). ---