From 40b3b92714da46bd669fc6ef86dbee9d26853ca5 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Fri, 9 Oct 2026 23:44:04 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D1=84=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE?= =?UTF-8?q?=D0=BC=D1=83=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20=E2=80=94=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=87=D0=B8=D0=B9=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=BB,=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B0,=20=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D1=83=D0=BB=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B8=20(#90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- context/03-architecture.md | 2 +- context/04-data-model-guide.md | 2 +- context/10-user-journey.md | 2 +- dev/api-contract-files-directories.md | 12 +++++++----- dev/frontend-api-guide.md | 10 +++++----- dev/frontend-auth-guide.md | 4 ++-- dev/qa-guide.md | 5 +++-- mockup/INDEX.md | 2 +- model/data-model-v5.18.dbml | 10 +++++----- model/diagrams/part07_consolidation.svg | 2 +- model/entities-v5.18.md | 6 +++--- openspec/changes/console-files/design.md | 6 +++++- openspec/changes/console-files/tasks.md | 2 +- 13 files changed, 36 insertions(+), 29 deletions(-) diff --git a/context/03-architecture.md b/context/03-architecture.md index 53f142c..42c5046 100644 --- a/context/03-architecture.md +++ b/context/03-architecture.md @@ -147,7 +147,7 @@ advisory-lock по `(ЮЛ, sha256)` (двойной клик не проскак `consolidation_documents` (привязка/отвязка), `consolidated_osv`, `counterparty_mapping`, `osv_export`; домен — `policy` (`ensure_version_editable`), `checklist`, `consolidation_periods`, `consolidated_osv`. - **Единственное место смены статуса** — `consolidation_status.transition`: ручной `POST …/status` и автоматические - переходы (загрузка с версией, маппинг, подтверждение документа) зовут её же, поэтому история и аудит одинаковы. Версия к + переходы (загрузка в консолидацию, маппинг, подтверждение документа) зовут её же, поэтому история и аудит одинаковы. Версия к моменту вызова уже под `FOR UPDATE` у вызывающего. - **Порядок блокировок: файл → документ → advisory-lock ГК → версии (по возрастанию `id`).** Подтверждение документа берёт файл, документ и затем все версии «в работе» ГК ЮЛ (`lock_versions_for_entity` блокирует надмножество — член ИЛИ та же ГК — и diff --git a/context/04-data-model-guide.md b/context/04-data-model-guide.md index f53d26e..a6ca68b 100644 --- a/context/04-data-model-guide.md +++ b/context/04-data-model-guide.md @@ -20,7 +20,7 @@ | 08 Корректировки и КФО | `correction`, `goodwill`, `kfo_result`, `kfo_result_line`, `kfo_result_line_company`, `client_kfo_line` | ручные решения и результат | | 09 Комментарии, аудит, ЕХ | `comment`, `audit_event`, `ex_snapshot`, `ex_snapshot_member`, `ex_snapshot_item` | полиморфные комментарии, append-only журнал, замороженные срезы | -**v5.18:** `stored_file.consolidation_id` — в какую консолидацию (период ГК) загружен файл; это рабочий стол консоли, общий для её версий. Что использует версия — `consolidation_document`. +**v5.18:** `stored_file.consolidation_id` — в какую консолидацию (период ГК) загружен файл; файлы, загруженные в консолидацию, — основа рабочего стола консоли, общего для её версий (полный состав стола, с файлами документов, привязанных к версиям, — `05-domain-rules.md` §9.5 п. 11). Что использует версия — `consolidation_document`. ## Соглашения diff --git a/context/10-user-journey.md b/context/10-user-journey.md index 161845b..7fb3d3b 100644 --- a/context/10-user-journey.md +++ b/context/10-user-journey.md @@ -76,7 +76,7 @@ | 2.2 | Отчётность → Группы компаний [03] → **Консолидации →** [34] | [03]: таблица ГК (Группа компаний, CRM ID, Основной РФ, Организаций), поиск по ГК, CRM ID или РФ. [34]: таблица консолидаций ГК: Год, Квартал, Версия (дерево версий под периодом), Статус (бейдж), ГСК, Дата создания, Дата верификации, Организаций; кнопки в строке **Взять в работу**, **К отчетности** (по снимку неактивна у «Инициация» и «Верификация РФ»; решение владельца 07.10.2026 — доступна во всех статусах, OQ-43), меню «…»; чекбокс «Только в работе». Выбор строки открывает панель **Организации** (Ответственный / Утверждён в РФ / Верифицирован в ГО; таблица Наименование, Документы, ОФР, Бух. баланс, ОСВ — перечень счетов, ИНН, Тип). **API:** `GET /company-groups/{id}/consolidations?in_work_only=` (периоды и версии, блокировка), `GET /consolidations/versions/{id}` (карточка: члены — тип ЮЛ `entity_type`, самоописывающие ячейки чек-листа ББ/ОФР, счета загруженных ОСВ `osv_accounts`; история; «Ответственный» — `lock.locked_by_name` при активной блокировке, иначе `initiator.name`; «Утверждён в РФ» / «Верифицирован в ГО» и колонка «ГСК» — Срез 7) | `consolidation_version`, `consolidation_lock`, `consolidation_member`, `document` | | 2.3 | [34] → **Взять в работу** [35] | «Консолидация … будет закреплена за вами для редактирования». **API:** `POST …/versions/{id}/lock` (перехват — `takeover_reason`), `DELETE …/lock`; ручной статус — `POST …/status` | `consolidation_lock`, `audit_event(CONSOLIDATION_LOCK)` | | 2.4 | [34] панель Организации → **Редактировать состав** [36] | фильтр по ГСК, «Показать все ЮЛ в ГК», чекбоксы, Сохранить. **API:** `PUT …/versions/{id}/members` (`{legal_entity_ids}`), нужны статус «в работе» и своя блокировка | `consolidation_member` | -| 2.5 | строка организации → **Документы** → drawer «Первичные документы» [39] | список: документ (имя, формат, дата; подпись типа у прочих — «Прочий документ», «Бухгалтерская отчетность»), Период («2024 К1», «2025 · 9 мес.»), Проверка (✓ / ✗ / — Период, Контрагент), Статус (Загружен / Обработка / Требуется проверка / Ошибка); иконки: комментарий (поповер «Комментарий к документу …», [39-01]) и удалить; **Редактировать документы** — в снимке неактивна; **Загрузить документы** [40]: модалка с зоной «Перетащите файлы сюда» / **Выбрать документы**, Загрузить; **тип документа и период в модалке не выбираются** — определяются при распознавании. **API:** список — `GET /consolidations/{cid}/legal-entities/{id}/files` (рабочий стол консоли: файлы, загруженные в эту консолидацию, и файлы с документами, привязанными к её версиям; переключатель «Все документы организации» — `GET /legal-entities/{id}/files`, у файла подпись консолидации); загрузка — `POST /consolidations/{cid}/legal-entities/{id}/files` (только в версии «в работе»); документы и подтверждение — `/files`, `/documents` (Срез 2c); подтверждённый документ привязывается к версиям «в работе» автоматически (v5.18, docs #90) | `stored_file(UPLOADED)`, `s3_object`, `recognition_job(queued)`, `document.period_check/counterparty_check` → `DOCUMENTS_PROCESSING` | +| 2.5 | строка организации → **Документы** → drawer «Первичные документы» [39] | список: документ (имя, формат, дата; подпись типа у прочих — «Прочий документ», «Бухгалтерская отчетность»), Период («2024 К1», «2025 · 9 мес.»), Проверка (✓ / ✗ / — Период, Контрагент), Статус (Загружен / Обработка / Требуется проверка / Ошибка); иконки: комментарий (поповер «Комментарий к документу …», [39-01]) и удалить; **Редактировать документы** — в снимке неактивна; **Загрузить документы** [40]: модалка с зоной «Перетащите файлы сюда» / **Выбрать документы**, Загрузить; **тип документа и период в модалке не выбираются** — определяются при распознавании. **API (v5.18, docs #90):** список — `GET /consolidations/{cid}/legal-entities/{id}/files` (рабочий стол консоли: файлы, загруженные в эту консолидацию, и файлы с документами, привязанными к её версиям; переключатель «Все документы организации» — `GET /legal-entities/{id}/files`, у файла подпись консолидации); загрузка — `POST /consolidations/{cid}/legal-entities/{id}/files` (только в версии «в работе»); документы и подтверждение — `/files`, `/documents` (Срез 2c); подтверждённый документ привязывается к версиям «в работе» автоматически | `stored_file(UPLOADED, consolidation_id)`, `s3_object`, `recognition_job(queued)`, `document.period_check/counterparty_check` → `DOCUMENTS_PROCESSING` | | 2.6 | [34] → **Скачать чек-лист** [37] | матрица Организация × (Бух. баланс, ОФР, ОСВ 01 58 60 62 66 67 76 90, Прочие); легенда: Загружен / Обработка / Требуется проверка / Ошибка загрузки / Отсутствует; Скачать CSV. **API:** `GET …/versions/{id}/checklist` (`rules[]`, `rows[].cells[]`: `document_type`, `account`, `status`, `missing_quarters`, `document_ids`); «Скачать CSV» — `?format=csv` (Срез 3b) | `required_document_rule × consolidation_member − document(CONFIRMED)` | | 2.7 | drawer [39] → клик по **PDF**-документу → **Проверка распознавания** [41] | слева «Исходный документ» постранично с масштабом; справа «Результат распознавания»: шапка формы (организация, ИНН, ОКПО/ОКОПФ/ОКФС, адрес, аудит, ОКУД, отчётная дата, ОКЕИ, единица измерения) и таблица Пояснения / Наименование показателя / Код / колонки-даты (в таблице есть строки без кода «в том числе …» и строка «Гудвилл 1105» ФСБУ 4/2023 — OQ-36, OQ-37); выпадающий список **Документ** для перехода между документами ЮЛ; **Добавить комментарий**; **Редактировать** [41-02] → кнопки **Сохранить** / **Отменить** (значения таблицы редактируются на месте); **Подтвердить данные**. Блок логических ошибок — по ТЗ (в снимках не виден). Для ОСВ (xlsx) экран в макете не открывается — строки readonly, OQ-42 | `financial_statement_meta/column/line/value.is_modified`, `osv_entry.is_modified`, `document(CONFIRMED)`, `comment`, `audit_event(RECOGNIZED_DATA_EDIT, DOCUMENT_CONFIRM)` → `DATA_CORRECTION` | diff --git a/dev/api-contract-files-directories.md b/dev/api-contract-files-directories.md index d0308ee..1cab3d1 100644 --- a/dev/api-contract-files-directories.md +++ b/dev/api-contract-files-directories.md @@ -23,7 +23,7 @@ | Метод и путь | Право | Запрос | Ответ | Ошибки | Экран | |---|---|---|---|---|---| -| `GET /legal-entities/{legal_entity_id}/files` | VIEW | query `limit`, `offset`, `include_superseded` (bool, по умолчанию `false` — заменённые скрыты) | `Page[FileOut]`, новые первыми (по убыванию `uploaded_at`) | 404 | [39] drawer «Первичные документы» | +| `GET /legal-entities/{legal_entity_id}/files` | VIEW | query `limit`, `offset`, `include_superseded` (bool, по умолчанию `false` — заменённые скрыты) | `Page[FileOut]`, новые первыми (по убыванию `uploaded_at`) | 404 | переключатель «Все документы организации» [39] / страница ЮЛ | | `GET /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` | VIEW | query `limit`, `offset`, `include_superseded` (bool, по умолчанию `false`) | `Page[FileOut]` — рабочий стол консоли для ЮЛ (файлы с этим `consolidation_id` + файлы с документами, привязанными к версиям консолидации), новые первыми; `SUPERSEDED` — только при `include_superseded=true` (скрыт по умолчанию) | 404 | [39] drawer внутри версии (v5.18, docs #90) | | `POST /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` | EDIT | multipart, поле `files` (повторяется) — загрузка в консолидацию | 201 `UploadResult` (принят хотя бы один файл) / 422 `UploadResult` (ни один) | 404 (консолидация, ЮЛ), 409 `CONSOLIDATION_NOT_EDITABLE`, 422 `ENTITY_NOT_IN_PERIMETER`, 503 `STORAGE_UNAVAILABLE` | [40] | | `POST /legal-entities/{legal_entity_id}/files` | EDIT | multipart, поле `files` (повторяется) — без контекста (`consolidation_id = null`); query `consolidation_version_id` удалён (v5.18) | 201 / 422 `UploadResult` | 404, 503 `STORAGE_UNAVAILABLE` | страница ЮЛ, монозаёмщики | @@ -34,15 +34,16 @@ | `GET /documents/{document_id}/entries` | VIEW | query `limit` (≤ 2000, по умолчанию 500), `offset` | `Page[EntryOut]` по возрастанию `row_number`; дерево — по `parent_entry_id` | 404 | строки ОСВ документа (только чтение) | | `POST /documents/{document_id}/confirm` | EDIT | — | `DocumentOut` | 404, 409 `ALREADY_CONFIRMED` / `FILE_SUPERSEDED` / `DOCUMENT_NOT_CONFIRMABLE`; для ББ/ОФР — `PERIOD_REQUIRED`, `CHECKS_NOT_PASSED` | «Подтвердить данные» | -Фильтра «файлы в контексте версии консолидации» **нет** (решение владельца 07.10.2026, arm-core #42): drawer показывает все -документы ЮЛ, период — в колонке «Период». Подходит ли документ версии, видно по ячейкам чек-листа версии (`document_ids`). +~~Фильтра «файлы в контексте версии консолидации» **нет** (решение владельца 07.10.2026, arm-core #42): drawer показывает все +документы ЮЛ, период — в колонке «Период».~~ (пересмотрено 09.10.2026, docs #90: drawer внутри версии — рабочий стол консоли, §9.5 п. 11.) +Подходит ли документ версии, видно по ячейкам чек-листа версии (`document_ids`). ## 3. Схемы: файлы и документы **`UploadResult`** `{accepted[], rejected[]}`: `accepted[]` — `{file_id, job_id, name}`; `rejected[]` — `{name, code, message, file_id?}`, где `code` — `UNSUPPORTED_FILE` (тип не из списка или сигнатура не совпала), `FILE_TOO_LARGE` (больше `UPLOAD_MAX_BYTES`, по умолчанию 50 МиБ), `DUPLICATE_FILE` (такой файл у ЮЛ уже есть — `file_id` указывает на него), `STORAGE_UNAVAILABLE`. **Два разных тела 422**: при -отказе всех файлов — `UploadResult` (смотрите `rejected[]`); при ЮЛ вне периметра версии — доменная ошибка +отказе всех файлов — `UploadResult` (смотрите `rejected[]`); при ЮЛ вне периметра всех версий консолидации «в работе» — доменная ошибка `{"detail": {"code": "ENTITY_NOT_IN_PERIMETER", "message": …}}`. Различайте по наличию `detail`. **`FileOut`** `{id, legal_entity_id, original_name?, file_type, status (FileStatus), version_no, size_bytes?, content_hash?, @@ -66,13 +67,14 @@ opening_debit?, opening_credit?, turnover_debit?, turnover_credit?, closing_debi нюанс 17). - «Проверка»: «Контрагент» — `counterparty_check` (`MATCH` ✓, `MISMATCH` ✗, `UNKNOWN`/`null` —); «Период» — `period_check` сейчас всегда `UNKNOWN` → показывайте «—» (OQ-120). +- Подпись консолидации: «<год> К<квартал>» из списка консолидаций ГК (`GET /company-groups/{id}/consolidations`) по `FileOut.consolidation_id`; `null` — «вне консолидации». - «Статус» (подписи — как в чек-листе и его CSV, `context/10-user-journey.md` «Словарь UI»): файл `UPLOADED`/`PROCESSING` — «Обработка»; файл `ERROR` — «Ошибка» (причина — `job.error_message` / `job.mapping_error`; задание `timeout`/`dlq` — тоже ошибка, причина в `job.error_message`); иначе по документу: `NEEDS_CHECK` и `RECOGNIZED` (старые и формы после правки) — «Требуется проверка», `CONFIRMED` (в т.ч. автоподтверждённый) — «Загружен», `ERROR` — «Ошибка». - Комментарий — у **документа** (`comments_count`, `GET/POST /documents/{id}/comments`, контракт 3b); у файла без документов комментария нет. -- Опрос во время распознавания: перечитывайте `GET /legal-entities/{id}/files` (или `GET /files/{id}` для одного файла), пока +- Опрос во время распознавания: перечитывайте активный список (стол консоли `GET /consolidations/{cid}/legal-entities/{id}/files` или файлы ЮЛ `GET /legal-entities/{id}/files`; или `GET /files/{id}` для одного файла), пока файл в `UPLOADED`/`PROCESSING`; разумный интервал — 3–5 с. - Клик по строке ББ/ОФР-документа (PDF и Excel) — экран [41] (`GET /documents/{id}/statement`, контракт 3b); строки ОСВ — только чтение (`GET /documents/{id}/entries`). diff --git a/dev/frontend-api-guide.md b/dev/frontend-api-guide.md index 553224b..08eff45 100644 --- a/dev/frontend-api-guide.md +++ b/dev/frontend-api-guide.md @@ -29,7 +29,7 @@ | Когда, PR | Что изменилось в API | Что сделать в клиенте | |---|---|---| -| 09.10, docs #90 (DBML v5.18; arm-core и arm-web — дочерние PR) | **Файлы в контексте консолидации.** Новые маршруты `POST /consolidations/{cid}/legal-entities/{le}/files` (загрузка в консоль: 404; 409 `CONSOLIDATION_NOT_EDITABLE` — нет версии «в работе»; 422 `ENTITY_NOT_IN_PERIMETER`) и `GET /consolidations/{cid}/legal-entities/{le}/files` (рабочий стол консоли для ЮЛ: файлы консоли + файлы с документами, привязанными к её версиям; `include_superseded`). Query `consolidation_version_id` у `POST /legal-entities/{id}/files` **удалён**; `FileOut.consolidation_id: uuid \| null`. Отменяет решение 07.10 «фильтра файлов ЮЛ в контексте версии нет» | панель [39] — стол консоли (`current_consolidation_id` из строки списка `con_id` / карточки версии `consolidation_id`), переключатель «Все документы организации» → `GET /legal-entities/{id}/files` с подписью консолидации у файла; загрузка [40] — новым маршрутом, кнопка недоступна, если версия не «в работе» | +| 09.10, docs #90 (DBML v5.18; arm-core и arm-web — дочерние PR) | **Файлы в контексте консолидации.** Новые маршруты `POST /consolidations/{cid}/legal-entities/{le}/files` (загрузка в консоль: 404; 409 `CONSOLIDATION_NOT_EDITABLE` — нет версии «в работе»; 422 `ENTITY_NOT_IN_PERIMETER`) и `GET /consolidations/{cid}/legal-entities/{le}/files` (рабочий стол консоли для ЮЛ: файлы консоли + файлы с документами, привязанными к её версиям; `include_superseded`). Query `consolidation_version_id` у `POST /legal-entities/{id}/files` **удалён**; `FileOut.consolidation_id: uuid \| null`. Отменяет решение 07.10 «фильтра файлов ЮЛ в контексте версии нет» | панель [39] — стол консоли (`current_consolidation_id` из `ConsolidationPeriodOut.consolidation_id` строки списка / карточки версии `consolidation_id`), переключатель «Все документы организации» → `GET /legal-entities/{id}/files` с подписью консолидации у файла; загрузка [40] — новым маршрутом, кнопка недоступна, если версия не «в работе» | | 09.10, arm-core #85 (#84) | **Форма ЮЛ одним запросом** (макет [51-02], [79]): `POST` и `PATCH /directories/legal-entities` принимают `aliases: string[]` (1–500 символов, ≤ 100), `gsk_id`, `gsz_id` и применяют их в той же транзакции, что и поля ЮЛ (ошибка — откат всего). `POST`: алиасы и членства создаются вместе с ЮЛ. `PATCH`: не переданное поле не меняется; `aliases` — **итоговый набор** (сверка по `normalized_alias`: совпавшие не трогаются, лишние удаляются — нужно право `DIRECTORY_DELETE`, иначе 403 строкой; `aliases: null` — 422), `gsk_id`/`gsz_id` — итоговая группа (`null` — выйти, другая — сменить). Новый код 422 `WRONG_GROUP_KIND`; дубль в списке — 409 `ALIAS_EXISTS`. Ответ обоих — **`LegalEntityDetail`** (было `LegalEntityOut`; поля прежние + `memberships`, `aliases`) | «Добавить»/«Сохранить» в модалках ЮЛ — один запрос со всей формой; в `PATCH` слать `aliases` и группы целиком, как они на экране; после ответа брать карточку из него, без `GET`; удаление тега-алиаса без `DIRECTORY_DELETE` (`/me.permissions`) не предлагать — сервер ответит 403 | | 08.10, arm-core #75 (#74) | **Отмена П-1** (решение владельца 08.10.2026): «несопоставленная» строка свода — нет ЮЛ после резолва **и** нет ИНН из файла. `unmapped_total`, `GET …/osv?unmapped=true` и экспорт с этим фильтром больше не включают строки с ИНН, которого нет в справочнике (`unmapped=false` — все остальные строки). Новое поле `ConsolidatedRowOut.counterparty_entity_inn` — ИНН сопоставленного ЮЛ справочника (П-8; `counterparty_inn` — по-прежнему ИНН из файла) | «Указать» — только у строк без `counterparty_id` и без `counterparty_inn`; у строки, сопоставленной без ИНН в файле, показывать `counterparty_entity_inn` с возможностью пересопоставить (макет [32-osv-no-inn], `osv-inn-mapped-button`; повторный `POST …/counterparty` разрешён) | | 08.10, arm-core #60 (#58) | **Предупреждение автозамены** (OQ-154): если новый файл заменил прежний целиком, а части документов прежнего в нём нет (книга «ББ + ОФР» → отдельный ОФР), в `job.mapping_warnings` **нового** файла приходит одна строка на заменённый файл: «автозамена: файл «…» (версия N) заменён этим файлом целиком, но в новом файле нет документов прежнего: …; привязки сняты с версий консолидации: …» — с пометкой `CONFIRMED` у подтверждённых документов. Схемы ответов не менялись; поведение замены прежнее | показать предупреждение в карточке нового файла заметно (не только в общем списке подсказок): аналитик должен догрузить выпавшие документы; текст не разбирать | @@ -224,8 +224,8 @@ UI прячет элементы по `GET /me → permissions` (объедин | Область | Чтение | Изменение | Особые | |---|---|---|---| | Справочники `/directories/*` | `DIRECTORY_VIEW` | `DIRECTORY_EDIT` | удалить ГСК/ГСЗ и алиас — `DIRECTORY_DELETE`; импорт ЕЦП — `DIRECTORY_ADMIN` | -| Файлы и документы `/legal-entities/{id}/files`, `/files/*`, `/documents/*` | `DOCUMENT_VIEW` | `DOCUMENT_EDIT` (загрузка, удаление, подтверждение, правка формы, акцепт, комментарий) | — | -| Консолидации `/consolidations*`, `/company-groups/{id}/consolidations` | `CONSOLIDATION_VIEW` (в т. ч. экспорт xlsx и CSV чек-листа) | `CONSOLIDATION_EDIT` (создание, блокировка, статус, периметр, сопоставление) | перенос чужого алиаса при сопоставлении (`move_alias`) права `DIRECTORY_DELETE` не требует | +| Файлы и документы `/legal-entities/{id}/files`, `/consolidations/{cid}/legal-entities/{le}/files` (GET — `DOCUMENT_VIEW`, POST — `DOCUMENT_EDIT`), `/files/*`, `/documents/*` | `DOCUMENT_VIEW` | `DOCUMENT_EDIT` (загрузка, удаление, подтверждение, правка формы, акцепт, комментарий) | — | +| Консолидации `/consolidations*` (кроме `…/legal-entities/{le}/files`), `/company-groups/{id}/consolidations` | `CONSOLIDATION_VIEW` (в т. ч. экспорт xlsx и CSV чек-листа) | `CONSOLIDATION_EDIT` (создание, блокировка, статус, периметр, сопоставление) | перенос чужого алиаса при сопоставлении (`move_alias`) права `DIRECTORY_DELETE` не требует | | Администрирование `/admin/*` | `USERS_ADMIN` | `USERS_ADMIN` | без права — 403 до любых проверок тела | | `/me`, `/users/brief` | любой вошедший | — | — | @@ -341,7 +341,7 @@ UI прячет элементы по `GET /me → permissions` (объедин Тип и период **не спрашиваются** — их определяет парсер по содержимому. - Коды `rejected[].code`: `UNSUPPORTED_FILE` (тип не из списка, сигнатура не совпала с расширением, пустое имя), `FILE_TOO_LARGE`, `DUPLICATE_FILE` (тот же файл у ЮЛ уже есть — `file_id` указывает на него), `STORAGE_UNAVAILABLE`. -- Два разных тела 422: все файлы отклонены — `UploadResult` (смотрите `rejected[]`); ЮЛ вне периметра версии — +- Два разных тела 422: все файлы отклонены — `UploadResult` (смотрите `rejected[]`); ЮЛ вне периметра всех версий консолидации «в работе» — `{"detail": {"code": "ENTITY_NOT_IN_PERIMETER", …}}`. Различайте по наличию `detail`. - Загрузка в консолидацию: консолидация видима, есть версия «в работе», ЮЛ в её периметре; первый принятый файл переводит **каждую** версию консолидации «в работе» с этим ЮЛ из `INITIATED` в `DOCUMENTS_PROCESSING`. Блокировка версии для загрузки @@ -467,7 +467,7 @@ UI прячет элементы по `GET /me → permissions` (объедин - **`CompanyGroupOut`** `{id, code, crm_id?, name, base_regional_office_id?, base_regional_office? {id, name, is_head_office}, is_archived, valid_from, legal_entities_count, created_at?, updated_at?}`. - **`LegalEntityOut`** `{id, inn, kpp?, crm_id?, entity_type?, name, company_group_id?, regional_office_id?, regional_office? {id, name, is_head_office}, close_date?, valid_from, created_at?, updated_at?, documents_count, outside_group, closed}`; **`LegalEntityDetail`** — + `memberships[] {related_group_id, code, kind, name, valid_from}`, `aliases[] {id, alias, normalized_alias, created_at?}`. - **`RelatedGroupOut`** `{id, code, company_group_id, kind, name, created_date?, members_count}`; **`RelatedGroupDetail`** — + `members[] {legal_entity_id, inn, name, valid_from}`. -- **`FileOut`** `{id, legal_entity_id, original_name?, file_type, status, version_no, size_bytes?, content_hash?, uploaded_at?, uploaded_by?, superseded_by_file_id?, job?, documents[]}`; **`JobBrief`** `{id, status, error_code?, error_message?, mapping_error?, warnings[], mapping_warnings[], finished_at?}`; **`DocumentBrief`** `{id, document_type, osv_account_code?, period_year?, period_quarter?, is_cumulative?, status, period_check?, counterparty_check?, locator?, comments_count}`. +- **`FileOut`** `{id, legal_entity_id, original_name?, file_type, status, version_no, size_bytes?, content_hash?, uploaded_at?, uploaded_by?, superseded_by_file_id?, consolidation_id: uuid | null (консолидация, в которую загружен файл; v5.18), job?, documents[]}`; **`JobBrief`** `{id, status, error_code?, error_message?, mapping_error?, warnings[], mapping_warnings[], finished_at?}`; **`DocumentBrief`** `{id, document_type, osv_account_code?, period_year?, period_quarter?, is_cumulative?, status, period_check?, counterparty_check?, locator?, comments_count}`. - **`DocumentOut`** = поля `DocumentBrief` + `{file_id, legal_entity_id, confirmed_by?, confirmed_at?, group_schema? [{type, name?, has_inn?}], warnings[]}`. - **`EntryOut`** `{id, row_number?, level?, parent_entry_id?, row_value?, group_type?, group_name?, data_type?, account_code?, account_root?, account_id?, counterparty_name?, counterparty_inn?, counterparty_id?, match_kind?, opening_debit?, opening_credit?, turnover_debit?, turnover_credit?, closing_debit?, closing_credit?}`. - **`VersionBrief`** `{id, version_no, status, scenario, approach, lock?, created_at?, members_count}`; **`LockOut`** `{locked_by, locked_by_name, locked_at, taken_over_from?, takeover_reason?}`. diff --git a/dev/frontend-auth-guide.md b/dev/frontend-auth-guide.md index 947dbe1..5faecc7 100644 --- a/dev/frontend-auth-guide.md +++ b/dev/frontend-auth-guide.md @@ -116,8 +116,8 @@ Dev-пользователи (`make seed-dev`), по одному на роль | Область | Чтение | Правки | Прочее | |---|---|---|---| | `/directories/regional-offices`, `/company-groups`, `/related-groups`, `/legal-entities` | `DIRECTORY_VIEW` | `DIRECTORY_EDIT` | удаление ГСК/алиаса — `DIRECTORY_DELETE`; `POST /directories/import` — `DIRECTORY_ADMIN` | -| `/legal-entities/{id}/files`, `/files/{id}`, `/documents/{id}` | `DOCUMENT_VIEW` | `DOCUMENT_EDIT` (загрузка, удаление, подтверждение) | | -| `/consolidations`, `/company-groups/{id}/consolidations`, `/consolidations/versions/{id}/*` | `CONSOLIDATION_VIEW` | `CONSOLIDATION_EDIT` (создание, блокировка, статус, периметр, сопоставление) | экспорт xlsx — `CONSOLIDATION_VIEW` | +| `/legal-entities/{id}/files`, `/consolidations/{cid}/legal-entities/{le}/files` (GET — `DOCUMENT_VIEW`, POST — `DOCUMENT_EDIT`), `/files/{id}`, `/documents/{id}` | `DOCUMENT_VIEW` | `DOCUMENT_EDIT` (загрузка, удаление, подтверждение) | | +| `/consolidations` (кроме `…/legal-entities/{le}/files`), `/company-groups/{id}/consolidations`, `/consolidations/versions/{id}/*` | `CONSOLIDATION_VIEW` | `CONSOLIDATION_EDIT` (создание, блокировка, статус, периметр, сопоставление) | экспорт xlsx — `CONSOLIDATION_VIEW` | | `/admin/users`, `/admin/roles`, `/admin/permissions` | `USERS_ADMIN` | `USERS_ADMIN` | проверка права — до разбора тела: без права 403 всегда | | `/me` | любой пользователь | — | | | `/healthcheck` (без префикса `/api/v1`) | без токена | — | живость сервера, не признак «вошёл» | diff --git a/dev/qa-guide.md b/dev/qa-guide.md index b9f6ee6..f437555 100644 --- a/dev/qa-guide.md +++ b/dev/qa-guide.md @@ -606,7 +606,7 @@ curl -s -o svod.xlsx -D - "localhost:8000/api/v1/consolidations/versions/$V/osv/ | K5 | ka_rf (ГК его филиала) | `POST …/lock` на версию, занятую `ka_go` | 409 `LOCKED_BY_OTHER` (`locked_by`, `locked_at`, `locked_by_name`); с телом `{"takeover_reason":"…"}` — 201, `taken_over_from` = id `ka_go`, `ka_go` теряет блокировку; в аудите `CONSOLIDATION_LOCK_TAKEOVER` | | K6 | ka_go | после K5 `PUT …/members` | 409 `LOCKED_BY_OTHER` (чужая блокировка), без блокировки вообще — 409 `LOCK_REQUIRED` | | K7 | владелец блокировки | `PUT …/members` с составом ≤ 1 ЮЛ, с ЮЛ другой ГК, с тем же составом | 422 `PERIMETER_TOO_SMALL`; 422 `ENTITY_NOT_IN_GROUP` (`legal_entity_ids`); 200 без изменений и без события `MEMBERSHIP_CHANGE` | -| K8 | владелец блокировки | загрузить ОСВ ЮЛ периметра в консолидацию `C` (раздел 6.6) | 201; версия `INITIATED` → `DOCUMENTS_PROCESSING`; ЮЛ вне периметра — 422 `ENTITY_NOT_IN_PERIMETER`; несуществующая консолидация — 404; консолидация без версии «в работе» (после `CANCELLED`) — 409 `CONSOLIDATION_NOT_EDITABLE`; `GET /consolidations/$C/legal-entities/$LE/files` — загруженный файл в списке, `consolidation_id = C` | +| K8 | владелец блокировки | загрузить ОСВ ЮЛ периметра в консолидацию `C` (раздел 6.6) | 201; версия `INITIATED` → `DOCUMENTS_PROCESSING`; ЮЛ вне периметра — 422 `ENTITY_NOT_IN_PERIMETER`; несуществующая консолидация — 404; `GET /consolidations/$C/legal-entities/$LE/files` — загруженный файл в списке, `consolidation_id = C` | | K9 | ka_go | после `PROCESSED` и `NEEDS_CHECK` документа — `GET …/versions/{V}`; затем `POST /documents/{id}/confirm` | `NEEDS_CHECK` → версия `DATA_CORRECTION` (если файл загружал пользователь); подтверждение переводит `INITIATED`/`DOCUMENTS_PROCESSING` → `DATA_CORRECTION`; документ привязан к версии (виден в чек-листе: ячейка `CONFIRMED`) | | K10 | ka_go | `GET …/checklist` до и после подтверждения; для квартальных ОСВ — только Q3 | ячейка ОСВ: `MISSING` → `NEEDS_CHECK`/`RECOGNIZED` → `CONFIRMED`; при неполных кварталах — `missing_quarters`; ОСВ по субсчёту (58.03) не закрывает «ОСВ 58» | | K11 | ka_go | `GET …/osv`, `…/osv/summary` по данным РБ (раздел «Данные для K11») | строки свода по парам, где покрыты все кварталы `Q1..Qn`; пары без квартала — в `gaps[]` с `missing_quarters`; деньги — строки с двумя знаками; `unmapped_total` > 0 | @@ -618,6 +618,7 @@ curl -s -o svod.xlsx -D - "localhost:8000/api/v1/consolidations/versions/$V/osv/ | K17 | ka_go | `GET …/osv/export` (в т. ч. с фильтрами) | 200, `Content-Disposition: attachment; filename="svod-osv.xlsx"; filename*=UTF-8''…`; файл открывается в Excel: лист «Сводная ОСВ» (суммы — числа, формат `#,##0.00`, число строк как в API) и лист «Пробелы» (от фильтров не зависит); в аудите `EXPORT` | | K18 | владелец блокировки | `POST …/status {"to_status":"CANCELLED"}` без комментария; с комментарием | 422 `COMMENT_REQUIRED`; 200, `status = CANCELLED`, блокировка снята (`lock = null`), `history` пополнена | | K19 | ka_go | после K18: `PUT …/members`, `POST …/lock`, `POST …/status`, сопоставление | 409 `VERSION_NOT_EDITABLE`; чтение (`GET …/osv`, экспорт, чек-лист) — 200 | +| K19а | ka_go | после K18 (версия `CANCELLED`, другой версии «в работе» нет): загрузить ОСВ ЮЛ периметра в консолидацию `C` (`POST /consolidations/$C/legal-entities/$LE/files`) | 409 `CONSOLIDATION_NOT_EDITABLE` | | K20 | владелец блокировки | `POST …/status {"to_status":"INITIATED"}` из `DATA_CORRECTION`; затем `{"to_status":"DATA_CORRECTION"}` и `{"to_status":"VERIFIED"}` | 200, привязки документов сохраняются; ручные `DATA_CORRECTION`/`VERIFIED` — 409 `TRANSITION_NOT_ALLOWED` (`from_status`, `to_status`) | | K21 | expert, client_manager | `GET …/osv`, `…/checklist`; `POST …/lock`, `PUT …/members` | чтение — 200 (client_manager — только ГК своего филиала, иначе 404); правки — 403 `недостаточно прав: требуется CONSOLIDATION_EDIT` | | K22 | ka_go | заменить файл (загрузить исправленную ОСВ того же счёта и периода) после подтверждения документа | старый файл `SUPERSEDED`, привязка его документов к версии снята (`FILE_REPLACE.after_value.unbound_version_ids` содержит `V`); новый документ привязывается только после подтверждения | @@ -637,7 +638,7 @@ K17 — `EXPORT`; во всех — `consolidation_version_id`. Блокиров Для сводной ОСВ нужны все квартальные файлы двух ЮЛ. Их 22: РБ (`../fixtures/osv/rb/2024-Q{1,2,3}/`, 2 + 2 + 7) и Счастливочная (`../fixtures/osv/schastl/2024-Q{1,2,3}/`, 3 + 3 + 5). Загружать по одному через Swagger долго, поэтому цикл (`ka_go`, `$H` из 6.6; `LE_RB` и `LE_SCH` — id ЮЛ «АО "Русский бисквит"» и «ООО "Пекарня Счастливочная"», обе в одной ГСК -ГК из раздела 7; `V` — версия за 2024 Q3, `C` — её консолидация (ответ K1), созданная и взятая в работу по K1/K4 **до** загрузки — тогда переходы статусов +ГК из раздела 7; `V` — версия за 2024 Q3, созданная и взятая в работу по K1/K4 **до** загрузки; `C` — её консолидация (`consolidation_id` из ответа K1) — тогда переходы статусов видны на K8/K9): ```bash diff --git a/mockup/INDEX.md b/mockup/INDEX.md index 049a046..bbae712 100644 --- a/mockup/INDEX.md +++ b/mockup/INDEX.md @@ -38,7 +38,7 @@ GSK-002), консолидации 2024 К1 (v1 Верифицирован, v2 | `36` | Модалка «Редактировать состав» | фильтры ГСК / Состав, чекбокс «Показать все ЮЛ в ГК», таблица Наименование/ИНН/Тип/ГСК с выбором, Сохранить | `consolidation_member`, `related_group_member` | 4 | | `37` | Модалка «Чек-лист загруженных документов» | фильтры Группа компаний / Документы; легенда статусов: Загружен, Обработка, Требуется проверка, Ошибка загрузки, Отсутствует; матрица: Организация × Бух. баланс, ОФР, ОСВ 01 58 60 62 66 67 76 90, Прочие документы (ОСВ №20, Прочий документ); **Скачать** (CSV) | `required_document_rule`, `document` | 3 | | `38` | Модалка «Импорт групп компаний из файла» | Файл (.xlsx, .csv), РФ, «Ожидаемые колонки: ИНН, Наименование, Тип, Базовый РФ ГК, ID ГК», «При дублировании: Пропустить существующие», Загрузить | `legal_entity`, `company_group`, `audit_event(DIRECTORY_IMPORT)` | 1 | -| `39` | **Панель «Первичные документы»** организации (drawer) | ИНН, **Загрузить документы**, Редактировать документы; таблица: Документ (имя, формат, дата; у прочих — подпись «Прочий документ» / «Бухгалтерская отчетность»), Период («2024 К1», «2025 · 9 мес.»), Проверка (✓ / ✗ / — Период, Контрагент), Статус (Загружен / Обработка / Требуется проверка / Ошибка), иконки комментарий и удалить. Строки PDF — `doc-row--previewable` (клик → `41`), строки xlsx (ОСВ, расшифровки) — `doc-row--readonly` (клик ничего не открывает) | `stored_file` (+ `consolidation_id`, v5.18: панель внутри версии показывает рабочий стол консоли), `document.period_check/counterparty_check/status`, `comment` | 2–3 | +| `39` | **Панель «Первичные документы»** организации (drawer) | ИНН, **Загрузить документы**, Редактировать документы; таблица: Документ (имя, формат, дата; у прочих — подпись «Прочий документ» / «Бухгалтерская отчетность»), Период («2024 К1», «2025 · 9 мес.»), Проверка (✓ / ✗ / — Период, Контрагент), Статус (Загружен / Обработка / Требуется проверка / Ошибка), иконки комментарий и удалить. Строки PDF — `doc-row--previewable` (клик → `41`), строки xlsx (ОСВ, расшифровки) — `doc-row--readonly` (клик ничего не открывает) | `stored_file` (+ `consolidation_id`, v5.18: файлы, загруженные в консолидацию, — основа рабочего стола консоли, который показывает панель внутри версии; полный состав — context/05-domain-rules.md §9.5 п. 11), `document.period_check/counterparty_check/status`, `comment` | 2–3 | | `39-01` | Панель документов → «Редактировать документы» | кнопка в снимке неактивна (режим не включается); иконка комментария в строке → поповер «Комментарий к документу <файл>» («Комментарий отсутствует», Закрыть) | `comment(object_type='document')` | 2–3 | | `40` | Модалка «Загрузка документов» | заголовок с организацией; зона «Перетащите файлы сюда» + **Выбрать документы**; Отмена, Загрузить (неактивна, пока нет файлов). Тип документа и период в модалке **не выбираются** — определяются при распознавании | `stored_file`, `recognition_job` | 2 | | `41` | **Проверка распознавания** (клик по PDF-документу в `39`) | крошки Отчётность › ГК › ЮЛ › Проверка документа; заголовок + имя файла, формат, дата; выпадающий список **Документ** (переход между документами организации) + бейдж статуса; **Добавить комментарий**. Слева «Исходный документ»: постраничные изображения, масштаб 100 % ±, сброс. Справа «Результат распознавания»: шапка формы (организация, ИНН, ОКПО/ОКОПФ/ОКФС, адрес, аудит), «Бухгалтерский баланс на 30 сентября 2025 г.», ОКУД, отчётная дата, ОКЕИ, единица измерения; таблица Пояснения / Наименование показателя / Код / колонки-даты, разделы и итоги; в таблице есть строки **без кода** («в том числе: Основные средства, пригодные к использованию…») и строка «Гудвилл 1105» (ФСБУ 4/2023); **Редактировать**, **Подтвердить данные**. В снимке — реальный скан ББ «Пекарни Счастливочной» из фикстур при имени файла «ОФР_2024_К1.pdf» (данные макета условны) | `document`, `financial_statement_meta/column/line/value`, `comment`, `audit_event(RECOGNIZED_DATA_EDIT, DOCUMENT_CONFIRM)` | 3 | diff --git a/model/data-model-v5.18.dbml b/model/data-model-v5.18.dbml index 6b78f45..7f274b5 100644 --- a/model/data-model-v5.18.dbml +++ b/model/data-model-v5.18.dbml @@ -6,7 +6,7 @@ // // v5.18 (решения владельца 09.10.2026; RSHB/arm-ka-docs#90, openspec/changes/console-files): // 1. stored_file.consolidation_id (uuid, nullable, FK → consolidation): консолидация (ГК + год + квартал), в контексте -// которой загружен файл, — «рабочий стол консоли», общий для всех версий периода. NULL — загрузка без контекста +// которой загружен файл, — основа «рабочего стола консоли» (полный состав стола — context/05-domain-rules.md §9.5 п. 11), общего для всех версий периода. NULL — загрузка без контекста // (страница ЮЛ, монозаёмщики, API). Пишется один раз при загрузке (POST /consolidations/{id}/legal-entities/{le}/files); // при автозамене новый файл без контекста наследует consolidation_id заменённого. Индекс (legal_entity_id, consolidation_id). // Что использует конкретная версия, по-прежнему определяет consolidation_document; заморозка после VERIFIED — привязки и ex_snapshot. @@ -722,7 +722,7 @@ Table s3_object { // ТЗ: ТЗ 6.2 (типы и форматы документов, UUID); 8.2 «первичные документы не редактируются, только замена с версионностью» // Аналитика: md «Загрузка документов» (панель, UC-01…05); FNR01 «Маппинг stored_file» // Макет: «Первичные документы», «Загрузка документов», «Замена документа», «Удаление документа» -// В модели: v4 + v5 (version_no, superseded_by) + v5.2 (s3_object_id); v5.13 — только ФИЗИЧЕСКИЙ файл, документы → document +// В модели: v4 + v5 (version_no, superseded_by) + v5.2 (s3_object_id); v5.13 — только ФИЗИЧЕСКИЙ файл, документы → document; v5.18 — consolidation_id Table stored_file { id uuid [pk] legal_entity_id uuid [not null, ref: > legal_entity.id, note: 'организация-владелец (выбрана при загрузке)'] @@ -738,10 +738,10 @@ Table stored_file { uploaded_by uuid [ref: > app_user.id] uploaded_at timestamptz updated_at timestamptz - consolidation_id uuid [ref: > consolidation.id, note: 'v5.18: консолидация (период ГК), в контексте которой загружен файл — «рабочий стол консоли», общий для всех версий периода; NULL — без контекста. Пишется при загрузке; при автозамене файл без контекста наследует значение заменённого'] + consolidation_id uuid [ref: > consolidation.id, note: 'v5.18: консолидация (период ГК), в контексте которой загружен файл — основа «рабочего стола консоли» (полный состав — context/05-domain-rules.md §9.5 п. 11), общего для версий периода; NULL — без контекста. Пишется при загрузке; при автозамене файл без контекста наследует значение заменённого'] Indexes { (legal_entity_id, status) - (legal_entity_id, consolidation_id) [note: 'v5.18: рабочий стол консоли для ЮЛ'] + (legal_entity_id, consolidation_id) [note: 'v5.18: основа рабочего стола консоли для ЮЛ (§9.5 п. 11)'] current_recognition_job_id [note: 'v5.15: проверка FK при удалении recognition_job / файла (OQ-117)'] } Note: 'v5.13: физический файл одной загрузки (S3 — только ссылка). Что внутри — document (1:N). Первичка не редактируется. Удаление физическое запрещено после INITIATED — только SUPERSEDED (ANL-020). v5.18: consolidation_id — где загружен; что использует версия — consolidation_document' @@ -978,7 +978,7 @@ Table consolidation { reporting_date date [not null, note: 'ADD: 01.04 / 01.07 / 01.10 / 01.01 след. года — для ЕХ и сравнений'] created_at timestamptz Indexes { (company_group_id, year, quarter) [unique] } - Note: 'Логическая консолидация ГК за период; версии различаются периметром (consolidation_member). Прошлые периоды — по company_group_id. v5.18: файлы, загруженные в консолидацию, — stored_file.consolidation_id (рабочий стол, общий для версий периода)' + Note: 'Логическая консолидация ГК за период; версии различаются периметром (consolidation_member). Прошлые периоды — по company_group_id. v5.18: файлы, загруженные в консолидацию, — stored_file.consolidation_id (основа рабочего стола; полный состав — context/05-domain-rules.md §9.5 п. 11)' } // ИСТОЧНИК: diff --git a/model/diagrams/part07_consolidation.svg b/model/diagrams/part07_consolidation.svg index ce387ff..f70a66d 100644 --- a/model/diagrams/part07_consolidation.svg +++ b/model/diagrams/part07_consolidation.svg @@ -209,7 +209,7 @@ consolidation - + diff --git a/model/entities-v5.18.md b/model/entities-v5.18.md index 8628aec..5d27d2f 100644 --- a/model/entities-v5.18.md +++ b/model/entities-v5.18.md @@ -6,7 +6,7 @@ | № | Изменение | Решение | |---|---|---| -| 1 | `stored_file.consolidation_id` (`uuid`, nullable, FK → `consolidation`) + индекс `(legal_entity_id, consolidation_id)` | Файл загружается **в консолидацию** (период ГК) и становится частью её «рабочего стола», общего для всех версий периода; `NULL` — загрузка без контекста (страница ЮЛ, монозаёмщики, API). Панель «Первичные документы» в версии показывает рабочий стол консоли для ЮЛ плюс файлы с документами, привязанными к версиям консоли. Что использует конкретная версия — по-прежнему `consolidation_document`; заморозка после `VERIFIED` — привязки и `ex_snapshot`. Привязка файла к **версии** (`consolidation_file`) отвергнута: рабочие версии периода делят первичку, а новая версия после `VERIFIED` подхватывает подтверждённое (`openspec/changes/console-files/design.md`) | +| 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`). @@ -110,7 +110,7 @@ | Сущность | Что это | Ключевые связи | Откуда | |---|---|---|---| | `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` — консолидация, в контексте которой файл загружен («рабочий стол консоли», общий для версий периода; `NULL` — без контекста). Что внутри файла — `document`. Замена — файл целиком со всеми документами. | → `legal_entity`, `consolidation`, `s3_object`, `recognition_job`; ← `document`, `recognition_job` | ТЗ 6.2, 8.2; UC-01…05 | +| `stored_file` | **v5.13: только физический файл** одной загрузки: чей (ЮЛ), формат, hash, кто/когда загрузил, статус обработки (`UPLOADED → PROCESSING → PROCESSED / ERROR / SUPERSEDED`), версия при замене. **v5.18:** `consolidation_id` — консолидация, в контексте которой файл загружен (основа «рабочего стола консоли», общего для версий периода; полный состав — `context/05-domain-rules.md` §9.5 п. 11; `NULL` — без контекста). Что внутри файла — `document`. Замена — файл целиком со всеми документами. | → `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`. На документ ссылаются разобранные данные, чек-лист, консолидация и ЕХ. | → `stored_file`, `legal_entity`, `app_user`; ← `osv_entry`, `financial_statement_meta`, `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`). | → `stored_file`, `s3_object`; ← `osv_entry`, `financial_statement_meta` | ТЗ 6.2, 6.10; DECISION-4 | @@ -133,7 +133,7 @@ | Сущность | Что это | Ключевые связи | Откуда | |---|---|---|---| -| `consolidation` | Логическая консолидация: **ГК** + отчётный период. ГСК фиксируется/создаётся при верификации по фактическому периметру. Уникальна по (ГК, год, квартал). **v5.18:** файлы, загруженные в консолидацию, — `stored_file.consolidation_id` (рабочий стол, общий для версий периода). | → `company_group`, `related_group`; ← `consolidation_version`, `stored_file` | ТЗ 6.10, 7.2 | +| `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` | макет | diff --git a/openspec/changes/console-files/design.md b/openspec/changes/console-files/design.md index 8874ca2..4b97373 100644 --- a/openspec/changes/console-files/design.md +++ b/openspec/changes/console-files/design.md @@ -71,7 +71,7 @@ SUPERSEDED — только при include_superseded = true (и для DESK, и ``` `BOUND` нужен для файлов, загруженных без контекста или в другой период и подхваченных версией при подтверждении -(ОСВ за `Q1`, подходящая версиям `Q2`–`Q4`, R-14). Файл отдаётся той же карточкой `FileOut`, что и список ЮЛ. +(ОСВ за `Q1`, подходящая версиям `Q2`–`Q4`, R-14 Среза 4, §3 п. 4). Файл отдаётся той же карточкой `FileOut`, что и список ЮЛ. **Автозамена.** Новый файл после маппинга: если `consolidation_id IS NULL`, берётся `consolidation_id` первого заменённого файла (по порядку `id`), у которого он не `NULL`. При загрузке в контексте своё значение сохраняется. @@ -167,3 +167,7 @@ SUPERSEDED — только при include_superseded = true (и для DESK, и 14. 09.10.2026 — **R-14 / R-15:** формулировка про `SUPERSEDED` одна по смыслу в `dev/frontend-api-guide.md`, `dev/api-contract-files-directories.md` и `context/05-domain-rules.md` §9.5 п. 11: «`SUPERSEDED` — только при `include_superseded=true` (скрыт по умолчанию)». Цена ошибки: разночтение, правится текстом. +15. 09.10.2026 — **R-16:** push ветки и создание PR выполняет контроллер, а не исполнитель Task 5 (шаг 6 плана). Цена ошибки: + нулевая. +16. 09.10.2026 — **R-17:** трейлер коммита Task 5 исправлен amend'ом локального непушнутого коммита на + `Co-Authored-By: Claude Fable 5.1` по явному требованию задачи. Цена ошибки: переписана одна локальная запись. diff --git a/openspec/changes/console-files/tasks.md b/openspec/changes/console-files/tasks.md index af0fa87..8a0de86 100644 --- a/openspec/changes/console-files/tasks.md +++ b/openspec/changes/console-files/tasks.md @@ -3,7 +3,7 @@ Подробный план с шагами и тестами — superpowers writing-plans (ledger SDD); здесь — крупные задачи по репозиториям в порядке зависимостей. -- [ ] 1. **docs** (этот change): `model/data-model-v5.18.dbml` + changelog, `model/entities-v5.18.md`, `04-data-model-guide.md`, +- [x] 1. **docs** (этот change): `model/data-model-v5.18.dbml` + changelog, `model/entities-v5.18.md`, `04-data-model-guide.md`, `05-domain-rules.md` §9.5, `10-user-journey.md` п. 2.5, `dev/frontend-api-guide.md`, `dev/api-contract-files-directories.md`, `dev/api-contract-slice-4.md`, `dev/qa-guide.md`, `07-open-questions.md` (целевая модель версий), ссылки на версию DBML в `CLAUDE.md` workspace и `repo-templates/*.CLAUDE.md`.