arm-ka-docs/context/04-data-model-guide.md
Andrey Epifancev 5545ee539f docs: entities-v5.15, guide, ссылки на DBML v5.15
entities-v5.15.md — копия v5.14 + «Что изменилось в v5.15» (osv_data_type NU, email в нижнем регистре, семантика
stored_file.status); 04-data-model-guide и шаблон CLAUDE.md arm-core — на v5.15; tasks.md change'а: 1.2 выполнена.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 21:27:52 +04:00

93 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 04. Как читать модель данных v5.15
Файлы: `docs/model/data-model-v5.15.dbml` (источник истины), `docs/model/entities-v5.15.md` (смысл таблиц; предыдущие
версии `data-model-v5.13.dbml` / `data-model-v5.14.dbml` и `entities-v5.13.md` / `entities-v5.14.md` остаются как история),
`docs/model/diagrams/part01…09.svg` (диаграммы v5.12 — на одну версию старше: нет `permission`/`role_permission`,
нет `document`, есть `osv_group_schema`, нет `related_group_member.kind`; читать с поправкой на changelog v5.13, v5.14 и v5.15 в шапке DBML).
## Девять частей модели
| Часть | Таблицы | Что это |
|---|---|---|
| 01 Группы и организации | `regional_office`, `company_group(+_history)`, `legal_entity(+_history)`, `legal_entity_alias`, `related_group`, `related_group_member` | справочник клиентов; SCD4 для ГК/ЮЛ, SCD2 для членства |
| 02 Пользователи и права | `app_user`, `role`, `permission`, `role_permission`, `user_role` | матрица прав как данные |
| 03 Бухгалтерские справочники | `chart_of_account`, `elimination_rule`, `elimination_rule_account`, `required_document_rule` | план счетов (seed из 1С), правила элиминации Прил. 3/4 (версионируются), чек-лист по подходу |
| 04 Файлы и распознавание | `s3_object`, `stored_file`, `document`, `recognition_job` | физический файл → задание → логические документы |
| 05 Разобранные ОСВ | `osv_entry` | строка ОСВ с шестью суммами, сырым контрагентом и резолвом |
| 06 Формы ББ/ОФР | `financial_statement_meta`, `_column`, `_line`, `_value` | шапка, колонки-даты, строки с кодами, значения с confidence |
| 07 Консолидация | `consolidation`, `consolidation_version`, `_status_history`, `_lock`, `_member`, `_document` | логическая консолидация (ГК × период) и её версии с периметром |
| 08 Корректировки и КФО | `correction`, `goodwill`, `kfo_result`, `kfo_result_line`, `kfo_result_line_company`, `client_kfo_line` | ручные решения и результат |
| 09 Комментарии, аудит, ЕХ | `comment`, `audit_event`, `ex_snapshot`, `ex_snapshot_member`, `ex_snapshot_item` | полиморфные комментарии, append-only журнал, замороженные срезы |
## Соглашения
- PK везде `uuid`; натуральные ключи — `UNIQUE` (ИНН, код счёта, crm_id, код ГСК). Для `osv_entry` и `audit_event`
допустима замена на `bigint identity` при объёмах.
- Денежные поля `numeric(18,2)`, проценты `numeric(7,4)`/`numeric(9,4)`, confidence `numeric(5,2)` (0–100).
- Временные метки `timestamptz`; отчётные даты `date`.
- Партиальные уникальные индексы (помечены в notes): `related_group_member (legal_entity_id, kind) WHERE is_current`
(v5.14: ЮЛ — не более одной текущей группы каждого вида, т.е. одна ГСК и одна ГСЗ одновременно; `kind` — денормализация
`related_group.kind`),
`consolidation_lock.consolidation_version_id WHERE released_at IS NULL`,
`document (stored_file_id, document_type, osv_account_code) NULLS NOT DISTINCT`.
- Enum'ы PostgreSQL — ровно как в DBML (`consolidation_status`, `document_status`, `audit_action` …). Добавление значения —
миграция + версия DBML.
- История: `*_history` — снимки предыдущего состояния (SCD4); `related_group_member` — версии строк (SCD2);
остальное — `audit_event(before_value, after_value)`.
- Поля `*_by` → `app_user.id`; `NULL` — системное действие.
## Что намеренно НЕ хранится (DECISION-5) и как это вычислять
| Объект | Вычисление |
|---|---|
| Сводная ОСВ | `osv_entry` актуальных `document` (OSV, CONFIRMED, период версии) всех `consolidation_member` версии; только строки `group_type = COUNTERPARTY` и `data_type IN (BU, SUM)`; строки не агрегируются |
| Признак контрагента | `counterparty_id ∈ member(version)` → ГСК; иначе `legal_entity.company_group_id = consolidation.company_group_id` → ГК; иначе Внешний |
| Пары ВГО | по `elimination_rule(_account)` версии правил `consolidation_version.elimination_rules_version` — §5 правил |
| Шахматка | агрегат пар по компаниям и выбранным наборам счетов — §6 |
| Логические проверки форм | формулы §7 по `financial_statement_value` |
| Чек-лист документов | `required_document_rule(approach) × consolidation_member − document(CONFIRMED)` |
| «Исправлено полей» | `COUNT(*) WHERE is_modified` |
| «Требует проверки» ячейка | `confidence < порог OR NOT is_recognized` |
Всё это — чистые функции от `consolidation_version_id`; результат кэшируется только в памяти запроса.
При `VERIFIED` единственный раз сериализуется в `ex_snapshot_item.payload`.
## v4 → v5.13: таблица переименований (обязательна при чтении ТЗ)
v5.14 имена таблиц и полей не менял (добавлены `related_group_member.kind` и два значения `audit_action`), v5.15 — тоже
(добавлено значение `osv_data_type.NU`), поэтому таблица справедлива и для v5.14, и для v5.15.
| В страницах ТЗ (модель v4 и старше) | В v5.13 / v5.14 / v5.15 |
|---|---|
| `stored_file.period_year / period_quarter / document_type / osv_account` | `document.period_year / period_quarter / document_type / osv_account_code / is_cumulative` |
| `stored_file.status` «Загружен / Обработка / Требуется проверка / Ошибка» | техника: `stored_file.status` UPLOADED/PROCESSING/PROCESSED/ERROR/SUPERSEDED; проверка: `document.status` RECOGNIZED/NEEDS_CHECK/CONFIRMED/ERROR |
| `stored_file.current_recognition_job_id` как источник строк | `osv_entry.document_id` / `financial_statement_meta.document_id`; `current_recognition_job_id` остаётся как «авторитетный прогон» файла |
| `osv_entry.legal_entity_id` | `osv_entry.owner_legal_entity_id` |
| `osv_entry.stored_file_id` | `osv_entry.document_id` (файл — через `document.stored_file_id`) |
| `osv_entry.group_schema_id → osv_group_schema / osv_grouping_schema` | `osv_entry.group_type` (enum) + `recognition_job.group_schema jsonb` |
| `osv_entry.counterparty_type` (ГК/ГСК/Внешний) | не хранится, вычисляется |
| `fin_report_header`, `Fin_report_rows`, `report_id`, `row_code`, `value_current/prior/prior2`, `needs_review` | `financial_statement_meta` / `_column` (`period_date`, `is_current`) / `_line.line_code` / `_value.amount, confidence, is_recognized` |
| `financial_statement_line.amount` | `financial_statement_value.amount` (строка × колонка) |
| `Consolidation_package`, `Consolidation_template`, `Company_data`, `Intercompany_reconciliation`, `vgo_pair_match`, `chess_cell`, `consolidated_osv_line` | `consolidation`/`consolidation_version`/`consolidation_member`; КФО — `kfo_result(_line)`; остальное вычисляется |
| `Company`, `Organizations`, `Organization_aliases`, `ref_crm_region`, `consolidation_group`, `group_membership` | `legal_entity`, `legal_entity_alias`, `regional_office`, `company_group`, `related_group(_member)` |
| `users` (email, role) | `app_user` + `user_role` + `role_permission` |
| `raw_result_s3_key`, `queue_msg_id` | `recognition_job.result_s3_object_id` (единственная ссылка на результат), `request_msg_id / result_msg_id` |
| `chart_of_account.account_code` | `chart_of_account.code` |
| `role.code` KA_HEAD / KA_GO_DM | `KA_RF, KA_GO, RKA, CLIENT_MANAGER, CURATOR_GO, EXPERT, ADMIN` (seed) |
| статус документа `MANUAL_CHECK` | `document.status = NEEDS_CHECK` |
| статус консолидации `CREATED` (черновик) | `INITIATED` |
## Открытые места модели (не придумывать, спросить)
- **Закрыто в v5.14:** OQ-32 (членство в ГСК и ГСЗ одновременно) — решение владельца 04.10.2026: ЮЛ в одной ГК и одновременно
в одной ГСК и одной ГСЗ (ANL-030 отменён); OQ-31 (КПП) — не вводится.
- **№2 `osv_entry.parent_entry_id`**: хранить ли все строки ОСВ (п. 11 «Парсинг ОСВ» — да) или только контрагентские;
нужно ли дерево. Рекомендация для среза 2: хранить **все** строки с `level` и `parent_entry_id` — это дёшево и
позволяет сверять «Σ контрагентов = итог счёта»; вопрос закрывать с аналитиками.
- `document.RECOGNIZED` — нужен ли статус «проверка не требуется», или всё идёт через `NEEDS_CHECK → CONFIRMED`.
- Замена по-документно (одна ОСВ из файла с пятью листами) — сейчас только файлом целиком.
- `goodwill.participation_amount` — входит ли стр. 1350 в базу (вопрос методологам).
- `user_role` M:N vs 1:1 — если ТЗ строго «одна роль», заменить на `app_user.role_id`.
- `consolidation_status` REJECTED/ARCHIVED — из макета, не из ТЗ (ANL-035).