Andrey Epifancev 01767fd2b9 chore(openspec): архив change slice-1-directories (2026-10-05)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 11:09:08 +04:00

79 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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

# Design: Срез 1 (сквозное) — DBML v5.14, импорт ЕЦП, видимость
## Context
См. `proposal.md`. Факты, на которых стоит дизайн:
- Выгрузка ЕЦП (`docs/source/biq/ecp-export-lagal-entity.xlsx`, лист «Выписки_01.04.26»): 8400 строк, колонки `ИНН`,
`iD ГК`, `Базовый РФ ГК в CRM`, `Группа компаний`, `Организация`, `ГСК`, `ГСЗ`, `Тип`; 345 ГК; 53 значения РФ (51 «… РФ»,
плюс «ЦКБ» 1370 строк и «Головная организация»); типы ЮЛ 7395, ИП 469, `нерез.` 354, `ФЛ` 180, `нет инн` 2; ИНН: 10
цифр у ЮЛ, 12 у ИП, 279 нечисловых; 215 ИНН встречаются в нескольких ГК; флаги ГСК/ГСЗ — строки «входит в ГСК» /
«входит в ГСЗ» (плюс мусор: `0`, ИНН в колонке флага); идентификатора ГСК/ГСЗ нет; у 213 ГК есть члены ГСК (до 83).
- Решения владельца 04.10.2026: без UI справочника; КПП не нужен; ЮЛ в одной ГК, одновременно в одной ГСК и одной ГСЗ;
экран администратора минимальный.
- Инварианты: права — данные, код роли в логике не проверяется; первичка не мутируется; append-only аудит; поля вне DBML не вводить.
## Goals / Non-Goals
**Goals:** одна версия DBML, которую реализует миграция 0002; правила импорта, по которым можно написать тесты на реальной
выгрузке; правило видимости без кода роли. **Non-Goals:** см. proposal.
## Decisions
### D-1. v5.14: денормализованный `kind` в `related_group_member`
Уникальность «одна группа каждого вида на ЮЛ» нельзя выразить индексом через join; варианты — триггер или денормализация.
Выбрана денормализация (`kind` = `related_group.kind`, равенство проверяет ядро при вставке, тест на рассинхрон), индекс
`(legal_entity_id, kind) WHERE is_current`. *Альтернатива* — триггер: сложнее переносить, невидим в ORM. *Цена ошибки:*
убрать колонку и индекс миграцией.
### D-2. Версия DBML — новый файл, старый остаётся
`data-model-v5.14.dbml` рядом с v5.13 (история версий — файлы, changelog в шапке); `entities-v5.14.md` — копия с таблицей
изменений наверху; ссылки в CLAUDE.md репозиториев и `Makefile`/`DBML_VERSION` arm-core переводятся на v5.14 в дочернем change.
### D-3. Импорт — правила §13 как данные для тестов, строки не блокируют файл
Построчные коды (`UNSUPPORTED_TYPE`, `INVALID_INN`, `DUPLICATE_IN_FILE`, `RF_CREATED`, `GK_*`, `LE_*`, `GSK_CREATED`,
`MEMBER_ADDED`, `UNKNOWN_FLAG`) фиксируются в §13.2 и становятся контрактом отчёта и тестов `arm-core`; файл отвергается
только при отсутствии обязательных колонок или нечитаемости. Одна транзакция, `dry_run`, стратегия `on_existing ∈ {skip, update}`.
### D-4. Неоднозначности выгрузки — осторожные допущения + OQ, не угадывание
`нерез.`/`ФЛ` — пропуск (OQ-87); ИНН только по длине (OQ-88); «ЦКБ»/«Головная организация» — обычные филиалы (OQ-89);
ИНН в нескольких ГК — первая выигрывает, остальные в отчёт (OQ-90); одна неявная ГСК/ГСЗ на ГК с именем ГК (OQ-91).
Каждое допущение помечается `ASSUMPTION(OQ-nn)` в коде импортёра, все обратимы одной командой или повторным импортом с `update`.
### D-5. Видимость — по `regional_office.is_head_office`, без ролей
ГО видит всё, филиал — ГК своего РФ и своих монозаёмщиков; ЗО не фильтрует (OQ-86). Запись вне видимости — 404.
### D-6. Выгрузка хранится в `docs/source/biq/`, срез — в fixtures
Полная выгрузка — первоисточник формата и прогон «на всём объёме» (помечена как внутренняя: реальные ИНН); для unit-тестов —
21 строка ГК «Русский Бисквит» в `fixtures/directories/`. `fixtures/README` и `06-test-data.md` §6 обновляются.
## Risks / Trade-offs
- [Импорт всей выгрузки создаст 53 филиала и ~345 ГК в dev-БД] → `dry_run` первым, отчёт показывает `RF_CREATED`.
- [Денормализованный `kind` разойдётся с группой] → проверка в сервисе + тест; индекс всё равно защищает уникальность.
- [Допущения D-4 окажутся неверны] → данные исправимы повторным импортом с `update` или одной миграцией данных; OQ отслеживаются.
## Migration Plan
Миграция 0002 (arm-core): `ALTER TABLE related_group_member ADD kind` (заполнение из `related_group.kind` для существующих строк —
в dev их нет), замена индекса. Откат — обратная замена индекса и `DROP COLUMN`.
## Open Questions
OQ-86…OQ-91 (см. `07-open-questions.md`) — ни один не блокирует: приняты допущения D-4/D-5. Вопросы владельцу: «ЦКБ» и
«Головная организация» = ГО? нужны ли нерезиденты/ФЛ?
## Decisions made without discussion
| № | Дата | Решение | Обоснование | Цена ошибки |
|---|---|---|---|---|
| 1 | 2026-10-04 | D-1: `kind` в `related_group_member` вместо триггера | индекс виден в ORM и сверке с DBML | миграция: убрать колонку |
| 2 | 2026-10-04 | D-2: новый файл v5.14, v5.13 остаётся | правило «новая версия DBML с changelog» | нет |
| 9 | 2026-10-04 | v5.14: два новых значения `audit_action` — `LEGAL_ENTITY_CHANGE`, `USER_CHANGE` | без них события ЮЛ/пользователей пришлось бы писать под чужим действием (`GROUP_CHANGE`) | удалить значения enum (миграция) |
| 3 | 2026-10-04 | D-3: коды отчёта импорта фиксированы в §13.2; строки не блокируют файл; `on_existing` skip/update; `dry_run` | макет [38] «Пропустить существующие»; реальная выгрузка грязная | добавить/переименовать коды |
| 4 | 2026-10-04 | D-4: пять допущений по неоднозначностям выгрузки (OQ-87…OQ-91) | нельзя угадывать; все обратимы | повторный импорт / миграция данных |
| 5 | 2026-10-04 | D-5: видимость по `is_head_office`, ЗО не фильтрует | права — данные; у ГК нет сегмента | добавить поле сегмента (DBML v5.15) и фильтр |
| 6 | 2026-10-04 | D-6: полная выгрузка в `docs/source/biq`, срез в fixtures | первоисточник формата vs тестовые данные | перенос файла |
| 7 | 2026-10-04 | Срез 1 без UI справочника, экран администратора минимальный | решение владельца 04.10.2026 | UI — отдельный срез |
| 8 | 2026-10-04 | Записи вне видимости отвечают 404, не 403 | не раскрывать существование чужих ГК | одна константа |