2026-11-06 23:25:40 +04:00

19 KiB
Raw Permalink Blame History

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; правила среза в §15; правки 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); quarter — "Q1"…"Q4", 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 Правила среза — §15 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 — схема, §15 (05-domain-rules.md), DBML; комментарий со ссылкой на PR. AURORA-2001 — ссылка в комментарии (чтение — по той же схеме).

5. Что остаётся исполнителю плана

Точная разметка схемы ($defs, имена), тексты §15, числа примеров (из 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
12 06.11.2026 Схема обязывает то, что читают выгрузки xlsx рабочей версии: итоги шахматки total_debit/total_credit, правило пресета и rules таблицы корректировок, pairs, balance корректировки, entry_ids строк Ревью C/I: без них выгрузка среза не совпадёт с рабочей (решение #9) Больше обязательных полей — писателю нельзя «урезать» DTO
13 06.11.2026 Проценты к меньшей стороне (шахматка, агрегаты, корректировки) — без ограничения разрядов; квартал — "Q1"…"Q4"; updated_by — Ref, как в DTO Ревью C-1, C-2, I-2: настоящие ответы API не проходили схему —
14 06.11.2026 КФО в срезе — только замороженная и VERIFIED; карточка — непустые состав и история Ревью M-1: пустой или незамороженный payload не должен проходить Срез версии без истории маршрута (миграция старых данных) схему не пройдёт
15 06.11.2026 Ошибка пресета правила (422 INVALID_RULE/ACCOUNTS_REQUIRED) — пресет пропускается; другая ошибка сборки — сбой записи среза Ревью M-5 Срез без пресета правила, которое на экране тоже не строится
8 06.11.2026 Без отдельного согласования дизайна с владельцем: схема описана в чате 06.11 («все так»), владелец сказал «делай схему» Срок 12.11, владелец просил не останавливаться Расхождение с ожиданием владельца видно только в PR