Merge pull request 'DBML v5.25: факты качества первички (AURORA-1759)' (#203) from feat/202-quality-metrics-dbml into main
2
Makefile
@ -6,7 +6,7 @@ PY := $(if $(wildcard $(VENV)/bin/python),$(CURDIR)/$(VENV)/bin/python,python3)
|
||||
# Пусто — проверяются все change'и и спеки; `make validate-openspec CHANGE=<id>` — один change
|
||||
CHANGE ?=
|
||||
# Текущая версия модели данных — по ней рисуются диаграммы (make diagrams)
|
||||
DBML ?= model/data-model-v5.24.dbml
|
||||
DBML ?= model/data-model-v5.25.dbml
|
||||
|
||||
.PHONY: venv validate-contracts validate-openspec test-snapshot test-sync-statements sync-statements statements-check check diagrams regress
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# 03. Архитектура (целевая, по решениям DECISION-1…5 и ARCH-* в DBML v5.24)
|
||||
# 03. Архитектура (целевая, по решениям DECISION-1…5 и ARCH-* в DBML v5.25)
|
||||
|
||||
## Компоненты (= репозитории, см. `00-workspace-layout.md`)
|
||||
|
||||
@ -213,15 +213,19 @@ advisory-lock по `(ЮЛ, sha256)` (двойной клик не проскак
|
||||
|
||||
**Один бакет** (`OPENBAO__MINIO__MINIO_BUCKET` шаблона); роль объекта — первый сегмент ключа:
|
||||
`{bucket_role}/{file_id}/{job_id}/{name}`. Роли: `uploads` (исходники, срок — весь срок хранения), `results`
|
||||
(нормализованные JSON; ретеншн — ARCH-010, открыт), `exports` (7 дней), `archive` (data lake). Все объекты регистрируются
|
||||
в `s3_object` (`bucket_role`, `bucket`, `key`, sha256, size, expires_at). Сырой ответ OCR `raw/{job_id}.json` — по
|
||||
конвенции, без записи в БД. Lifecycle-правила — по префиксам.
|
||||
(нормализованные JSON; ретеншн — ARCH-010, открыт), `exports` (7 дней), `archive` (data lake), **`raw`** (v5.25,
|
||||
AURORA-1759: сырой ответ ИС Сканирование `raw/{job_id}.json` — теперь регистрируется в `s3_object` через
|
||||
`recognition_job.raw_s3_object_id`; `expires_at` не ставится при удалении файла — вход для эталонного прогона
|
||||
метрик качества, срок хранения — OQ-179). Все объекты регистрируются в `s3_object` (`bucket_role`, `bucket`, `key`,
|
||||
sha256, size, expires_at). Lifecycle-правила — по префиксам.
|
||||
|
||||
Срез 2c: ядро кладёт исходник по ключу `uploads/{file_id}/{job_id}/{безопасное имя}` (`job_id` задаётся заранее — ключ
|
||||
известен до записи в БД; имя очищается от путей и управляющих символов); `results/{file_id}/{job_id}/…` пишет сервис
|
||||
распознавания, а ядро перед чтением проверяет, что ключ лежит именно в папке задания (OQ-70). При удалении файла объектам
|
||||
`uploads` и `results` проставляется `s3_object.expires_at = now()`, физически они не стираются (ретеншн — OQ-111, ждёт
|
||||
lifecycle-правил платформы); объект, записанный в S3 до сбоя БД, остаётся сиротой (то же правило).
|
||||
lifecycle-правил платформы); объект, записанный в S3 до сбоя БД, остаётся сиротой (то же правило). **v5.25:** исключение —
|
||||
объект роли `raw` и объект `uploads`, на который ссылается `quality_intake_fact`: `expires_at` им не ставится вовсе
|
||||
(вход для эталонного прогона метрик качества, срок — OQ-179).
|
||||
|
||||
## Аутентификация и авторизация
|
||||
|
||||
@ -251,7 +255,7 @@ api/src/
|
||||
# машины статусов, policy — pydantic-модели на входе и выходе
|
||||
services/ # use-cases: оркестрация domain + repositories + outbox + audit_event
|
||||
repositories/ # SQLAlchemy-запросы, в т. ч. запросы-вычисления (сводная ОСВ, шахматка)
|
||||
models/ # ORM 1:1 с DBML v5.24; имена таблиц/колонок/enum — как в DBML
|
||||
models/ # ORM 1:1 с DBML v5.25; имена таблиц/колонок/enum — как в DBML
|
||||
schemas/ # pydantic DTO API /api/v1
|
||||
core/ # config, clients (S3; NATS outbox-publisher и result-consumer), auth (JWT РАИСА / dev-эмитент),
|
||||
# logger, exception_handlers
|
||||
@ -341,7 +345,11 @@ FastAPI» платформы РАИСА/aurora): дерево импортиро
|
||||
`version_table_schema` и `include_name` Alembic). Следуем шаблону, не `public`.
|
||||
- Alembic берёт URL из настроек, не из `alembic.ini`; ревизии — `api/alembic/versions/`, имя файла стандартное
|
||||
`<rev>_<slug>.py`. Автогенерация — только черновик: итоговую ревизию сверяет с DBML `api/scripts/check_dbml_vs_orm.py`.
|
||||
- PK везде `uuid` через `UUIDPrimaryMixin`; имена таблиц, колонок и enum'ов — ровно как в DBML v5.24.
|
||||
- PK везде `uuid` через `UUIDPrimaryMixin`; имена таблиц, колонок и enum'ов — ровно как в DBML v5.25.
|
||||
- **v5.25 (AURORA-1759):** факты качества первички (`quality_*_fact`) — в отдельной схеме PostgreSQL `dkb_metrics`
|
||||
(имя — настройка), той же БД, миграции — общей цепочкой Alembic с `dkb`. Платформенный Superset читает её отдельной
|
||||
ролью БД **только на чтение** (создаёт платформа); arm-core не пишет код для Superset и не выдаёт ему прав сверх
|
||||
`GRANT SELECT` на эту схему.
|
||||
|
||||
### Инфраструктурные клиенты
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
# 04. Как читать модель данных v5.24
|
||||
# 04. Как читать модель данных v5.25
|
||||
|
||||
Файлы: `docs/model/data-model-v5.24.dbml` (источник истины), `docs/model/entities-v5.24.md` (смысл таблиц; предыдущие
|
||||
Файлы: `docs/model/data-model-v5.25.dbml` (источник истины), `docs/model/entities-v5.25.md` (смысл таблиц; предыдущие
|
||||
версии `data-model-v5.13…v5.20.dbml` и `entities-v5.13…v5.20.md` остаются как история),
|
||||
`docs/model/diagrams/part01…09.{svg,png}` (диаграммы v5.21 по частям из таблицы ниже; перерисовываются из DBML командой
|
||||
`docs/model/diagrams/part01…10.{svg,png}` (диаграммы v5.25 по частям из таблицы ниже; перерисовываются из DBML командой
|
||||
`make diagrams` в корне репозитория docs — скрипт `scripts/gen_model_diagrams.py`, нужен npx; при новой версии DBML
|
||||
обновить `DBML` в Makefile, а новую таблицу — добавить в раскладку частей скрипта и в эту таблицу).
|
||||
|
||||
## Девять частей модели
|
||||
## Десять частей модели
|
||||
|
||||
| Часть | Таблицы | Что это |
|
||||
|---|---|---|
|
||||
@ -19,6 +19,11 @@
|
||||
| 07 Консолидация | `consolidation`, `consolidation_version`, `_status_history`, `_lock`, `_member`, `_document` | логическая консолидация (ГК × период) и её версии с периметром |
|
||||
| 08 Корректировки и КФО | `correction`, `vgo_assignment`, `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 журнал, замороженные срезы |
|
||||
| 10 Метрики качества первички | `quality_intake_fact`, `quality_outcome_fact`, `quality_failure_fact` | факты распознавания и исхода документа, технические отказы — append-only, без FK |
|
||||
|
||||
**v5.25:** три таблицы фактов качества распознавания (`quality_intake_fact`/`_outcome_fact`/`_failure_fact`),
|
||||
`s3_bucket_role.raw`, `stored_file.is_scan`, `recognition_job.raw_s3_object_id`, `permission_object.QUALITY_METRICS`
|
||||
(AURORA-1759).
|
||||
|
||||
**v5.24:** новая таблица `vgo_assignment` — ручное решение аналитика по строке сводной ОСВ сверх автоматического разнесения по правилам ВГО (§5): привязка к правилу / снятие, «не учитывать в КФО» у нераспределённой строки (AURORA-1751).
|
||||
|
||||
|
||||
@ -1222,7 +1222,7 @@ attempt+1») устарела — исправить в следующей ве
|
||||
как у ОСВ (§3 п. 1, §9.1): ББ/ОФР за квартал версии (`Q1` — только версии за `Q1`, R-14a Среза 4).
|
||||
5. **Удаление** (`DELETE /files/{id}`, `DOCUMENT_EDIT`): запрещено, если у файла есть документ, подтверждённый пользователем (`confirmed_by` не NULL), или автоподтверждённый документ привязан к версии вне `INITIATED`/`DOCUMENTS_PROCESSING`/`DATA_CORRECTION` (`FILE_HAS_CONFIRMED_DOCUMENTS`; OQ-157, уточняет OQ-110); привязки автоподтверждённых документов снимаются, статус версий не меняется, `FILE_DELETE.after_value.unbound_version_ids`; запрещено также, если файл заменил другие (`FILE_SUPERSEDES_OTHERS`); `SUPERSEDED` файл удалить
|
||||
можно. Удаляются строки, документы (вместе с данными форм `financial_statement_*` и комментариями документов), задания и `stored_file`; объектам S3 ставится `expires_at = now()` (физически не
|
||||
стираются — OQ-111); аудит `FILE_DELETE` с карточкой файла в `before_value`. **OQ-110 закрыт для Среза 4:** к версии
|
||||
стираются — OQ-111) — **кроме** объекта роли `raw` и объекта `uploads`, на который ссылается `quality_intake_fact` (`upload_s3_key`): им `expires_at` не ставится вовсе, срок — OQ-179 (§14); аудит `FILE_DELETE` с карточкой файла в `before_value`. **OQ-110 закрыт для Среза 4:** к версии
|
||||
привязываются только `CONFIRMED` документы, а файл с таким документом удалить нельзя — удалить файл с документом в
|
||||
версии невозможно; расширять удаление не требуется (уточнено OQ-157: для автоподтверждённых документов — см. выше).
|
||||
6. **Аудит.** `FILE_UPLOAD`, `FILE_REPLACE`, `FILE_DELETE`, `FILE_REPROCESS` (п. 13, v5.21), `DOCUMENT_CONFIRM` (раздел
|
||||
@ -1382,15 +1382,17 @@ attempt+1») устарела — исправить в следующей ве
|
||||
|
||||
## §10. Роли и матрица прав (ТЗ 8.1, DOC-036960) — seed для `role_permission`
|
||||
|
||||
| Роль (`role.code`) | DIRECTORY | DOCUMENT | CONSOLIDATION | KFO | EX | EXPORT | USERS | AUDIT |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| ADMIN | VIEW, EDIT, DELETE, ADMIN (импорт) | — | — | — | VIEW | — | ADMIN | VIEW |
|
||||
| CURATOR_GO (Куратор КП ГО) | VIEW, EDIT (ГК: создание, перезакрепление) | — | VIEW (по закреплённым ГК) | VIEW | VIEW | — | — | — |
|
||||
| KA_RF | VIEW (свой РФ), EDIT (состав ГСК своей ГК) | VIEW, EDIT (загрузка, правка, подтверждение) | VIEW, EDIT (INITIATED…CONSOLIDATION_RF) | VIEW, EXPORT | VIEW | EXPORT | — | — |
|
||||
| RKA (РКА РФ) | VIEW, EDIT (состав ГСК в рамках корректировки) | VIEW | VIEW, EDIT (VERIFICATION_RF) | VIEW, APPROVE | VIEW | EXPORT | — | — |
|
||||
| KA_GO | VIEW, EDIT (состав ГСК, без ограничения по филиалу) | VIEW, EDIT | VIEW, EDIT (всё, что KA_RF + CONSOLIDATION_GO) | VIEW, VERIFY (№/дата УОБ), EXPORT | VIEW | EXPORT | — | — |
|
||||
| EXPERT | VIEW | VIEW | VIEW | VIEW | VIEW | — | — | — |
|
||||
| CLIENT_MANAGER | VIEW (свои клиенты) | VIEW, EDIT (только загрузка по своей ГК) | VIEW (статус) | VIEW | — | — | — | — |
|
||||
| Роль (`role.code`) | DIRECTORY | DOCUMENT | CONSOLIDATION | KFO | EX | EXPORT | USERS | AUDIT | QUALITY_METRICS |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| ADMIN | VIEW, EDIT, DELETE, ADMIN (импорт) | — | — | — | VIEW | — | ADMIN | VIEW | VIEW |
|
||||
| CURATOR_GO (Куратор КП ГО) | VIEW, EDIT (ГК: создание, перезакрепление) | — | VIEW (по закреплённым ГК) | VIEW | VIEW | — | — | — | VIEW |
|
||||
| KA_RF | VIEW (свой РФ), EDIT (состав ГСК своей ГК) | VIEW, EDIT (загрузка, правка, подтверждение) | VIEW, EDIT (INITIATED…CONSOLIDATION_RF) | VIEW, EXPORT | VIEW | EXPORT | — | — | VIEW |
|
||||
| RKA (РКА РФ) | VIEW, EDIT (состав ГСК в рамках корректировки) | VIEW | VIEW, EDIT (VERIFICATION_RF) | VIEW, APPROVE | VIEW | EXPORT | — | — | VIEW |
|
||||
| KA_GO | VIEW, EDIT (состав ГСК, без ограничения по филиалу) | VIEW, EDIT | VIEW, EDIT (всё, что KA_RF + CONSOLIDATION_GO) | VIEW, VERIFY (№/дата УОБ), EXPORT | VIEW | EXPORT | — | — | VIEW |
|
||||
| EXPERT | VIEW | VIEW | VIEW | VIEW | VIEW | — | — | — | VIEW |
|
||||
| CLIENT_MANAGER | VIEW (свои клиенты) | VIEW, EDIT (только загрузка по своей ГК) | VIEW (статус) | VIEW | — | — | — | — | VIEW |
|
||||
|
||||
Право `QUALITY_METRICS_VIEW` (объект `QUALITY_METRICS`, §14; метрики качества первички) seed выдаёт всем семи ролям; всего в seed 17 кодов прав.
|
||||
|
||||
Policy-слой (не права): KA_RF/RKA/CLIENT_MANAGER видят только ГК своего `regional_office`; редактирование версии — только в
|
||||
допустимом статусе и при отсутствии чужой активной `consolidation_lock`; ЗО (`business_segment`) — фильтр видимости.
|
||||
@ -2102,3 +2104,90 @@ Excel — §11.2, раскладка — §11.3, строки — §11.4, зна
|
||||
`43b4b80`. Ссылки «§12 п. N» в старых документах: п. 1 → §11.2 п. 1; п. 2 → §11.3 п. 1; п. 3 → §11.3 п. 7; п. 4 → §11.3
|
||||
п. 3, п. 6; п. 5 → §11.2 п. 3, §11.4, §11.5; п. 6 → §11.2 п. 2; п. 7 → §7, §11.8; п. 8 → §11.7 п. 1; п. 9 → §11.2 п. 4;
|
||||
п. 10 → §11.9; п. 11 → §11.11.
|
||||
|
||||
---
|
||||
|
||||
## §14. Метрики качества первички (AURORA-1759; модель — `model/data-model-v5.25.dbml`, таблицы `quality_*_fact`)
|
||||
|
||||
Полное WHY, кому и зачем — `../arm-core/openspec/changes/quality-metrics/design.md` §1-3, §10 (решения владельца
|
||||
27.10.2026, подтверждено 05.11.2026). Здесь — только алгоритм подсчёта и атрибуции, на который ссылается код ядра
|
||||
(`§14.N` в докстринге).
|
||||
|
||||
### §14.1. Какие документы считаются
|
||||
|
||||
Факт `quality_intake_fact`/`quality_outcome_fact` пишется на документ типа `BALANCE`, `INCOME`, `OSV`.
|
||||
`DISCLOSURE`/`OTHER` факт не получают (это расшифровки и прочие документы — не форма с правилами подсчёта).
|
||||
|
||||
Для `OSV` `payload` обоих фактов **не содержит `lines`/`values`** — построчного снимка нет (правок сумм ОСВ в ядре
|
||||
нет, §14.2 для ОСВ не применяется, кроме строки «Период / счёт ОСВ»); вместо них — счётчики строк и предупреждения
|
||||
`OSV_*` (`osv_warnings`). Для `BALANCE`/`INCOME` `payload` содержит `lines`/`values` построчно.
|
||||
|
||||
### §14.2. Атрибуция правки (сервис / наш разбор)
|
||||
|
||||
Правка — отличие подтверждённого результата от снимка приёма (`quality_intake_fact.payload`). Правило одно: **верный
|
||||
ответ есть в сыром тексте сервиса — ошибка наша; нет — ошибка сервиса.** Для Excel сервис разбора — наш
|
||||
tabular-parser, поэтому у Excel любая ошибка распознавания — «наш разбор» (источник правды — design arm-core#190 §5):
|
||||
|
||||
| Что правили | «Наш разбор», если | Иначе |
|
||||
|---|---|---|
|
||||
| Сумма | цифры подтверждённой суммы (без знака) совпадают с цифрами сырого текста после замены букв-двойников §11.3 — сервис прочитал верно, а мы неверно разобрали (знак, скобки, разряды, мусор по краям) | сервис |
|
||||
| Код строки | подтверждённый код есть среди кодов, извлекаемых из `line_code_text` (в т. ч. одна из частей склейки `1250\n1260`) | сервис |
|
||||
| Добавленная строка (`row_index IS NULL`) | её код есть в наборе кодов сырого ответа (для PDF — четырёхзначные токены, стоящие отдельной строкой в тексте ячеек `raw/{job_id}.json`, извлечённые при приёме; для Excel — всегда «наш разбор») | сервис |
|
||||
| Шапка: период, ИНН, единицы, наименование | подтверждённое значение извлекается из `header_source[*].text` | сервис |
|
||||
| Дата колонки | подтверждённая дата извлекается из подписи колонки (`label`) | сервис |
|
||||
| Период / счёт ОСВ | всегда «наш разбор» (Excel) | — |
|
||||
|
||||
Правка «Дата колонки» считается вместе с «Шапкой»: обе пишутся как `fixes_header_service`/`fixes_header_ours`
|
||||
(`quality_outcome_fact`) и как `fixes[].field = "header"` (`quality-facts.schema.json`) — отдельного счётчика для
|
||||
колонки нет, это та же структурная область документа, что и шапка.
|
||||
|
||||
Сравнение — чистая функция (без БД), тем же кодом, что разбирал сервис (`arm_statements`: `fix_lookalikes`,
|
||||
`parse_amount`, `parse_code`, `parse_date`, `default_rules`). Только два источника правки — «сервис» и «наш разбор»;
|
||||
«документ клиента» (§14.4) — свойство исхода, не правки.
|
||||
|
||||
### §14.3. Причина документа (`quality_outcome_fact.primary_cause`)
|
||||
|
||||
Каждый документ с исходом попадает ровно в одну ячейку матрицы, по первому сработавшему правилу (приоритет
|
||||
убывает сверху вниз):
|
||||
|
||||
1. `outcome ∈ {DELETED, SUPERSEDED, DELETED_AFTER_CONFIRM, SUPERSEDED_AFTER_CONFIRM}` → `primary_cause = NULL`,
|
||||
отдельный столбец «удалён/заменён (до/после подтверждения)» — в доли матрицы не входит;
|
||||
2. есть правки «сервис» (§14.2) → `SERVICE_ERROR`;
|
||||
3. есть правки «наш разбор» → `OUR_ERROR`;
|
||||
4. подтверждён с акцептом нарушений (§14.4) → `CLIENT_DOCUMENT`;
|
||||
5. `outcome = AUTO_CONFIRMED` → `WITHOUT_PARTICIPATION`;
|
||||
6. `outcome = CONFIRMED` без правок → `AS_IS`.
|
||||
|
||||
Знаменатель долей — документы с `outcome ∈ {AUTO_CONFIRMED, CONFIRMED}`. Документы без исхода (нет
|
||||
`quality_outcome_fact`) — отдельный столбец «в работе», в доли не входит.
|
||||
|
||||
У документа может быть несколько фактов `quality_outcome_fact` во времени (переподтверждение ОСВ после правки,
|
||||
исход `*_AFTER_CONFIRM` поверх прежнего, §1.5 модели — `document_id` там не unique). Правило этого параграфа
|
||||
применяется к **последнему** факту по `outcome_at`; более ранние факты того же документа в матрицу не входят.
|
||||
|
||||
### §14.4. «Документ клиента»
|
||||
|
||||
Не правка, а исход: подтверждён **вручную** (не `AUTO_CONFIRMED`) с акцептом нарушенных **жёстких** проверок §7
|
||||
(`checks_accepted = true`), и нарушенное соотношение не закрыто правками. Мягкие нарушения (в т. ч. «в пределах
|
||||
округления» и межформенная 1370↔2400) не учитываются — подтверждение они не блокируют и в основном шум округления.
|
||||
Если часть нарушений закрыта правками, а остальные акцептованы — у документа одновременно есть и правки (§14.2), и
|
||||
`CLIENT_DOCUMENT`; приоритет §14.3 отдаёт ячейку правкам (`SERVICE_ERROR`/`OUR_ERROR` стоят выше `CLIENT_DOCUMENT`).
|
||||
|
||||
### §14.5. Технические отказы
|
||||
|
||||
`quality_failure_fact` пишется при переходе `recognition_job.status` в `error`/`timeout`/`dlq` и при неповторяемой
|
||||
ошибке маппинга (`MappingFatal`, файл → `ERROR`). Считаются **по файлам**, не по документам (у отказавшего файла
|
||||
документов и типа нет): знаменатель — «отказавшие файлы от загруженных файлов того же `pipeline`», отдельная доля,
|
||||
не складывается с долями §14.3 в 100%; фильтр по типу документа на отказы не действует.
|
||||
|
||||
`FILE_REPROCESS` (повторная обработка файла, новое `recognition_job` с `attempt + 1`): отказ первой попытки остаётся
|
||||
фактом `quality_failure_fact`, документы успешной попытки получают свои `quality_intake_fact`/`quality_outcome_fact`
|
||||
по новому `job_id`/`attempt` — один файл может быть и в отказах, и в исходах (виден по `file_id`), это ожидаемо, не
|
||||
двойной учёт одного события.
|
||||
|
||||
### §14.6. Признак скана (`stored_file.is_scan`)
|
||||
|
||||
Определяется при загрузке PDF по наличию текстового слоя (шрифтов в PDF). ASSUMPTION: PDF со скрытым OCR-слоем
|
||||
считается цифровым (`is_scan = false`) — слой есть, но получен постобработкой, а не исходно цифровым документом;
|
||||
различить программно эти два случая без эвристик за пределами среза не планируется. Для не-PDF (`pipeline = tabular`)
|
||||
`is_scan = NULL`.
|
||||
|
||||
@ -183,3 +183,4 @@
|
||||
| OQ-175 | Процент расхождения шахматки при отрицательной меньшей стороне: `variance_pct = variance / min(amount_a, amount_b) * 100` при отрицательном сальдо (возможно по §1) уходит в минус — пара (100, −5) даёт −2100 %, порог > 5 % не срабатывает, пара не подсвечивается. Считать от `\|min\|`, от меньшей по модулю стороны или подсвечивать пары с разными знаками всегда? | ревью arm-core #165 (AURORA-1651), 22.10.2026 | §6, шахматка, xlsx | открыт; до решения — как в коде (min со знаком); у пар ВГО §5 суммы сторон тоже со знаком (решение владельца 23.10.2026), но при `min ≤ 0` процент не считается и тройка подсвечивается |
|
||||
| OQ-176 | Счёт `000` «Вспомогательный» (технический счёт 1С для ввода остатков, `kind = AP`, `is_off_balance = false`) входит в шахматку «все счета». Исключать его вместе с забалансовыми? | ревью arm-core #165 (AURORA-1651), 22.10.2026 | §6, режим «все счета» | открыт; до решения — входит (решение владельца 22.10.2026: не трогать) |
|
||||
| OQ-178 | Порог превышения отклонения агрегата в таблице корректировок — ровно 5 % в допуске (строго `>`) или на проверку («от 5 % включительно», как читается DOC-272613/ТЗ)? Аналитик (Лысенко) на прямой вопрос не отвечал | `dev/api-contract-corrections.md` §2; R-34/R-35 (`arm-core`, `openspec/changes/corrections-table-ui/design.md`) | §5 п. 2a, §8 «Корректировка», экран «Таблица корректировок» | открыт; реализовано строго `>` 5 % (R-35, `domain/corrections.py`) — фронт и сервер синхронны между собой, но не точно со спорным текстом ТЗ; правка при подтверждении — один оператор в `editorModel.ts`/`CorrectionTable.tsx` и в `domain/corrections.py` |
|
||||
| OQ-179 | Срок хранения сырых ответов ИС Сканирование (`raw/{job_id}.json`, роль `s3_bucket_role.raw`) и подтверждённых `uploads/`, на которые ссылаются факты качества (`quality_intake_fact`/`quality_outcome_fact`): эталонный прогон перенормализации использует их неопределённо долго, пока change `quality-metrics` не отменён | `openspec/changes/quality-metrics/design.md` §1.1; `arm-core/openspec/changes/quality-metrics/design.md` §9 | §14, ретеншн S3 (решает платформа) | открыт; до решения — `expires_at` не ставится ни одному из этих объектов (05.11.2026) |
|
||||
|
||||
109
contracts/metrics/quality-facts.schema.json
Normal file
@ -0,0 +1,109 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "arm-ka/quality-facts/v1",
|
||||
"title": "Payload фактов качества распознавания первички (AURORA-1759)",
|
||||
"description": "Структура jsonb-столбца payload таблиц quality_intake_fact и quality_outcome_fact (model/data-model-v5.25.dbml, context/05-domain-rules.md §14). quality_failure_fact не описан здесь — у него нет payload, все поля плоские. НЕ валидируется make check / scripts/validate_contracts.py: этот скрипт жёстко завязан на три сообщения NATS-контракта распознавания (request-/result-message-/result- примеры с дедупом и версией сообщения); payload фактов не ходит по NATS и не требует той же идемпотентности. Схему проверяет тест в arm-core, где payload формируется (см. openspec/changes/quality-metrics/design.md §2 этого репозитория).",
|
||||
"$defs": {
|
||||
"money": {
|
||||
"type": ["string", "null"],
|
||||
"pattern": "^-?\\d+(\\.\\d{1,2})?$",
|
||||
"description": "Decimal как строка (как contracts/recognition-result.schema.json#/$defs/money) — деньги не float"
|
||||
},
|
||||
"intake-payload": {
|
||||
"type": "object",
|
||||
"description": "Снимок документа на момент приёма результата (до подтверждения). Для OSV — без lines/values, только osv_warnings (взаимоисключение — см. dependentSchemas ниже).",
|
||||
"dependentSchemas": {
|
||||
"osv_warnings": {
|
||||
"not": { "anyOf": [{ "required": ["lines"] }, { "required": ["values"] }] }
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"header": {
|
||||
"type": "object",
|
||||
"description": "header_source и распознанные поля шапки (period, inn, units, organization_name, …)",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"lines": {
|
||||
"type": "array",
|
||||
"description": "Отсутствует для document_type = OSV",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["ref", "line_status"],
|
||||
"properties": {
|
||||
"ref": { "type": "string" },
|
||||
"row_index": { "type": ["integer", "null"] },
|
||||
"line_code": { "type": ["string", "null"] },
|
||||
"line_code_text": { "type": ["string", "null"] },
|
||||
"line_status": { "enum": ["ok", "unreadable", "missing", "detail"] },
|
||||
"needs_review": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"values": {
|
||||
"type": "array",
|
||||
"description": "Отсутствует для document_type = OSV",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["line_ref", "column"],
|
||||
"properties": {
|
||||
"line_ref": { "type": "string" },
|
||||
"column": { "type": "string" },
|
||||
"amount": { "$ref": "#/$defs/money" },
|
||||
"string_value": { "type": ["string", "null"] },
|
||||
"source_text": { "type": ["string", "null"] },
|
||||
"confidence": { "type": ["number", "null"] },
|
||||
"is_recognized": { "type": ["boolean", "null"] },
|
||||
"needs_review": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["code"],
|
||||
"properties": {
|
||||
"code": { "type": "string" },
|
||||
"level": { "enum": ["relation", "soft", "warning", "info"] }
|
||||
}
|
||||
}
|
||||
},
|
||||
"raw_line_codes": {
|
||||
"type": "array",
|
||||
"description": "Только PDF: четырёхзначные токены сырого ответа ИС, стоящие отдельной строкой — вход для §14.2 (добавленная строка)",
|
||||
"items": { "type": "string", "pattern": "^\\d{4}$" }
|
||||
},
|
||||
"osv_warnings": {
|
||||
"type": "array",
|
||||
"description": "Только для document_type = OSV, вместо lines/values",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"outcome-payload": {
|
||||
"type": "object",
|
||||
"description": "Подтверждённое состояние (то же строение header/lines/values, что и intake-payload) плюс список правок",
|
||||
"properties": {
|
||||
"header": { "$ref": "#/$defs/intake-payload/properties/header" },
|
||||
"lines": { "$ref": "#/$defs/intake-payload/properties/lines" },
|
||||
"values": { "$ref": "#/$defs/intake-payload/properties/values" },
|
||||
"fixes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["field", "after", "source", "rule"],
|
||||
"properties": {
|
||||
"field": { "enum": ["value", "code", "added_row", "header", "osv_period_account"], "description": "header покрывает и правку даты колонки — §14.2 считает их вместе" },
|
||||
"before_raw": { "type": ["string", "null"], "description": "сырой текст сервиса на этом поле, если был" },
|
||||
"before_recognized": { "description": "как было распознано до правки" },
|
||||
"after": { "description": "подтверждённое значение" },
|
||||
"source": { "enum": ["service", "ours"], "description": "§14.2 — только два источника правки" },
|
||||
"rule": { "type": "string", "description": "строка таблицы §14.2, которая сработала" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$comment": "Корневая схема не инстанцируется напрямую: тест в arm-core валидирует quality_intake_fact.payload против #/$defs/intake-payload и quality_outcome_fact.payload против #/$defs/outcome-payload (не oneOf — оба $defs допускают пустой объект, и oneOf отверг бы его как совпавший с обоими)."
|
||||
}
|
||||
327
docs/superpowers/plans/2026-11-05-quality-metrics-dbml.md
Normal file
@ -0,0 +1,327 @@
|
||||
# Метрики качества первички — модель данных (DBML v5.25) Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Добавить в модель данных DBML v5.25 три таблицы фактов качества распознавания первички, связанные
|
||||
перечисления и столбцы, контракт payload и правило подсчёта/атрибуции в `05-domain-rules.md` §14 — так, чтобы
|
||||
`arm-core` могло написать по ним миграцию и ORM без дальнейших решений об именах или типах.
|
||||
|
||||
**Architecture:** Чисто документный change в `arm-ka-docs`: новая версия DBML (копия v5.24 + диффы), её
|
||||
человекочитаемое описание (`entities-v5.25.md`), алгоритм (`05-domain-rules.md` §14), контракт payload
|
||||
(JSON Schema) и обновление диаграмм/гида. Данных и кода здесь нет — читатель этого change — исполнитель
|
||||
`arm-core/openspec/changes/quality-metrics`.
|
||||
|
||||
**Tech Stack:** DBML (dbdiagram.io синтаксис), Markdown, JSON Schema Draft 2020-12, Python (`scripts/gen_model_diagrams.py`,
|
||||
`scripts/validate_contracts.py`), `make` (`diagrams`, `check`), Node/npx (`dbml-renderer`, `resvg`) — только для диаграмм.
|
||||
|
||||
**Spec:** `openspec/changes/quality-metrics/{proposal,design}.md` (этот репозиторий); контекст решений и WHY —
|
||||
`../arm-core/openspec/changes/quality-metrics/design.md` (не копируется, только читается).
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- DBML — единственный источник имён и структур; расхождение с кодом решается в пользу DBML (`../CLAUDE.md`).
|
||||
- Версия DBML меняется только вперёд, с записью в changelog в шапке файла (`../CLAUDE.md`, «Чего не делать»).
|
||||
- Факты — append-only, без FK на рабочие таблицы (design §1.4–1.6).
|
||||
- Язык документов и идентификаторов — русский текст / английские имена, как в остальной DBML.
|
||||
- `openspec validate --strict` должен проходить без ошибок к концу последней задачи.
|
||||
- `docs/source/**` не редактируется (не затрагивается этим change).
|
||||
|
||||
## Review Focus
|
||||
|
||||
- **OSV-документы получают `quality_intake_fact` без построчного снимка** (`payload` без `lines`/`values`, только
|
||||
счётчики и `osv_warnings[]`) — если это не сказано явно и одинаково в entities.md, домен-правилах и схеме контракта,
|
||||
читающий код в `arm-core` заполнит `lines: []` вместо того, чтобы не писать их — задача 2 и 4 должны явно повторить
|
||||
эту оговорку, не только задача 1.
|
||||
- **`quality_outcome_fact.document_id` не unique** — у документа может быть несколько исходов (переподтверждение ОСВ,
|
||||
`*_AFTER_CONFIRM`); без явного индекса-подсказки и фразы «метрики берут последний по `outcome_at`» в тексте таблицы
|
||||
читатель DBML предположит один факт на документ, как у `quality_intake_fact`.
|
||||
- **Старая заметка `recognition_job`** «сырой ответ ИС Сканирование… в БД не регистрируется» прямо противоречит новому
|
||||
`raw_s3_object_id` — задача 1 должна отредактировать этот текст в Note самой таблицы, а не только добавить столбец.
|
||||
- **`make diagrams` жёстко проверяет полноту `PARTS`** (`sys.exit` при несовпадении множества таблиц) — не
|
||||
зафиксировано, что проверка пройдёт, если забыть одну из трёх новых таблиц или опечатать имя; задача 1 обязана
|
||||
прогнать `make diagrams` и показать, что он не падает, а не только отредактировать словарь на глаз.
|
||||
- **`quality-facts.schema.json` сознательно не подключается к `validate_contracts.py`** (design §2) — без явной
|
||||
строки в самом файле схемы (`"description"` верхнего уровня) читатель контракта через полгода предположит, что
|
||||
`make check` его проверяет, и не заметит, что сломал JSON без предупреждения.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: DBML v5.25 — таблицы фактов, перечисления, изменённые столбцы
|
||||
|
||||
**Files:**
|
||||
- Create: `model/data-model-v5.25.dbml` (копия `model/data-model-v5.24.dbml` + диффы ниже)
|
||||
- Modify: `Makefile:9` (`DBML ?= model/data-model-v5.25.dbml`)
|
||||
- Modify: `scripts/gen_model_diagrams.py` (словарь `PARTS`: новая часть `10_quality_metrics`)
|
||||
- Modify: `context/04-data-model-guide.md` (строка 1–7 — имена файлов и диапазон частей; раздел «Девять частей
|
||||
модели» → «Десять частей модели» с новой строкой; новый абзац `**v5.25:** …` в начале списка изменений)
|
||||
|
||||
**Interfaces:**
|
||||
- Produces (имена, на которые ссылаются задачи 2–4 и `arm-core`): enum `s3_bucket_role.raw`,
|
||||
`permission_object.QUALITY_METRICS`, `recognition_pipeline` (переиспользуется, без изменений), новые enum
|
||||
`quality_outcome`, `quality_cause`, `quality_failure_kind` (значения — design §1.3); таблицы
|
||||
`quality_intake_fact`, `quality_outcome_fact`, `quality_failure_fact` (точный список столбцов — design §1.4–1.6);
|
||||
новые столбцы `stored_file.is_scan`, `recognition_job.raw_s3_object_id`.
|
||||
|
||||
- [ ] **Step 1: Скопировать DBML и поднять версию**
|
||||
|
||||
```bash
|
||||
cp model/data-model-v5.24.dbml model/data-model-v5.25.dbml
|
||||
```
|
||||
Поменять заголовок (строка 1: `v5.24` → `v5.25`) и вставить новый блок changelog в начало (после строки 1, перед
|
||||
блоком `v5.24`) по образцу существующих блоков (см. `v5.24`/`v5.23` в шапке файла):
|
||||
```
|
||||
// v5.25 (AURORA-1759, RSHB/arm-ka-docs#202; миграция в arm-core — отдельный change arm-core#190):
|
||||
// 1. Три новые таблицы фактов качества распознавания первички: quality_intake_fact, quality_outcome_fact,
|
||||
// quality_failure_fact (отдельная схема dkb_metrics, append-only, без FK на рабочие таблицы) — design §1.4-1.6.
|
||||
// 2. s3_bucket_role: + raw (сырой ответ ИС Сканирование, не экспирится с файлом); recognition_job.raw_s3_object_id
|
||||
// — ссылка на него (отменяет решение v5.13 «сырой ответ в БД не регистрируется»).
|
||||
// 3. stored_file.is_scan — признак скан/цифровой PDF (NULL для не-PDF).
|
||||
// 4. permission_object: + QUALITY_METRICS (право QUALITY_METRICS_VIEW — seed в arm-core).
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Enum `s3_bucket_role` — добавить `raw`**
|
||||
|
||||
В блоке `Enum s3_bucket_role { uploads results exports archive }` добавить строку
|
||||
`raw [note: 'сырой ответ ИС Сканирование, raw/{job_id}.json; не экспирится с файлом — вход для эталонного прогона (OQ-111)']`.
|
||||
|
||||
- [ ] **Step 3: Enum `permission_object` — добавить `QUALITY_METRICS`**
|
||||
|
||||
В блоке `Enum permission_object { ... }` добавить `QUALITY_METRICS [note: 'метрики качества распознавания первички']`.
|
||||
|
||||
- [ ] **Step 4: Три новых enum для фактов**
|
||||
|
||||
Вставить перед `Table quality_intake_fact` (после существующего `Enum recognition_pipeline`, рядом по смыслу)
|
||||
точные блоки `quality_outcome`, `quality_cause`, `quality_failure_kind` — текст design §1.3 (скопировать как есть,
|
||||
это уже финальная формулировка).
|
||||
|
||||
- [ ] **Step 5: Изменить `stored_file`**
|
||||
|
||||
Добавить столбец `is_scan boolean [note: 'только PDF: признак текстового слоя при загрузке; true = цифровой
|
||||
(в т. ч. скрытый OCR-слой — допущение §14); NULL для не-PDF']` после `superseded_by_file_id`.
|
||||
|
||||
- [ ] **Step 6: Изменить `recognition_job`**
|
||||
|
||||
Добавить столбец `raw_s3_object_id uuid [ref: > s3_object.id, note: 'сырой ответ ИС Сканирование, роль raw;
|
||||
заполняется при приёме результата image pipeline']` после `result_s3_object_id`. В тексте столбца
|
||||
`result_s3_object_id` и в `Note` таблицы убрать/переписать фразу «Сырой ответ ИС Сканирование... в БД не
|
||||
регистрируется» — он теперь регистрируется.
|
||||
|
||||
- [ ] **Step 7: Три новые таблицы**
|
||||
|
||||
Добавить `Table quality_intake_fact`, `Table quality_outcome_fact`, `Table quality_failure_fact` в самостоятельном
|
||||
разделе `// ============ МЕТРИКИ КАЧЕСТВА ============` в самом конце файла, после `Table required_document_rule`
|
||||
(последняя таблица в текущем v5.24, раздел «ПРОЧЕЕ» — после него файл кончается, отдельных `Ref`-блоков нет).
|
||||
Точные столбцы, типы, индексы и пояснения — design §1.4 (intake), §1.5 (outcome),
|
||||
§1.6 (failure); перенести 1:1, включая оговорку про OSV (payload без `lines`/`values`) в `Note` `quality_intake_fact`
|
||||
и оговорку про неуникальность `document_id` в `Note` `quality_outcome_fact`.
|
||||
|
||||
- [ ] **Step 8: Обновить `Makefile`**
|
||||
|
||||
`Makefile:9`: `DBML ?= model/data-model-v5.24.dbml` → `DBML ?= model/data-model-v5.25.dbml`.
|
||||
|
||||
- [ ] **Step 9: Добавить часть 10 в `scripts/gen_model_diagrams.py`**
|
||||
|
||||
В словарь `PARTS` добавить запись после `"09_audit_ex"`:
|
||||
```python
|
||||
"10_quality_metrics": (
|
||||
"Метрики качества первички",
|
||||
["quality_intake_fact", "quality_outcome_fact", "quality_failure_fact"],
|
||||
),
|
||||
```
|
||||
|
||||
- [ ] **Step 10: Прогнать рендер диаграмм и убедиться, что скрипт не падает на несовпадении `PARTS`**
|
||||
|
||||
Run: `make diagrams DBML=model/data-model-v5.25.dbml`
|
||||
Expected: скрипт доходит до рендера SVG/PNG (сеть/npx может быть недоступна в песочнице — тогда ожидаемый результат
|
||||
это ошибка `npx`/сети, а НЕ `sys.exit(...Раскладка частей не совпадает...)`; если видно именно эту ошибку —
|
||||
значит забыта таблица или опечатка в `PARTS`, вернуться к Step 9).
|
||||
|
||||
- [ ] **Step 11: Обновить `context/04-data-model-guide.md`**
|
||||
|
||||
Строки 1–7: имена файлов `v5.24` → `v5.25`, диапазон диаграмм `part01…09` → `part01…10`. Заголовок «Девять частей
|
||||
модели» → «Десять частей модели», новая строка таблицы:
|
||||
`| 10 Метрики качества первички | \`quality_intake_fact\`, \`quality_outcome_fact\`, \`quality_failure_fact\` | факты распознавания и исхода документа, технические отказы — append-only, без FK |`.
|
||||
Перед существующим абзацем `**v5.24:** …` вставить `**v5.25:** три таблицы фактов качества распознавания
|
||||
(\`quality_intake_fact\`/\`_outcome_fact\`/\`_failure_fact\`), \`s3_bucket_role.raw\`, \`stored_file.is_scan\`,
|
||||
\`recognition_job.raw_s3_object_id\`, \`permission_object.QUALITY_METRICS\` (AURORA-1759).`
|
||||
|
||||
- [ ] **Step 12: Коммит**
|
||||
|
||||
```bash
|
||||
git add model/data-model-v5.25.dbml Makefile scripts/gen_model_diagrams.py context/04-data-model-guide.md
|
||||
git commit -m "docs(#202): DBML v5.25 — факты качества первички (AURORA-1759)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: `entities-v5.25.md` — бизнес-описание
|
||||
|
||||
**Files:**
|
||||
- Create: `model/entities-v5.25.md` (копия `model/entities-v5.24.md` + диффы)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: имена таблиц/столбцов из Task 1 (Produces).
|
||||
|
||||
- [ ] **Step 1: Скопировать файл**
|
||||
|
||||
```bash
|
||||
cp model/entities-v5.24.md model/entities-v5.25.md
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Добавить блок изменений**
|
||||
|
||||
В начало файла, после заголовка, вставить `## Что изменилось в v5.25 (AURORA-1759, RSHB/arm-ka-docs#202)` с
|
||||
перечислением: три новые таблицы фактов (append-only, без FK — зачем, одной фразой со ссылкой на
|
||||
`../arm-core/openspec/changes/quality-metrics/design.md` §1–3 за полным WHY), `s3_bucket_role.raw`,
|
||||
`stored_file.is_scan`, `recognition_job.raw_s3_object_id`, `permission_object.QUALITY_METRICS`.
|
||||
|
||||
- [ ] **Step 3: Дополнить существующие строки «Часть 04»**
|
||||
|
||||
В строке `stored_file` добавить предложение `**v5.25:** \`is_scan\` — скан/цифровой PDF по текстовому слою при
|
||||
загрузке.` В строке `recognition_job` — `**v5.25:** сырой ответ ИС Сканирование теперь регистрируется в
|
||||
\`s3_object\` (роль \`raw\`) через \`raw_s3_object_id\` — решение v5.13 «не регистрируется» отменено.`
|
||||
|
||||
- [ ] **Step 4: Новая «Часть 10 — Метрики качества первички»**
|
||||
|
||||
После «Часть 09» добавить раздел с таблицей (формат как в остальных частях: Сущность | Что это | Ключевые связи |
|
||||
Откуда), строка на каждую из трёх таблиц. В описании `quality_intake_fact` явно сказать: «для ОСВ — без построчного
|
||||
снимка строк/значений, только счётчики и предупреждения `OSV_*`» (Review Focus, п.1). В описании
|
||||
`quality_outcome_fact` явно сказать: «не один факт на документ — повторное подтверждение ОСВ и исход после
|
||||
подтверждения пишут новый факт; метрики берут последний по `outcome_at`» (Review Focus, п.2). Колонка «Откуда» —
|
||||
`AURORA-1759; arm-core#190` для всех трёх строк.
|
||||
|
||||
- [ ] **Step 5: Коммит**
|
||||
|
||||
```bash
|
||||
git add model/entities-v5.25.md
|
||||
git commit -m "docs(#202): entities-v5.25 — метрики качества первички"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: `05-domain-rules.md` §14 — правило подсчёта и атрибуции
|
||||
|
||||
**Files:**
|
||||
- Modify: `context/05-domain-rules.md` (новый раздел `## §14.` в конце файла, после текущего `## §12`)
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: enum/таблицы Task 1; структуру `payload` из Task 4 (писать после Task 4, либо держать формулировки
|
||||
согласованными — Task 4 должен быть написан первым или одновременно, см. порядок задач).
|
||||
|
||||
- [ ] **Step 1: Написать §14.1 «Какие документы считаются»**
|
||||
|
||||
BALANCE/INCOME/OSV — факт пишется; DISCLOSURE/OTHER — нет (как в `document.document_type`, design §1.4).
|
||||
|
||||
- [ ] **Step 2: Написать §14.2 «Атрибуция правки (сервис / наш разбор)»**
|
||||
|
||||
Перенести таблицу из `../arm-core/openspec/changes/quality-metrics/design.md` §5 текстуально (источник правды —
|
||||
design arm-core; здесь — рабочая копия для ссылок `§14.2` из кода `arm-core`, явно подписать
|
||||
«источник: design arm-core#190 §5»).
|
||||
|
||||
- [ ] **Step 3: Написать §14.3 «Причина документа (приоритет `quality_cause`)»**
|
||||
|
||||
Перенести правило приоритета из `design.md` (этого репозитория) §6 / арм-core design §6: `SERVICE_ERROR` >
|
||||
`OUR_ERROR` > `CLIENT_DOCUMENT` > `WITHOUT_PARTICIPATION` > `AS_IS`; `DELETED*`/`SUPERSEDED*` — отдельные столбцы
|
||||
`outcome`, не входят в матрицу, `primary_cause` = NULL.
|
||||
|
||||
- [ ] **Step 4: Написать §14.4 «Документ клиента»**
|
||||
|
||||
Правило: ручное подтверждение с `checks_accepted = true` (акцепт жёстких нарушений §7) и нет правки, закрывающей
|
||||
нарушенное соотношение; мягкие нарушения и межформенная 1370↔2400 не учитываются.
|
||||
|
||||
- [ ] **Step 5: Написать §14.5 «Технические отказы»**
|
||||
|
||||
Считаются по файлам (`quality_failure_fact`), не по документам; знаменатель — загруженные файлы того же `pipeline`;
|
||||
`FILE_REPROCESS` — первая неудачная попытка остаётся отказом, успешная — получает свои факты intake/outcome.
|
||||
|
||||
- [ ] **Step 6: Написать §14.6 «Признак скана»**
|
||||
|
||||
PDF с текстовым слоем — цифровой; PDF со скрытым OCR-слоем — тоже цифровой (ASSUMPTION(OQ-111 не подходит — завести
|
||||
новый номер следующей свободной OQ, см. Task 5) явно помечено как допущение.
|
||||
|
||||
- [ ] **Step 7: Коммит**
|
||||
|
||||
```bash
|
||||
git add context/05-domain-rules.md
|
||||
git commit -m "docs(#202): §14 — счёт и атрибуция метрик качества первички"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: `docs/contracts/metrics/quality-facts.schema.json` — контракт payload
|
||||
|
||||
**Files:**
|
||||
- Create: `contracts/metrics/quality-facts.schema.json`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: имена и смысл полей `payload` из Task 1 (`quality_intake_fact.payload`, `quality_outcome_fact.payload`).
|
||||
- Produces: `$id`/`$defs` `intake-payload`, `outcome-payload` — имена, под которыми на схему будет ссылаться тест
|
||||
в `arm-core` (design §2).
|
||||
|
||||
- [ ] **Step 1: Написать JSON Schema**
|
||||
|
||||
Draft 2020-12, `$defs.intake-payload` и `$defs.outcome-payload` по составу из design §2 (header/lines/values/issues/
|
||||
raw_line_codes для intake; + fixes[] для outcome; у OSV — `osv_warnings`/счётчики вместо `lines`/`values`, выразить
|
||||
через `oneOf` по наличию `document_type` или через оба варианта структуры — на выбор исполнителя, с комментарием
|
||||
в самой схеме). Верхнеуровневое `"description"` схемы должно явно сказать: «не валидируется `make check`
|
||||
(`scripts/validate_contracts.py`) — проверяется тестом в arm-core, который формирует payload» (Review Focus, п.5).
|
||||
|
||||
- [ ] **Step 2: Проверить, что файл — валидный JSON Schema**
|
||||
|
||||
Run: `python3 -c "import json, jsonschema; jsonschema.Draft202012Validator.check_schema(json.load(open('contracts/metrics/quality-facts.schema.json')))"`
|
||||
Expected: без вывода и без исключения (код возврата 0).
|
||||
|
||||
- [ ] **Step 3: Коммит**
|
||||
|
||||
```bash
|
||||
git add contracts/metrics/quality-facts.schema.json
|
||||
git commit -m "docs(#202): контракт payload фактов качества первички"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Документы контекста и `openspec validate`
|
||||
|
||||
**Files:**
|
||||
- Modify: `context/07-open-questions.md` (новый OQ — срок хранения `raw/{job_id}.json`, design §9 арм-core/design §1.1 этого файла)
|
||||
- Modify: `context/03-architecture.md` (если там есть раздел про S3/бакеты — отметить роль `raw`; раздел про внешних
|
||||
читателей БД — отметить read-only роль Superset к схеме `dkb_metrics`)
|
||||
- Modify: `openspec/changes/quality-metrics/proposal.md` / `design.md` — поставить реальный номер OQ вместо
|
||||
плейсхолдера OQ-111, если он занят (проверить в Step 1)
|
||||
|
||||
- [ ] **Step 1: Проверить следующий свободный номер OQ**
|
||||
|
||||
Run: `grep -n "^### OQ-" context/07-open-questions.md | tail -5`
|
||||
Записать новый вопрос под следующим свободным номером (не обязательно OQ-111 — он мог быть занят после 27.10);
|
||||
везде, где в `design.md`/`proposal.md` этого change и арм-core стоит плейсхолдер OQ-111, заменить на реальный номер
|
||||
(если он совпал — ничего менять не нужно).
|
||||
|
||||
- [ ] **Step 2: Дописать вопрос**
|
||||
|
||||
Текст: «Срок хранения сырых ответов ИС Сканирование (`raw/{job_id}.json`, роль `raw`) и подтверждённых `uploads/`,
|
||||
на которые ссылаются факты качества — решает платформа (эталонный прогон использует их неопределённо долго, пока
|
||||
change не отменён)».
|
||||
|
||||
- [ ] **Step 3: Отметить в `03-architecture.md`**
|
||||
|
||||
Если в файле есть таблица ролей бакета S3 — добавить строку `raw`; если есть раздел про внешние читатели БД —
|
||||
добавить абзац про read-only роль Superset к схеме `dkb_metrics` (design арм-core §8). Если ни одного из разделов
|
||||
нет — создать короткий абзац в конце файла, не переписывая остальное.
|
||||
|
||||
- [ ] **Step 4: Прогнать валидацию OpenSpec**
|
||||
|
||||
Run: `openspec validate quality-metrics --strict`
|
||||
Expected: без ошибок.
|
||||
|
||||
- [ ] **Step 5: Прогнать `make check`**
|
||||
|
||||
Run: `make check`
|
||||
Expected: код возврата 0 (`validate-contracts`, `validate-openspec`, `test-snapshot`, `test-sync-statements` — этот
|
||||
change их не касается, должны остаться зелёными как были).
|
||||
|
||||
- [ ] **Step 6: Коммит**
|
||||
|
||||
```bash
|
||||
git add context/07-open-questions.md context/03-architecture.md openspec/changes/quality-metrics/
|
||||
git commit -m "docs(#202): открытые вопросы и architecture — метрики качества первички"
|
||||
```
|
||||
1725
model/data-model-v5.25.dbml
Normal file
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 330 KiB |
@ -4,60 +4,63 @@
|
||||
<!-- Generated by graphviz version 2.47.0 (20210316.0004)
|
||||
-->
|
||||
<!-- Title: dbml Pages: 1 -->
|
||||
<svg width="2056pt" height="2852pt"
|
||||
viewBox="0.00 0.00 2055.66 2851.76" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 2847.76)">
|
||||
<svg width="2056pt" height="2888pt"
|
||||
viewBox="0.00 0.00 2055.66 2887.76" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 2883.76)">
|
||||
<title>dbml</title>
|
||||
<!-- business_segment -->
|
||||
<g id="business_segment" class="node">
|
||||
<title>business_segment</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1752.79" cy="-2164.24" rx="294.73" ry="172.57"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1546.79,-2224.24 1546.79,-2284.24 1959.79,-2284.24 1959.79,-2224.24 1546.79,-2224.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2224.24 1546.79,-2284.24 1959.79,-2284.24 1959.79,-2224.24 1546.79,-2224.24"/>
|
||||
<text text-anchor="start" x="1557.67" y="-2245.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       business_segment       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1546.79,-2164.24 1546.79,-2224.24 1959.79,-2224.24 1959.79,-2164.24 1546.79,-2164.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2164.24 1546.79,-2224.24 1959.79,-2224.24 1959.79,-2164.24 1546.79,-2164.24"/>
|
||||
<text text-anchor="start" x="1684.83" y="-2185.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DKB    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1546.79,-2104.24 1546.79,-2164.24 1959.79,-2164.24 1959.79,-2104.24 1546.79,-2104.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2104.24 1546.79,-2164.24 1959.79,-2164.24 1959.79,-2104.24 1546.79,-2104.24"/>
|
||||
<text text-anchor="start" x="1671.5" y="-2125.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DMSB    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1546.79,-2044.24 1546.79,-2104.24 1959.79,-2104.24 1959.79,-2044.24 1546.79,-2044.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2044.24 1546.79,-2104.24 1959.79,-2104.24 1959.79,-2044.24 1546.79,-2044.24"/>
|
||||
<text text-anchor="start" x="1692.84" y="-2065.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DM    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1545.29,-2043.24 1545.29,-2285.24 1960.29,-2285.24 1960.29,-2043.24 1545.29,-2043.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1752.79" cy="-2200.24" rx="294.73" ry="172.57"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1546.79,-2260.24 1546.79,-2320.24 1959.79,-2320.24 1959.79,-2260.24 1546.79,-2260.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2260.24 1546.79,-2320.24 1959.79,-2320.24 1959.79,-2260.24 1546.79,-2260.24"/>
|
||||
<text text-anchor="start" x="1557.67" y="-2281.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       business_segment       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1546.79,-2200.24 1546.79,-2260.24 1959.79,-2260.24 1959.79,-2200.24 1546.79,-2200.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2200.24 1546.79,-2260.24 1959.79,-2260.24 1959.79,-2200.24 1546.79,-2200.24"/>
|
||||
<text text-anchor="start" x="1684.83" y="-2221.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DKB    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1546.79,-2140.24 1546.79,-2200.24 1959.79,-2200.24 1959.79,-2140.24 1546.79,-2140.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2140.24 1546.79,-2200.24 1959.79,-2200.24 1959.79,-2140.24 1546.79,-2140.24"/>
|
||||
<text text-anchor="start" x="1671.5" y="-2161.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DMSB    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1546.79,-2080.24 1546.79,-2140.24 1959.79,-2140.24 1959.79,-2080.24 1546.79,-2080.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1546.79,-2080.24 1546.79,-2140.24 1959.79,-2140.24 1959.79,-2080.24 1546.79,-2080.24"/>
|
||||
<text text-anchor="start" x="1692.84" y="-2101.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DM    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1545.29,-2079.24 1545.29,-2321.24 1960.29,-2321.24 1960.29,-2079.24 1545.29,-2079.24"/>
|
||||
</g>
|
||||
<!-- permission_object -->
|
||||
<g id="permission_object" class="node">
|
||||
<title>permission_object</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1752.79" cy="-1087.24" rx="288.5" ry="384.83"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1550.79,-1297.24 1550.79,-1357.24 1954.79,-1357.24 1954.79,-1297.24 1550.79,-1297.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1297.24 1550.79,-1357.24 1954.79,-1357.24 1954.79,-1297.24 1550.79,-1297.24"/>
|
||||
<text text-anchor="start" x="1561.64" y="-1318.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       permission_object       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1237.24 1550.79,-1297.24 1954.79,-1297.24 1954.79,-1237.24 1550.79,-1237.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1237.24 1550.79,-1297.24 1954.79,-1297.24 1954.79,-1237.24 1550.79,-1237.24"/>
|
||||
<text text-anchor="start" x="1623.01" y="-1258.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DIRECTORY    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1177.24 1550.79,-1237.24 1954.79,-1237.24 1954.79,-1177.24 1550.79,-1177.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1177.24 1550.79,-1237.24 1954.79,-1237.24 1954.79,-1177.24 1550.79,-1177.24"/>
|
||||
<text text-anchor="start" x="1624.8" y="-1198.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DOCUMENT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1117.24 1550.79,-1177.24 1954.79,-1177.24 1954.79,-1117.24 1550.79,-1117.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1117.24 1550.79,-1177.24 1954.79,-1177.24 1954.79,-1117.24 1550.79,-1117.24"/>
|
||||
<text text-anchor="start" x="1584.78" y="-1138.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    CONSOLIDATION    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1057.24 1550.79,-1117.24 1954.79,-1117.24 1954.79,-1057.24 1550.79,-1057.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1057.24 1550.79,-1117.24 1954.79,-1117.24 1954.79,-1057.24 1550.79,-1057.24"/>
|
||||
<text text-anchor="start" x="1684.33" y="-1078.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    KFO    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-997.24 1550.79,-1057.24 1954.79,-1057.24 1954.79,-997.24 1550.79,-997.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-997.24 1550.79,-1057.24 1954.79,-1057.24 1954.79,-997.24 1550.79,-997.24"/>
|
||||
<text text-anchor="start" x="1695.88" y="-1018.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    EX    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-937.24 1550.79,-997.24 1954.79,-997.24 1954.79,-937.24 1550.79,-937.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-937.24 1550.79,-997.24 1954.79,-997.24 1954.79,-937.24 1550.79,-937.24"/>
|
||||
<text text-anchor="start" x="1651.44" y="-958.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    EXPORT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-877.24 1550.79,-937.24 1954.79,-937.24 1954.79,-877.24 1550.79,-877.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-877.24 1550.79,-937.24 1954.79,-937.24 1954.79,-877.24 1550.79,-877.24"/>
|
||||
<text text-anchor="start" x="1662.11" y="-898.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    USERS    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-817.24 1550.79,-877.24 1954.79,-877.24 1954.79,-817.24 1550.79,-817.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-817.24 1550.79,-877.24 1954.79,-877.24 1954.79,-817.24 1550.79,-817.24"/>
|
||||
<text text-anchor="start" x="1669.23" y="-838.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    AUDIT    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1549.79,-816.24 1549.79,-1358.24 1955.79,-1358.24 1955.79,-816.24 1549.79,-816.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1752.79" cy="-1129.24" rx="288.5" ry="427.19"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1550.79,-1369.24 1550.79,-1429.24 1954.79,-1429.24 1954.79,-1369.24 1550.79,-1369.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1369.24 1550.79,-1429.24 1954.79,-1429.24 1954.79,-1369.24 1550.79,-1369.24"/>
|
||||
<text text-anchor="start" x="1561.64" y="-1390.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       permission_object       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1309.24 1550.79,-1369.24 1954.79,-1369.24 1954.79,-1309.24 1550.79,-1309.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1309.24 1550.79,-1369.24 1954.79,-1369.24 1954.79,-1309.24 1550.79,-1309.24"/>
|
||||
<text text-anchor="start" x="1623.01" y="-1330.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DIRECTORY    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1249.24 1550.79,-1309.24 1954.79,-1309.24 1954.79,-1249.24 1550.79,-1249.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1249.24 1550.79,-1309.24 1954.79,-1309.24 1954.79,-1249.24 1550.79,-1249.24"/>
|
||||
<text text-anchor="start" x="1624.8" y="-1270.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DOCUMENT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1189.24 1550.79,-1249.24 1954.79,-1249.24 1954.79,-1189.24 1550.79,-1189.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1189.24 1550.79,-1249.24 1954.79,-1249.24 1954.79,-1189.24 1550.79,-1189.24"/>
|
||||
<text text-anchor="start" x="1584.78" y="-1210.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    CONSOLIDATION    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1129.24 1550.79,-1189.24 1954.79,-1189.24 1954.79,-1129.24 1550.79,-1129.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1129.24 1550.79,-1189.24 1954.79,-1189.24 1954.79,-1129.24 1550.79,-1129.24"/>
|
||||
<text text-anchor="start" x="1684.33" y="-1150.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    KFO    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1069.24 1550.79,-1129.24 1954.79,-1129.24 1954.79,-1069.24 1550.79,-1069.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1069.24 1550.79,-1129.24 1954.79,-1129.24 1954.79,-1069.24 1550.79,-1069.24"/>
|
||||
<text text-anchor="start" x="1695.88" y="-1090.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    EX    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-1009.24 1550.79,-1069.24 1954.79,-1069.24 1954.79,-1009.24 1550.79,-1009.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-1009.24 1550.79,-1069.24 1954.79,-1069.24 1954.79,-1009.24 1550.79,-1009.24"/>
|
||||
<text text-anchor="start" x="1651.44" y="-1030.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    EXPORT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-949.24 1550.79,-1009.24 1954.79,-1009.24 1954.79,-949.24 1550.79,-949.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-949.24 1550.79,-1009.24 1954.79,-1009.24 1954.79,-949.24 1550.79,-949.24"/>
|
||||
<text text-anchor="start" x="1662.11" y="-970.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    USERS    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-889.24 1550.79,-949.24 1954.79,-949.24 1954.79,-889.24 1550.79,-889.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-889.24 1550.79,-949.24 1954.79,-949.24 1954.79,-889.24 1550.79,-889.24"/>
|
||||
<text text-anchor="start" x="1669.23" y="-910.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    AUDIT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1550.79,-829.24 1550.79,-889.24 1954.79,-889.24 1954.79,-829.24 1550.79,-829.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1550.79,-829.24 1550.79,-889.24 1954.79,-889.24 1954.79,-829.24 1550.79,-829.24"/>
|
||||
<text text-anchor="start" x="1567.89" y="-850.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    QUALITY_METRICS    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1549.79,-828.24 1549.79,-1430.24 1955.79,-1430.24 1955.79,-828.24 1549.79,-828.24"/>
|
||||
</g>
|
||||
<!-- permission_action -->
|
||||
<g id="permission_action" class="node">
|
||||
@ -93,131 +96,131 @@
|
||||
<g id="regional_office" class="node">
|
||||
<title>regional_office</title>
|
||||
<g id="a_regional_office"><a xlink:title="regional_office STUB — полное определение в part01_groups_entities">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1752.79" cy="-2644.24" rx="253.29" ry="87.86"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1575.79,-2644.24 1575.79,-2704.24 1929.79,-2704.24 1929.79,-2644.24 1575.79,-2644.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1575.79,-2644.24 1575.79,-2704.24 1929.79,-2704.24 1929.79,-2644.24 1575.79,-2644.24"/>
|
||||
<text text-anchor="start" x="1586.52" y="-2665.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       regional_office       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1575.79,-2584.24 1575.79,-2644.24 1929.79,-2644.24 1929.79,-2584.24 1575.79,-2584.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1575.79,-2584.24 1575.79,-2644.24 1929.79,-2644.24 1929.79,-2584.24 1575.79,-2584.24"/>
|
||||
<text text-anchor="start" x="1586.79" y="-2605.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1611.68" y="-2605.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1858.33" y="-2605.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1574.79,-2583.24 1574.79,-2705.24 1930.79,-2705.24 1930.79,-2583.24 1574.79,-2583.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1752.79" cy="-2680.24" rx="253.29" ry="87.86"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="1575.79,-2680.24 1575.79,-2740.24 1929.79,-2740.24 1929.79,-2680.24 1575.79,-2680.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1575.79,-2680.24 1575.79,-2740.24 1929.79,-2740.24 1929.79,-2680.24 1575.79,-2680.24"/>
|
||||
<text text-anchor="start" x="1586.52" y="-2701.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       regional_office       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1575.79,-2620.24 1575.79,-2680.24 1929.79,-2680.24 1929.79,-2620.24 1575.79,-2620.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1575.79,-2620.24 1575.79,-2680.24 1929.79,-2680.24 1929.79,-2620.24 1575.79,-2620.24"/>
|
||||
<text text-anchor="start" x="1586.79" y="-2641.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="1611.68" y="-2641.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1858.33" y="-2641.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1574.79,-2619.24 1574.79,-2741.24 1930.79,-2741.24 1930.79,-2619.24 1574.79,-2619.24"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- app_user -->
|
||||
<g id="app_user" class="node">
|
||||
<title>app_user</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1001.91" cy="-2374.24" rx="420.04" ry="469.54"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="706.91,-2644.24 706.91,-2704.24 1296.91,-2704.24 1296.91,-2644.24 706.91,-2644.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2644.24 706.91,-2704.24 1296.91,-2704.24 1296.91,-2644.24 706.91,-2644.24"/>
|
||||
<text text-anchor="start" x="872.97" y="-2665.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       app_user       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2584.24 706.91,-2644.24 1296.91,-2644.24 1296.91,-2584.24 706.91,-2584.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2584.24 706.91,-2644.24 1296.91,-2644.24 1296.91,-2584.24 706.91,-2584.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2605.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="742.8" y="-2605.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1225.44" y="-2605.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2524.24 706.91,-2584.24 1296.91,-2584.24 1296.91,-2524.24 706.91,-2524.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2524.24 706.91,-2584.24 1296.91,-2584.24 1296.91,-2524.24 706.91,-2524.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2544.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">external_id    </text>
|
||||
<text text-anchor="start" x="1179.24" y="-2545.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2464.24 706.91,-2524.24 1296.91,-2524.24 1296.91,-2464.24 706.91,-2464.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2464.24 706.91,-2524.24 1296.91,-2524.24 1296.91,-2464.24 706.91,-2464.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2484.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">email    </text>
|
||||
<text text-anchor="start" x="1179.24" y="-2485.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2404.24 706.91,-2464.24 1296.91,-2464.24 1296.91,-2404.24 706.91,-2404.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2404.24 706.91,-2464.24 1296.91,-2464.24 1296.91,-2404.24 706.91,-2404.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2424.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">full_name    </text>
|
||||
<text text-anchor="start" x="1140.14" y="-2425.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1246.82" y="-2425.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1255.71" y="-2425.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2344.24 706.91,-2404.24 1296.91,-2404.24 1296.91,-2344.24 706.91,-2344.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2344.24 706.91,-2404.24 1296.91,-2404.24 1296.91,-2344.24 706.91,-2344.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2364.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">employee_no    </text>
|
||||
<text text-anchor="start" x="1179.24" y="-2365.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2284.24 706.91,-2344.24 1296.91,-2344.24 1296.91,-2284.24 706.91,-2284.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2284.24 706.91,-2344.24 1296.91,-2344.24 1296.91,-2284.24 706.91,-2284.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2304.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">regional_office_id    </text>
|
||||
<text text-anchor="start" x="1186.35" y="-2305.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="1246.82" y="-2305.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1255.71" y="-2305.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2224.24 706.91,-2284.24 1296.91,-2284.24 1296.91,-2224.24 706.91,-2224.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2224.24 706.91,-2284.24 1296.91,-2284.24 1296.91,-2224.24 706.91,-2224.24"/>
|
||||
<text text-anchor="start" x="717.75" y="-2244.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">business_segment    </text>
|
||||
<text text-anchor="start" x="1019.54" y="-2245.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">business_segment</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2164.24 706.91,-2224.24 1296.91,-2224.24 1296.91,-2164.24 706.91,-2164.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2164.24 706.91,-2224.24 1296.91,-2224.24 1296.91,-2164.24 706.91,-2164.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2184.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_active    </text>
|
||||
<text text-anchor="start" x="1132.98" y="-2185.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="1246.82" y="-2185.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1255.71" y="-2185.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2104.24 706.91,-2164.24 1296.91,-2164.24 1296.91,-2104.24 706.91,-2104.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2104.24 706.91,-2164.24 1296.91,-2164.24 1296.91,-2104.24 706.91,-2104.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2124.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="1113.46" y="-2125.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2044.24 706.91,-2104.24 1296.91,-2104.24 1296.91,-2044.24 706.91,-2044.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2044.24 706.91,-2104.24 1296.91,-2104.24 1296.91,-2044.24 706.91,-2044.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2064.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="1113.46" y="-2065.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="705.91,-2043.24 705.91,-2705.24 1297.91,-2705.24 1297.91,-2043.24 705.91,-2043.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1001.91" cy="-2410.24" rx="420.04" ry="469.54"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="706.91,-2680.24 706.91,-2740.24 1296.91,-2740.24 1296.91,-2680.24 706.91,-2680.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2680.24 706.91,-2740.24 1296.91,-2740.24 1296.91,-2680.24 706.91,-2680.24"/>
|
||||
<text text-anchor="start" x="872.97" y="-2701.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       app_user       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2620.24 706.91,-2680.24 1296.91,-2680.24 1296.91,-2620.24 706.91,-2620.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2620.24 706.91,-2680.24 1296.91,-2680.24 1296.91,-2620.24 706.91,-2620.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2641.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="742.8" y="-2641.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1225.44" y="-2641.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2560.24 706.91,-2620.24 1296.91,-2620.24 1296.91,-2560.24 706.91,-2560.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2560.24 706.91,-2620.24 1296.91,-2620.24 1296.91,-2560.24 706.91,-2560.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2580.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">external_id    </text>
|
||||
<text text-anchor="start" x="1179.24" y="-2581.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2500.24 706.91,-2560.24 1296.91,-2560.24 1296.91,-2500.24 706.91,-2500.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2500.24 706.91,-2560.24 1296.91,-2560.24 1296.91,-2500.24 706.91,-2500.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2520.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">email    </text>
|
||||
<text text-anchor="start" x="1179.24" y="-2521.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2440.24 706.91,-2500.24 1296.91,-2500.24 1296.91,-2440.24 706.91,-2440.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2440.24 706.91,-2500.24 1296.91,-2500.24 1296.91,-2440.24 706.91,-2440.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2460.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">full_name    </text>
|
||||
<text text-anchor="start" x="1140.14" y="-2461.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1246.82" y="-2461.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1255.71" y="-2461.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2380.24 706.91,-2440.24 1296.91,-2440.24 1296.91,-2380.24 706.91,-2380.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2380.24 706.91,-2440.24 1296.91,-2440.24 1296.91,-2380.24 706.91,-2380.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2400.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">employee_no    </text>
|
||||
<text text-anchor="start" x="1179.24" y="-2401.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2320.24 706.91,-2380.24 1296.91,-2380.24 1296.91,-2320.24 706.91,-2320.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2320.24 706.91,-2380.24 1296.91,-2380.24 1296.91,-2320.24 706.91,-2320.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2340.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">regional_office_id    </text>
|
||||
<text text-anchor="start" x="1186.35" y="-2341.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="1246.82" y="-2341.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1255.71" y="-2341.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2260.24 706.91,-2320.24 1296.91,-2320.24 1296.91,-2260.24 706.91,-2260.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2260.24 706.91,-2320.24 1296.91,-2320.24 1296.91,-2260.24 706.91,-2260.24"/>
|
||||
<text text-anchor="start" x="717.75" y="-2280.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">business_segment    </text>
|
||||
<text text-anchor="start" x="1019.54" y="-2281.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">business_segment</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2200.24 706.91,-2260.24 1296.91,-2260.24 1296.91,-2200.24 706.91,-2200.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2200.24 706.91,-2260.24 1296.91,-2260.24 1296.91,-2200.24 706.91,-2200.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2220.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_active    </text>
|
||||
<text text-anchor="start" x="1132.98" y="-2221.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="1246.82" y="-2221.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1255.71" y="-2221.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2140.24 706.91,-2200.24 1296.91,-2200.24 1296.91,-2140.24 706.91,-2140.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2140.24 706.91,-2200.24 1296.91,-2200.24 1296.91,-2140.24 706.91,-2140.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2160.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">created_at    </text>
|
||||
<text text-anchor="start" x="1113.46" y="-2161.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="706.91,-2080.24 706.91,-2140.24 1296.91,-2140.24 1296.91,-2080.24 706.91,-2080.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="706.91,-2080.24 706.91,-2140.24 1296.91,-2140.24 1296.91,-2080.24 706.91,-2080.24"/>
|
||||
<text text-anchor="start" x="717.91" y="-2100.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">updated_at    </text>
|
||||
<text text-anchor="start" x="1113.46" y="-2101.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="705.91,-2079.24 705.91,-2741.24 1297.91,-2741.24 1297.91,-2079.24 705.91,-2079.24"/>
|
||||
</g>
|
||||
<!-- app_user->business_segment -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>app_user:e->business_segment:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1297.91,-2254.24C1408.08,-2254.24 1435.62,-2254.24 1545.79,-2254.24"/>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1297.91,-2290.24C1408.08,-2290.24 1435.62,-2290.24 1545.79,-2290.24"/>
|
||||
</g>
|
||||
<!-- app_user->regional_office -->
|
||||
<!-- app_user->regional_office -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>app_user:e->regional_office:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1297.91,-2314.24C1475.9,-2314.24 1396.53,-2602.92 1564.71,-2613.92"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1564.69,-2617.42 1574.79,-2614.24 1564.91,-2610.42 1564.69,-2617.42"/>
|
||||
<text text-anchor="middle" x="1583.69" y="-2623.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="1304.13" y="-2323.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1297.91,-2350.24C1475.9,-2350.24 1396.53,-2638.92 1564.71,-2649.92"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="1564.69,-2653.42 1574.79,-2650.24 1564.91,-2646.42 1564.69,-2653.42"/>
|
||||
<text text-anchor="middle" x="1583.69" y="-2659.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="1304.13" y="-2359.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- role -->
|
||||
<g id="role" class="node">
|
||||
<title>role</title>
|
||||
<g id="a_role"><a xlink:title="role Роль. Полномочия — через role_permission (v5.13); код роли в бизнес-логике больше не проверяется">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1001.91" cy="-1587.24" rx="251.05" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="826.91,-1737.24 826.91,-1797.24 1177.91,-1797.24 1177.91,-1737.24 826.91,-1737.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1737.24 826.91,-1797.24 1177.91,-1797.24 1177.91,-1737.24 826.91,-1737.24"/>
|
||||
<text text-anchor="start" x="913.49" y="-1758.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       role       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1677.24 826.91,-1737.24 1177.91,-1737.24 1177.91,-1677.24 826.91,-1677.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1677.24 826.91,-1737.24 1177.91,-1737.24 1177.91,-1677.24 826.91,-1677.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1698.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="862.8" y="-1698.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1106.44" y="-1698.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1617.24 826.91,-1677.24 1177.91,-1677.24 1177.91,-1617.24 826.91,-1617.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1617.24 826.91,-1677.24 1177.91,-1677.24 1177.91,-1617.24 826.91,-1617.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1637.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">code    </text>
|
||||
<text text-anchor="start" x="1021.14" y="-1638.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1127.82" y="-1638.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1136.71" y="-1638.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1557.24 826.91,-1617.24 1177.91,-1617.24 1177.91,-1557.24 826.91,-1557.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1557.24 826.91,-1617.24 1177.91,-1617.24 1177.91,-1557.24 826.91,-1557.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1577.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">name    </text>
|
||||
<text text-anchor="start" x="1021.14" y="-1578.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1127.82" y="-1578.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1136.71" y="-1578.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1497.24 826.91,-1557.24 1177.91,-1557.24 1177.91,-1497.24 826.91,-1497.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1497.24 826.91,-1557.24 1177.91,-1557.24 1177.91,-1497.24 826.91,-1497.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1517.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">description    </text>
|
||||
<text text-anchor="start" x="1115.33" y="-1518.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1437.24 826.91,-1497.24 1177.91,-1497.24 1177.91,-1437.24 826.91,-1437.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1437.24 826.91,-1497.24 1177.91,-1497.24 1177.91,-1437.24 826.91,-1437.24"/>
|
||||
<text text-anchor="start" x="837.51" y="-1457.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_system    </text>
|
||||
<text text-anchor="start" x="1014.45" y="-1458.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="1128.28" y="-1458.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1137.17" y="-1458.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1377.24 826.91,-1437.24 1177.91,-1437.24 1177.91,-1377.24 826.91,-1377.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1377.24 826.91,-1437.24 1177.91,-1437.24 1177.91,-1377.24 826.91,-1377.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1397.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_active    </text>
|
||||
<text text-anchor="start" x="1013.98" y="-1398.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="1127.82" y="-1398.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1136.71" y="-1398.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="825.41,-1376.24 825.41,-1798.24 1178.41,-1798.24 1178.41,-1376.24 825.41,-1376.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1001.91" cy="-1623.24" rx="251.05" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="826.91,-1773.24 826.91,-1833.24 1177.91,-1833.24 1177.91,-1773.24 826.91,-1773.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1773.24 826.91,-1833.24 1177.91,-1833.24 1177.91,-1773.24 826.91,-1773.24"/>
|
||||
<text text-anchor="start" x="913.49" y="-1794.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       role       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1713.24 826.91,-1773.24 1177.91,-1773.24 1177.91,-1713.24 826.91,-1713.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1713.24 826.91,-1773.24 1177.91,-1773.24 1177.91,-1713.24 826.91,-1713.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1734.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="862.8" y="-1734.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1106.44" y="-1734.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1653.24 826.91,-1713.24 1177.91,-1713.24 1177.91,-1653.24 826.91,-1653.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1653.24 826.91,-1713.24 1177.91,-1713.24 1177.91,-1653.24 826.91,-1653.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1673.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">code    </text>
|
||||
<text text-anchor="start" x="1021.14" y="-1674.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1127.82" y="-1674.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1136.71" y="-1674.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1593.24 826.91,-1653.24 1177.91,-1653.24 1177.91,-1593.24 826.91,-1593.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1593.24 826.91,-1653.24 1177.91,-1653.24 1177.91,-1593.24 826.91,-1593.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1613.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">name    </text>
|
||||
<text text-anchor="start" x="1021.14" y="-1614.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1127.82" y="-1614.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1136.71" y="-1614.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1533.24 826.91,-1593.24 1177.91,-1593.24 1177.91,-1533.24 826.91,-1533.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1533.24 826.91,-1593.24 1177.91,-1593.24 1177.91,-1533.24 826.91,-1533.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1553.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">description    </text>
|
||||
<text text-anchor="start" x="1115.33" y="-1554.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1473.24 826.91,-1533.24 1177.91,-1533.24 1177.91,-1473.24 826.91,-1473.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1473.24 826.91,-1533.24 1177.91,-1533.24 1177.91,-1473.24 826.91,-1473.24"/>
|
||||
<text text-anchor="start" x="837.51" y="-1493.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_system    </text>
|
||||
<text text-anchor="start" x="1014.45" y="-1494.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="1128.28" y="-1494.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1137.17" y="-1494.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="826.91,-1413.24 826.91,-1473.24 1177.91,-1473.24 1177.91,-1413.24 826.91,-1413.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="826.91,-1413.24 826.91,-1473.24 1177.91,-1473.24 1177.91,-1413.24 826.91,-1413.24"/>
|
||||
<text text-anchor="start" x="837.91" y="-1433.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_active    </text>
|
||||
<text text-anchor="start" x="1013.98" y="-1434.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="1127.82" y="-1434.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1136.71" y="-1434.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="825.41,-1412.24 825.41,-1834.24 1178.41,-1834.24 1178.41,-1412.24 825.41,-1412.24"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
@ -225,88 +228,88 @@
|
||||
<g id="permission" class="node">
|
||||
<title>permission</title>
|
||||
<g id="a_permission"><a xlink:title="permission Справочник прав (seed, привязан к коду). Ограничения по ЗО/филиалу и статусу КФО — отдельный policy-слой поверх прав: право говорит «может», policy — «эту ли и сейчас ли»">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1001.91" cy="-969.24" rx="368.31" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="743.91,-1119.24 743.91,-1179.24 1260.91,-1179.24 1260.91,-1119.24 743.91,-1119.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-1119.24 743.91,-1179.24 1260.91,-1179.24 1260.91,-1119.24 743.91,-1119.24"/>
|
||||
<text text-anchor="start" x="862.83" y="-1140.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       permission       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-1059.24 743.91,-1119.24 1260.91,-1119.24 1260.91,-1059.24 743.91,-1059.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-1059.24 743.91,-1119.24 1260.91,-1119.24 1260.91,-1059.24 743.91,-1059.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-1080.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="779.8" y="-1080.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1189.44" y="-1080.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-999.24 743.91,-1059.24 1260.91,-1059.24 1260.91,-999.24 743.91,-999.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-999.24 743.91,-1059.24 1260.91,-1059.24 1260.91,-999.24 743.91,-999.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-1019.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">code    </text>
|
||||
<text text-anchor="start" x="1104.14" y="-1020.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1210.82" y="-1020.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1219.71" y="-1020.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-939.24 743.91,-999.24 1260.91,-999.24 1260.91,-939.24 743.91,-939.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-939.24 743.91,-999.24 1260.91,-999.24 1260.91,-939.24 743.91,-939.24"/>
|
||||
<text text-anchor="start" x="754.81" y="-959.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">object_type    </text>
|
||||
<text text-anchor="start" x="953.46" y="-960.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">permission_object</text>
|
||||
<text text-anchor="start" x="1211.27" y="-960.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1220.16" y="-960.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-879.24 743.91,-939.24 1260.91,-939.24 1260.91,-879.24 743.91,-879.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-879.24 743.91,-939.24 1260.91,-939.24 1260.91,-879.24 743.91,-879.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-899.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">action    </text>
|
||||
<text text-anchor="start" x="953.01" y="-900.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">permission_action</text>
|
||||
<text text-anchor="start" x="1210.82" y="-900.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1219.71" y="-900.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-819.24 743.91,-879.24 1260.91,-879.24 1260.91,-819.24 743.91,-819.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-819.24 743.91,-879.24 1260.91,-879.24 1260.91,-819.24 743.91,-819.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-839.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">name    </text>
|
||||
<text text-anchor="start" x="1104.14" y="-840.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1210.82" y="-840.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1219.71" y="-840.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-759.24 743.91,-819.24 1260.91,-819.24 1260.91,-759.24 743.91,-759.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-759.24 743.91,-819.24 1260.91,-819.24 1260.91,-759.24 743.91,-759.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-779.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">description    </text>
|
||||
<text text-anchor="start" x="1198.33" y="-780.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="742.41,-758.24 742.41,-1180.24 1261.41,-1180.24 1261.41,-758.24 742.41,-758.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1001.91" cy="-1005.24" rx="368.31" ry="299.63"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="743.91,-1155.24 743.91,-1215.24 1260.91,-1215.24 1260.91,-1155.24 743.91,-1155.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-1155.24 743.91,-1215.24 1260.91,-1215.24 1260.91,-1155.24 743.91,-1155.24"/>
|
||||
<text text-anchor="start" x="862.83" y="-1176.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       permission       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-1095.24 743.91,-1155.24 1260.91,-1155.24 1260.91,-1095.24 743.91,-1095.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-1095.24 743.91,-1155.24 1260.91,-1155.24 1260.91,-1095.24 743.91,-1095.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-1116.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="779.8" y="-1116.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="1189.44" y="-1116.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-1035.24 743.91,-1095.24 1260.91,-1095.24 1260.91,-1035.24 743.91,-1035.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-1035.24 743.91,-1095.24 1260.91,-1095.24 1260.91,-1035.24 743.91,-1035.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-1055.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">code    </text>
|
||||
<text text-anchor="start" x="1104.14" y="-1056.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1210.82" y="-1056.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1219.71" y="-1056.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-975.24 743.91,-1035.24 1260.91,-1035.24 1260.91,-975.24 743.91,-975.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-975.24 743.91,-1035.24 1260.91,-1035.24 1260.91,-975.24 743.91,-975.24"/>
|
||||
<text text-anchor="start" x="754.81" y="-995.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">object_type    </text>
|
||||
<text text-anchor="start" x="953.46" y="-996.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">permission_object</text>
|
||||
<text text-anchor="start" x="1211.27" y="-996.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1220.16" y="-996.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-915.24 743.91,-975.24 1260.91,-975.24 1260.91,-915.24 743.91,-915.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-915.24 743.91,-975.24 1260.91,-975.24 1260.91,-915.24 743.91,-915.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-935.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">action    </text>
|
||||
<text text-anchor="start" x="953.01" y="-936.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">permission_action</text>
|
||||
<text text-anchor="start" x="1210.82" y="-936.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1219.71" y="-936.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-855.24 743.91,-915.24 1260.91,-915.24 1260.91,-855.24 743.91,-855.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-855.24 743.91,-915.24 1260.91,-915.24 1260.91,-855.24 743.91,-855.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-875.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">name    </text>
|
||||
<text text-anchor="start" x="1104.14" y="-876.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="1210.82" y="-876.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="1219.71" y="-876.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="743.91,-795.24 743.91,-855.24 1260.91,-855.24 1260.91,-795.24 743.91,-795.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="743.91,-795.24 743.91,-855.24 1260.91,-855.24 1260.91,-795.24 743.91,-795.24"/>
|
||||
<text text-anchor="start" x="754.91" y="-815.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">description    </text>
|
||||
<text text-anchor="start" x="1198.33" y="-816.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">text</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="742.41,-794.24 742.41,-1216.24 1261.41,-1216.24 1261.41,-794.24 742.41,-794.24"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- permission->permission_object -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>permission:e->permission_object:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1261.91,-969.24C1466.08,-969.24 1345.62,-1327.24 1549.79,-1327.24"/>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1261.91,-1005.24C1478.78,-1005.24 1332.92,-1399.24 1549.79,-1399.24"/>
|
||||
</g>
|
||||
<!-- permission->permission_action -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>permission:e->permission_action:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1261.91,-909.24C1465.74,-909.24 1345.96,-552.24 1549.79,-552.24"/>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M1261.91,-945.24C1478.42,-945.24 1333.28,-552.24 1549.79,-552.24"/>
|
||||
</g>
|
||||
<!-- role_permission -->
|
||||
<g id="role_permission" class="node">
|
||||
<title>role_permission</title>
|
||||
<g id="a_role_permission"><a xlink:title="role_permission effective_permissions(user) = ∪ permissions(roles(user)). Прямых прав у пользователя нет (решение 30.09): исключения — через заведение роли">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="272.94" cy="-1647.24" rx="272.89" ry="214.92"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="81.94,-1737.24 81.94,-1797.24 463.94,-1797.24 463.94,-1737.24 81.94,-1737.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1737.24 81.94,-1797.24 463.94,-1797.24 463.94,-1737.24 81.94,-1737.24"/>
|
||||
<text text-anchor="start" x="97.8" y="-1758.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       role_permission       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1677.24 81.94,-1737.24 463.94,-1737.24 463.94,-1677.24 81.94,-1677.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1677.24 81.94,-1737.24 463.94,-1737.24 463.94,-1677.24 81.94,-1677.24"/>
|
||||
<text text-anchor="start" x="92.94" y="-1698.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">role_id</text>
|
||||
<text text-anchor="start" x="188.95" y="-1698.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="353.38" y="-1698.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="413.85" y="-1698.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="422.74" y="-1698.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1617.24 81.94,-1677.24 463.94,-1677.24 463.94,-1617.24 81.94,-1617.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1617.24 81.94,-1677.24 463.94,-1677.24 463.94,-1617.24 81.94,-1617.24"/>
|
||||
<text text-anchor="start" x="92.94" y="-1638.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">permission_id</text>
|
||||
<text text-anchor="start" x="290.28" y="-1638.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="353.38" y="-1638.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="413.85" y="-1638.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="422.74" y="-1638.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1557.24 81.94,-1617.24 463.94,-1617.24 463.94,-1557.24 81.94,-1557.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1557.24 81.94,-1617.24 463.94,-1617.24 463.94,-1557.24 81.94,-1557.24"/>
|
||||
<text text-anchor="start" x="92.94" y="-1577.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">granted_by    </text>
|
||||
<text text-anchor="start" x="392.48" y="-1578.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1497.24 81.94,-1557.24 463.94,-1557.24 463.94,-1497.24 81.94,-1497.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1497.24 81.94,-1557.24 463.94,-1557.24 463.94,-1497.24 81.94,-1497.24"/>
|
||||
<text text-anchor="start" x="92.68" y="-1517.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">granted_at    </text>
|
||||
<text text-anchor="start" x="280.72" y="-1518.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="80.94,-1496.24 80.94,-1798.24 464.94,-1798.24 464.94,-1496.24 80.94,-1496.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="272.94" cy="-1683.24" rx="272.89" ry="214.92"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="81.94,-1773.24 81.94,-1833.24 463.94,-1833.24 463.94,-1773.24 81.94,-1773.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1773.24 81.94,-1833.24 463.94,-1833.24 463.94,-1773.24 81.94,-1773.24"/>
|
||||
<text text-anchor="start" x="97.8" y="-1794.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       role_permission       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1713.24 81.94,-1773.24 463.94,-1773.24 463.94,-1713.24 81.94,-1713.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1713.24 81.94,-1773.24 463.94,-1773.24 463.94,-1713.24 81.94,-1713.24"/>
|
||||
<text text-anchor="start" x="92.94" y="-1734.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">role_id</text>
|
||||
<text text-anchor="start" x="188.95" y="-1734.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="353.38" y="-1734.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="413.85" y="-1734.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="422.74" y="-1734.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1653.24 81.94,-1713.24 463.94,-1713.24 463.94,-1653.24 81.94,-1653.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1653.24 81.94,-1713.24 463.94,-1713.24 463.94,-1653.24 81.94,-1653.24"/>
|
||||
<text text-anchor="start" x="92.94" y="-1674.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">permission_id</text>
|
||||
<text text-anchor="start" x="290.28" y="-1674.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="353.38" y="-1674.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="413.85" y="-1674.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="422.74" y="-1674.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1593.24 81.94,-1653.24 463.94,-1653.24 463.94,-1593.24 81.94,-1593.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1593.24 81.94,-1653.24 463.94,-1653.24 463.94,-1593.24 81.94,-1593.24"/>
|
||||
<text text-anchor="start" x="92.94" y="-1613.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">granted_by    </text>
|
||||
<text text-anchor="start" x="392.48" y="-1614.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="81.94,-1533.24 81.94,-1593.24 463.94,-1593.24 463.94,-1533.24 81.94,-1533.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="81.94,-1533.24 81.94,-1593.24 463.94,-1593.24 463.94,-1533.24 81.94,-1533.24"/>
|
||||
<text text-anchor="start" x="92.68" y="-1553.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">granted_at    </text>
|
||||
<text text-anchor="start" x="280.72" y="-1554.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="80.94,-1532.24 80.94,-1834.24 464.94,-1834.24 464.94,-1532.24 80.94,-1532.24"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
@ -314,55 +317,55 @@
|
||||
<!-- role_permission->app_user -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>role_permission:e->app_user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M464.94,-1587.24C695.93,-1587.24 478.06,-2584.37 695.9,-2613.59"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="695.7,-2617.08 705.91,-2614.24 696.16,-2610.09 695.7,-2617.08"/>
|
||||
<text text-anchor="middle" x="697.01" y="-2623.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="471.17" y="-1596.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M464.94,-1623.24C695.93,-1623.24 478.06,-2620.37 695.9,-2649.59"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="695.7,-2653.08 705.91,-2650.24 696.16,-2646.09 695.7,-2653.08"/>
|
||||
<text text-anchor="middle" x="697.01" y="-2659.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="471.17" y="-1632.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- role_permission->role -->
|
||||
<!-- role_permission->role -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>role_permission:e->role:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M464.94,-1707.24C621.93,-1707.24 663.7,-1707.24 815.73,-1707.24"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="815.91,-1710.74 825.91,-1707.24 815.91,-1703.74 815.91,-1710.74"/>
|
||||
<text text-anchor="middle" x="817.01" y="-1716.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="471.17" y="-1716.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M464.94,-1743.24C621.93,-1743.24 663.7,-1743.24 815.73,-1743.24"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="815.91,-1746.74 825.91,-1743.24 815.91,-1739.74 815.91,-1746.74"/>
|
||||
<text text-anchor="middle" x="817.01" y="-1752.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="471.17" y="-1752.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- role_permission->permission -->
|
||||
<!-- role_permission->permission -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>role_permission:e->permission:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M464.94,-1647.24C636.98,-1647.24 498.46,-1428.7 581.89,-1278.24 633.73,-1184.75 632.68,-1095.02 732.89,-1089.51"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="733.01,-1093.01 742.91,-1089.24 732.82,-1086.01 733.01,-1093.01"/>
|
||||
<text text-anchor="middle" x="734.01" y="-1098.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="471.17" y="-1656.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M464.94,-1683.24C636.98,-1683.24 498.46,-1464.7 581.89,-1314.24 633.73,-1220.75 632.68,-1131.02 732.89,-1125.51"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="733.01,-1129.01 742.91,-1125.24 732.82,-1122.01 733.01,-1129.01"/>
|
||||
<text text-anchor="middle" x="734.01" y="-1134.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="471.17" y="-1692.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- user_role -->
|
||||
<g id="user_role" class="node">
|
||||
<title>user_role</title>
|
||||
<g id="a_user_role"><a xlink:title="user_role M:N current-state. История назначений — audit_event(USER_ROLE_CHANGE)">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="272.94" cy="-2318.24" rx="200.22" ry="172.57"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="133.94,-2378.24 133.94,-2438.24 412.94,-2438.24 412.94,-2378.24 133.94,-2378.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2378.24 133.94,-2438.24 412.94,-2438.24 412.94,-2378.24 133.94,-2378.24"/>
|
||||
<text text-anchor="start" x="144.52" y="-2399.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       user_role       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="133.94,-2318.24 133.94,-2378.24 412.94,-2378.24 412.94,-2318.24 133.94,-2318.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2318.24 133.94,-2378.24 412.94,-2378.24 412.94,-2318.24 133.94,-2318.24"/>
|
||||
<text text-anchor="start" x="144.94" y="-2339.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="169.83" y="-2339.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="341.48" y="-2339.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="133.94,-2258.24 133.94,-2318.24 412.94,-2318.24 412.94,-2258.24 133.94,-2258.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2258.24 133.94,-2318.24 412.94,-2318.24 412.94,-2258.24 133.94,-2258.24"/>
|
||||
<text text-anchor="start" x="144.94" y="-2278.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="302.38" y="-2279.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="362.85" y="-2279.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="371.74" y="-2279.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="133.94,-2198.24 133.94,-2258.24 412.94,-2258.24 412.94,-2198.24 133.94,-2198.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2198.24 133.94,-2258.24 412.94,-2258.24 412.94,-2198.24 133.94,-2198.24"/>
|
||||
<text text-anchor="start" x="144.94" y="-2218.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">role_id    </text>
|
||||
<text text-anchor="start" x="302.38" y="-2219.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="362.85" y="-2219.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="371.74" y="-2219.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="132.44,-2197.24 132.44,-2439.24 413.44,-2439.24 413.44,-2197.24 132.44,-2197.24"/>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="272.94" cy="-2354.24" rx="200.22" ry="172.57"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="133.94,-2414.24 133.94,-2474.24 412.94,-2474.24 412.94,-2414.24 133.94,-2414.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2414.24 133.94,-2474.24 412.94,-2474.24 412.94,-2414.24 133.94,-2414.24"/>
|
||||
<text text-anchor="start" x="144.52" y="-2435.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       user_role       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="133.94,-2354.24 133.94,-2414.24 412.94,-2414.24 412.94,-2354.24 133.94,-2354.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2354.24 133.94,-2414.24 412.94,-2414.24 412.94,-2354.24 133.94,-2354.24"/>
|
||||
<text text-anchor="start" x="144.94" y="-2375.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="169.83" y="-2375.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="341.48" y="-2375.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="133.94,-2294.24 133.94,-2354.24 412.94,-2354.24 412.94,-2294.24 133.94,-2294.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2294.24 133.94,-2354.24 412.94,-2354.24 412.94,-2294.24 133.94,-2294.24"/>
|
||||
<text text-anchor="start" x="144.94" y="-2314.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">user_id    </text>
|
||||
<text text-anchor="start" x="302.38" y="-2315.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="362.85" y="-2315.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="371.74" y="-2315.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="133.94,-2234.24 133.94,-2294.24 412.94,-2294.24 412.94,-2234.24 133.94,-2234.24"/>
|
||||
<polygon fill="none" stroke="#29235c" points="133.94,-2234.24 133.94,-2294.24 412.94,-2294.24 412.94,-2234.24 133.94,-2234.24"/>
|
||||
<text text-anchor="start" x="144.94" y="-2254.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">role_id    </text>
|
||||
<text text-anchor="start" x="302.38" y="-2255.44" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="362.85" y="-2255.44" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="371.74" y="-2255.44" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="132.44,-2233.24 132.44,-2475.24 413.44,-2475.24 413.44,-2233.24 132.44,-2233.24"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
@ -370,19 +373,19 @@
|
||||
<!-- user_role->app_user -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>user_role:e->app_user:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M413.94,-2288.24C604.93,-2288.24 514.82,-2602.57 695.65,-2613.92"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="695.81,-2617.43 705.91,-2614.24 696.02,-2610.43 695.81,-2617.43"/>
|
||||
<text text-anchor="middle" x="714.8" y="-2623.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="420.17" y="-2297.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M413.94,-2324.24C604.93,-2324.24 514.82,-2638.57 695.65,-2649.92"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="695.81,-2653.43 705.91,-2650.24 696.02,-2646.43 695.81,-2653.43"/>
|
||||
<text text-anchor="middle" x="714.8" y="-2659.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="420.17" y="-2333.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
<!-- user_role->role -->
|
||||
<!-- user_role->role -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>user_role:e->role:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M413.94,-2228.24C579.7,-2228.24 476.28,-2023 581.89,-1895.24 666.9,-1792.39 687.95,-1711.44 815.7,-1707.4"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="815.96,-1710.89 825.91,-1707.24 815.85,-1703.9 815.96,-1710.89"/>
|
||||
<text text-anchor="middle" x="834.8" y="-1716.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="420.17" y="-2237.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M413.94,-2264.24C579.7,-2264.24 476.28,-2059 581.89,-1931.24 666.9,-1828.39 687.95,-1747.44 815.7,-1743.4"/>
|
||||
<polygon fill="#29235c" stroke="#29235c" stroke-width="3" points="815.96,-1746.89 825.91,-1743.24 815.85,-1739.9 815.96,-1746.89"/>
|
||||
<text text-anchor="middle" x="834.8" y="-1752.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">1</text>
|
||||
<text text-anchor="middle" x="420.17" y="-2273.84" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">*</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 492 KiB After Width: | Height: | Size: 522 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 100 KiB |
BIN
model/diagrams/part10_quality_metrics.png
Normal file
|
After Width: | Height: | Size: 782 KiB |
550
model/diagrams/part10_quality_metrics.svg
Normal file
@ -0,0 +1,550 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.47.0 (20210316.0004)
|
||||
-->
|
||||
<!-- Title: dbml Pages: 1 -->
|
||||
<svg width="1662pt" height="5916pt"
|
||||
viewBox="0.00 0.00 1661.86 5916.01" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 5912.01)">
|
||||
<title>dbml</title>
|
||||
<!-- document_type -->
|
||||
<g id="document_type" class="node">
|
||||
<title>document_type</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1224.65" cy="-2909.22" rx="260.84" ry="257.27"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1042.65,-3029.22 1042.65,-3089.22 1407.65,-3089.22 1407.65,-3029.22 1042.65,-3029.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1042.65,-3029.22 1042.65,-3089.22 1407.65,-3089.22 1407.65,-3029.22 1042.65,-3029.22"/>
|
||||
<text text-anchor="start" x="1053.52" y="-3050.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       document_type       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1042.65,-2969.22 1042.65,-3029.22 1407.65,-3029.22 1407.65,-2969.22 1042.65,-2969.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1042.65,-2969.22 1042.65,-3029.22 1407.65,-3029.22 1407.65,-2969.22 1042.65,-2969.22"/>
|
||||
<text text-anchor="start" x="1114.9" y="-2990.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    BALANCE    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1042.65,-2909.22 1042.65,-2969.22 1407.65,-2969.22 1407.65,-2909.22 1042.65,-2909.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1042.65,-2909.22 1042.65,-2969.22 1407.65,-2969.22 1407.65,-2909.22 1042.65,-2909.22"/>
|
||||
<text text-anchor="start" x="1125.58" y="-2930.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    INCOME    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1042.65,-2849.22 1042.65,-2909.22 1407.65,-2909.22 1407.65,-2849.22 1042.65,-2849.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1042.65,-2849.22 1042.65,-2909.22 1407.65,-2909.22 1407.65,-2849.22 1042.65,-2849.22"/>
|
||||
<text text-anchor="start" x="1155.79" y="-2870.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    OSV    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1042.65,-2789.22 1042.65,-2849.22 1407.65,-2849.22 1407.65,-2789.22 1042.65,-2789.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1042.65,-2789.22 1042.65,-2849.22 1407.65,-2849.22 1407.65,-2789.22 1042.65,-2789.22"/>
|
||||
<text text-anchor="start" x="1085.58" y="-2810.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DISCLOSURE    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1042.65,-2729.22 1042.65,-2789.22 1407.65,-2789.22 1407.65,-2729.22 1042.65,-2729.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1042.65,-2729.22 1042.65,-2789.22 1407.65,-2789.22 1407.65,-2729.22 1042.65,-2729.22"/>
|
||||
<text text-anchor="start" x="1133.58" y="-2750.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    OTHER    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1041.15,-2728.22 1041.15,-3090.22 1408.15,-3090.22 1408.15,-2728.22 1041.15,-2728.22"/>
|
||||
</g>
|
||||
<!-- recognition_pipeline -->
|
||||
<g id="recognition_pipeline" class="node">
|
||||
<title>recognition_pipeline</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1224.65" cy="-1309.22" rx="307.68" ry="130.22"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1009.65,-1339.22 1009.65,-1399.22 1440.65,-1399.22 1440.65,-1339.22 1009.65,-1339.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1009.65,-1339.22 1009.65,-1399.22 1440.65,-1399.22 1440.65,-1339.22 1009.65,-1339.22"/>
|
||||
<text text-anchor="start" x="1020.64" y="-1360.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       recognition_pipeline       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1009.65,-1279.22 1009.65,-1339.22 1440.65,-1339.22 1440.65,-1279.22 1009.65,-1279.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1009.65,-1279.22 1009.65,-1339.22 1440.65,-1339.22 1440.65,-1279.22 1009.65,-1279.22"/>
|
||||
<text text-anchor="start" x="1140.67" y="-1300.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    tabular    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1009.65,-1219.22 1009.65,-1279.22 1440.65,-1279.22 1440.65,-1219.22 1009.65,-1219.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1009.65,-1219.22 1009.65,-1279.22 1440.65,-1279.22 1440.65,-1219.22 1009.65,-1219.22"/>
|
||||
<text text-anchor="start" x="1146.02" y="-1240.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    image    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1008.15,-1218.22 1008.15,-1400.22 1441.15,-1400.22 1441.15,-1218.22 1008.15,-1218.22"/>
|
||||
</g>
|
||||
<!-- quality_outcome -->
|
||||
<g id="quality_outcome" class="node">
|
||||
<title>quality_outcome</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1224.65" cy="-5496.22" rx="429.43" ry="299.63"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="923.65,-5646.22 923.65,-5706.22 1526.65,-5706.22 1526.65,-5646.22 923.65,-5646.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5646.22 923.65,-5706.22 1526.65,-5706.22 1526.65,-5646.22 923.65,-5646.22"/>
|
||||
<text text-anchor="start" x="1046.42" y="-5667.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       quality_outcome       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="923.65,-5586.22 923.65,-5646.22 1526.65,-5646.22 1526.65,-5586.22 923.65,-5586.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5586.22 923.65,-5646.22 1526.65,-5646.22 1526.65,-5586.22 923.65,-5586.22"/>
|
||||
<text text-anchor="start" x="1039.37" y="-5607.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    AUTO_CONFIRMED    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="923.65,-5526.22 923.65,-5586.22 1526.65,-5586.22 1526.65,-5526.22 923.65,-5526.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5526.22 923.65,-5586.22 1526.65,-5586.22 1526.65,-5526.22 923.65,-5526.22"/>
|
||||
<text text-anchor="start" x="1092.71" y="-5547.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    CONFIRMED    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="923.65,-5466.22 923.65,-5526.22 1526.65,-5526.22 1526.65,-5466.22 923.65,-5466.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5466.22 923.65,-5526.22 1526.65,-5526.22 1526.65,-5466.22 923.65,-5466.22"/>
|
||||
<text text-anchor="start" x="1115.79" y="-5487.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DELETED    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="923.65,-5406.22 923.65,-5466.22 1526.65,-5466.22 1526.65,-5406.22 923.65,-5406.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5406.22 923.65,-5466.22 1526.65,-5466.22 1526.65,-5406.22 923.65,-5406.22"/>
|
||||
<text text-anchor="start" x="1079.35" y="-5427.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    SUPERSEDED    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="923.65,-5346.22 923.65,-5406.22 1526.65,-5406.22 1526.65,-5346.22 923.65,-5346.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5346.22 923.65,-5406.22 1526.65,-5406.22 1526.65,-5346.22 923.65,-5346.22"/>
|
||||
<text text-anchor="start" x="970.92" y="-5367.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    DELETED_AFTER_CONFIRM    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="923.65,-5286.22 923.65,-5346.22 1526.65,-5346.22 1526.65,-5286.22 923.65,-5286.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="923.65,-5286.22 923.65,-5346.22 1526.65,-5346.22 1526.65,-5286.22 923.65,-5286.22"/>
|
||||
<text text-anchor="start" x="934.48" y="-5307.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    SUPERSEDED_AFTER_CONFIRM    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="922.15,-5285.22 922.15,-5707.22 1527.15,-5707.22 1527.15,-5285.22 922.15,-5285.22"/>
|
||||
</g>
|
||||
<!-- quality_cause -->
|
||||
<g id="quality_cause" class="node">
|
||||
<title>quality_cause</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1224.65" cy="-4921.22" rx="359.83" ry="257.27"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="972.65,-5041.22 972.65,-5101.22 1477.65,-5101.22 1477.65,-5041.22 972.65,-5041.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="972.65,-5041.22 972.65,-5101.22 1477.65,-5101.22 1477.65,-5041.22 972.65,-5041.22"/>
|
||||
<text text-anchor="start" x="1065.09" y="-5062.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       quality_cause       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="972.65,-4981.22 972.65,-5041.22 1477.65,-5041.22 1477.65,-4981.22 972.65,-4981.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="972.65,-4981.22 972.65,-5041.22 1477.65,-5041.22 1477.65,-4981.22 972.65,-4981.22"/>
|
||||
<text text-anchor="start" x="1052.68" y="-5002.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    SERVICE_ERROR    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="972.65,-4921.22 972.65,-4981.22 1477.65,-4981.22 1477.65,-4921.22 972.65,-4921.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="972.65,-4921.22 972.65,-4981.22 1477.65,-4981.22 1477.65,-4921.22 972.65,-4921.22"/>
|
||||
<text text-anchor="start" x="1087.37" y="-4942.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    OUR_ERROR    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="972.65,-4861.22 972.65,-4921.22 1477.65,-4921.22 1477.65,-4861.22 972.65,-4861.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="972.65,-4861.22 972.65,-4921.22 1477.65,-4921.22 1477.65,-4861.22 972.65,-4861.22"/>
|
||||
<text text-anchor="start" x="1031.38" y="-4882.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    CLIENT_DOCUMENT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="972.65,-4801.22 972.65,-4861.22 1477.65,-4861.22 1477.65,-4801.22 972.65,-4801.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="972.65,-4801.22 972.65,-4861.22 1477.65,-4861.22 1477.65,-4801.22 972.65,-4801.22"/>
|
||||
<text text-anchor="start" x="983.37" y="-4822.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    WITHOUT_PARTICIPATION    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="972.65,-4741.22 972.65,-4801.22 1477.65,-4801.22 1477.65,-4741.22 972.65,-4741.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="972.65,-4741.22 972.65,-4801.22 1477.65,-4801.22 1477.65,-4741.22 972.65,-4741.22"/>
|
||||
<text text-anchor="start" x="1144.22" y="-4762.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    AS_IS    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="971.15,-4740.22 971.15,-5102.22 1478.15,-5102.22 1478.15,-4740.22 971.15,-4740.22"/>
|
||||
</g>
|
||||
<!-- quality_failure_kind -->
|
||||
<g id="quality_failure_kind" class="node">
|
||||
<title>quality_failure_kind</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1224.65" cy="-219.22" rx="299.63" ry="214.92"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1014.65,-309.22 1014.65,-369.22 1434.65,-369.22 1434.65,-309.22 1014.65,-309.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1014.65,-309.22 1014.65,-369.22 1434.65,-369.22 1434.65,-309.22 1014.65,-309.22"/>
|
||||
<text text-anchor="start" x="1025.48" y="-330.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       quality_failure_kind       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1014.65,-249.22 1014.65,-309.22 1434.65,-309.22 1434.65,-249.22 1014.65,-249.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1014.65,-249.22 1014.65,-309.22 1434.65,-309.22 1434.65,-249.22 1014.65,-249.22"/>
|
||||
<text text-anchor="start" x="1052.18" y="-270.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    SERVICE_ERROR    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1014.65,-189.22 1014.65,-249.22 1434.65,-249.22 1434.65,-189.22 1014.65,-189.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1014.65,-189.22 1014.65,-249.22 1434.65,-249.22 1434.65,-189.22 1014.65,-189.22"/>
|
||||
<text text-anchor="start" x="1117.09" y="-210.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    TIMEOUT    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1014.65,-129.22 1014.65,-189.22 1434.65,-189.22 1434.65,-129.22 1014.65,-129.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1014.65,-129.22 1014.65,-189.22 1434.65,-189.22 1434.65,-129.22 1014.65,-129.22"/>
|
||||
<text text-anchor="start" x="1123.29" y="-150.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    NO_ACK    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1014.65,-69.22 1014.65,-129.22 1434.65,-129.22 1434.65,-69.22 1014.65,-69.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1014.65,-69.22 1014.65,-129.22 1434.65,-129.22 1434.65,-69.22 1014.65,-69.22"/>
|
||||
<text text-anchor="start" x="1115.29" y="-90.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    MAPPING    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1013.65,-68.22 1013.65,-370.22 1435.65,-370.22 1435.65,-68.22 1013.65,-68.22"/>
|
||||
</g>
|
||||
<!-- document_status -->
|
||||
<g id="document_status" class="node">
|
||||
<title>document_status</title>
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="1224.65" cy="-2399.22" rx="278.7" ry="214.92"/>
|
||||
<polygon fill="#29235c" stroke="transparent" points="1029.65,-2489.22 1029.65,-2549.22 1419.65,-2549.22 1419.65,-2489.22 1029.65,-2489.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1029.65,-2489.22 1029.65,-2549.22 1419.65,-2549.22 1419.65,-2489.22 1029.65,-2489.22"/>
|
||||
<text text-anchor="start" x="1040.58" y="-2510.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       document_status       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1029.65,-2429.22 1029.65,-2489.22 1419.65,-2489.22 1419.65,-2429.22 1029.65,-2429.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1029.65,-2429.22 1029.65,-2489.22 1419.65,-2489.22 1419.65,-2429.22 1029.65,-2429.22"/>
|
||||
<text text-anchor="start" x="1082.42" y="-2450.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    RECOGNIZED    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1029.65,-2369.22 1029.65,-2429.22 1419.65,-2429.22 1419.65,-2369.22 1029.65,-2369.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1029.65,-2369.22 1029.65,-2429.22 1419.65,-2429.22 1419.65,-2369.22 1029.65,-2369.22"/>
|
||||
<text text-anchor="start" x="1069.08" y="-2390.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    NEEDS_CHECK    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1029.65,-2309.22 1029.65,-2369.22 1419.65,-2369.22 1419.65,-2309.22 1029.65,-2309.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1029.65,-2309.22 1029.65,-2369.22 1419.65,-2369.22 1419.65,-2309.22 1029.65,-2309.22"/>
|
||||
<text text-anchor="start" x="1092.21" y="-2330.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    CONFIRMED    </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="1029.65,-2249.22 1029.65,-2309.22 1419.65,-2309.22 1419.65,-2249.22 1029.65,-2249.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="1029.65,-2249.22 1029.65,-2309.22 1419.65,-2309.22 1419.65,-2249.22 1029.65,-2249.22"/>
|
||||
<text text-anchor="start" x="1131.31" y="-2270.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#1d71b8">    ERROR    </text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="1028.65,-2248.22 1028.65,-2550.22 1420.65,-2550.22 1420.65,-2248.22 1028.65,-2248.22"/>
|
||||
</g>
|
||||
<!-- quality_intake_fact -->
|
||||
<g id="quality_intake_fact" class="node">
|
||||
<title>quality_intake_fact</title>
|
||||
<g id="a_quality_intake_fact"><a xlink:title="quality_intake_fact Отдельная схема PostgreSQL dkb_metrics (имя — настройка). Append-only, без FK на рабочие таблицы: переживает удаление/перераспознавание документа. Пишется в транзакции маппинга, после map_file, до auto_confirm — один факт на созданный документ BALANCE/INCOME/OSV.">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="379.72" cy="-2699.22" rx="379.93" ry="1402.8"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="113.72,-3629.22 113.72,-3689.22 646.72,-3689.22 646.72,-3629.22 113.72,-3629.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3629.22 113.72,-3689.22 646.72,-3689.22 646.72,-3629.22 113.72,-3629.22"/>
|
||||
<text text-anchor="start" x="185.48" y="-3650.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       quality_intake_fact       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3569.22 113.72,-3629.22 646.72,-3629.22 646.72,-3569.22 113.72,-3569.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3569.22 113.72,-3629.22 646.72,-3629.22 646.72,-3569.22 113.72,-3569.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3590.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="149.61" y="-3590.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="575.25" y="-3590.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3509.22 113.72,-3569.22 646.72,-3569.22 646.72,-3509.22 113.72,-3509.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3509.22 113.72,-3569.22 646.72,-3569.22 646.72,-3509.22 113.72,-3509.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3529.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">document_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-3530.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-3530.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-3530.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3449.22 113.72,-3509.22 646.72,-3509.22 646.72,-3449.22 113.72,-3449.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3449.22 113.72,-3509.22 646.72,-3509.22 646.72,-3449.22 113.72,-3449.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3469.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">file_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-3470.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-3470.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-3470.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3389.22 113.72,-3449.22 646.72,-3449.22 646.72,-3389.22 113.72,-3389.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3389.22 113.72,-3449.22 646.72,-3449.22 646.72,-3389.22 113.72,-3389.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3409.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">job_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-3410.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-3410.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-3410.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3329.22 113.72,-3389.22 646.72,-3389.22 646.72,-3329.22 113.72,-3329.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3329.22 113.72,-3389.22 646.72,-3389.22 646.72,-3329.22 113.72,-3329.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3349.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">attempt    </text>
|
||||
<text text-anchor="start" x="488.2" y="-3350.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">smallint</text>
|
||||
<text text-anchor="start" x="596.63" y="-3350.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-3350.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3269.22 113.72,-3329.22 646.72,-3329.22 646.72,-3269.22 113.72,-3269.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3269.22 113.72,-3329.22 646.72,-3329.22 646.72,-3269.22 113.72,-3269.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3289.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">legal_entity_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-3290.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-3290.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-3290.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3209.22 113.72,-3269.22 646.72,-3269.22 646.72,-3209.22 113.72,-3209.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3209.22 113.72,-3269.22 646.72,-3269.22 646.72,-3209.22 113.72,-3209.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3229.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">legal_entity_name    </text>
|
||||
<text text-anchor="start" x="489.95" y="-3230.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="596.63" y="-3230.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-3230.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3149.22 113.72,-3209.22 646.72,-3209.22 646.72,-3149.22 113.72,-3149.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3149.22 113.72,-3209.22 646.72,-3209.22 646.72,-3149.22 113.72,-3149.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3169.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">group_id    </text>
|
||||
<text text-anchor="start" x="575.25" y="-3170.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3089.22 113.72,-3149.22 646.72,-3149.22 646.72,-3089.22 113.72,-3089.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3089.22 113.72,-3149.22 646.72,-3149.22 646.72,-3089.22 113.72,-3089.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-3109.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">group_name    </text>
|
||||
<text text-anchor="start" x="529.04" y="-3110.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-3029.22 113.72,-3089.22 646.72,-3089.22 646.72,-3029.22 113.72,-3029.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-3029.22 113.72,-3089.22 646.72,-3089.22 646.72,-3029.22 113.72,-3029.22"/>
|
||||
<text text-anchor="start" x="124.56" y="-3049.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">document_type    </text>
|
||||
<text text-anchor="start" x="378.3" y="-3050.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">document_type</text>
|
||||
<text text-anchor="start" x="597.05" y="-3050.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.94" y="-3050.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2969.22 113.72,-3029.22 646.72,-3029.22 646.72,-2969.22 113.72,-2969.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2969.22 113.72,-3029.22 646.72,-3029.22 646.72,-2969.22 113.72,-2969.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2989.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">pipeline    </text>
|
||||
<text text-anchor="start" x="312.11" y="-2990.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">recognition_pipeline</text>
|
||||
<text text-anchor="start" x="596.63" y="-2990.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-2990.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2909.22 113.72,-2969.22 646.72,-2969.22 646.72,-2909.22 113.72,-2909.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2909.22 113.72,-2969.22 646.72,-2969.22 646.72,-2909.22 113.72,-2909.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2929.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_scan    </text>
|
||||
<text text-anchor="start" x="521.88" y="-2930.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2849.22 113.72,-2909.22 646.72,-2909.22 646.72,-2849.22 113.72,-2849.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2849.22 113.72,-2909.22 646.72,-2909.22 646.72,-2849.22 113.72,-2849.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2869.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">service_name    </text>
|
||||
<text text-anchor="start" x="529.04" y="-2870.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2789.22 113.72,-2849.22 646.72,-2849.22 646.72,-2789.22 113.72,-2789.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2789.22 113.72,-2849.22 646.72,-2849.22 646.72,-2789.22 113.72,-2789.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2809.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">service_version    </text>
|
||||
<text text-anchor="start" x="529.04" y="-2810.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2729.22 113.72,-2789.22 646.72,-2789.22 646.72,-2729.22 113.72,-2729.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2729.22 113.72,-2789.22 646.72,-2789.22 646.72,-2729.22 113.72,-2729.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2749.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">statements_version    </text>
|
||||
<text text-anchor="start" x="529.04" y="-2750.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2669.22 113.72,-2729.22 646.72,-2729.22 646.72,-2669.22 113.72,-2669.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2669.22 113.72,-2729.22 646.72,-2729.22 646.72,-2669.22 113.72,-2669.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2689.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">result_schema_version    </text>
|
||||
<text text-anchor="start" x="529.04" y="-2690.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2609.22 113.72,-2669.22 646.72,-2669.22 646.72,-2609.22 113.72,-2609.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2609.22 113.72,-2669.22 646.72,-2669.22 646.72,-2609.22 113.72,-2609.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2629.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">report_date    </text>
|
||||
<text text-anchor="start" x="573.46" y="-2630.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">date</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2549.22 113.72,-2609.22 646.72,-2609.22 646.72,-2549.22 113.72,-2549.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2549.22 113.72,-2609.22 646.72,-2609.22 646.72,-2549.22 113.72,-2549.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2569.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">intake_at    </text>
|
||||
<text text-anchor="start" x="424.17" y="-2570.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<text text-anchor="start" x="596.63" y="-2570.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-2570.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2489.22 113.72,-2549.22 646.72,-2549.22 646.72,-2489.22 113.72,-2489.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2489.22 113.72,-2549.22 646.72,-2549.22 646.72,-2489.22 113.72,-2489.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2509.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">intake_status    </text>
|
||||
<text text-anchor="start" x="352.98" y="-2510.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">document_status</text>
|
||||
<text text-anchor="start" x="596.63" y="-2510.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-2510.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2429.22 113.72,-2489.22 646.72,-2489.22 646.72,-2429.22 113.72,-2429.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2429.22 113.72,-2489.22 646.72,-2489.22 646.72,-2429.22 113.72,-2429.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2449.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">line_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2450.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2369.22 113.72,-2429.22 646.72,-2429.22 646.72,-2369.22 113.72,-2369.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2369.22 113.72,-2429.22 646.72,-2429.22 646.72,-2369.22 113.72,-2369.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2389.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">value_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2390.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2309.22 113.72,-2369.22 646.72,-2369.22 646.72,-2309.22 113.72,-2309.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2309.22 113.72,-2369.22 646.72,-2369.22 646.72,-2309.22 113.72,-2309.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2329.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">value_needs_review_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2330.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2249.22 113.72,-2309.22 646.72,-2309.22 646.72,-2249.22 113.72,-2249.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2249.22 113.72,-2309.22 646.72,-2309.22 646.72,-2249.22 113.72,-2249.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2269.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">line_unreadable_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2270.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2189.22 113.72,-2249.22 646.72,-2249.22 646.72,-2189.22 113.72,-2189.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2189.22 113.72,-2249.22 646.72,-2249.22 646.72,-2189.22 113.72,-2189.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2209.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">line_missing_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2210.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2129.22 113.72,-2189.22 646.72,-2189.22 646.72,-2129.22 113.72,-2129.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2129.22 113.72,-2189.22 646.72,-2189.22 646.72,-2129.22 113.72,-2129.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2149.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">issue_relation_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2150.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2069.22 113.72,-2129.22 646.72,-2129.22 646.72,-2069.22 113.72,-2069.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2069.22 113.72,-2129.22 646.72,-2129.22 646.72,-2069.22 113.72,-2069.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2089.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">issue_soft_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2090.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-2009.22 113.72,-2069.22 646.72,-2069.22 646.72,-2009.22 113.72,-2009.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-2009.22 113.72,-2069.22 646.72,-2069.22 646.72,-2009.22 113.72,-2009.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-2029.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">warning_count    </text>
|
||||
<text text-anchor="start" x="601.93" y="-2030.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-1949.22 113.72,-2009.22 646.72,-2009.22 646.72,-1949.22 113.72,-1949.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-1949.22 113.72,-2009.22 646.72,-2009.22 646.72,-1949.22 113.72,-1949.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-1969.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">raw_s3_key    </text>
|
||||
<text text-anchor="start" x="529.04" y="-1970.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-1889.22 113.72,-1949.22 646.72,-1949.22 646.72,-1889.22 113.72,-1889.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-1889.22 113.72,-1949.22 646.72,-1949.22 646.72,-1889.22 113.72,-1889.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-1909.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">result_s3_key    </text>
|
||||
<text text-anchor="start" x="529.04" y="-1910.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-1829.22 113.72,-1889.22 646.72,-1889.22 646.72,-1829.22 113.72,-1829.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-1829.22 113.72,-1889.22 646.72,-1889.22 646.72,-1829.22 113.72,-1829.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-1849.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">upload_s3_key    </text>
|
||||
<text text-anchor="start" x="529.04" y="-1850.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-1769.22 113.72,-1829.22 646.72,-1829.22 646.72,-1769.22 113.72,-1769.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-1769.22 113.72,-1829.22 646.72,-1829.22 646.72,-1769.22 113.72,-1769.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-1789.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">payload    </text>
|
||||
<text text-anchor="start" x="520.16" y="-1790.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">jsonb</text>
|
||||
<text text-anchor="start" x="596.63" y="-1790.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-1790.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-1709.22 113.72,-1769.22 646.72,-1769.22 646.72,-1709.22 113.72,-1709.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-1709.22 113.72,-1769.22 646.72,-1769.22 646.72,-1709.22 113.72,-1709.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-1729.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">payload_schema_version    </text>
|
||||
<text text-anchor="start" x="529.04" y="-1730.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="112.22,-1708.22 112.22,-3690.22 647.22,-3690.22 647.22,-1708.22 112.22,-1708.22"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- quality_intake_fact->document_type -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>quality_intake_fact:e->document_type:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M647.72,-3059.22C822.8,-3059.22 866.57,-3059.22 1041.65,-3059.22"/>
|
||||
</g>
|
||||
<!-- quality_intake_fact->recognition_pipeline -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>quality_intake_fact:e->recognition_pipeline:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M647.72,-2999.22C833.75,-2999.22 755.2,-2356.85 795.43,-2175.22 875.57,-1813.45 638.1,-1369.22 1008.65,-1369.22"/>
|
||||
</g>
|
||||
<!-- quality_intake_fact->document_status -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>quality_intake_fact:e->document_status:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M647.72,-2519.22C817.02,-2519.22 859.34,-2519.22 1028.65,-2519.22"/>
|
||||
</g>
|
||||
<!-- quality_outcome_fact -->
|
||||
<g id="quality_outcome_fact" class="node">
|
||||
<title>quality_outcome_fact</title>
|
||||
<g id="a_quality_outcome_fact"><a xlink:title="quality_outcome_fact НЕ unique на document_id: повторное подтверждение ОСВ и исход DELETED_AFTER_CONFIRM/SUPERSEDED_AFTER_CONFIRM пишут новый факт поверх прежнего. Метрики берут последний факт по outcome_at. Пишется при первом из событий: подтверждение (ручное/auto_confirm), удаление до подтверждения, автозамена.">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="379.72" cy="-5014.22" rx="374.53" ry="893.57"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="116.72,-5584.22 116.72,-5644.22 642.72,-5644.22 642.72,-5584.22 116.72,-5584.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5584.22 116.72,-5644.22 642.72,-5644.22 642.72,-5584.22 116.72,-5584.22"/>
|
||||
<text text-anchor="start" x="166.31" y="-5605.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       quality_outcome_fact       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5524.22 116.72,-5584.22 642.72,-5584.22 642.72,-5524.22 116.72,-5524.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5524.22 116.72,-5584.22 642.72,-5584.22 642.72,-5524.22 116.72,-5524.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5545.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="152.61" y="-5545.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="571.25" y="-5545.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5464.22 116.72,-5524.22 642.72,-5524.22 642.72,-5464.22 116.72,-5464.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5464.22 116.72,-5524.22 642.72,-5524.22 642.72,-5464.22 116.72,-5464.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5484.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">document_id    </text>
|
||||
<text text-anchor="start" x="532.16" y="-5485.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="592.63" y="-5485.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5485.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5404.22 116.72,-5464.22 642.72,-5464.22 642.72,-5404.22 116.72,-5404.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5404.22 116.72,-5464.22 642.72,-5464.22 642.72,-5404.22 116.72,-5404.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5424.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">outcome    </text>
|
||||
<text text-anchor="start" x="359.67" y="-5425.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">quality_outcome</text>
|
||||
<text text-anchor="start" x="592.63" y="-5425.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5425.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5344.22 116.72,-5404.22 642.72,-5404.22 642.72,-5344.22 116.72,-5344.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5344.22 116.72,-5404.22 642.72,-5404.22 642.72,-5344.22 116.72,-5344.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5364.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">outcome_at    </text>
|
||||
<text text-anchor="start" x="420.17" y="-5365.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<text text-anchor="start" x="592.63" y="-5365.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5365.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5284.22 116.72,-5344.22 642.72,-5344.22 642.72,-5284.22 116.72,-5284.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5284.22 116.72,-5344.22 642.72,-5344.22 642.72,-5284.22 116.72,-5284.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5304.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">primary_cause    </text>
|
||||
<text text-anchor="start" x="436.1" y="-5305.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">quality_cause</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5224.22 116.72,-5284.22 642.72,-5284.22 642.72,-5224.22 116.72,-5224.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5224.22 116.72,-5284.22 642.72,-5284.22 642.72,-5224.22 116.72,-5224.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5244.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_value_service    </text>
|
||||
<text text-anchor="start" x="558.84" y="-5245.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-5245.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5245.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5164.22 116.72,-5224.22 642.72,-5224.22 642.72,-5164.22 116.72,-5164.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5164.22 116.72,-5224.22 642.72,-5224.22 642.72,-5164.22 116.72,-5164.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5184.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_value_ours    </text>
|
||||
<text text-anchor="start" x="558.84" y="-5185.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-5185.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5185.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5104.22 116.72,-5164.22 642.72,-5164.22 642.72,-5104.22 116.72,-5104.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5104.22 116.72,-5164.22 642.72,-5164.22 642.72,-5104.22 116.72,-5104.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5124.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_code_service    </text>
|
||||
<text text-anchor="start" x="558.84" y="-5125.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-5125.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5125.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-5044.22 116.72,-5104.22 642.72,-5104.22 642.72,-5044.22 116.72,-5044.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-5044.22 116.72,-5104.22 642.72,-5104.22 642.72,-5044.22 116.72,-5044.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5064.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_code_ours    </text>
|
||||
<text text-anchor="start" x="558.84" y="-5065.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-5065.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5065.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4984.22 116.72,-5044.22 642.72,-5044.22 642.72,-4984.22 116.72,-4984.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4984.22 116.72,-5044.22 642.72,-5044.22 642.72,-4984.22 116.72,-4984.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-5004.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_added_row_service    </text>
|
||||
<text text-anchor="start" x="558.84" y="-5005.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-5005.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-5005.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4924.22 116.72,-4984.22 642.72,-4984.22 642.72,-4924.22 116.72,-4924.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4924.22 116.72,-4984.22 642.72,-4984.22 642.72,-4924.22 116.72,-4924.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4944.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_added_row_ours    </text>
|
||||
<text text-anchor="start" x="558.84" y="-4945.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-4945.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4945.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4864.22 116.72,-4924.22 642.72,-4924.22 642.72,-4864.22 116.72,-4864.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4864.22 116.72,-4924.22 642.72,-4924.22 642.72,-4864.22 116.72,-4864.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4884.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_header_service    </text>
|
||||
<text text-anchor="start" x="558.84" y="-4885.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-4885.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4885.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4804.22 116.72,-4864.22 642.72,-4864.22 642.72,-4804.22 116.72,-4804.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4804.22 116.72,-4864.22 642.72,-4864.22 642.72,-4804.22 116.72,-4804.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4824.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_header_ours    </text>
|
||||
<text text-anchor="start" x="558.84" y="-4825.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-4825.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4825.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4744.22 116.72,-4804.22 642.72,-4804.22 642.72,-4744.22 116.72,-4744.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4744.22 116.72,-4804.22 642.72,-4804.22 642.72,-4744.22 116.72,-4744.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4764.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">fixes_osv_period_account    </text>
|
||||
<text text-anchor="start" x="558.84" y="-4765.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-4765.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4765.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4684.22 116.72,-4744.22 642.72,-4744.22 642.72,-4684.22 116.72,-4684.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4684.22 116.72,-4744.22 642.72,-4744.22 642.72,-4684.22 116.72,-4684.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4704.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">checks_accepted    </text>
|
||||
<text text-anchor="start" x="478.79" y="-4705.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<text text-anchor="start" x="592.63" y="-4705.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4705.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4624.22 116.72,-4684.22 642.72,-4684.22 642.72,-4624.22 116.72,-4624.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4624.22 116.72,-4684.22 642.72,-4684.22 642.72,-4624.22 116.72,-4624.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4644.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">issue_count_at_outcome    </text>
|
||||
<text text-anchor="start" x="558.84" y="-4645.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">int</text>
|
||||
<text text-anchor="start" x="592.63" y="-4645.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4645.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4564.22 116.72,-4624.22 642.72,-4624.22 642.72,-4564.22 116.72,-4564.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4564.22 116.72,-4624.22 642.72,-4624.22 642.72,-4564.22 116.72,-4564.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4584.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">report_date    </text>
|
||||
<text text-anchor="start" x="569.46" y="-4585.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">date</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4504.22 116.72,-4564.22 642.72,-4564.22 642.72,-4504.22 116.72,-4504.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4504.22 116.72,-4564.22 642.72,-4564.22 642.72,-4504.22 116.72,-4504.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4524.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">confirmed_by    </text>
|
||||
<text text-anchor="start" x="571.25" y="-4525.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4444.22 116.72,-4504.22 642.72,-4504.22 642.72,-4444.22 116.72,-4444.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4444.22 116.72,-4504.22 642.72,-4504.22 642.72,-4444.22 116.72,-4444.22"/>
|
||||
<text text-anchor="start" x="127.72" y="-4464.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">payload    </text>
|
||||
<text text-anchor="start" x="516.16" y="-4465.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">jsonb</text>
|
||||
<text text-anchor="start" x="592.63" y="-4465.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="601.52" y="-4465.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="116.72,-4384.22 116.72,-4444.22 642.72,-4444.22 642.72,-4384.22 116.72,-4384.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="116.72,-4384.22 116.72,-4444.22 642.72,-4444.22 642.72,-4384.22 116.72,-4384.22"/>
|
||||
<text text-anchor="start" x="127.55" y="-4404.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">payload_schema_version    </text>
|
||||
<text text-anchor="start" x="525.38" y="-4405.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="115.72,-4383.22 115.72,-5645.22 643.72,-5645.22 643.72,-4383.22 115.72,-4383.22"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- quality_outcome_fact->quality_outcome -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>quality_outcome_fact:e->quality_outcome:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M643.72,-5434.22C807.84,-5434.22 758.52,-5676.22 922.65,-5676.22"/>
|
||||
</g>
|
||||
<!-- quality_outcome_fact->quality_cause -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>quality_outcome_fact:e->quality_cause:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M643.72,-5314.22C731.65,-5314.22 724.88,-5239.71 795.43,-5187.22 870.66,-5131.26 877.88,-5071.22 971.65,-5071.22"/>
|
||||
</g>
|
||||
<!-- quality_failure_fact -->
|
||||
<g id="quality_failure_fact" class="node">
|
||||
<title>quality_failure_fact</title>
|
||||
<g id="a_quality_failure_fact"><a xlink:title="quality_failure_fact Технический отказ задания распознавания (recognition_job.status error/timeout/dlq) или неповторяемая ошибка маппинга (MappingFatal). Считается по файлам, не по документам — знаменатель «отказавших файлов от загруженных того же pipeline» (§14), фильтр по типу документа не действует. FILE_REPROCESS: отказ первой попытки остаётся фактом, документы удачной попытки получают свои intake/outcome. Нет payload/payload_schema_version — все поля плоские.">
|
||||
<ellipse fill="none" stroke="black" stroke-width="0" cx="379.72" cy="-639.22" rx="379.93" ry="639.45"/>
|
||||
<polygon fill="#1d71b8" stroke="transparent" points="113.72,-1029.22 113.72,-1089.22 646.72,-1089.22 646.72,-1029.22 113.72,-1029.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-1029.22 113.72,-1089.22 646.72,-1089.22 646.72,-1029.22 113.72,-1029.22"/>
|
||||
<text text-anchor="start" x="184.6" y="-1050.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#ffffff">       quality_failure_fact       </text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-969.22 113.72,-1029.22 646.72,-1029.22 646.72,-969.22 113.72,-969.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-969.22 113.72,-1029.22 646.72,-1029.22 646.72,-969.22 113.72,-969.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-990.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">id</text>
|
||||
<text text-anchor="start" x="149.61" y="-990.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">    </text>
|
||||
<text text-anchor="start" x="575.25" y="-990.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-909.22 113.72,-969.22 646.72,-969.22 646.72,-909.22 113.72,-909.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-909.22 113.72,-969.22 646.72,-969.22 646.72,-909.22 113.72,-909.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-929.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">job_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-930.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-930.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-930.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-849.22 113.72,-909.22 646.72,-909.22 646.72,-849.22 113.72,-849.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-849.22 113.72,-909.22 646.72,-909.22 646.72,-849.22 113.72,-849.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-869.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">file_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-870.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-870.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-870.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-789.22 113.72,-849.22 646.72,-849.22 646.72,-789.22 113.72,-789.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-789.22 113.72,-849.22 646.72,-849.22 646.72,-789.22 113.72,-789.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-809.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">attempt    </text>
|
||||
<text text-anchor="start" x="488.2" y="-810.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">smallint</text>
|
||||
<text text-anchor="start" x="596.63" y="-810.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-810.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-729.22 113.72,-789.22 646.72,-789.22 646.72,-729.22 113.72,-729.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-729.22 113.72,-789.22 646.72,-789.22 646.72,-729.22 113.72,-729.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-749.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">legal_entity_id    </text>
|
||||
<text text-anchor="start" x="536.16" y="-750.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<text text-anchor="start" x="596.63" y="-750.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-750.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-669.22 113.72,-729.22 646.72,-729.22 646.72,-669.22 113.72,-669.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-669.22 113.72,-729.22 646.72,-729.22 646.72,-669.22 113.72,-669.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-689.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">legal_entity_name    </text>
|
||||
<text text-anchor="start" x="489.95" y="-690.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<text text-anchor="start" x="596.63" y="-690.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-690.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-609.22 113.72,-669.22 646.72,-669.22 646.72,-609.22 113.72,-609.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-609.22 113.72,-669.22 646.72,-669.22 646.72,-609.22 113.72,-609.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-629.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">group_id    </text>
|
||||
<text text-anchor="start" x="575.25" y="-630.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">uuid</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-549.22 113.72,-609.22 646.72,-609.22 646.72,-549.22 113.72,-549.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-549.22 113.72,-609.22 646.72,-609.22 646.72,-549.22 113.72,-549.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-569.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">group_name    </text>
|
||||
<text text-anchor="start" x="529.04" y="-570.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-489.22 113.72,-549.22 646.72,-549.22 646.72,-489.22 113.72,-489.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-489.22 113.72,-549.22 646.72,-549.22 646.72,-489.22 113.72,-489.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-509.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">pipeline    </text>
|
||||
<text text-anchor="start" x="312.11" y="-510.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">recognition_pipeline</text>
|
||||
<text text-anchor="start" x="596.63" y="-510.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-510.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-429.22 113.72,-489.22 646.72,-489.22 646.72,-429.22 113.72,-429.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-429.22 113.72,-489.22 646.72,-489.22 646.72,-429.22 113.72,-429.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-449.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">is_scan    </text>
|
||||
<text text-anchor="start" x="521.88" y="-450.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">boolean</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-369.22 113.72,-429.22 646.72,-429.22 646.72,-369.22 113.72,-369.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-369.22 113.72,-429.22 646.72,-429.22 646.72,-369.22 113.72,-369.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-389.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">service_name    </text>
|
||||
<text text-anchor="start" x="529.04" y="-390.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-309.22 113.72,-369.22 646.72,-369.22 646.72,-309.22 113.72,-309.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-309.22 113.72,-369.22 646.72,-369.22 646.72,-309.22 113.72,-309.22"/>
|
||||
<text text-anchor="start" x="124.64" y="-329.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">failure_kind    </text>
|
||||
<text text-anchor="start" x="323.26" y="-330.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">quality_failure_kind</text>
|
||||
<text text-anchor="start" x="597.09" y="-330.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.98" y="-330.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-249.22 113.72,-309.22 646.72,-309.22 646.72,-249.22 113.72,-249.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-249.22 113.72,-309.22 646.72,-309.22 646.72,-249.22 113.72,-249.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-269.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">error_code    </text>
|
||||
<text text-anchor="start" x="529.04" y="-270.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">varchar</text>
|
||||
<polygon fill="#e7e2dd" stroke="transparent" points="113.72,-189.22 113.72,-249.22 646.72,-249.22 646.72,-189.22 113.72,-189.22"/>
|
||||
<polygon fill="none" stroke="#29235c" points="113.72,-189.22 113.72,-249.22 646.72,-249.22 646.72,-189.22 113.72,-189.22"/>
|
||||
<text text-anchor="start" x="124.72" y="-209.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c">failed_at    </text>
|
||||
<text text-anchor="start" x="424.17" y="-210.42" font-family="Helvetica,sans-Serif" font-style="italic" font-size="32.00" fill="#29235c">timestamptz</text>
|
||||
<text text-anchor="start" x="596.63" y="-210.42" font-family="Helvetica,sans-Serif" font-size="32.00" fill="#29235c"> </text>
|
||||
<text text-anchor="start" x="605.52" y="-210.42" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="32.00" fill="#29235c">(!)</text>
|
||||
<polygon fill="none" stroke="#29235c" stroke-width="2" points="112.22,-188.22 112.22,-1090.22 647.22,-1090.22 647.22,-188.22 112.22,-188.22"/>
|
||||
</a>
|
||||
</g>
|
||||
</g>
|
||||
<!-- quality_failure_fact->recognition_pipeline -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>quality_failure_fact:e->recognition_pipeline:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M647.72,-519.22C1058.14,-519.22 598.22,-1369.22 1008.65,-1369.22"/>
|
||||
</g>
|
||||
<!-- quality_failure_fact->quality_failure_kind -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>quality_failure_fact:e->quality_failure_kind:w</title>
|
||||
<path fill="none" stroke="#29235c" stroke-width="3" d="M647.72,-339.22C810.35,-339.22 851.01,-339.22 1013.65,-339.22"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 70 KiB |
276
model/entities-v5.25.md
Normal file
@ -0,0 +1,276 @@
|
||||
# АРМ КА — описание сущностей модели данных v5.25
|
||||
|
||||
Источник истины по структуре — `data-model-v5.25.dbml` (полный). Диаграммы по частям — `diagrams/` (part01…10 svg/png; перерисовываются `make diagrams` из текущего DBML). Здесь — что каждая таблица значит для бизнеса, как связана с соседями и откуда взялась.
|
||||
|
||||
## Что изменилось в v5.25 (AURORA-1759; RSHB/arm-ka-docs#202; миграция — отдельный change arm-core#190)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | Три новые таблицы `quality_intake_fact`, `quality_outcome_fact`, `quality_failure_fact` | Append-only факты качества распознавания первички (документ «как распознано», его исход, технический отказ задания), без FK на рабочие таблицы — переживают удаление/перераспознавание. Полное WHY и решения владельца — `../arm-core/openspec/changes/quality-metrics/design.md` §1-3, §10; состав столбцов — `openspec/changes/quality-metrics/design.md` §1.4-1.6 этого репозитория. Часть 10 ниже |
|
||||
| 2 | `s3_bucket_role.raw` | Сырой ответ ИС Сканирование (`raw/{job_id}.json`) теперь регистрируется в `s3_object`; не экспирится с удалением файла — вход для будущего эталонного прогона перенормализации |
|
||||
| 3 | `stored_file.is_scan` | Признак скан/цифровой PDF по текстовому слою при загрузке; NULL для не-PDF |
|
||||
| 4 | `recognition_job.raw_s3_object_id` | Ссылка на зарегистрированный сырой ответ (image pipeline) — отменяет решение v5.13 «сырой ответ в БД не регистрируется» |
|
||||
| 5 | `permission_object.QUALITY_METRICS` | Объект права экрана «Качество первички» (действие `VIEW`); право `QUALITY_METRICS_VIEW` — seed в arm-core, не в DBML |
|
||||
|
||||
Остальные таблицы и enum — как в v5.24.
|
||||
|
||||
## Что изменилось в v5.24 (AURORA-1751/1540/1541; RSHB/arm-ka-docs#196; миграция уже слита в arm-core main)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | Новая таблица `vgo_assignment` | Ручное решение аналитика по строке сводной ОСВ сверх автоматического разнесения по правилам ВГО (`context/05-domain-rules.md` §5): привязка к правилу, снятие привязки, «не учитывать в КФО» у нераспределённой строки. Само разнесение остаётся чистой функцией и не хранится (DECISION-5) — таблица только перекрывает его решением аналитика. Одна действующая запись на строку ОСВ в версии и типе отчётности |
|
||||
| 2 | Поле `side` не добавлено | Черновик контракта (`dev/api-contract-corrections.md` §5) предполагал отдельную позицию для строки с одновременно дебетовым и кредитовым сальдо; в уже слитой миграции 0011 решение одно на обе позиции строки, не по стороне |
|
||||
|
||||
Остальные таблицы и enum — как в v5.23.
|
||||
|
||||
## Что изменилось в v5.23 (решения владельца 23.10.2026; RSHB/arm-ka-docs#164, AURORA-1536)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `consolidation_version.elimination_rules_version` — `not null` | Версия правил элиминации (`elimination_rule.version_no`), действующая на **дату создания** версии консолидации (OQ-174), фиксируется при создании и дальше не меняется. По ней считаются шахматка по правилу-пресету и пары ВГО (`context/05-domain-rules.md` §4, §5). Вариант «пусто — значит последние открытые правила» отвергнут: после публикации новой версии правил старые консолидации молча пересчитались бы по ней. Версия консолидации без действующих правил не создаётся |
|
||||
|
||||
Остальные таблицы и enum — как в v5.22. Реализация — одна миграция в `arm-core`: существующим версиям проставляется номер
|
||||
версии правил, действовавшей на дату `created_at` (по Москве; если такой нет — последней открытой), затем `NOT NULL`; откат
|
||||
снимает только ограничение.
|
||||
|
||||
## Что изменилось в v5.22 (22.10.2026; AURORA-1446)
|
||||
|
||||
Из описания `comment.object_type` убраны устаревшие варианты `chess_cell` и `kfo_result_line`.
|
||||
Сохранены `document | consolidation_version | …`; сейчас используется привязка к документу. Комментарий к правке пары ВГО хранится
|
||||
в `correction.comment`, к строкам КФО — в `kfo_result_line.comment` и `client_kfo_line.comment`.
|
||||
Структура БД не меняется, миграция не требуется. Предыдущие версии модели сохранены.
|
||||
|
||||
## Что изменилось в v5.21 (решение владельца 22.10.2026; RSHB/arm-ka-docs#149, AURORA-1442)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `audit_action` + `FILE_REPROCESS` | Повторная обработка файла пользователем (`context/05-domain-rules.md` §9.5 п. 13) — отдельное событие журнала, раздел `PRIMARY_DOCUMENTS`. Файл не загружается заново: создаётся новое `recognition_job` с `attempt + 1` и становится `current_recognition_job_id`. `FILE_UPLOAD` отвергнут — это приём нового файла, и журнал показал бы вторую загрузку, которой не было; `FILE_REPLACE` — автозамена одного файла другим. Событие пишется на файл (`object_type = stored_file`): `before_value` — прежнее задание (`job_id`, `attempt`, `status`, `error_code`), `after_value` — новое (`job_id`, `attempt`); повторная обработка пакета версии — по событию на каждый отправленный файл, с `consolidation_id` в `after_value` |
|
||||
|
||||
Остальные таблицы и enum — как в v5.20. Реализация — одна миграция в `arm-core`: только добавляет значение enum; откат при
|
||||
наличии событий `FILE_REPROCESS` останавливается с ошибкой (журнал append-only).
|
||||
|
||||
## Что изменилось в v5.20 (решения владельца 21.10.2026; RSHB/arm-ka-docs#147, OQ-161, AURORA-1442)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `document`: `is_modified` (not null, default `false`), `original_values` (jsonb), `modified_by` (FK → `app_user`), `modified_at` | Аналитик уточняет **период и счёт документа ОСВ**, если они распознаны неверно (`context/05-domain-rules.md` §9.5 п. 12; OQ-161, вариант 2). Новые значения пишутся **на месте** — в `period_year`, `period_quarter`, `is_cumulative`, `osv_account_code` той же строки `document`; при первой правке прежние значения этих четырёх полей копируются в `original_values` и дальше не меняются; `is_modified` — текущие отличаются от исходных. Так же устроена правка сумм `osv_entry` (`original_values`) — первичка не мутируется: файл, JSON результата в S3 и исходные значения остаются как пришли. Копия `document` (второй документ с другим `file_ordinal`) отвергнута: `file_ordinal` — номер документа в `documents[]` результата, а не номер редакции; копия задвоила бы строки ОСВ, подтверждение и привязки. Строки `osv_entry` при смене счёта не меняются (у них свои коды субсчетов) |
|
||||
|
||||
Остальные таблицы и enum — как в v5.19. Реализация — одна миграция в `arm-core`: только добавляет колонки (`is_modified =
|
||||
false`, остальные `NULL`); откат на данных с `is_modified = true` останавливается с ошибкой (потерялись бы исходные значения).
|
||||
|
||||
## Что изменилось в v5.19 (решения владельца 17.10.2026, Р-1…Р-19; RSHB/arm-ka-docs#116)
|
||||
|
||||
Change `openspec/changes/archive/2026-10-19-unified-statement-normalization`: формы ББ/ОФР нормализуются общим кодом сервисов, контракт
|
||||
результата v2.0; ядро хранит результат как пришёл (`context/05-domain-rules.md` §11, §9.3, §9.5).
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `financial_statement_line`: снята уникальность `(meta_id, line_code)` (индекс остаётся неуникальным); новые `row_index`, `source_ref` (частичный уникальный `(meta_id, source_ref) WHERE source_ref IS NOT NULL`), `line_status` (enum `statement_line_status`: `ok` / `unreadable` / `missing` / `detail`), `line_code_text`, `parent_row_index`, `needs_review`, `is_confirmed` | Повтор кода — законный случай (один код, разные наименования; Р-4): хранятся все строки, чтения «по коду» идут через агрегат формы по коду (сумма строк `ok`, не хранится — DECISION-5). Строки без кода хранятся со статусом (Р-8, отменяет OQ-36 / OQ-141): `detail` — расшифровка под строкой с кодом, в §7, агрегаты, КФО и ЕХ не входит; `unreadable` / `missing` блокируют подтверждение, пока у них есть суммы (Р-13). Порядок и положение в источнике (`row_index`, `source_ref`) нужны экрану, чтобы показать строку и предупреждение у места. **Признак «строка создана правкой аналитика» — `row_index IS NULL`** (прежний признак `line_code_original_value IS NULL` не годится: у строк `unreadable` / `missing` / `detail` источника кода тоже нет); `line_code_original_value` — код из результата как пришёл, правками не меняется |
|
||||
| 2 | `financial_statement_value`: `source_text`, `needs_review`, `is_confirmed`, `confirmed_by`, `confirmed_at` | `needs_review` **хранится** (пересматривает п. 4 v5.13): его считает сервис («подтверждение проверкой» §7 — Р-5, Р-7), ядро пересчитывает только после правок; подтверждение ячейки без правки аналитиком переживает пересчёт. Сырой текст источника — подсказка ячейки |
|
||||
| 3 | `financial_statement_column`: `period_kind`, `label_confidence` | Относительные подписи бланка 66н («На отчётную дату», «На 31 декабря предыдущего года») — дата колонки от эффективной даты документа, ядро досчитывает после правки даты отчёта (Р-6); колонка без даты остаётся с `period_kind = none` |
|
||||
| 4 | `financial_statement_meta`: `form_variant` (enum `statement_form_variant`), `needs_review_fields`, `header_source` (jsonb), `organization_name_original_value`, `organization_name_modified` | Упрощённая форма — свой набор соотношений §7 (`NULL` — документ до v5.19 или результат 1.x, набор полный); поля шапки, требующие проверки (сейчас — неуверенная дата отчёта); сырой текст и уверенность всех полей шапки результата (`<поле>_text`, `<поле>_confidence`) — подсказка у поля на экране; наименование организации правится, как ИНН |
|
||||
| 5 | Новая таблица `document_issue` + enum `document_issue_kind`, `issue_severity`, `issue_source` | Предупреждения и нарушения §7 документа с уровнем и привязкой к строкам (`line_ids`), колонке (`column_id`, а вне колонок формы — `column_index`), полю шапки; у нарушения — `codes` (коды цели и членов); как пришли от сервиса или посчитаны ядром. Очищается при перезагрузке файла; при пересчёте после правки `relation` / `soft` заменяются целиком, `warning` сервиса сохраняются, кроме снимаемых правкой. **Единственный источник нарушений** для экрана и подтверждения: для результатов 1.x ядро один раз при приёме считает §7 копией `arm_statements` и пишет записи с `source = core`; формы до миграции не пересчитываются (база очищается, Р-24). Ведётся и у документов ОСВ — предупреждения листа `OSV_*` результата 2.0 |
|
||||
| 6 | `recognition_job.statements_version` | Коммит копии общего кода `arm_statements`, которым посчитан результат (`service.statements_version`); расхождение с копией ядра при пересчёте — `info` |
|
||||
| 7 | `document`: уникальность `(stored_file_id, document_type, osv_account_code)` — частичная, кроме `BALANCE` / `INCOME`; новая колонка `file_ordinal` + уникальный `(stored_file_id, file_ordinal)` | Вторая форма того же типа в файле хранится (Р-10, Р-15); при двух формах одного типа и периода ни одна не автоподтверждается, подтверждение второй при подтверждённой первой — 409 `DUPLICATE_FORM` (Р-18). ОСВ по счёту, расшифровка и прочий — по-прежнему один на тип на файл (§9.5 п. 2) |
|
||||
| 8 | `related_group.crm_id` (`varchar`, nullable, unique) | ID ГСК/ГСЗ в ЕЦП CRM из форм `51-03`, `51-04`, `77-02` (AURORA-1619, arm-core#112, OQ-33); вводится вручную, импорт ЕЦП не заполняет (OQ-91); уникален, как `crm_id` ГК и ЮЛ |
|
||||
|
||||
Остальные таблицы и enum — как в v5.18. Реализация — одна миграция в `arm-core`; перед выкладкой база очищается от форм
|
||||
ББ/ОФР (решение владельца 18.10.2026, Р-24), поэтому миграция только добавляет колонки, таблицу и значения по умолчанию и
|
||||
§7 по существующим формам не считает. Заполнение (миграция проходит и на непустой базе): `row_index` — `NULL` у строк,
|
||||
созданных правкой (`line_code_original_value IS NULL`), у остальных — по возрастанию `line_code` в форме; `line_status =
|
||||
ok`, `needs_review` значений — **НЕ** `values_ok`, `source_text = string_value`, `period_kind` — `absolute` при
|
||||
`period_date`, иначе `none`, `header_source` — из `*_original_value`, `file_ordinal` — по `(created_at, id)` в файле;
|
||||
`document_issue` пуст — у форм, оставшихся в неочищенной базе, нарушения до первой правки не показываются. Откат
|
||||
гарантирован на пустой БД и на данных, которые v5.18 представляет без потери первичных данных и ручного ввода (без
|
||||
повторов кода, строк без кода, двух форм одного типа в файле, `crm_id` групп и правленого наименования организации); на
|
||||
таких данных `downgrade` останавливается с ошибкой, а производные колонки v5.19 и `document_issue` удаляет с записью в
|
||||
журнал миграции.
|
||||
|
||||
## Что изменилось в v5.18 (решения владельца 09.10.2026, RSHB/arm-ka-docs#90)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `stored_file.consolidation_id` (`uuid`, nullable, FK → `consolidation`) + индекс `(legal_entity_id, consolidation_id)` | Файл загружается **в консолидацию** (период ГК) и становится основой её «рабочего стола» (полный состав стола — `context/05-domain-rules.md` §9.5 п. 11), общего для всех версий периода; `NULL` — загрузка без контекста (страница ЮЛ, монозаёмщики, API). Панель «Первичные документы» в версии показывает рабочий стол консоли для ЮЛ плюс файлы с документами, привязанными к версиям консоли. Что использует конкретная версия — по-прежнему `consolidation_document`; заморозка после `VERIFIED` — привязки и `ex_snapshot`. Привязка файла к **версии** (`consolidation_file`) отвергнута: рабочие версии периода делят первичку, а новая версия после `VERIFIED` подхватывает подтверждённое (`openspec/changes/console-files/design.md`) |
|
||||
| 2 | Note `recognition_job.reply_deadline` | Без изменения структуры: срок ответа OCR — 20 мин (OQ-159) |
|
||||
|
||||
Остальные таблицы и enum — как в v5.17. Реализация — миграция `0006` в `arm-core` (backfill `consolidation_id` по `consolidation_document`).
|
||||
|
||||
## Что изменилось в v5.17 (решение владельца 07.10.2026, пересмотр OQ-31, RSHB/arm-ka-docs#53)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `legal_entity.kpp` и `legal_entity_history.kpp` (`varchar`, nullable) | КПП юридического лица нужен (макет: колонка «КПП» на экранах `50`, `61`, поле форм `51-02`, `79`; фронтенд: «в ручке получения ЮЛ не приходит КПП»). Формат — 9 символов: 4 цифры, 2 символа (цифра или латинская A–Z), 3 цифры, иначе `INVALID_KPP`. У ИП (`entity_type = ИП`) КПП запрещён. Для ЮЛ необязателен: существующие записи и импорт без колонки остаются валидными. Уникален по-прежнему только `inn` (КПП — атрибут; сопоставление контрагентов ОСВ по ИНН не меняется). Изменение КПП — обычная правка со снимком в `legal_entity_history`. Отменяет п. 2 v5.14 («КПП не вводится») |
|
||||
|
||||
Остальные таблицы и enum — как в v5.16. Реализация — миграция `0005` в `arm-core`.
|
||||
|
||||
## Что изменилось в v5.16 (Срез 4, решения владельца 06.10.2026)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | Enum `counterparty_match_kind` (`INN`, `NAME`, `ALIAS`, `MANUAL`, `PROPAGATED`) и колонка `osv_entry.counterparty_match_kind` (nullable) | Способ сопоставления контрагента строки ОСВ хранится. `NULL` ⇔ `counterparty_id` `NULL`; `INN` / `NAME` / `ALIAS` — шаг автоматического резолва при маппинге (ИНН; точное имя; нормализованное имя ЮЛ или алиас); `MANUAL` — ручное сопоставление аналитиком; `PROPAGATED` — автоприменение по имени в версии (DOC-221278 п. 12–13). Вычислять на чтение нельзя: после ручного связывания появляется алиас, и ручное сопоставление неотличимо от `ALIAS`. Миграция `0004` заполняет колонку по уже смапленным строкам (ИНН без пробелов = `legal_entity.inn` → `INN`; `trim(name) = legal_entity.name` → `NAME`; остальные с `counterparty_id` → `ALIAS` — приближение: ручных сопоставлений до Среза 4 не было) |
|
||||
| 2 | Семантика `consolidation_document` | Без изменения структуры: строка создаётся при подтверждении документа (по документам ЮЛ — членов периметра версий «в работе») и при добавлении ЮЛ в периметр (подтверждённые подходящие документы подхватываются); удаляется при замене/удалении файла и исключении ЮЛ из периметра. Для одной (ЮЛ, `document_type`, `osv_account_code`, период, признак нарастающего) привязан один документ — самый поздний `confirmed_at` (D-5 Среза 4) |
|
||||
| 3 | Семантика `consolidation_lock` | Без изменения структуры: блокировка без истечения по времени — активна, пока её не снял владелец, администратор или не перехватил другой пользователь с `CONSOLIDATION_EDIT` по причине (OQ-119) |
|
||||
|
||||
Пробелы квартальной склейки и сама сводная ОСВ по-прежнему не хранятся (DECISION-5). Остальные таблицы и enum — как в v5.15 (43 таблицы; enum — 28). Реализация — миграция `0004` в `arm-core`.
|
||||
|
||||
## Что изменилось в v5.15 (Срез 2c, решения владельца 05.10.2026)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `osv_data_type` + `NU` (после `BU`) | Строки налогового учёта из ОСВ «БУ, НУ» хранятся в `osv_entry` как есть (OQ-45); контракт результата допускал `NU` с v1.0, ядро раньше такой строки принять не могло |
|
||||
| 2 | `app_user.email` — в нижнем регистре | Без изменения структуры: нормализация при записи (seed, администрирование), поиск по `lower(email)` сохраняется, уникальность — существующий UNIQUE по `email` (OQ-59). Expression-индекс `lower(email)` не вводится: сверка ORM↔DBML не умеет expression-индексы. Миграция `0003` приводит существующие email к нижнему регистру (при дублях по регистру — падает, слияние решает человек) |
|
||||
| 3 | Семантика `stored_file.status`, `recognition_job.group_schema` | Без изменения структуры: `PROCESSING` ставит inbox по ack сервиса, `PROCESSED`/`ERROR` — цикл маппинга результата (OQ-67); маппинг выполняется отдельно от inbox (OQ-69); `group_schema` заполняет маппер; «Итого» в `osv_entry` не хранится (OQ-01) |
|
||||
| 4 | Индексы `osv_entry (parent_entry_id)`, `osv_entry (recognition_job_id)`, `stored_file (current_recognition_job_id)` | Индексы для удаления файла и обхода дерева строк: без них проверки FK (в том числе self-FK `parent_entry_id`) при `DELETE /files/{id}` и очистке файла перед повторным маппингом шли seq scan'ом. Замер: DELETE документа 1000 строк 8,6 с → 16 мс на 200 тыс. строк. Обычные (не unique) индексы; закрывает OQ-117 (I-1 финального ревью Среза 2c) |
|
||||
|
||||
Остальные таблицы и enum — как в v5.14 (43 таблицы, 27 enum). Реализация — миграция `0003` в `arm-core`.
|
||||
|
||||
## Что изменилось в v5.14 (Срез 1, решения владельца 04.10.2026)
|
||||
|
||||
| № | Изменение | Решение |
|
||||
|---|---|---|
|
||||
| 1 | `related_group_member.kind` + индекс `(legal_entity_id, kind) WHERE is_current` | ЮЛ состоит **одновременно в одной ГСК и одной ГСЗ** (но только в одной группе каждого вида). Отменяет ANL-030 / v5.8 («только в одной ГСК или ГСЗ»). `kind` — денормализация `related_group.kind` (равенство проверяет ядро при записи, тест на рассинхрон); индекс не выразить через join, триггер не выбран. Закрывает OQ-32 |
|
||||
| 2 | КПП | **Не вводится** *(отменено в v5.17: КПП введён)*. Поле есть только в макете; у `legal_entity` его нет, импорт его не читает (закрывал OQ-31 до v5.17) |
|
||||
| 3 | Семантика `company_group.crm_id`, `base_regional_office_id` | Без изменения структуры: `crm_id` = «iD ГК» выгрузки ЕЦП CRM, `base_regional_office_id` = «Базовый РФ ГК в CRM»; флаги «входит в ГСК/ГСЗ» выгрузки → членство в одной неявной ГСК/ГСЗ на ГК (правила — `05-domain-rules.md` §13) |
|
||||
| 4 | `audit_action` + `LEGAL_ENTITY_CHANGE`, `USER_CHANGE` | Журнал изменений ЮЛ (создание/изменение/закрытие/перевод, алиасы) и пользователей (создание/деактивация администратором) — ТЗ 8.2; в v5.13 для них не было действия (были `GROUP_CHANGE`, `MEMBERSHIP_CHANGE`, `USER_ROLE_CHANGE`) |
|
||||
|
||||
Остальные таблицы и enum — как в v5.13 (43 таблицы). Реализация — миграция `0002` в `arm-core`.
|
||||
|
||||
## Что изменилось в v5.13 (ревью 30.09–01.10)
|
||||
|
||||
| № | Замечание | Решение |
|
||||
|---|---|---|
|
||||
| 1 | Вместо RBAC «в коде» — роли **и** права | `permission` + `role_permission` возвращены; права только через роли, прямых назначений пользователю нет. Исключения — заведением роли |
|
||||
| 2 | `osv_entry.parent_entry_id` не нужен — храним только строки с контрагентами | **Отложено.** Открыт вопрос: хранить ли строки уровня ACCOUNT для сверки «Σ контрагентов = итог счёта»; аналитика «Парсинг ОСВ» п.11 пока говорит «все строки» |
|
||||
| 3 | `osv_group_schema` не особо нужна | Убрана. Схема шапки — `recognition_job.group_schema jsonb`; тип строки — `osv_entry.group_type` |
|
||||
| 4 | `financial_statement_value.needs_review` непонятен | Убран: производное от `confidence` / `is_recognized`, порог может меняться |
|
||||
| 5 | В `recognition_job` не нужны и `result`, и `raw_result` | Оставлен только `result_s3_object_id`. Сырой ответ ИС Сканирование — S3 `raw/{job_id}.json` по конвенции, в БД не регистрируется |
|
||||
| 6 | `stored_file.fields_modified` — что это | Счётчик «исправлено полей» с карточки документа (v5.7). Убран — `COUNT(is_modified)` по данным |
|
||||
| 6-бис | `document_type` не предусматривает несколько ОСВ или ББ+ОФР в одном файле | **Разделение файл / документ**: `stored_file` — физический файл, `document` — логическая единица (1:N). Чек-лист, проверки, подтверждение, FK разобранных данных, `consolidation_document`, `ex_snapshot_item` — на `document`. Замена (`superseded_by`) — файл целиком |
|
||||
| 7 | `file_type`: убрать Р7 | Убран. `xls/xlsx/xlsb → tabular-parser`, `pdf/png/jpg → scan-gateway` |
|
||||
|
||||
**Принципы модели (коротко):**
|
||||
- Первичка не редактируется: файлы и распознанные значения хранятся как пришли; правки аналитика — рядом (`is_modified`, `original_*`) и в аудите.
|
||||
- Производные консолидации в работе (сводная ОСВ, пары ВГО, шахматка) **не хранятся** — считаются запросом. Хранятся только ручные решения (корректировки, гудвилл, подтверждение КФО клиента).
|
||||
- При верификации всё замораживается в Единое хранилище (ЕХ) как самодостаточный срез, который не зависит от таблиц консолидации.
|
||||
- Единственный писатель в БД — ядро `arm-core`; сервисы распознавания видят только NATS и S3.
|
||||
- Права — данные (`role_permission`), ограничения по ЗО/филиалу/статусу — policy-слой поверх прав.
|
||||
|
||||
---
|
||||
|
||||
## Часть 01 — Группы компаний, организации, филиалы
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `regional_office` | Филиал банка: головной офис (ГО, `is_head_office`) и региональные филиалы (РФ). Определяет зону видимости пользователя и закрепление ГК. | ← `company_group.base_regional_office_id`, `legal_entity.regional_office_id`, `app_user.regional_office_id` | ТЗ 8.1 |
|
||||
| `company_group` | Группа компаний (ГК) — верхний уровень справочника клиентов. Текущее состояние (SCD4). `crm_id` = «iD ГК» из ЕЦП CRM (NULL, если создана вручную Куратором; v5.14 — семантика по выгрузке), внутренний `code`, закрепление за филиалом (`base_regional_office_id` = «Базовый РФ ГК в CRM»), флаг архива. | → `regional_office`; ← `legal_entity`, `related_group`, `consolidation` | ТЗ 6.1, Прил. 2; макет |
|
||||
| `company_group_history` | Прошлые снимки ГК: каждое изменение — новая строка с `valid_from/valid_to`. | → `company_group` | ТЗ 6.10, 8.2 |
|
||||
| `legal_entity` | Юридическое лицо / ИП. Натуральный ключ — ИНН; **v5.17:** `kpp` — КПП (9 символов, nullable, только у ЮЛ, не ключ). `company_group_id` = текущая ГК; **NULL = монозаёмщик**. `close_date` — закрыто/архивировано. | → `company_group`, `regional_office`; ← `related_group_member`, `stored_file`, `document`, `osv_entry.counterparty_id`, `consolidation_member` | ТЗ 6.1, Прил. 2; ЕХ 6.1 |
|
||||
| `legal_entity_history` | Прошлые снимки ЮЛ + вид события (создание, изменение, переход в другую ГК, закрытие, вывод из ГК) и дата вступления в силу. | → `legal_entity` | ТЗ 8.2; макет |
|
||||
| `legal_entity_alias` | Словарь написаний контрагента: как имя встречается в ОСВ и нормализованный ключ для матчинга. Пополняется при ручном сопоставлении. | → `legal_entity` | ТЗ 6.5 |
|
||||
| `related_group` | ГСК или ГСЗ внутри ГК; `kind` различает. Для ГСК формируется КФО. Иерархия не поддерживается. **v5.19:** `crm_id` — ID группы в ЕЦП CRM (вручную, уникален). | → `company_group`; ← `related_group_member`, `consolidation.related_group_id` | ТЗ 6.1, Прил. 2 |
|
||||
| `related_group_member` | Состав ГСК/ГСЗ — история членства (SCD2). **v5.14:** ЮЛ может одновременно входить в **одну ГСК и одну ГСЗ** (не более одной группы каждого вида): колонка `kind` = `related_group.kind` (денормализация) и частичный уникальный индекс `(legal_entity_id, kind) WHERE is_current`. Решение владельца 04.10.2026, отменяет ANL-030. | → `related_group`, `legal_entity` | ТЗ 6.1; макет [79] |
|
||||
|
||||
## Часть 02 — Пользователи, роли, права
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `app_user` | Пользователь АРМ. Аутентификация внешняя (РАИСА/SSO, `external_id`). Филиал (ГО/РФ), зона ответственности (ДКБ/ДМСБ/ДМ), табельный номер. Видимость данных = права роли + филиал + ЗО. | → `regional_office`; ← `user_role`, все `*_by` поля | ТЗ 8.1, Прил. 2 |
|
||||
| `role` | Роли: seed из ТЗ 8.1 (КА РФ, КА ГО, РКА, КМ, Куратор ГО, Эксперт, Администратор; `is_system`) + роли, заведённые администратором для исключений. **v5.13:** код роли в бизнес-логике не проверяется — только права. | ← `user_role`, `role_permission` | ТЗ 8.1 |
|
||||
| `permission` | **v5.13.** Атомарное право «объект × действие»: `DIRECTORY/DOCUMENT/CONSOLIDATION/KFO/EX/EXPORT/USERS/AUDIT` × `VIEW/EDIT/APPROVE/VERIFY/DELETE/EXPORT/ADMIN`. Seed, привязан к коду — администратор новые коды не создаёт. Право говорит «может»; policy-слой (ЗО, филиал, статус КФО) — «эту ли и сейчас ли». | ← `role_permission` | ТЗ Прил. 2, сноска 29 |
|
||||
| `role_permission` | **v5.13.** Матрица доступов как данные: `effective_permissions(user) = ∪ permissions(roles(user))`. Редактируется администратором на экране «Изменение ролей и прав доступа»; история — `audit_event(ROLE_PERMISSION_CHANGE)`. Прямых прав у пользователя нет. | → `role`, `permission` | ТЗ Прил. 2; макет |
|
||||
| `user_role` | Назначение ролей пользователю (M:N). История — в аудите. | → `app_user`, `role` | ТЗ 8.1 |
|
||||
|
||||
## Часть 03 — Бухгалтерские справочники и правила
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `chart_of_account` | План счетов с иерархией, тип A/P/AP, признак забалансового. Seed — полный план 1С; нестандартные субсчета клиентов добавляет администратор. | ← `osv_entry.account_id`, `elimination_rule_account`, `required_document_rule` | ТЗ 6.2/6.5, Прил. 3/4 |
|
||||
| `elimination_rule` | Правило элиминации из Прил. 3 (ББ) / Прил. 4 (ОФР) как данные: пара статей, сторона, мера, режим, НДС, акцизы. Версионируется. | ← `elimination_rule_account`, `correction.rule_id`; версия фиксируется в `consolidation_version` | ТЗ 6.4, Прил. 3/4 |
|
||||
| `elimination_rule_account` | Счета/субсчета каждой стороны правила, включая исключения («76 кроме 76.7.1»). | → `elimination_rule`, `chart_of_account` | ТЗ Прил. 3/4 |
|
||||
| `required_document_rule` | Какие документы обязательны по подходу. **v5.13:** сверяется с `document` (тип + счёт + период), а не с файлом: выполнено = есть `document CONFIRMED` у каждого ЮЛ периметра. | → `chart_of_account` | ТЗ 5.1, 6.2, сноска 12 |
|
||||
|
||||
## Часть 04 — Файлы, документы, S3, задания распознавания
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `s3_object` | Реестр всех объектов в S3: бакет-роль, ключ, размер, sha256, срок жизни, ссылка на архив в data lake. Единая точка ретеншна (5 лет по ТЗ 8.4) и дедупа. | ← `stored_file`, `recognition_job` | ТЗ 6.2, 8.4; ЕХ 8.3 |
|
||||
| `stored_file` | **v5.13: только физический файл** одной загрузки: чей (ЮЛ), формат, hash, кто/когда загрузил, статус обработки (`UPLOADED → PROCESSING → PROCESSED / ERROR / SUPERSEDED`), версия при замене. **v5.18:** `consolidation_id` — консолидация, в контексте которой файл загружен (основа «рабочего стола консоли», общего для версий периода; полный состав — `context/05-domain-rules.md` §9.5 п. 11; `NULL` — без контекста). Что внутри файла — `document`. Замена — файл целиком со всеми документами. **v5.25:** `is_scan` — скан/цифровой PDF по текстовому слою при загрузке. | → `legal_entity`, `consolidation`, `s3_object`, `recognition_job`; ← `document`, `recognition_job` | ТЗ 6.2, 8.2; UC-01…05 |
|
||||
| `document` | **v5.13, новая.** Логический документ внутри файла: ББ, ОФР, ОСВ по счёту (`osv_account_code`), расшифровка, прочее. Период, отчётная дата, где в файле (`locator`: лист / страницы), статус проверки (`RECOGNIZED / NEEDS_CHECK / CONFIRMED / ERROR`), результаты проверок периода и контрагента, кто подтвердил. Один файл → N документов (PDF с ББ+ОФР; xlsx с несколькими ОСВ). Создаёт ядро при маппинге результата `recognition_job`. На документ ссылаются разобранные данные, чек-лист, консолидация и ЕХ. **v5.19:** `file_ordinal` — индекс документа в `documents[]` результата (у всех документов); формы ББ/ОФР одного типа в файле могут повторяться (ОСВ по счёту, расшифровка, прочий — один на тип); предупреждения и нарушения — `document_issue`. **v5.20:** период и счёт ОСВ уточняются аналитиком на месте, распознанные — в `original_values` (`is_modified`, `modified_by/at`). | → `stored_file`, `legal_entity`, `app_user`; ← `osv_entry`, `financial_statement_meta`, `document_issue`, `consolidation_document`, `ex_snapshot_item` | ТЗ 6.2, 5.1, 8.2; макет (чек-лист, «Подтвердить данные») |
|
||||
| `recognition_job` | Одна попытка распознать/распарсить файл. **Единственная точка обмена с NATS** (outbox/inbox, дедуп по `result_msg_id`, DLQ). Хранит сервис и версию, **одну** ссылку на нормализованный JSON-результат в S3 (v5.13), метрики, и **схему группировок шапки ОСВ по листам** (`group_schema jsonb`, v5.13 — вместо `osv_group_schema`). **v5.19:** `statements_version` — версия копии общего кода нормализации, которой посчитан результат форм. **v5.25:** сырой ответ ИС Сканирование теперь регистрируется в `s3_object` (роль `raw`) через `raw_s3_object_id` — решение v5.13 «не регистрируется» отменено. | → `stored_file`, `s3_object`; ← `osv_entry`, `financial_statement_meta` | ТЗ 6.2, 6.10; DECISION-4 |
|
||||
|
||||
## Часть 05 — Разобранные ОСВ
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `osv_entry` | Строка ОСВ: документ (счёт + период), владелец, тип строки по схеме шапки (`group_type`, v5.13), уровень и родитель (`parent_entry_id` — **открыт вопрос, замечание 2**), код счёта и резолв в план счетов, сырое имя/ИНН контрагента, резолв в ЮЛ и способ сопоставления (`counterparty_match_kind`, v5.16), шесть сумм, тип данных (БУ/валюта/кол-во), «подакцизный» для 90-го. Ручные правки: `is_modified`, `original_values`, `modified_by`. Признак ГСК/ГК/Внешний не хранится — выводится из периметра версии; способ сопоставления контрагента хранится (`NULL` ⇔ контрагент не сопоставлен). | → `document`, `recognition_job`, `legal_entity` ×2, `chart_of_account` | ТЗ 6.2/6.5, Прил. 2; «Парсинг ОСВ» |
|
||||
|
||||
## Часть 06 — Распознанные формы ББ/ОФР
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `financial_statement_meta` | Шапка распознанной формы (1:1 с `document` BALANCE/INCOME): ИНН и наименование как в документе, отчётная дата, единица измерения, реквизиты. Ревью формы (`reviewed_by/at`) и акцепт КА непройденных логических проверок с комментарием. Подтверждение документа — `document.confirmed_by`. **v5.19:** `form_variant` (полная / упрощённая — набор соотношений §7), `needs_review_fields`, `header_source` (сырой текст и уверенность полей шапки), правка наименования (`organization_name_original_value`, `organization_name_modified`); результат проверок §7 и предупреждения хранятся в `document_issue` как пришли от сервиса, ядро пересчитывает их только после правок. | → `document`, `recognition_job`, `app_user`; ← `column`, `line` | ТЗ 6.2/6.3; FNR01; макет |
|
||||
| `financial_statement_column` | Колонки-периоды формы с датой — нужны для межформенной проверки (1370 на начало года) и гудвилла. **v5.19:** `period_kind` (абсолютная / относительная подпись бланка / без даты), `label_confidence`. | → `meta`; ← `value` | ТЗ 6.3 п.7, 6.7 |
|
||||
| `financial_statement_line` | Строка формы как в источнике: код (или его сырой текст) и наименование как распознано. **v5.19:** все строки источника — с кодом (`ok`, повторы кода тоже) и без (`unreadable`, `missing`, `detail` — расшифровка под родителем `parent_row_index`); порядок `row_index` (`NULL` ⇔ строка создана правкой аналитика), положение `source_ref`, `needs_review` неуверенного кода, подтверждение кода `is_confirmed`. Раскладка экрана — по коду «как на бумаге». | → `meta`; ← `value`, `document_issue.line_ids` | ТЗ 6.2, Прил. 2 |
|
||||
| `financial_statement_value` | Число в ячейке (строка × колонка): сумма, уверенность, `is_recognized`, ручная правка с исходным значением. **v5.19:** подсветка — только `needs_review` (хранится: уверенность, `is_recognized` и §7 сведены сервисом, ядро пересчитывает после правок); `source_text` — сырой текст источника; `is_confirmed` / `confirmed_by/at` — подтверждено без правки. (v5.13 этот флаг убирала как производный.) | → `line`, `column`, `app_user` | ТЗ 6.2, Прил. 2 |
|
||||
| `document_issue` | **v5.19, новая.** Предупреждение или нарушение §7 документа (у формы; у ОСВ — предупреждения листа): вид (`warning` / `relation` / `soft`), код и уровень (`error` / `info`), сообщение, привязка к строкам (`line_ids`), колонке (`column_id` или `column_index`) и полю шапки, источник (`service` / `core`); для нарушения — соотношение, `codes`, `expected`, `actual`. Экран показывает их у места. | → `document`, `financial_statement_column` | change `unified-statement-normalization` (design, шаг 8) |
|
||||
|
||||
## Часть 07 — Консолидация
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `consolidation` | Логическая консолидация: **ГК** + отчётный период. ГСК фиксируется/создаётся при верификации по фактическому периметру. Уникальна по (ГК, год, квартал). **v5.18:** файлы, загруженные в консолидацию, — `stored_file.consolidation_id` (основа рабочего стола, общего для версий периода; полный состав — `context/05-domain-rules.md` §9.5 п. 11). | → `company_group`, `related_group`; ← `consolidation_version`, `stored_file` | ТЗ 6.10, 7.2 |
|
||||
| `consolidation_version` | Версия консолидации: номер, статус, сценарий, подход, гудвилл, инициатор и его офис (маршрут), кто утвердил / верифицировал, решение УОБ, отклонения от Методики, версия правил элиминации, ссылка на предыдущую. После VERIFIED — read-only. | → `consolidation`, `app_user`, `regional_office`, self; ← всё в частях 07–08 | ТЗ 5.1, 6.4, 6.10; макет |
|
||||
| `consolidation_status_history` | Каждый переход статуса: из → в, кто, когда, комментарий (обязателен при возврате). | → `consolidation_version`, `app_user` | ТЗ 6.10, 8.2 |
|
||||
| `consolidation_lock` | «Взять в работу»: кто редактирует версию, перехват с причиной (v5.16: без истечения по времени, OQ-119). Из макета — ANL-036. | → `consolidation_version`, `app_user` | макет |
|
||||
| `consolidation_member` | Периметр версии — зафиксированный список ЮЛ; `is_head_entity` для гудвилла. | → `consolidation_version`, `legal_entity` | ТЗ 6.1, 6.10 |
|
||||
| `consolidation_document` | **v5.13:** какие **документы** (не файлы) участвуют в версии. Чек-лист = `required_document_rule` × периметр − `consolidation_document`. Переиспользование одного документа в нескольких версиях/периодах, монозаёмщики из ЕХ. | → `consolidation_version`, `document` | ТЗ Прил. 2; ЕХ 7 |
|
||||
|
||||
*Не хранятся (DECISION-5), считаются запросом по версии:* сводная ОСВ, признак контрагента ГСК/ГК/Внешний, пары ВГО, шахматка, результирующая таблица ВГО.
|
||||
|
||||
## Часть 08 — Корректировки, гудвилл, результат КФО
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `correction` | Ручная корректировка ВГО: пара (правило + компания 1 + компания 2 — естественный ключ), ББ/ОФР, строки и суммы по Дт и Кт, дочерние строки для распределения, причина, обязательный комментарий, статус, номер версии (история — в аудите). КФО = свод − Σ корректировок. | → `consolidation_version`, `elimination_rule`, `legal_entity` ×2, `chart_of_account` ×2, self | ТЗ 6.4, 6.8, Прил. 9 |
|
||||
| `vgo_assignment` | Ручное решение аналитика по строке сводной ОСВ сверх автоматического разнесения по правилам ВГО: привязка к правилу / снятие привязки, «не учитывать в КФО» у нераспределённой строки. Разнесение само по себе не хранится — только это решение поверх него. | → `consolidation_version`, `osv_entry` (ON DELETE CASCADE), `elimination_rule`, `app_user` ×2 | DOC-272613 §5, AURORA-1751 |
|
||||
| `goodwill` | Строка расчёта гудвилла: головная × дочерняя, доля владения, ФВ по 58.01, УК (1310) и добавочный капитал (1350 — вопрос методологам), гудвилл, «включить в КФО», комментарий. | → `consolidation_version`, `legal_entity` ×2, `app_user` | ТЗ 6.7, Прил. 3 п.2, Прил. 8 |
|
||||
| `kfo_result` | Шапка результата КФО: когда посчитан, заморожен ли, ЧА и ВБ, выручка, прибыль, расхождения, пороги, обоснование, итог гудвилла. | → `consolidation_version` (1:1); ← `kfo_result_line` | ТЗ 6.4, 6.8, Прил. 10 |
|
||||
| `kfo_result_line` | Строка консолидированного ББ/ОФР по коду ФСБУ 4/2023: сумма → авто-элиминация → корректировки → гудвилл → итог; «в т.ч. ВГО», источник, расхождение, комментарий. | → `kfo_result`; ← `kfo_result_line_company` | ТЗ 6.4, Прил. 10; макет |
|
||||
| `kfo_result_line_company` | Разрез строки КФО по компаниям периметра: сумма и доля. | → `kfo_result_line`, `legal_entity` | ЕХ 6.6; макет |
|
||||
| `client_kfo_line` | Сценарий «подтверждение КФО клиента»: по строке — значение и ВГО от клиента (ручной ввод), значение и ВГО банка, расхождение, причина. | → `consolidation_version`, `app_user` | ТЗ 5.1, 6.10; макет |
|
||||
|
||||
## Часть 09 — Комментарии, аудит, Единое хранилище
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `comment` | Полиморфный комментарий к объекту (`document | consolidation_version | …`); сейчас используется для документов. Правка и удаление не предусмотрены; аудит не ведётся. | → `app_user`; `object_type + object_id` без FK | ТЗ 6.3; AURORA-1446; макет |
|
||||
| `audit_event` | Журнал действий (append-only): кто, когда, действие, раздел, объект, версия консолидации, before/after, результат, IP/браузер. Покрывает историю правок распознанных данных, корректировок, выгрузок, импорта справочников, входов, **изменений матрицы прав** (v5.13), подтверждения документов, **изменений ЮЛ и пользователей** (v5.14: `LEGAL_ENTITY_CHANGE`, `USER_CHANGE`). | → `app_user`, `consolidation_version` | ТЗ 8.2, Прил. 2; макет |
|
||||
| `ex_snapshot` | Срез ЕХ: одна ГСК на одну отчётную дату, версия, статус (актуальный/архив), когда и кем верифицирован и записан. Самодостаточен — на консолидацию ссылается только данными. | → `related_group`, `company_group`, `app_user`, self; ← `member`, `item` | ЕХ ТЗ 6.2, 6.4, 5.3 |
|
||||
| `ex_snapshot_member` | Периметр среза на дату: ЮЛ с ИНН и наименованием на момент верификации. | → `ex_snapshot`, `legal_entity` | ЕХ ТЗ 6.3 |
|
||||
| `ex_snapshot_item` | Содержимое среза. Два вида: исходный документ → ссылка на **`document`** (v5.13; скачать — через его файл) и всё производное → `payload` jsonb. | → `ex_snapshot`, `document`, `legal_entity` | ЕХ ТЗ 5.2, 6.7 |
|
||||
|
||||
## Часть 10 — Метрики качества первички
|
||||
|
||||
| Сущность | Что это | Ключевые связи | Откуда |
|
||||
|---|---|---|---|
|
||||
| `quality_intake_fact` | Документ «как распознано»: снимок на момент приёма результата (до авто/ручного подтверждения) — счётчики строк/значений/предупреждений, `payload` со строками и значениями. **Для ОСВ — без построчного снимка**: только счётчики и предупреждения `OSV_*` (правок сумм ОСВ в ядре нет). Пишется один раз на документ BALANCE/INCOME/OSV, в транзакции маппинга, до `auto_confirm`; `DISCLOSURE`/`OTHER` факт не получают. Append-only, без FK — переживает удаление/перераспознавание документа. | `document_id`/`file_id`/`job_id`/`legal_entity_id`/`group_id` — без FK, по значению | AURORA-1759; arm-core#190 |
|
||||
| `quality_outcome_fact` | Исход документа: автоподтверждён / подтверждён / удалён / заменён (в т. ч. после подтверждения — отдельные значения), с атрибуцией правок по источнику (сервис / наш разбор) и причиной попадания в ячейку матрицы (`primary_cause`). **Не один факт на документ**: повторное подтверждение ОСВ и исход после подтверждения пишут новый факт — метрики берут последний по `outcome_at`. | `document_id` — связь с `quality_intake_fact` по значению, без FK | AURORA-1759; arm-core#190 |
|
||||
| `quality_failure_fact` | Технический отказ задания распознавания (ошибка сервиса, таймаут, DLQ) или неповторяемая ошибка маппинга. Считается по файлам, не по документам (у отказавшего файла документов нет). Плоская таблица, без `payload`. | `job_id`/`file_id`/`legal_entity_id`/`group_id` — без FK, по значению | AURORA-1759; arm-core#190 |
|
||||
|
||||
---
|
||||
|
||||
## Как читать модель по сценарию «сформировать КФО»
|
||||
|
||||
1. **Справочники** (01–03): ГК → ЮЛ → ГСК/ГСЗ; план счетов; правила элиминации; что обязательно загрузить.
|
||||
2. **Создание консолидации** (07): `consolidation` от ГК + период → `consolidation_version` → `consolidation_member` (периметр).
|
||||
3. **Загрузка** (04): `stored_file` + `s3_object` → `recognition_job` (queued → NATS → сервис → результат в S3 → done) → ядро создаёт **`document`** на каждый ББ / ОФР / ОСВ по счёту, найденный в файле.
|
||||
4. **Разбор** (05–06): ОСВ → `osv_entry`; ББ/ОФР → `financial_statement_meta/column/line/value`. Аналитик проверяет, правит, подтверждает **документ**; логические проверки — на лету; сопоставляет контрагентов (→ `osv_entry.counterparty_id`, `legal_entity_alias`). Чек-лист закрывается по `document CONFIRMED`.
|
||||
5. **Консолидация** (вычисляется): сводная ОСВ, пары ВГО, шахматка — из `osv_entry` × периметр × правила. Аналитик вносит `correction`, заполняет `goodwill`, при сценарии подтверждения — `client_kfo_line`. Результат — `kfo_result(_line)`.
|
||||
6. **Согласование** (07): `consolidation_status_history` по маршруту; блокировка `consolidation_lock`. Что можно — решает `role_permission` + policy-слой по статусу/ЗО.
|
||||
7. **Верификация → ЕХ** (09): `ex_snapshot` + `member` + `item` (документы по ссылке, остальное — payload). Версия → read-only. Всё это время — `audit_event`.
|
||||
|
||||
## Открытые вопросы после v5.14
|
||||
|
||||
- **Замечание 2** (`osv_entry.parent_entry_id`, какие строки ОСВ хранить) — отложено; затрагивает и аналитику «Парсинг ОСВ» п.11.
|
||||
- Замена по-документно (одна ОСВ из файла с пятью) — сейчас не предусмотрена, замена файлом целиком. Если понадобится — `superseded_by` переезжает в `document`.
|
||||
- Статус `document.RECOGNIZED` (ручная проверка не требуется по порогу) — подтвердить с аналитиками, нужен ли, или все документы проходят через `NEEDS_CHECK → CONFIRMED`.
|
||||
182
openspec/changes/quality-metrics/design.md
Normal file
@ -0,0 +1,182 @@
|
||||
# Дизайн: модель данных для метрик качества первички (DBML v5.25)
|
||||
|
||||
Зачем, для кого и все решения владельца (27.10.2026, подтверждено 05.11.2026) — в
|
||||
`../../arm-core/openspec/changes/quality-metrics/design.md` (разделы 1–3, 10). Здесь — только то, что входит в
|
||||
DBML v5.25 и производные документы этого репозитория: точные имена, типы, перечисления.
|
||||
|
||||
## 1. Новые и изменённые объекты модели
|
||||
|
||||
### 1.1 Enum `s3_bucket_role` — добавить значение
|
||||
`raw` — сырой ответ ИС Сканирование, `raw/{job_id}.json`. Не получает `expires_at` при удалении файла/`uploads/`,
|
||||
на которые ссылаются факты (вход для эталонного прогона).
|
||||
|
||||
### 1.2 Enum `permission_object` — добавить значение
|
||||
`QUALITY_METRICS` — объект права экрана «Качество первички» (действие `VIEW`; seed права `QUALITY_METRICS_VIEW` —
|
||||
в arm-core, не в DBML).
|
||||
|
||||
### 1.3 Новые enum для фактов
|
||||
```
|
||||
Enum quality_pipeline_is_scan — не нужен: используется существующий recognition_pipeline (tabular=Excel, image=PDF)
|
||||
и новый boolean stored_file.is_scan (NULL для не-PDF).
|
||||
|
||||
Enum quality_outcome {
|
||||
AUTO_CONFIRMED
|
||||
CONFIRMED
|
||||
DELETED
|
||||
SUPERSEDED
|
||||
DELETED_AFTER_CONFIRM
|
||||
SUPERSEDED_AFTER_CONFIRM
|
||||
}
|
||||
|
||||
Enum quality_cause {
|
||||
SERVICE_ERROR [note: 'есть правка, не найденная в сыром тексте сервиса']
|
||||
OUR_ERROR [note: 'есть правка, найденная в сыром тексте сервиса (наш разбор ошибся)']
|
||||
CLIENT_DOCUMENT [note: 'подтверждён с акцептом нарушенных жёстких проверок, без несписанных правок на это нарушение']
|
||||
WITHOUT_PARTICIPATION [note: 'AUTO_CONFIRMED']
|
||||
AS_IS [note: 'CONFIRMED без правок и без акцепта']
|
||||
}
|
||||
// NULL у исходов DELETED* / SUPERSEDED* (не входят в матрицу)
|
||||
|
||||
Enum quality_failure_kind {
|
||||
SERVICE_ERROR [note: 'recognition_job.status = error']
|
||||
TIMEOUT
|
||||
NO_ACK [note: 'dlq — redelivery после max_deliver']
|
||||
MAPPING [note: 'MappingFatal, файл → ERROR']
|
||||
}
|
||||
```
|
||||
Приоритет значений `quality_cause` при вычислении (несколько правил могут совпасть) — пункт §14.3
|
||||
`05-domain-rules.md`: SERVICE_ERROR > OUR_ERROR > CLIENT_DOCUMENT > WITHOUT_PARTICIPATION > AS_IS.
|
||||
|
||||
### 1.4 Таблица `quality_intake_fact` — документ «как распознано»
|
||||
Отдельная схема `dkb_metrics` (имя — настройка). Без FK на рабочие таблицы.
|
||||
|
||||
| Столбец | Тип | Прим. |
|
||||
|---|---|---|
|
||||
| id | uuid [pk] | |
|
||||
| document_id | uuid [not null] | без FK; один факт на документ |
|
||||
| file_id | uuid [not null] | |
|
||||
| job_id | uuid [not null] | |
|
||||
| attempt | smallint [not null] | |
|
||||
| legal_entity_id | uuid [not null] | |
|
||||
| legal_entity_name | varchar [not null] | копия имени на момент факта |
|
||||
| group_id | uuid | NULL — ЮЛ вне ГК |
|
||||
| group_name | varchar | |
|
||||
| document_type | document_type [not null] | BALANCE / INCOME / OSV (DISCLOSURE/OTHER не пишут факт) |
|
||||
| pipeline | recognition_pipeline [not null] | tabular = Excel, image = PDF |
|
||||
| is_scan | boolean | только pipeline = image |
|
||||
| service_name | varchar | |
|
||||
| service_version | varchar | |
|
||||
| statements_version | varchar | |
|
||||
| result_schema_version | varchar | |
|
||||
| report_date | date | как распознано |
|
||||
| intake_at | timestamptz [not null] | |
|
||||
| intake_status | document_status [not null] | RECOGNIZED / NEEDS_CHECK |
|
||||
| line_count | int | |
|
||||
| value_count | int | |
|
||||
| value_needs_review_count | int | |
|
||||
| line_unreadable_count | int | |
|
||||
| line_missing_count | int | |
|
||||
| issue_relation_count | int | |
|
||||
| issue_soft_count | int | |
|
||||
| warning_count | int | |
|
||||
| raw_s3_key | varchar | PDF; NULL для Excel |
|
||||
| result_s3_key | varchar | |
|
||||
| upload_s3_key | varchar | |
|
||||
| payload | jsonb [not null] | снимок — §2 |
|
||||
| payload_schema_version | varchar | схема как в ex_snapshot_item.payload_schema_version; формат «1», «1.1» |
|
||||
|
||||
Индексы: `(document_id)` unique; `(legal_entity_id, intake_at)`; `(group_id, intake_at)`.
|
||||
|
||||
### 1.5 Таблица `quality_outcome_fact` — исход документа
|
||||
| Столбец | Тип | Прим. |
|
||||
|---|---|---|
|
||||
| id | uuid [pk] | |
|
||||
| document_id | uuid [not null] | связь с 1.4 по значению, без FK |
|
||||
| outcome | quality_outcome [not null] | |
|
||||
| outcome_at | timestamptz [not null] | |
|
||||
| primary_cause | quality_cause | NULL для DELETED*/SUPERSEDED* |
|
||||
| fixes_value_service | int [not null, default: 0] | |
|
||||
| fixes_value_ours | int [not null, default: 0] | |
|
||||
| fixes_code_service | int [not null, default: 0] | |
|
||||
| fixes_code_ours | int [not null, default: 0] | |
|
||||
| fixes_added_row_service | int [not null, default: 0] | |
|
||||
| fixes_added_row_ours | int [not null, default: 0] | |
|
||||
| fixes_header_service | int [not null, default: 0] | |
|
||||
| fixes_header_ours | int [not null, default: 0] | |
|
||||
| fixes_osv_period_account | int [not null, default: 0] | всегда «наш разбор» (Excel) |
|
||||
| checks_accepted | boolean [not null, default: false] | подтверждён с акцептом жёстких нарушений |
|
||||
| issue_count_at_outcome | int [not null, default: 0] | |
|
||||
| report_date | date | подтверждённая |
|
||||
| confirmed_by | uuid | для агрегатов не используется |
|
||||
| payload | jsonb [not null] | подтверждённый результат + список правок — §2 |
|
||||
| payload_schema_version | varchar | схема как в ex_snapshot_item.payload_schema_version; формат «1», «1.1» |
|
||||
|
||||
Индексы: `(document_id, outcome_at)`; `(outcome, outcome_at)`. **Не unique** на `document_id` — повторное
|
||||
подтверждение ОСВ и исходы after-confirm пишут новый факт; метрики берут последний по `outcome_at`.
|
||||
|
||||
### 1.6 Таблица `quality_failure_fact` — технический отказ
|
||||
| Столбец | Тип | Прим. |
|
||||
|---|---|---|
|
||||
| id | uuid [pk] | |
|
||||
| job_id | uuid [not null] | |
|
||||
| file_id | uuid [not null] | |
|
||||
| attempt | smallint [not null] | |
|
||||
| legal_entity_id | uuid [not null] | |
|
||||
| legal_entity_name | varchar [not null] | |
|
||||
| group_id | uuid | |
|
||||
| group_name | varchar | |
|
||||
| pipeline | recognition_pipeline [not null] | |
|
||||
| is_scan | boolean | |
|
||||
| service_name | varchar | |
|
||||
| failure_kind | quality_failure_kind [not null] | |
|
||||
| error_code | varchar | |
|
||||
| failed_at | timestamptz [not null] | |
|
||||
|
||||
Нет `payload`/`payload_schema_version` — все поля плоские, в отличие от intake/outcome (§2).
|
||||
|
||||
Индексы: `(job_id)` unique; `(file_id, attempt)`.
|
||||
|
||||
### 1.7 Изменения существующих таблиц
|
||||
- `stored_file.is_scan boolean` — NULL для не-PDF; PDF — определяется при загрузке по текстовому слою
|
||||
(ASSUMPTION §14: скрытый OCR-слой считается цифровым).
|
||||
- `recognition_job.raw_s3_object_id uuid [ref: > s3_object.id]` — заменяет прежнюю заметку «сырой ответ в БД не
|
||||
регистрируется» (v5.13); заполняется при приёме результата image pipeline.
|
||||
|
||||
## 2. Контракт `docs/contracts/metrics/quality-facts.schema.json`
|
||||
|
||||
JSON Schema (Draft 2020-12), три подсхемы с `$id` `intake-payload`, `outcome-payload`, `failure-fact` (у failure
|
||||
payload нет — все поля плоские). Описывает только `payload` интейка и исхода:
|
||||
- `intake-payload`: `header` (`header_source`, распознанные поля шапки), `lines[]` (`ref`, `row_index`, `line_code`,
|
||||
`line_code_text`, `line_status`, `needs_review`), `values[]` (`line_ref`, `column`, `amount`, `string_value`,
|
||||
`source_text`, `confidence`, `is_recognized`, `needs_review`), `issues[]` (код, уровень), `raw_line_codes[]`
|
||||
(только PDF — четырёхзначные токены сырого ответа, см. §5 `arm-core/.../design.md`); для OSV — `osv_warnings[]` и
|
||||
счётчики строк вместо `lines`/`values`.
|
||||
- `outcome-payload`: тот же `header`/`lines`/`values`, что и intake (подтверждённое состояние), плюс `fixes[]`
|
||||
(`field`, `before_raw`, `before_recognized`, `after`, `source`, `rule`).
|
||||
|
||||
**Валидация.** `scripts/validate_contracts.py` не расширяется этим change: он жёстко завязан на три сообщения
|
||||
NATS-контракта (`request-`/`result-message-`/`result-` префиксы примеров). Payload фактов не ходит по NATS и не
|
||||
исполняет формат идемпотентности — расширение скрипта под него добавило бы ветвление без необходимости. Схема
|
||||
проверяется отдельным тестом в `arm-core` (где и формируется payload), а не `make check` здесь. Решение записано,
|
||||
так как расходится с общим правилом «каждый контракт в `contracts/` валидируется этим скриптом».
|
||||
|
||||
## 3. §14 `05-domain-rules.md` — состав раздела
|
||||
1. Какие документы получают факты (BALANCE/INCOME/OSV, не DISCLOSURE/OTHER).
|
||||
2. Правило атрибуции правки «сервис / наш разбор» (таблица из `arm-core/.../design.md` §5) — переносится как есть,
|
||||
источник правды один (здесь — табличная форма для ссылок из кода).
|
||||
3. Правило «документ клиента» (ручное подтверждение с акцептом жёстких нарушений, мягкие и 1370↔2400 не считаются).
|
||||
4. Приоритет `quality_cause` (§1.3) и знаменатель долей матрицы.
|
||||
5. Признак скана — определение по текстовому слою PDF, допущение о скрытом OCR-слое.
|
||||
6. Технические отказы считаются по файлам, не по документам; `FILE_REPROCESS` — первая попытка остаётся отказом.
|
||||
|
||||
## Decisions made without discussion
|
||||
|
||||
| Дата | Решение | Обоснование | Цена ошибки |
|
||||
|---|---|---|---|
|
||||
| 05.11.2026 | Имена таблиц/столбцов/enum — как в разделе 1 (DBML v5.25) | исполнитель решает в рамках design arm-core §11 («оставлено исполнителю») | переименование потребует новой мажорной версии DBML |
|
||||
| 05.11.2026 | `quality_cause` — отдельный enum-столбец (денормализация §6 вместо вычисления на лету при каждом запросе матрицы) | факт append-only, пересчёт не нужен; упрощает API метрик (`GROUP BY primary_cause`) | расхождение между сохранённым `primary_cause` и правилом §14, если правило изменится — старые факты не пересчитываются (ожидаемо для append-only) |
|
||||
| 05.11.2026 | Атрибуция правок — 2 источника (service/ours), не 3: «документ клиента» — свойство исхода, не правки (см. §5 исходного design: таблица даёт только «сервис» или «наш разбор») | в design arm-core таблица §5 бинарна; «документ клиента» в §6 — отдельное правило по checks_accepted | лишний enum-источник правки, если окажется нужен позже |
|
||||
| 05.11.2026 | `quality-facts.schema.json` не подключается к `scripts/validate_contracts.py` | скрипт — для NATS wire-контракта с дедупом/версией сообщений; payload фактов — внутренний формат arm-core, не обмен между сервисами | изменение формата payload не поймает `make check` в этом репозитории; ловит тест arm-core |
|
||||
| 05.11.2026 | `legal_entity_name`/`group_name` добавлены и в `quality_failure_fact`, хотя design arm-core §4.3 их не перечислял | общее правило §4 design arm-core («имена ЮЛ и ГК копируются на момент факта») относится ко всем фактам; итемized список там был неполным | лишние 2 столбца, если экран всё же джойнит live-справочник для отказов |
|
||||
| 07.11.2026 | Схема перенесена в `contracts/metrics/quality-facts.schema.json` (R-16 arm-core) | в корне `contracts/` каждая `*.schema.json` обязана иметь копию в сервисах (`contract_identity.py`); подкаталог глубины 2 вне `examples/` копию не требует — схема не относится к NATS-контракту распознавания; содержание схемы не менялось | при возврате в корень тесты идентичности tabular-parser и scan-gateway покраснеют |
|
||||
| 07.11.2026 | В схеме `contracts/metrics/quality-facts.schema.json` поле `is_recognized` значений — `["boolean", "null"]` (R-24 arm-core) | в модели `financial_statement_value.is_recognized` NULL: ячейка, созданная правкой аналитика, и пустая ячейка колонки источника при приёме; схема с `boolean` отвергала такие payload | потребитель фактов обязан обрабатывать null |
|
||||
65
openspec/changes/quality-metrics/proposal.md
Normal file
@ -0,0 +1,65 @@
|
||||
# Proposal: Метрики качества первички (AURORA-1759)
|
||||
|
||||
**Срез:** вне `docs/context/09-delivery-plan.md` (спринт `AWPCA_Sprint_3_Corrections`, эпик AURORA-1353).
|
||||
**Репозиторий:** arm-ka-docs (сквозная часть — модель данных). **Issue:** RSHB/arm-ka-docs#202.
|
||||
**Дочерние change'и:** `arm-core/openspec/changes/quality-metrics` (arm-core#190) — запись фактов, атрибуция,
|
||||
API, экран. `tabular-parser` и `scan-gateway` не меняются.
|
||||
|
||||
Полное обоснование и все решения владельца — `../../arm-core/openspec/changes/quality-metrics/design.md`
|
||||
(брейнсторминг 27.10.2026, подтверждено владельцем 05.11.2026). Этот change переносит из него в модель данных
|
||||
только то, что становится структурой: таблицы, перечисления, столбцы, контракт payload, правила подсчёта.
|
||||
|
||||
## Why
|
||||
|
||||
Заказчику нужно подтверждать эффект АРМ КА цифрами (доля ББ/ОФР, дошедшая без правок), владельцу — доказательная база
|
||||
о качестве сервиса разбора PDF с разделением «ошибка сервиса / наша нормализация / документ клиента». Ядро сейчас не
|
||||
хранит ничего для этого: `document`/`financial_statement_*` переписываются при правке и перестройке, подтверждённый
|
||||
результат недоступен после следующей правки, сырой ответ ИС Сканирование не регистрируется в БД (решение v5.13,
|
||||
отменяется этим change).
|
||||
|
||||
## What Changes
|
||||
|
||||
- **Три новые таблицы фактов** (плоские, append-only, без FK на рабочие таблицы, отдельная схема PostgreSQL
|
||||
`dkb_metrics` — имя настройка): `quality_intake_fact` (документ «как распознано», пишется в момент маппинга),
|
||||
`quality_outcome_fact` (исход: автоподтверждён / подтверждён / удалён / заменён — в т. ч. после подтверждения — с
|
||||
атрибуцией правок и причиной попадания в ячейку матрицы), `quality_failure_fact` (технический отказ задания
|
||||
распознавания). Точные столбцы — `design.md` §1.
|
||||
- **`s3_bucket_role`**: новое значение `raw` — сырой ответ ИС Сканирование (`raw/{job_id}.json`) регистрируется в
|
||||
`s3_object`, не удаляется вместе с файлом (вход для будущего эталонного прогона, ASSUMPTION(OQ-179) — срок хранения
|
||||
решает платформа).
|
||||
- **`recognition_job.raw_s3_object_id`** — ссылка на зарегистрированный сырой ответ (image pipeline).
|
||||
- **`stored_file.is_scan`** — признак скан/цифровой PDF, определяется при загрузке по текстовому слою.
|
||||
- **`permission_object`**: новое значение `QUALITY_METRICS` — объект права для экрана (действие `VIEW`,
|
||||
право `QUALITY_METRICS_VIEW`; seed — в arm-core).
|
||||
- **`docs/contracts/metrics/quality-facts.schema.json`** — JSON Schema payload (jsonb) трёх фактов.
|
||||
- **`docs/context/05-domain-rules.md` §14** — счёт документов/матрица причин, правило атрибуции правки
|
||||
(сервис/наш разбор), правило «документ клиента» (акцепт жёстких нарушений), признак скана.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `quality-metrics-model`: модель данных и контракт фактов качества распознавания первички — какие факты пишутся,
|
||||
в каком формате, как считается матрица причин.
|
||||
|
||||
### Modified Capabilities
|
||||
<!-- openspec/specs пуст для этой области — изменяемых capability нет -->
|
||||
|
||||
## Impact
|
||||
|
||||
- Пишет факты только `arm-core` (единственный писатель в БД, см. `../CLAUDE.md`). Читает — Superset платформы
|
||||
отдельной read-only ролью к схеме `dkb_metrics` (создаёт платформа, описание в `03-architecture.md`).
|
||||
- Таблицы DBML v5.24, которые это затрагивает: `recognition_job`, `s3_object`, `s3_bucket_role`, `stored_file`,
|
||||
`document`, `financial_statement_meta/column/line/value`, `osv_entry`, `document_issue`, `permission_object`.
|
||||
Новых FK на них из таблиц фактов нет (факты самодостаточны).
|
||||
- Миграция Alembic — в `arm-core` (общая цепочка, не в этом репозитории).
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Метрики по документам до выкладки фичи (ретро-подсчёт) — не считаем.
|
||||
- Время работы аналитика (визиты документа) — будущий раунд; факты уже ключуются `document_id` для последующего
|
||||
присоединения.
|
||||
- Отдельный счётчик «документ есть, но сервис его не разбирает» — не отделить от технических отказов (решение
|
||||
владельца 27.10.2026).
|
||||
- Сам эталонный прогон перенормализации сохранённых сырых ответов — этот change только обеспечивает вход (хранение
|
||||
`raw/{job_id}.json`, отказ от ретеншна).
|
||||
- Ограничение видимости метрик по филиалу/ГК — пока все роли видят всё.
|
||||
@ -0,0 +1,63 @@
|
||||
# Spec Delta: quality-metrics-model
|
||||
|
||||
## Purpose
|
||||
|
||||
Модель данных и контракт фактов качества распознавания первички (AURORA-1759): какие факты пишутся, в каком
|
||||
формате, как они переживают удаление/перераспознавание документа и чем отличаются от рабочих таблиц. Алгоритм
|
||||
подсчёта и атрибуции — `context/05-domain-rules.md` §14 (не дублируется здесь).
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Факты качества — append-only и без FK на рабочие таблицы
|
||||
`quality_intake_fact`, `quality_outcome_fact`, `quality_failure_fact` SHALL не иметь внешних ключей на `document`,
|
||||
`stored_file`, `recognition_job`, `legal_entity`, `company_group` — только простые `uuid` и денормализованные имена
|
||||
ЮЛ/ГК. Факты SHALL жить в отдельной схеме PostgreSQL (имя — настройка, по умолчанию `dkb_metrics`).
|
||||
|
||||
#### Scenario: Документ удалён после записи факта
|
||||
- **WHEN** документ, по которому есть `quality_intake_fact`, физически удалён (`primary_files.delete`)
|
||||
- **THEN** строка факта остаётся читаемой, её `document_id` не разрешается в существующий `document`, и запрос к
|
||||
факту не падает на отсутствующем FK
|
||||
|
||||
### Requirement: `quality_intake_fact` — один факт на документ, кроме ОСВ без построчного снимка
|
||||
Таблица SHALL иметь ровно один факт на `document_id` (`unique`). Для `document_type = OSV` `payload` SHALL не
|
||||
содержать `lines`/`values` — только счётчики строк и предупреждения `OSV_*`; для `BALANCE`/`INCOME` `payload` SHALL
|
||||
содержать построчный снимок (`lines`, `values`).
|
||||
|
||||
#### Scenario: Приём результата ОСВ
|
||||
- **WHEN** ядро мапит результат распознавания ОСВ в документ `OSV`
|
||||
- **THEN** `quality_intake_fact.payload` не содержит ключей `lines`/`values`, но содержит `osv_warnings`
|
||||
|
||||
#### Scenario: Приём результата ББ
|
||||
- **WHEN** ядро мапит результат распознавания в документ `BALANCE`
|
||||
- **THEN** `quality_intake_fact.payload` содержит `lines` и `values` построчно
|
||||
|
||||
### Requirement: `quality_outcome_fact` — не unique на документ, метрики берут последний факт
|
||||
Таблица SHALL допускать несколько строк с одним `document_id` (повторное подтверждение ОСВ после правки,
|
||||
исход `*_AFTER_CONFIRM` поверх прежнего). Любой читатель метрик SHALL использовать факт с максимальным `outcome_at`
|
||||
для данного `document_id`.
|
||||
|
||||
#### Scenario: Документ удалён после подтверждения
|
||||
- **WHEN** подтверждённый документ впоследствии удалён или вытеснен автозаменой
|
||||
- **THEN** пишется новый факт с `outcome ∈ {DELETED_AFTER_CONFIRM, SUPERSEDED_AFTER_CONFIRM}`, прежний факт
|
||||
(`CONFIRMED`/`AUTO_CONFIRMED`) не удаляется и не перезаписывается
|
||||
|
||||
### Requirement: Сырой ответ ИС Сканирование регистрируется и не экспирится с файлом
|
||||
`s3_object` SHALL поддерживать роль бакета `raw`; `recognition_job.raw_s3_object_id` SHALL ссылаться на
|
||||
зарегистрированный объект для image pipeline. Удаление `stored_file` SHALL НЕ устанавливать `expires_at` ни объекту
|
||||
с ролью `raw`, ни объекту `uploads`, на который ссылается `quality_intake_fact` (`upload_s3_key`) — оба нужны
|
||||
эталонному прогону (OQ-179). Объекты `results` и прочие `uploads` (без факта) — без изменений, `expires_at = now()`
|
||||
при удалении файла, как и раньше.
|
||||
|
||||
#### Scenario: Удаление файла с зарегистрированным сырым ответом
|
||||
- **WHEN** PDF-файл с заполненным `recognition_job.raw_s3_object_id` и существующим `quality_intake_fact` удаляется
|
||||
- **THEN** `s3_object.expires_at` остаётся `NULL` у объекта роли `raw` и у объекта `uploads`, на который ссылается
|
||||
факт; у объекта `results` того же файла `expires_at` проставляется `now()`, как для любого удаления
|
||||
того же файла
|
||||
|
||||
### Requirement: Контракт payload не входит в `make check` этого репозитория
|
||||
`contracts/metrics/quality-facts.schema.json` SHALL существовать как валидная JSON Schema (Draft 2020-12), но SHALL NOT
|
||||
быть подключена к `scripts/validate_contracts.py` — payload не является сообщением NATS-контракта распознавания.
|
||||
|
||||
#### Scenario: `make check` в arm-ka-docs
|
||||
- **WHEN** выполняется `make check` в этом репозитории
|
||||
- **THEN** `quality-facts.schema.json` не упоминается в выводе `validate-contracts`, и это не считается ошибкой
|
||||
@ -54,6 +54,10 @@ PARTS = {
|
||||
["correction", "vgo_assignment", "goodwill", "kfo_result", "kfo_result_line", "kfo_result_line_company", "client_kfo_line"],
|
||||
),
|
||||
"09_audit_ex": ("Комментарии, аудит, ЕХФД", ["comment", "audit_event", "ex_snapshot", "ex_snapshot_member", "ex_snapshot_item"]),
|
||||
"10_quality_metrics": (
|
||||
"Метрики качества первички",
|
||||
["quality_intake_fact", "quality_outcome_fact", "quality_failure_fact"],
|
||||
),
|
||||
}
|
||||
|
||||
LEGEND = (
|
||||
|
||||