17 KiB
Design: схема среза ЕХ ex-payload-v1
Change ex-payload-schema, issue RSHB/arm-ka-docs#208, ветка feat/208-ex-payload (от feat/206-kfo-contract).
Читатель — Потапова (AURORA-1560, запись среза), следом — исполнитель AURORA-2001 (чтение среза) и тестировщик 1562.
Читают как постановку, без созвона.
1. Зачем
Срез ЕХ — самодостаточная заморозка верифицированной версии: его читают и выгружают, когда рабочих таблиц консолидации
уже нет. Всё производное (сводная ОСВ, агрегаты ВГО, шахматка, КФО, гудвилл, корректировки, сравнение с клиентом,
карточка версии) лежит в ex_snapshot_item.payload (jsonb). Без схемы payload каждый, кто пишет и читает срез, решает
формат сам — и просмотр среза разойдётся с экраном рабочей версии.
Успех: Потапова пишет срез, проверяя каждый элемент схемой; исполнитель 2001 рендерит и выгружает срез по той же схеме, не заглядывая в таблицы консолидации.
2. Цели, не цели, анти-цели
Цели — схема конверта и данных по каждому item_type, примеры, проверка в make check; правила среза в §14; правки
DBML, без которых схему не записать (version_card, действие журнала).
Не цели — proposal.md.
Анти-цели
- Payload, который без таблиц консолидации не прочитать: ссылки допустимы только на то, что живёт не меньше среза —
document,legal_entity,related_group,company_group,app_user(DOC-274687 правило 4); остальные id (строк ОСВ, корректировок, правил) — справочно, для рендера не нужны. - Схема, которая заставляет фронт ЕХ пересчитывать: в payload лежат готовые значения так, как их видел аналитик.
- Повторный перевод единиц: суммы в payload — как в источнике (DOC-274687 правило 5), единица — рядом.
3. Ограничения
- JSON Schema 2020-12, как остальные контракты; проверка примеров —
scripts/validate_contracts.py(make check). - Деньги — строки с двумя знаками (
^-?\d{1,16}\.\d{2}$), как в API;null— «не рассчитано». - Схема версионируется:
schema_versionв конверте иex_snapshot_item.payload_schema_version="1.0"; несовместимое изменение —ex-payload-v2.schema.jsonрядом, старые срезы не переписываются. - Модель — DBML v5.26 из #207: эта ветка дописывает в неё пункты changelog (версия ещё не слита, номер не тратим).
4. Что решено
4.1 Конверт элемента
Каждый payload (у всех item_type, кроме primary_document, у которого payload = null и есть document_id):
{schema_version: "1.0", item_type, units: "rub" | "thousand_rub" | "none", generated_at (date-time),
source_version_no (int), data: {...}}
item_type в конверте совпадает с колонкой; units — единица всех денег в data; generated_at — момент расчёта
перед записью. Конверт — additionalProperties: false.
4.2 Данные по типам
Общий принцип (главнее любой таблицы ниже): data — ответ API экрана рабочей версии в момент верификации, теми же
DTO, именами и вложенностью, без полей редактирования (editable, read_only_reason, lock) и плюс то, что нужно
выгрузке xlsx рабочей версии (срез выгружается на лету из payload и должен совпадать с выгрузкой рабочей версии —
proposal, AURORA-1562). Обязательные поля задаёт схема; лишние поля допускаются (additionalProperties: true), рендер
опирается только на обязательные. Ссылки на компании — как в DTO (Ref {id, name} или legal_entity_id +
legal_entity_name/_inn): имена в DTO уже есть, отдельный CompanyRef не вводится; список компаний периметра с ИНН —
в version_card.members. Id строк ОСВ, корректировок и правил остаются в данных справочно.
item_type |
units |
data (DTO) |
|---|---|---|
summary_osv |
rub |
{rows: ConsolidatedRowOut[], summary: OsvSummaryOut} (dev/api-contract-slice-4.md §3) — строки свода, включая match_kind (колонка «Способ сопоставления» выгрузки), и summary.gaps[] (лист «Пробелы») |
vgo_pairs |
rub |
{balance: CorrectionTableOut, income: CorrectionTableOut | null} (dev/api-contract-corrections.*) — агрегаты таблицы корректировок со сторонами и строками ОСВ (entries, нужны выгрузке), нераспределённые строки, итоги; без editable/read_only_reason; income — null, пока агрегатов ОФР нет (AURORA-1999). Это вход КФО, не прежний экран «Пары ВГО» |
chess |
rub |
{matrix_all: IntercompanyMatrixOut, presets: [{rule_no, matrix: IntercompanyMatrixOut}], result_table} (dev/frontend-api-guide.md §5.7.1) — «все счета», пресет каждого правила ББ версии правил, результирующая таблица пяти статей |
kfo_balance / kfo_income |
thousand_rub |
KfoResultOut (dev/api-contract-kfo.md) без editable/read_only_reason, с balance или income своего отчёта (второй отчёт — в своём элементе); requisites (в т. ч. corrections_balance/_income для формы 2.03.01.01с), summary, goodwill, обоснование, warnings — в обоих элементах одинаковые |
goodwill |
rub |
только при goodwill_enabled: GoodwillTableOut (dev/api-contract-goodwill.*) без editable/read_only_reason — строки, группы, итоги |
corrections |
rub |
применённые корректировки (APPLIED; REVOKED нет, DRAFT не пишется): {items: [{statement_type, rule_no, company_1: Ref, company_2: Ref, correction: CorrectionOut}]} — CorrectionOut как в контракте корректировок (updated_by/updated_at — кто и когда сохранил) |
other_report |
thousand_rub |
только при scenario = CONFIRM: {report_kind: "client_kfo_comparison", lines[] {statement_type, line_code, line_name, client_amount, client_vgo_amount, bank_amount, bank_vgo_amount, deviation_amount, deviation_percent, deviation_reason, comment}} по client_kfo_line (контракта API ещё нет — AURORA-1549; имена — как в DBML) |
version_card |
none |
один на срез, новый тип: company_group {id, name}, related_group {id, name}, reporting_date, year, quarter, version_no, scenario, approach, goodwill_enabled, initiator (UserRef), initiator_office {id, name}, members[] {legal_entity_id, name, inn, is_head_entity}, history[] как VersionCard.history ({from_status, to_status, changed_by (UserRef), changed_at, comment}), verified_by (UserRef), verified_at, uob_decision_no, uob_decision_date, methodology_deviations |
UserRef {user_id, full_name} — ФИО на дату верификации (пользователь может быть отключён, но не удаляется).
4.3 Правила среза — §14 05-domain-rules.md
Выжимка DOC-274687 под нашу модель: срез пишется один раз при «Верифицирован» (после фиксации ГСК, AURORA-2002), один на
версию (source_version_id уникален); состав — таблица 4.2 + primary_document по каждому документу
consolidation_document + ex_snapshot_member по каждому ЮЛ версии; строки форм без кода, непривязанные документы и
черновики корректировок не входят; goodwill — только при goodwill_enabled, other_report — только при CONFIRM;
номер среза — следующий по (ГСК, год, квартал) (уникальный индекс DBML; новая ГСК после смены периметра начинает
с 1); прежний срез запись в архив не переводит (архив ручной, решение 27.10.2026): переход в «Верифицирован» уже
проверил, что у той же ГК за ту же дату актуального среза нет (AURORA-2002), поэтому после записи актуальный срез по
ГК и дате ровно один — новый; архивным срезам той же ГК и даты без ссылки ставится superseded_by_snapshot_id нового
(ГК, а не ГСК — чтобы ссылку получил и срез прежней ГСК); разархивирование ссылку снимает (AURORA-2001). Если заказчик
выберет ключ «ГСК × дата» (вопрос AURORA-1397) — меняются проверка 2002 и это правило связи, схема payload — нет; производные считаются в
последний раз и замораживаются, kfo_result.is_frozen = true; сбой записи не отменяет верификацию (повтор — вопрос
заказчику, OQ); аудит записи — EX_SNAPSHOT_WRITE. Вопросы заказчику (кто архивирует, ключ ГК или ГСК, повтор при
сбое, PDF) — OQ со ссылкой на AURORA-1397.
4.4 DBML v5.26 (дописать в changelog #207)
ex_snapshot_item.item_type— +version_card;payload— «конвертcontracts/ex-payload-v1.schema.json, уprimary_document— null»;payload_schema_version—"1.0".audit_action+EX_SNAPSHOT_WRITE(разделKFO,object_type = ex_snapshot,after— номер среза, ГСК, дата, число элементов).ex_snapshot.status— «ACTUAL — не архивирован; ARCHIVE — архивирован пользователем в ЕХ» (сейчас — «предыдущие → ARCHIVE», противоречит ручному архиву). Миграция колонок не нужна; значение enum — в миграции AURORA-1560.
4.5 Вложения в Jira
После открытия PR: AURORA-1560 — схема, §14 (05-domain-rules.md), DBML; комментарий со ссылкой на PR. AURORA-2001 —
ссылка в комментарии (чтение — по той же схеме).
5. Что остаётся исполнителю плана
Точная разметка схемы ($defs, имена), тексты §14, числа примеров (из scripts/kfo_contract/kfo_example.py), какие
элементы показать примерами (минимум: kfo_balance, version_card, corrections, summary_osv).
6. Decisions made without discussion
| # | Дата | Решение | Обоснование | Цена ошибки |
|---|---|---|---|---|
| 1 | 06.11.2026 | data = замороженный ответ экрана теми же именами полей, обязательные поля — схемой, лишние допускаются |
Рендер ЕХ переиспользует экраны рабочей версии; исполнителю не надо вырезать поля | Лишние поля раздувают срез; рендер, опирающийся на необязательное поле, сломается на старом срезе |
| 2 | 06.11.2026 | vgo_pairs — агрегаты таблицы корректировок, не прежний экран «Пары ВГО» |
Это вход КФО и то, что аналитик видит в UI | Если ЕХ нужна детализация упаковки по строкам — новый тип элемента |
| 3 | 06.11.2026 | chess — «все счета» + пресет каждого правила ББ + результирующая таблица; ручной выбор счетов не замораживается |
Ручной режим — исследование, его состояние не хранится | В ЕХ нельзя посмотреть шахматку по произвольным счетам |
| 4 | 06.11.2026 | Карточка версии — новый item_type version_card с ФИО, а не колонки ex_snapshot |
DOC-274687 оставляет выбор команде; элемент не трогает схему таблицы | Фильтры ЕХ по участникам маршрута пойдут по jsonb |
| 5 | 06.11.2026 | В срез — только APPLIED корректировки (DOC-274687 предполагал и REVOKED) |
REVOKED в системе нет: корректировку меняют пересохранением (ответ Лысенко п. 9) |
История правок корректировки — только в аудите |
| 6 | 06.11.2026 | DBML-правки — в ту же неслитую v5.26, что в #207 | Одна версия на пакет КФО + ЕХ; номер не тратим | Если #207 сольют раньше и v5.26 «закроется» — перенести правки в v5.27 |
| 7 | 06.11.2026 | EX_SNAPSHOT_WRITE — раздел журнала KFO |
Раздела EX в audit_section нет; запись среза — часть верификации КФО |
Фильтр журнала по ЕХ не найдёт событие |
| 9 | 06.11.2026 | Payload покрывает и выгрузку xlsx рабочей версии (пробелы, способ сопоставления, строки ОСВ агрегатов, сводка корректировок), не только экран | Срез выгружается на лету из payload, выгрузка должна совпасть с рабочей (1562); ответ на вопрос проверки исполнителем 1 | Срез заметно больше (строки ОСВ агрегатов) |
| 10 | 06.11.2026 | data — DTO API без изменений имён и вложенности; таблица §4.2 подчинена принципу |
Рендер и выгрузка ЕХ переиспользуют виджеты и выгрузки рабочей версии без маппинга; вопрос проверки 2 | Изменение DTO API после 1.0 требует новой версии схемы или совместимого расширения |
| 11 | 06.11.2026 | Нумерация среза — по ГСК; «один актуальный» и superseded_by — по ГК и дате |
Как в DBML и DOC-274686 (решения Р-35/Р-36 по ГК); вопрос проверки 3 | При ключе «ГСК» у заказчика — правка правила связи и проверки 2002 |
| 8 | 06.11.2026 | Без отдельного согласования дизайна с владельцем: схема описана в чате 06.11 («все так»), владелец сказал «делай схему» | Срок 12.11, владелец просил не останавливаться | Расхождение с ожиданием владельца видно только в PR |