From 1cf067cd8b32c1f334fc4c2c2ef89e1ffa642818 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Fri, 9 Oct 2026 23:10:32 +0400 Subject: [PATCH] =?UTF-8?q?plan:=20console-files=20=E2=80=94=20=D0=BF?= =?UTF-8?q?=D0=BB=D0=B0=D0=BD=20=D0=B4=D0=BB=D1=8F=20=D1=80=D0=B5=D0=BF?= =?UTF-8?q?=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8=D1=8F=20docs=20(#90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5.1 --- .../plans/2026-10-09-console-files-docs.md | 557 ++++++++++++++++++ 1 file changed, 557 insertions(+) create mode 100644 docs/superpowers/plans/2026-10-09-console-files-docs.md diff --git a/docs/superpowers/plans/2026-10-09-console-files-docs.md b/docs/superpowers/plans/2026-10-09-console-files-docs.md new file mode 100644 index 0000000..ba414e7 --- /dev/null +++ b/docs/superpowers/plans/2026-10-09-console-files-docs.md @@ -0,0 +1,557 @@ +# Файлы в контексте консолидации — план для репозитория docs + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Поднять модель данных до v5.18 (`stored_file.consolidation_id`) и привести документы контекста, правила домена, +гайды API/QA и открытые вопросы к решениям владельца 09.10.2026 о загрузке файлов в консолидацию. + +**Architecture:** Только документы: новая версия DBML и entities копированием предыдущей с правкой, замена ссылок +`v5.17 → v5.18`, правка §9.5 и §9.1 правил, гайдов и QA-сценариев под новые маршруты +`/consolidations/{cid}/legal-entities/{le}/files`. Кода нет; код — дочерние планы arm-core и arm-web. + +**Tech Stack:** Markdown, DBML, `make check` репозитория docs (`validate-contracts`, `validate-openspec`, +`test-snapshot`), `make diagrams` (Node/npx), git, `tea`. + +**Spec:** `openspec/changes/console-files/` (`proposal.md`, `design.md`) в этом репозитории. + +## Global Constraints + +- Работать только в worktree `/Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs`, ветка `feat/90-console-files`; + git-команды — `git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs …`. +- Язык документов и коммитов — русский; идентификаторы — как в DBML (английские). +- `docs/source/**` не редактировать. +- Нумерацию версий DBML задним числом не менять: новая версия — `v5.18`, файлы v5.17 остаются как история. +- Имя колонки — ровно `consolidation_id` (nullable, FK → `consolidation.id`); индекс — `(legal_entity_id, consolidation_id)`. +- Маршруты — ровно `POST /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` и + `GET /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files`; query `consolidation_version_id` у + `POST /legal-entities/{id}/files` удаляется. +- Коды ошибок загрузки в консоль: 404 `NOT_FOUND`, 409 `CONSOLIDATION_NOT_EDITABLE`, 422 `ENTITY_NOT_IN_PERIMETER`. +- Каждый коммит заканчивается строкой `Co-Authored-By: Claude Fable 5.1 `. + +## Review Focus + +1. Файл, загруженный без контекста и подтверждённый, подхвачен версией — он должен быть описан как часть рабочего стола + (`BOUND`), иначе читатель §9.5 решит, что стол — только `consolidation_id`. Проверяется grep'ом в Task 3. +2. Файл `SUPERSEDED` на рабочем столе — скрыт по умолчанию, виден при `include_superseded=true`; формулировка должна быть + одинаковой в §9.5, гайде фронта и контракте. Проверяется grep'ом в Task 4. +3. Переход `INITIATED → DOCUMENTS_PROCESSING` теперь у **всех** версий консоли «в работе» с ЮЛ в периметре — таблица §9.1 + и п. 8 §9.5 не должны говорить «версия» в единственном числе. Проверяется в Task 3. +4. Решение владельца 07.10.2026 «фильтра файлов ЮЛ в контексте версии нет и не будет» (гайд фронта) пересмотрено 09.10.2026: + строка не удаляется, а зачёркивается со ссылкой. Проверяется в Task 4. +5. QA-сценарии, где `consolidation_version_id=V` использовался только ради перехода статуса (U17, K8, 7.1), должны + стать загрузкой в консоль `$C` — иначе гайд описывает удалённый параметр. Проверяется grep'ом в Task 5. + +--- + +### Task 1: DBML v5.18 + +**Files:** +- Create: `model/data-model-v5.18.dbml` (копия `model/data-model-v5.17.dbml` с правками) +- Modify: `Makefile` (переменная `DBML`) +- Modify: `model/diagrams/part04_files_jobs.{svg,png}`, `part07_consolidation.{svg,png}` — перерисовка `make diagrams` + +**Interfaces:** +- Produces: файл `model/data-model-v5.18.dbml` — его читают Task 2 (entities) и дочерний план arm-core (`make dbml-check`). + +- [ ] **Step 1: Скопировать модель** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +cp model/data-model-v5.17.dbml model/data-model-v5.18.dbml +``` + +- [ ] **Step 2: Шапка и changelog** + +В `model/data-model-v5.18.dbml` первую строку заменить на: + +``` +// ДКБ · Модель данных v5.18: справочники, файлы/распознавание, консолидация, КФО, аудит, ЕХФД +``` + +После строки `// страница аналитики (md); экран макета dkb_24.09.26; версия модели, в которой таблица появилась (v4 = исходная DBML аналитики).` +и пустой `//` вставить перед блоком `// v5.17 (…)`: + +``` +// v5.18 (решения владельца 09.10.2026; RSHB/arm-ka-docs#90, openspec/changes/console-files): +// 1. stored_file.consolidation_id (uuid, nullable, FK → consolidation): консолидация (ГК + год + квартал), в контексте +// которой загружен файл, — «рабочий стол консоли», общий для всех версий периода. NULL — загрузка без контекста +// (страница ЮЛ, монозаёмщики, API). Пишется один раз при загрузке (POST /consolidations/{id}/legal-entities/{le}/files); +// при автозамене новый файл без контекста наследует consolidation_id заменённого. Индекс (legal_entity_id, consolidation_id). +// Что использует конкретная версия, по-прежнему определяет consolidation_document; заморозка после VERIFIED — привязки и ex_snapshot. +// Миграция 0006 arm-core: backfill по consolidation_document (при нескольких периодах — самый ранний). +// 2. Note recognition_job.reply_deadline: срок ответа OCR — 20 мин (OQ-159, решение владельца 09.10.2026), структура не меняется. +// +``` + +- [ ] **Step 3: Колонка и индекс `stored_file`** + +В блоке `Table stored_file {` после строки ` legal_entity_id uuid [not null, ref: > legal_entity.id, note: 'организация-владелец (выбрана при загрузке)']` +добавить: + +``` + consolidation_id uuid [ref: > consolidation.id, note: 'v5.18: консолидация (период ГК), в контексте которой загружен файл — «рабочий стол консоли», общий для всех версий периода; NULL — без контекста. Пишется при загрузке; при автозамене файл без контекста наследует значение заменённого'] +``` + +В `Indexes {` того же блока после `(legal_entity_id, status)` добавить строку: + +``` + (legal_entity_id, consolidation_id) [note: 'v5.18: рабочий стол консоли для ЮЛ'] +``` + +Note таблицы `stored_file` (строка `Note: 'v5.13: физический файл одной загрузки …'`) дополнить в конце перед закрывающей +кавычкой: `. v5.18: consolidation_id — где загружен; что использует версия — consolidation_document`. + +- [ ] **Step 4: Note `consolidation` и `reply_deadline`** + +В блоке `Table consolidation {` строку `Note: 'Логическая консолидация ГК за период; версии различаются периметром (consolidation_member). Прошлые периоды — по company_group_id'` +заменить на: + +``` + Note: 'Логическая консолидация ГК за период; версии различаются периметром (consolidation_member). Прошлые периоды — по company_group_id. v5.18: файлы, загруженные в консолидацию, — stored_file.consolidation_id (рабочий стол, общий для версий периода)' +``` + +Найти в `Table recognition_job` колонку `reply_deadline` и в её note заменить `OCR — 5 мин` на `OCR — 20 мин` (OQ-159). +Проверить: `grep -n "reply_deadline" model/data-model-v5.18.dbml` — в note нет «5 мин». + +- [ ] **Step 5: Makefile и диаграммы** + +В `Makefile` строку `DBML ?= model/data-model-v5.17.dbml` заменить на `DBML ?= model/data-model-v5.18.dbml`. +Затем: + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs && make diagrams 2>&1 | tail -5 +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs status --short model/diagrams | head +``` + +Ожидание: изменились `part04_files_jobs.*` (новая колонка и FK) и `part07_consolidation.*`; остальные могут +перерисоваться без смысловых изменений — это допустимо. Если `make diagrams` падает из-за окружения (нет сети для `npx`), +не чинить: записать в итоговый отчёт «диаграммы не перерисованы», шаг не блокирует. + +- [ ] **Step 6: Проверка** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +diff <(sed -n '/^Table stored_file {/,/^}/p' model/data-model-v5.17.dbml) <(sed -n '/^Table stored_file {/,/^}/p' model/data-model-v5.18.dbml) +grep -c "v5.18" model/data-model-v5.18.dbml +``` + +Ожидание: diff показывает ровно добавленную колонку, индекс и хвост Note; счётчик ≥ 5. + +- [ ] **Step 7: Коммит** + +```bash +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs add Makefile model/data-model-v5.18.dbml model/diagrams +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs commit -q -m "$(cat <<'EOF' +model: DBML v5.18 — stored_file.consolidation_id, рабочий стол консоли (#90) + +Co-Authored-By: Claude Fable 5.1 +EOF +)" +``` + +--- + +### Task 2: entities v5.18 и ссылки на версию модели + +**Files:** +- Create: `model/entities-v5.18.md` (копия `model/entities-v5.17.md` с правками) +- Modify: `context/04-data-model-guide.md`, `context/08-source-docs-index.md`, `context/00-workspace-layout.md`, + `context/03-architecture.md`, `context/06-test-data.md`, `context/KICKOFF-PROMPT.md`, `dev/checks.md`, + `repo-templates/arm-core.CLAUDE.md`, `/Users/andrey.epifancev/projects/awp-ca/CLAUDE.md` (вне git — workspace) + +**Interfaces:** +- Consumes: `model/data-model-v5.18.dbml` (Task 1). + +- [ ] **Step 1: Скопировать и переписать шапку entities** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +cp model/entities-v5.17.md model/entities-v5.18.md +``` + +В `model/entities-v5.18.md`: +- заголовок → `# АРМ КА — описание сущностей модели данных v5.18`; +- строку 3 (`Источник истины по структуре — \`data-model-v5.17.dbml\` …`) заменить на: + +``` +Источник истины по структуре — `data-model-v5.18.dbml` (полный). Диаграммы по частям — `diagrams/` (part01…09 svg/png; перерисовываются `make diagrams` из текущего DBML). Здесь — что каждая таблица значит для бизнеса, как связана с соседями и откуда взялась. +``` + +- перед разделом `## Что изменилось в v5.17 …` вставить: + +``` +## Что изменилось в v5.18 (решения владельца 09.10.2026, RSHB/arm-ka-docs#90) + +| № | Изменение | Решение | +|---|---|---| +| 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`) | +| 2 | Note `recognition_job.reply_deadline` | Без изменения структуры: срок ответа OCR — 20 мин (OQ-159) | + +Остальные таблицы и enum — как в v5.17. Реализация — миграция `0006` в `arm-core` (backfill `consolidation_id` по `consolidation_document`). + +``` + +- [ ] **Step 2: Строки таблиц `stored_file` и `consolidation`** + +В таблице части 04 строку `| \`stored_file\` | **v5.13: только физический файл** …` заменить на: + +``` +| `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 | +``` + +Строку `| \`consolidation\` | Логическая консолидация: **ГК** + отчётный период. …` заменить на: + +``` +| `consolidation` | Логическая консолидация: **ГК** + отчётный период. ГСК фиксируется/создаётся при верификации по фактическому периметру. Уникальна по (ГК, год, квартал). **v5.18:** файлы, загруженные в консолидацию, — `stored_file.consolidation_id` (рабочий стол, общий для версий периода). | → `company_group`, `related_group`; ← `consolidation_version`, `stored_file` | ТЗ 6.10, 7.2 | +``` + +- [ ] **Step 3: Ссылки v5.17 → v5.18 в документах** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +for f in context/00-workspace-layout.md context/03-architecture.md context/08-source-docs-index.md context/KICKOFF-PROMPT.md dev/checks.md repo-templates/arm-core.CLAUDE.md; do + sed -i '' -e 's/data-model-v5\.17\.dbml/data-model-v5.18.dbml/g' -e 's/entities-v5\.17\.md/entities-v5.18.md/g' -e 's/DBML v5\.17/DBML v5.18/g' "$f" +done +sed -i '' -e 's/data-model-v5\.17\.dbml/data-model-v5.18.dbml/g' -e 's/entities-v5\.17\.md/entities-v5.18.md/g' -e 's/приведённая к именам v5\.17/приведённая к именам v5.18/' -e 's/(v5\.14–v5\.17 имена не меняли)/(v5.14–v5.18 имена не меняли)/' /Users/andrey.epifancev/projects/awp-ca/CLAUDE.md +grep -n "v5\.17" context/00-workspace-layout.md context/03-architecture.md context/08-source-docs-index.md context/KICKOFF-PROMPT.md dev/checks.md repo-templates/arm-core.CLAUDE.md /Users/andrey.epifancev/projects/awp-ca/CLAUDE.md +``` + +Ожидание: grep пуст, кроме исторических упоминаний (в `08-source-docs-index.md` строка про changelog `v5.1…v5.17` → вручную +заменить на `v5.1…v5.18`; в `06-test-data.md` строка «с v5.17 диаграммы перерисовываются» — история, оставить). +`08-source-docs-index.md` строка `| \`diagrams/part01…09.{svg,png}\` | диаграммы v5.17 по частям …` → `v5.18`. + +- [ ] **Step 4: `04-data-model-guide.md`** + +- Заголовок → `# 04. Как читать модель данных v5.18`. +- Строки 3–5: `data-model-v5.17.dbml` → `data-model-v5.18.dbml`, `entities-v5.17.md` → `entities-v5.18.md`, + `v5.13…v5.16` → `v5.13…v5.17` (оба упоминания), «диаграммы v5.17» → «диаграммы v5.18». +- Строку 61 (`… v5.17 — тоже (колонка \`legal_entity.kpp\`), поэтому таблица справедлива и для v5.14…v5.17.`) дополнить: + `, v5.18 — тоже (колонка \`stored_file.consolidation_id\`), поэтому таблица справедлива и для v5.14…v5.18.` (заменив + хвост `и для v5.14…v5.17.`). +- Заголовок таблицы строки 63: `| В v5.13 / v5.14 / v5.15 / v5.16 / v5.17 |` → `| В v5.13 / v5.14 / v5.15 / v5.16 / v5.17 / v5.18 |`. +- В разделе про файлы (где описан `stored_file` ↔ `document`, найти `grep -n "stored_file" context/04-data-model-guide.md`) + добавить предложение: «**v5.18:** `stored_file.consolidation_id` — в какую консолидацию (период ГК) загружен файл; это + рабочий стол консоли, общий для её версий. Что использует версия — `consolidation_document`.» + +Проверка: `grep -n "v5\.17" context/04-data-model-guide.md` — только исторические упоминания (список версий, «введён в v5.17»). + +- [ ] **Step 5: Коммит** + +```bash +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs add model/entities-v5.18.md context dev/checks.md repo-templates +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs commit -q -m "$(cat <<'EOF' +docs: entities v5.18 и ссылки на модель v5.18 (#90) + +Co-Authored-By: Claude Fable 5.1 +EOF +)" +``` + +--- + +### Task 3: Правила домена §9.1 и §9.5 + +**Files:** +- Modify: `context/05-domain-rules.md` (§9.1 таблица переходов, §9.5 п. 1, 3, 8; новый п. 11) + +**Interfaces:** +- Produces: формулировки, на которые ссылаются спеки arm-core (`primary-files`, `documents-api`) в дочернем плане. + +- [ ] **Step 1: §9.1 — переход при загрузке** + +Строку `| загрузка файла с \`consolidation_version_id\`, принят ≥ 1 файл | INITIATED → DOCUMENTS_PROCESSING | загрузивший |` +заменить на: + +``` +| загрузка файла в консолидацию (`POST /consolidations/{id}/legal-entities/{le}/files`), принят ≥ 1 файл | INITIATED → DOCUMENTS_PROCESSING у **каждой** версии консолидации «в работе», где ЮЛ в периметре | загрузивший | +``` + +- [ ] **Step 2: §9.5 п. 1 — два маршрута загрузки** + +В п. 1 заменить начало `1. **Загрузка** (\`POST /legal-entities/{id}/files\`, право \`DOCUMENT_EDIT\`, ЮЛ в видимости):` на: + +``` +1. **Загрузка** (`POST /legal-entities/{id}/files` — без контекста, `stored_file.consolidation_id = NULL`; в консолидацию — + п. 8; право `DOCUMENT_EDIT`, ЮЛ в видимости): +``` + +- [ ] **Step 3: §9.5 п. 3 — наследование при автозамене** + +В п. 3 после предложения `… \`version_no\` нового = максимум заменённых + 1.` добавить: + +``` +Новый файл без контекста (`consolidation_id IS NULL`) наследует `consolidation_id` первого (по `id`) заменённого файла, у +которого он задан; файл, загруженный в консолидацию, сохраняет свою (v5.18). +``` + +- [ ] **Step 4: §9.5 п. 8 — загрузка в консолидацию** + +Пункт 8 целиком заменить на: + +``` +8. **Загрузка в консолидацию** (`POST /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files`, + `DOCUMENT_EDIT`; v5.18, решения владельца 09.10.2026, RSHB/arm-ka-docs#90): до приёма — консолидация видима (404 + `NOT_FOUND`), ЮЛ видимо (404), есть версия консолидации «в работе» (409 `CONSOLIDATION_NOT_EDITABLE`), ЮЛ — член + периметра хотя бы одной такой версии (422 `ENTITY_NOT_IN_PERIMETER`). Принятый файл получает + `stored_file.consolidation_id`; `FILE_UPLOAD.after_value.consolidation_id`. После приёма хотя бы одного файла, отдельной + транзакцией, каждая версия консолидации «в работе» с этим ЮЛ в периметре и статусом INITIATED переходит в + DOCUMENTS_PROCESSING (§9.1; версии блокируются `FOR UPDATE` по возрастанию `id`, статус перечитывается); сбой перехода не + отменяет принятые файлы. Блокировка версии для загрузки не нужна. Query `consolidation_version_id` у + `POST /legal-entities/{id}/files` (Срез 4) удалён. +``` + +- [ ] **Step 5: §9.5 новый п. 11 — рабочий стол консоли** + +После п. 10 добавить: + +``` +11. **Рабочий стол консоли** (`GET /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files`, + `DOCUMENT_VIEW`; 404 на невидимые консолидацию или ЮЛ; `limit`, `offset`, `include_superseded`): файлы ЮЛ с + `consolidation_id` этой консолидации **плюс** файлы ЮЛ, у которых есть документ, привязанный (`consolidation_document`) + к любой версии этой консолидации (подхваченные ОСВ за `Q1` и файлы, загруженные без контекста); новые первыми + (`uploaded_at` desc, `id`); `SUPERSEDED` — только при `include_superseded=true`. Карточка файла та же, что в + `GET /legal-entities/{id}/files` (`FileOut` + `consolidation_id`). Рабочие версии одного периода видят один стол; + верифицированная версия заморожена привязками и `ex_snapshot` (Срез 7), отдельного «замороженного списка» в панели + нет. Панель [39] из карточки версии показывает стол консоли; переключатель «Все документы организации» — + `GET /legal-entities/{id}/files` с подписью консолидации у файла. +``` + +- [ ] **Step 6: Проверка** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +grep -n "consolidation_version_id" context/05-domain-rules.md +grep -n "каждой\* версии\|каждая версия консолидации" context/05-domain-rules.md +grep -n "привязанный (\`consolidation_document\`)\|привязанный (.consolidation_document.)" context/05-domain-rules.md +``` + +Ожидание: первый grep — только исторические упоминания (строка про Срез 4 в п. 8 «удалён» и §3/OQ, если есть) — ни одного +описания действующего параметра; второй и третий — по одной строке. + +- [ ] **Step 7: Коммит** + +```bash +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs add context/05-domain-rules.md +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs commit -q -m "$(cat <<'EOF' +rules: §9.1/§9.5 — загрузка в консолидацию и рабочий стол консоли (#90) + +Co-Authored-By: Claude Fable 5.1 +EOF +)" +``` + +--- + +### Task 4: Гайд фронта, контракты API, пользовательский путь + +**Files:** +- Modify: `dev/frontend-api-guide.md` (changelog, §5.5, таблица экранов), `dev/api-contract-files-directories.md`, + `dev/api-contract-slice-4.md`, `context/10-user-journey.md` (п. 2.5), `mockup/INDEX.md` (строка `39`) + +**Interfaces:** +- Consumes: формулировки §9.5 п. 8 и 11 (Task 3). + +- [ ] **Step 1: Changelog гайда фронта** + +В `dev/frontend-api-guide.md` сразу после строки `|---|---|---|` таблицы «Когда, PR | Что изменилось в API | Что сделать в клиенте» +(строка 31) вставить: + +``` +| 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] — новым маршрутом, кнопка недоступна, если версия не «в работе» | +``` + +Строку `| 07.10, решение владельца | Фильтра «файлы ЮЛ в контексте версии» нет и не будет | drawer [39] показывает все файлы ЮЛ; подходящесть — по \`document_ids\` ячеек чек-листа |` +заменить на: + +``` +| 07.10, решение владельца | ~~Фильтра «файлы ЮЛ в контексте версии» нет и не будет~~ (пересмотрено 09.10, см. docs #90 выше) | ~~drawer [39] показывает все файлы ЮЛ~~; подходящесть документа версии — по-прежнему по `document_ids` ячеек чек-листа | +``` + +- [ ] **Step 2: §5.5 гайда фронта** + +В таблице §5.5 строку `| \`POST /legal-entities/{legal_entity_id}/files\` | EDIT | multipart, поле **\`files\`** повторяется на каждый файл (не \`files[]\`); query \`consolidation_version_id?\` | … |` +заменить на две строки: + +``` +| `POST /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` | EDIT | multipart, поле **`files`** повторяется на каждый файл (не `files[]`) — загрузка **в консолидацию** (панель [40] внутри версии) | 201 `UploadResult {accepted[] {file_id, job_id, name}, rejected[] {name, code, message, file_id?}}`, если принят ≥ 1 файл; **422 тем же телом**, если ни одного | 404 (консолидация или ЮЛ), 409 `CONSOLIDATION_NOT_EDITABLE` (нет версии «в работе»), 422 `ENTITY_NOT_IN_PERIMETER` (объектом `detail`), 503 `STORAGE_UNAVAILABLE` | +| `POST /legal-entities/{legal_entity_id}/files` | EDIT | то же, **без контекста** (страница ЮЛ, монозаёмщики): `consolidation_id = null` | как выше | 404, 503 `STORAGE_UNAVAILABLE` | +``` + +После строки `| \`GET /legal-entities/{legal_entity_id}/files\` | VIEW | … |` добавить: + +``` +| `GET /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` | VIEW | `limit`, `offset`, `include_superseded` | `Page[FileOut]` — **рабочий стол консоли** для ЮЛ: файлы с этим `consolidation_id` плюс файлы, чьи документы привязаны к любой версии консолидации; новые первыми | 404 | +``` + +В списке «Загрузка:» пункт `- С \`consolidation_version_id\` версия должна быть видима, «в работе» и содержать ЮЛ; первый принятый файл переводит версию \`INITIATED\` → \`DOCUMENTS_PROCESSING\`. Блокировка версии для загрузки **не нужна**.` +заменить на: + +``` +- Загрузка в консолидацию: консолидация видима, есть версия «в работе», ЮЛ в её периметре; первый принятый файл переводит + **каждую** версию консолидации «в работе» с этим ЮЛ из `INITIATED` в `DOCUMENTS_PROCESSING`. Блокировка версии для загрузки + **не нужна**. `FileOut.consolidation_id` — куда загружен файл (`null` — без контекста). +``` + +В таблице экранов строки `[39]` и `[40]` заменить на: + +``` +| [39] Первичные документы ЮЛ | `GET /consolidations/{cid}/legal-entities/{id}/files` (+ опрос при `UPLOADED`/`PROCESSING`); переключатель «Все документы организации» — `GET /legal-entities/{id}/files`, подпись консолидации у файла по `consolidation_id` (год и квартал — из списка консолидаций ГК, `null` — «вне консолидации»); «Загрузил» — `GET /users/brief?ids=…`; удалить — `DELETE /files/{id}` | +| [40] Загрузить документы | `POST /consolidations/{cid}/legal-entities/{id}/files` → показать `accepted`/`rejected` → опрос списка; кнопка недоступна, если версия не «в работе» | +``` + +- [ ] **Step 3: Контракты** + +`dev/api-contract-files-directories.md`, таблица §2: строку `GET /legal-entities/{legal_entity_id}/files` оставить, после неё +добавить: + +``` +| `GET /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` | VIEW | query `limit`, `offset`, `include_superseded` | `Page[FileOut]` — рабочий стол консоли для ЮЛ (файлы с этим `consolidation_id` + файлы с документами, привязанными к версиям консолидации), новые первыми | 404 | [39] drawer внутри версии (v5.18, docs #90) | +``` + +Строку `POST /legal-entities/{legal_entity_id}/files` заменить на две: + +``` +| `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` | страница ЮЛ, монозаёмщики | +``` + +В описании `FileOut` этого файла (найти `grep -n "FileOut" dev/api-contract-files-directories.md`) добавить поле +`consolidation_id: uuid | null` с пояснением «консолидация, в которую загружен файл (v5.18)». + +`dev/api-contract-slice-4.md`: строку `| \`POST /legal-entities/{legal_entity_id}/files?consolidation_version_id=\` | …` заменить на: + +``` +| `POST /consolidations/{consolidation_id}/legal-entities/{legal_entity_id}/files` | `DOCUMENT_EDIT` | multipart `files` (v5.18, docs #90; прежний query `consolidation_version_id` у `POST /legal-entities/{id}/files` удалён) | как в Срезе 2c: 201/422 `{accepted[], rejected[]}` | 404 (консолидация или ЮЛ), 409 `CONSOLIDATION_NOT_EDITABLE`, 422 `ENTITY_NOT_IN_PERIMETER` | [39] / [40] | +``` + +и строку `| [39]/[40] Документы организации | \`GET /legal-entities/{id}/files\` (все файлы ЮЛ, …` на: + +``` +| [39]/[40] Документы организации | `GET /consolidations/{cid}/legal-entities/{id}/files` (рабочий стол консоли; «Все документы организации» — `GET /legal-entities/{id}/files`; опрос во время распознавания — им же или `GET /files/{id}`; схема — `dev/api-contract-files-directories.md`), `POST /consolidations/{cid}/legal-entities/{id}/files` | +``` + +- [ ] **Step 4: Пользовательский путь и макет** + +`context/10-user-journey.md` строка п. 2.5: фрагмент `**API:** загрузка — \`POST /legal-entities/{id}/files?consolidation_version_id=\`; документы и подтверждение — \`/files\`, \`/documents\` (Срез 2c); подтверждённый документ привязывается к версиям «в работе» автоматически` +заменить на: + +``` +**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) +``` + +`mockup/INDEX.md`, строка `| \`39\` | **Панель «Первичные документы»** …`: в колонке «В модели» (`\`stored_file\`, \`document.period_check/…\`, \`comment\``) +добавить `stored_file.consolidation_id` первым элементом: `` `stored_file` (+ `consolidation_id`, v5.18: панель внутри версии показывает рабочий стол консоли) ``. + +- [ ] **Step 5: Проверка** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +grep -n "consolidation_version_id" dev/frontend-api-guide.md dev/api-contract-files-directories.md dev/api-contract-slice-4.md context/10-user-journey.md +grep -n "include_superseded" dev/frontend-api-guide.md dev/api-contract-files-directories.md context/05-domain-rules.md | grep -c "consolidations/{" +``` + +Ожидание: первый grep — только упоминания «удалён» и исторические (changelog, `consolidation_lock`, `osv`-маршруты); +второй — ≥ 3 (стол описан с `include_superseded` во всех трёх документах). + +- [ ] **Step 6: Коммит** + +```bash +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs add dev/frontend-api-guide.md dev/api-contract-files-directories.md dev/api-contract-slice-4.md context/10-user-journey.md mockup/INDEX.md +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs commit -q -m "$(cat <<'EOF' +dev: маршруты файлов консолидации в гайде фронта, контрактах и пути пользователя (#90) + +Co-Authored-By: Claude Fable 5.1 +EOF +)" +``` + +--- + +### Task 5: QA-гайд, открытые вопросы, план срезов, проверка и PR + +**Files:** +- Modify: `dev/qa-guide.md` (U17, 6.6, K8, 7.1, W17, 8.7), `context/07-open-questions.md` (OQ-159, новый OQ-160), + `context/09-delivery-plan.md` (Срез 2d), `openspec/changes/console-files/design.md` (решение R-9) + +- [ ] **Step 1: QA-гайд — curl и сценарии** + +В `dev/qa-guide.md` все вызовы вида `localhost:8000/api/v1/legal-entities/$LE…/files?consolidation_version_id=$V` заменить на +`localhost:8000/api/v1/consolidations/$C/legal-entities/$LE…/files` (три места: блок в 6.6/7, два цикла в 7.1; `$LE_RB`, +`$LE_SCH` сохраняются). Перед первым таким вызовом (блок команд раздела 7, строка с `curl -s -X POST localhost:8000/api/v1/consolidations …`) +дополнить комментарий ответа: `# 201: VersionCard; V = ответ.id, C = ответ.consolidation_id, status = INITIATED, reporting_date = 2024-10-01`. + +Строку U17: `загрузить ОСВ ЮЛ с \`consolidation_version_id=V\`, где \`V\` в статусе «Корректировка данных»` → +`загрузить ОСВ ЮЛ в консолидацию \`C\` (\`POST /consolidations/$C/legal-entities/$LE/files\`), у которой версия \`V\` в статусе «Корректировка данных»`. + +Строку K8: `загрузить ОСВ ЮЛ периметра с \`?consolidation_version_id=V\` (раздел 6.6)` → +`загрузить ОСВ ЮЛ периметра в консолидацию \`C\` (раздел 6.6)`; в ожидании `несуществующая версия — 404` → +`несуществующая консолидация — 404; консолидация без версии «в работе» (после \`CANCELLED\`) — 409 \`CONSOLIDATION_NOT_EDITABLE\`; \`GET /consolidations/$C/legal-entities/$LE/files\` — загруженный файл в списке, \`consolidation_id = C\``. + +Строку W17: `без \`consolidation_version_id\`` → `без консолидации — маршрутом ЮЛ`; в ожидании добавить в конец: +`; в панели [39] версии этот файл виден только по переключателю «Все документы организации» с подписью «вне консолидации»`. + +В 8.7 строку `- Панель документов показывает первые 100 файлов ЮЛ; загрузка — только из панели ЮЛ внутри версии.` → +`- Панель документов показывает первые 100 файлов рабочего стола консоли (или ЮЛ — по переключателю); загрузка — только из панели ЮЛ внутри версии «в работе».` + +Строку K17-примечания `… во всех — \`consolidation_version_id\`.` не трогать (речь об аудите версий). + +- [ ] **Step 2: Открытые вопросы** + +В `context/07-open-questions.md` в строке OQ-159 колонку статуса `открыт: код и §9.4 — 20 мин; note DBML правится с ближайшей версией модели` → +`**закрыт 09.10.2026:** note исправлен в DBML v5.18 (docs #90)`. + +После строки OQ-159 добавить: + +``` +| OQ-160 | Целевая модель версий консолидации (владелец, 09.10.2026): несколько рабочих версий одного периода с **разным периметром** делят первичку (рабочий стол консоли, `stored_file.consolidation_id`); после `VERIFIED` новая версия (`previous_version_id`) может менять документы при **том же** периметре. Ядро сейчас создаёт только версию 1 (`POST /consolidations`), «новая версия» и параллельные версии не реализованы. Нужны правила: создание второй рабочей версии (обязательно другой периметр?), создание версии после `VERIFIED` (копия периметра, подхват привязок), что видит панель [39] у верифицированной версии до Среза 7 (ЕХ) | brainstorming docs #90, `openspec/changes/console-files/design.md` R-6, R-7 | срез «версии консолидации» (после Среза 4), Срез 7 | открыт: модель файлов совместима; реализация — отдельный срез | +``` + +- [ ] **Step 3: План срезов** + +В `context/09-delivery-plan.md` в разделе `### Срез 2d — UI «Первичные документы»` после строки +`- Панель «Первичные документы», окно загрузки, таблица ОСВ с деревом строк и подсветкой нераспознанных контрагентов.` добавить: + +``` +- **Доработка 09.10.2026 (docs #90, DBML v5.18):** файлы в контексте консолидации — `stored_file.consolidation_id`, маршруты + `POST/GET /consolidations/{cid}/legal-entities/{le}/files`, панель [39] показывает рабочий стол консоли; спецификация — + `openspec/changes/console-files/`; дочерние PR arm-core и arm-web. Целевая модель версий — OQ-160. +``` + +- [ ] **Step 4: design.md — решение R-9** + +В `openspec/changes/console-files/design.md` в конец раздела «Decisions made without discussion» добавить: + +``` +9. 09.10.2026 — **R-9:** решение владельца 07.10.2026 «фильтра файлов ЮЛ в контексте версии нет и не будет» + (`dev/frontend-api-guide.md`) считается пересмотренным решениями 09.10.2026; строка в гайде зачёркнута со ссылкой на + docs #90, не удалена. Цена ошибки: низкая — документальная. +10. 09.10.2026 — **R-10:** note `recognition_job.reply_deadline` (OQ-159, «20 мин») исправлен в v5.18 попутно: владелец + просил править при ближайшей версии модели. Цена ошибки: нулевая. +``` + +- [ ] **Step 5: Проверка репозитория** + +```bash +cd /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs +grep -rn "consolidation_version_id" dev/qa-guide.md | grep -v "аудит\|во всех —\|versions/" +make check CHANGE=console-files 2>&1 | tail -15 +``` + +Ожидание: grep пуст или только строки про аудит; `make check` зелёный (валидация контрактов, `openspec validate console-files --strict`, снимок). + +- [ ] **Step 6: Коммит и PR** + +```bash +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs add dev/qa-guide.md context/07-open-questions.md context/09-delivery-plan.md openspec/changes/console-files/design.md docs/superpowers/plans/2026-10-09-console-files-docs.md +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs commit -q -m "$(cat <<'EOF' +docs: QA-гайд, OQ-160 (целевая модель версий), план срезов — файлы консолидации (#90) + +Co-Authored-By: Claude Fable 5.1 +EOF +)" +git -C /Users/andrey.epifancev/projects/awp-ca/.wt/console-files/docs push -u origin feat/90-console-files +``` + +PR — через superpowers:finishing-a-development-branch (`tea pulls create --login home --repo RSHB/arm-ka-docs …`): заголовок +«DBML v5.18: файлы в контексте консолидации — stored_file.consolidation_id, маршруты консоли (#90)», в описании — ссылка на +issue #90, список решений R-1…R-10 из design.md, вывод `make check`, пометка «дочерние PR arm-core и arm-web — следом».