Задача З-1.1 плана «Обзвон под клиента». До этой правки фичи в портале не было
вовсе, и звонок было некуда положить: нечего списывать, нечего показать клиенту и
нечем ответить через год на вопрос «за что вы взяли с меня деньги в августе».
Заведены две таблицы, обе с защитой по клиентам ENABLE + FORCE:
- obzvon_calls — одна попытка набора. По номеру их бывает до двенадцати, и каждая
своя строка со своим исходом. Держит два плеча врозь: робот с человеком и
человек с менеджером после перевода, у каждого своя длительность и свой признак
«состоялось». Держит два срока хранения и два следа удаления: звук месяц, текст
три месяца, дальше живут сухие итоги.
- obzvon_number_results — единственный итог на всю работу с номером. Именно он
стоит в карточке сделки, а не последняя попытка. Замок — UNIQUE по клиенту,
кампании и номеру: двенадцать недозвонов дают ОДИН итог, а не двенадцать.
Расшифровка лежит в той же строке звонка. Отдельного хранилища под неё нет
намеренно — решение Р50 сняло бессрочную обезличенную расшифровку.
Имя своё, а не call_recordings из закомментированного чертежа: чертёж был про
телефонию вообще и не знает ни статуса обзвона, ни сроков со следом удаления, ни
«почему звонили», ни двух плеч, ни попыток с итогом. Чертёж не тронут.
Цена звонка запоминается в строке вместе со снимком тарифа, а не вычисляется из
действующего тарифа при показе: иначе смена тарифа задним числом перепишет
вчерашние счета. Образец — lead_charges.tier_no + price_per_lead_kopecks. Деньги
целыми копейками.
Строку звонка никто не удаляет: право DELETE не выдано ни одной роли. Вместе со
строкой ушли бы деньги, а спросить «за что вы взяли» клиент вправе и через год.
Канон — db/schema_modules.sql, новый раздел 23. Тело db/schema.sql таблиц не
получает: оно исполняется первой миграцией, и таблицы дельта-миграций в него
класть нельзя — это прямо запрещает сторож канона. В db/schema.sql добавлена
только пометка над закомментированным чертежом call_recordings: чертёж не
использован и не будет, модуль живёт в obzvon_*, и перечислено, чего чертёж не
знает. Чтобы следующая смена не воскресила его по недоразумению.
Журнал схемы — запись v9.68, номер свободен, столкновения нет.
Проверено: 21 сторож, в том числе изоляция клиентов живым запросом из-под роли
crm_app_user, а не глазами по миграции; служебная роль после перезапуска
db/03_service_bypass_policies.sql правит именно ту строку, а не «успешно ноль»;
откат миграции хвостов не оставляет; squawk с конфигом проекта чист; статанализ
по новым файлам ноль. Каждый сторож показан красным.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Канон знал 82 таблицы и 995 столбцов, а база — 121 и 1470: не описаны были
рекламный модуль, телеграм-рассылки и весь отдел продаж.
Главное, что выяснилось по дороге: db/schema.sql не документ, а исполняемый
файл — миграция 0001_01_01_000000_load_initial_schema заливает его целиком
первым шагом сборки. Перенести туда DDL модулей нельзя: те же таблицы создают
дельта-миграции, их 77 и 49 из них без стражей. Сборка с нуля падала дважды.
Поэтому канон разбит на два файла: schema.sql исполняется, новый
schema_modules.sql только описывает.
Проверено не глазами:
- сборка с нуля 148 из 148 DONE;
- столбцы 1470 против 1470, ноль расхождений по имени, типу, длине и NULL;
- все четыре счётчика расхождений инструмента — ноль;
- schema.sql отдельно исполняется без единой ошибки, ограничения 495=495,
политики 64=64;
- статанализ 0.
Инструмент сверки усилен: считал только одну сторону и потому не видел
переименования jivo_chat_id в chat_id — старое имя жило в каноне месяц.
Теперь обе стороны, канон из нескольких файлов, понимание RENAME/DROP COLUMN
и DROP TABLE. Починен разбор переносов строки внутри определения столбца.
Сторож SchemaDeltaTest дополнен: файл модулей обязан быть на месте и описывать
39 таблиц, а тело schema.sql их не содержать. Принят вырезанием.
Найдено и НЕ исправлено, нужно решение владельца: задвоенный указатель на
deals и пять политик без NULLIF в миграциях. Оба помечены в тексте канона.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>