From 7d23097004c0a5777c49b73b2da89745431bc285 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 21 Oct 2026 09:45:51 +0400 Subject: [PATCH 1/4] =?UTF-8?q?docs(CLAUDE.md):=20=D1=84=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=20=D0=B2=D0=B5=D0=B4=D1=91=D1=82=D1=81=D1=8F=20=D0=B2=20?= =?UTF-8?q?arm-core/web,=20arm-web=20=D0=B7=D0=B0=D0=BC=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=20(#148)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index e9c53a8..68934db 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -178,6 +178,12 @@ - ORM 1:1 с `../docs/model/data-model-v5.19.dbml` (текущая версия; миграции `0001_dbml_v5_13` + `0002_dbml_v5_14` + `0003_dbml_v5_15` + `0004_dbml_v5_16` + `0005_dbml_v5_17` + `0006_dbml_v5_18` + `0007_dbml_v5_19`); `api/scripts/check_dbml_vs_orm.py` (`make dbml-check`, входит в `check-full`) — обязательная проверка. - Алгоритмы — только из `../docs/context/05-domain-rules.md`; номер § — в docstring. - Вычисляемые объекты консолидации — `api/src/domain/`, без ORM-таблиц. +- Фронт (`web/`) разрабатывается здесь (с 21.10.2026): фронтовые задачи — worktree arm-core и PR в `main`, как и + бэкенд. Отдельный репозиторий `RSHB/arm-web` заморожен на `test` `de4e477` (= arm-core `3157a15`), синхронизация + `make -C ../docs sync-web` больше не используется; правило «`web/` напрямую не править» отменено. Проверки фронта — + `make web-check` (biome + tsc + build, входит в `check-full`) и из `web/`: `npm test` (vitest), `npm run lint` + (ESLint + Prettier), форматирование — `npm run format`. Спеки экранов (`*-ui`) пока лежат в `../arm-web/openspec/specs/`; + новые и изменённые требования к экранам — в `openspec/` этого репозитория. - Фронт: пользователь слаб во фронте — для TS/React изменений делай ревью сам и объясняй решения в PR. - `api/arm_statements/` — копия пакета `arm-statements`, напрямую не править: обновление — `../docs/scripts/sync-statements.sh` (`--in-place` в PR фичи), свежесть — `make statements-check` (в `check-full`). - OpenSpec: `openspec/` здесь; сквозные изменения — change в `../docs`. -- 2.47.2 From 7e05cdedf6dc71a2432b55f1fc4b98e6156d264f Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 21 Oct 2026 09:52:56 +0400 Subject: [PATCH 2/4] =?UTF-8?q?docs(web):=20README,=20CLAUDE.md=20=D0=B8?= =?UTF-8?q?=20ARCHITECTURE.md=20=D1=84=D1=80=D0=BE=D0=BD=D1=82=D0=B0=20?= =?UTF-8?q?=E2=80=94=20=D0=B8=D0=B7=20arm-web=20=D0=B2=20arm-core/web=20(#?= =?UTF-8?q?148)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- README.md | 6 ++--- web/ARCHITECTURE.md | 27 +++++++++++++++++++ web/CLAUDE.md | 66 +++++++++++++++++++++++++++++++++++++++++++++ web/README.md | 33 +++++++++++------------ 4 files changed, 112 insertions(+), 20 deletions(-) create mode 100644 web/ARCHITECTURE.md create mode 100644 web/CLAUDE.md diff --git a/README.md b/README.md index 47f00ed..e4e9f66 100644 --- a/README.md +++ b/README.md @@ -360,7 +360,7 @@ curl -s -X POST localhost:8000/api/v1/directories/import -H "Authorization: Bear ## Администрирование и экран /admin Бэкенд — `/api/v1/admin/*`, все маршруты требуют `USERS_ADMIN` (без права — 403 до любых проверок тела и существования -объектов). Фронтенд — страница `/admin` («Пользователи и роли» в боковом меню; видна только с `USERS_ADMIN`): таблица +объектов). Фронтенд — страница `/admin` («Пользователи и роли» в боковом меню; пункт пока виден всем ролям): таблица пользователей (создание, смена ролей и активности) и вкладка «Матрица прав» (роль × право). Без права экран показывает «Нет доступа» и запросов к `/admin/*` не делает (настоящую защиту обеспечивает сервер). @@ -374,7 +374,7 @@ curl -s -X POST localhost:8000/api/v1/directories/import -H "Authorization: Bear make migrate && make seed-dev # схема, справочники и dev-пользователи make up # если инфраструктура ещё не поднята cd api && .venv/bin/python run_server.py # бэкенд, :8000 (в api/.env — DEBUG=true и AUTH_DEV_ISSUER=true) -cd web && npm install && npm run start # фронтенд (rsbuild dev), откроется браузер +cd web && npm install && REACT_APP_ROOT_PATH=/ npm run start # фронтенд (rsbuild dev, :3000), откроется браузер ``` Вход — dev-форма «Вход для разработки» (`web/src/auth/DevLogin.tsx`): введите `admin@armka.local`; форма вызывает @@ -1155,7 +1155,7 @@ api/ Срез 4 — consolidation_periods (выбор источников, §2), consolidated_osv (свод), checklist (чек-лист), policy (`ensure_version_editable`, §10) tests/ pytest (юнит и integration/fixtures по маркерам) -web/ фронтенд (React 18 + TypeScript, rsbuild, antd): api/ (клиент), auth/ (вход, профиль), layouts/Admin (/admin); сборка web/dist -> api/web/ +web/ фронтенд (React 18 + TypeScript, rsbuild, antd; ведётся здесь с 21.10.2026, см. web/README.md, web/CLAUDE.md): api/ (клиент), auth/, services/api/, store/, layouts/ (страницы), widgets/ (экраны); сборка web/dist -> api/web/ setup/ бутстрап шаблона через Nexus банка (pip.conf, setup.sh) openspec/ спецификации и изменения (OpenSpec) docs/superpowers/ планы реализации diff --git a/web/ARCHITECTURE.md b/web/ARCHITECTURE.md new file mode 100644 index 0000000..e73ada3 --- /dev/null +++ b/web/ARCHITECTURE.md @@ -0,0 +1,27 @@ +# Архитектура фронта arm-core/web + +SPA поверх API arm-core (`/api/v1`). Своих данных и бизнес-вычислений нет: всё производное (чек-лист, сводная ОСВ, +статусы) считает сервер, фронт показывает и отправляет действия пользователя. До 21.10.2026 фронт вёлся в отдельном +репозитории `RSHB/arm-web` и переносился сюда синхронизацией; теперь — только здесь. + +## Модули + +| Модуль | Ответственность | Зависит от | +|---|---|---| +| `src/api/` | HTTP-клиент, токен, разбор ошибок | `conf/`, `auth/token` | +| `src/auth/` | профиль `/me`, dev-вход, права для меню | `api/` | +| `src/services/api/` | вызовы ресурсов arm-core | `api/`, `types/` | +| `src/store/` | состояние экранов (Redux Toolkit) | `services/api/` | +| `src/utils/` | чистые функции: деньги, подписи, скачивание | `types/` | +| `src/types/` | DTO API (повторяют `../api/src/schemas/`) | — | +| `src/components/` | примитивы UI (таблица, теги, заголовок) | antd | +| `src/widgets/` | блоки экранов (`DocumentReview` — проверка документа со сканом, `ConsolidatedOsv` — сводная ОСВ, `FilesDrawer`) | `components/`, `store/`, `services/api/`, `utils/` | +| `src/layouts/` | страницы-маршруты | `widgets/` | + +## Границы +- Сетевые запросы — только через `src/api/client.ts`; `fetch` напрямую не вызывается. +- `components/` не знают про store и API; `types/` ни от чего не зависят. +- `utils/` не импортирует React, store и API. + +## Сборка +`npm run build` → `web/dist`, Dockerfile ядра кладёт его в `api/web/` и FastAPI отдаёт SPA (`../README.md`). diff --git a/web/CLAUDE.md b/web/CLAUDE.md new file mode 100644 index 0000000..d55dcb9 --- /dev/null +++ b/web/CLAUDE.md @@ -0,0 +1,66 @@ +# CLAUDE.md — arm-core/web (фронт АРМ КА) + +Общий контекст — `../../CLAUDE.md` (workspace) и `../CLAUDE.md` (arm-core). Этот файл — только про фронт. +Язык общения, коммитов, комментариев и документации — русский; идентификаторы — английские, как в DBML и API. + +## Что это +SPA кредитного аналитика АРМ КА: справочники групп, консолидации ГК по периодам, карточка версии с чек-листом +документов, загрузка и проверка первичных файлов (ОСВ, ББ/ОФР из PDF), сводная ОСВ и шаги консолидации. +Бэкенд — `../api` (`/api/v1`, единственный источник данных). С 21.10.2026 фронт ведётся здесь: задачи — worktree arm-core, +ветка `feat/-`, PR в `main`. Прежний репозиторий `RSHB/arm-web` заморожен на `test` `de4e477` +(= arm-core `3157a15`), в нём остались история, открытые issue (номера вида `arm-web#7` в комментариях кода — оттуда) +и спеки экранов `openspec/specs/*-ui`. + +## Источники истины для фронта +1. OpenAPI arm-core и гайд `../../docs/dev/frontend-api-guide.md` — эндпоинты, тела, коды ошибок. Типы в `src/types/` + повторяют схемы бэка (`../api/src/schemas/`), поля не придумываем. +2. Пользовательский путь — `../../docs/context/10-user-journey.md`; макет — `../../docs/mockup/` (по одному экрану через + `../../docs/mockup/INDEX.md`). +3. Права — данные: доступ решает сервер (403). Меню пока не скрывается по правам (`Sidebar` не применяет permission); + коды прав из `/me` лежат в `src/auth/permissions.ts`. +- Требования к экранам: действующие — `../../arm-web/openspec/specs/*-ui/spec.md` (пока не перенесены), новые и + изменённые — `../openspec/` arm-core. +- `../../reference-old-arm/` — только чтение: инфраструктурные идеи (PDFResultViewer) можно смотреть, эндпоинты старого + АРМ (`/fsl/...`, `/osv/by-file-id`, `POST /files`) в arm-core не существуют. + +## Стек и ограничения +- React 18 + TypeScript strict, rsbuild, antd 6 (основной UI-кит; daisyui/tailwind — из шаблона), react-router 7, + Redux Toolkit, pdfjs-dist (legacy-сборка — для Яндекс Браузера, см. `src/widgets/DocumentReview/pdfjs.ts`). +- Пакеты `raisa-*` — `optionalDependencies` (вне банка недоступны); `package-lock.json` в git не хранится (в банке + зависимости ставятся через Nexus). В контуре `package.json` урезается до сборки + (`../../docs/dev/contour-transfer-guide.md` §3.2): новые пакеты, нужные сборке, добавлять и в разрешённый список там. +- env только `REACT_APP_*` через `src/conf/config.ts`; `REACT_APP_API_URL` — адрес arm-core, `REACT_APP_ROOT_PATH` = + `ROOT_PATH` бэка. + +## Архитектура +Карта модулей и границы — `ARCHITECTURE.md`. Главное: +- `src/api/` — единый HTTP-клиент `apiFetch` / `api.get|post|put|patch|del`: префикс `${API_URL}/api/v1`, Bearer-токен, + `ApiError {status, code, message}` по трём формам `detail`, событие `armka:unauthorized` на 401. **Все запросы — только + через него** (прямой `fetch` теряет токен и разбор ошибок). `apiFetchBlob(path) → {blob, filename}` — бинарные ответы + (скан PDF, экспорт xlsx) с той же обработкой токена/401/ошибок. +- `src/services/api/` — функции по ресурсам arm-core (consolidations, files, documents, osv, directories/…). +- `src/utils/` — чистые функции без React/store/API: деньги (`money.ts`, суммы — строки), подписи статусов/типов/периодов + (`labels.ts`), скачивание и имя файла (`download.ts`). +- `src/auth/` — `AuthGate` (профиль `/me`), `DevLogin` (`POST /dev/token`, только не в production), `token.ts`. +- `src/store/` — Redux Toolkit: `store.ts`, слайсы `companyGroupsSlice` и `consolidations` (+ `thunks.ts`). +- `src/layouts/` — страницы (маршруты в `src/App.tsx`, в т.ч. `/documents/:document_id` и + `/groups/:group_id/versions/:version_id/osv`), `src/widgets/` — блоки экранов (`DocumentReview` — проверка ББ/ОФР/ОСВ + со сканом, `ConsolidatedOsv` — сводная ОСВ, `FilesDrawer` — файлы ЮЛ), `src/components/` — примитивы + (`GenericTable`, `TableTag`, `PageTitle`), `src/types/` — DTO API. + +## Команды (из `web/`) +- `npm install`; `npm test` — vitest; `npm run lint` — ESLint + `prettier --check`; `npm run format` — **перед PR** + (`eslint --fix` → `biome check --write` → `prettier --write`). +- `REACT_APP_ROOT_PATH=/ npm run start` — dev-сервер на :3000 (без переменной приложение ждёт префикс + `/aurora/apps/fastapi-dkb-armka` и открывается белый экран) с proxy `/api` → `ARM_CORE_URL` (по умолчанию + `http://localhost:8000`); бэкенд — локальный стенд по `../../docs/dev/qa-guide.md` §4. +- Из корня arm-core: `make web-check` (install + biome + `tsc --noEmit` + build, входит в `check-full`). Перед PR фронта + зелёными должны быть `make web-check`, `npm test` и `npm run lint`; вывод — в описание PR. + +## Тесты +Unit-тесты — vitest на чистых функциях (`src/**/*.test.ts`); компоненты не тестируются — ручной сценарий по стенду с +фикстурами из `../../fixtures` (`../../docs/dev/qa-guide.md` §8, `../../docs/scripts/demo-prepare.sh`). Экран сверять с +макетом и проходить сценарий в браузере до сдачи. + +## Для владельца +Пользователь слаб во фронте: на TS/React-изменения агент делает код-ревью сам и объясняет решения простым языком. diff --git a/web/README.md b/web/README.md index c4e24fe..9c54972 100644 --- a/web/README.md +++ b/web/README.md @@ -1,34 +1,35 @@ -# arm-web — фронт АРМ КА (демо-прототип) +# arm-core/web — фронт АРМ КА -SPA кредитного аналитика поверх API `arm-core` (`/api/v1`). Контекст системы — `../CLAUDE.md`, архитектура — -`ARCHITECTURE.md`, соглашения репозитория — `CLAUDE.md`. +SPA кредитного аналитика поверх API `arm-core` (`/api/v1`). Контекст системы — `../../CLAUDE.md`, ядро — `../README.md`, +архитектура фронта — `ARCHITECTURE.md`, соглашения — `CLAUDE.md`. С 21.10.2026 фронт ведётся здесь (PR в arm-core +`main`); прежний репозиторий `RSHB/arm-web` заморожен. ## Запуск -1. `make install`. -2. Стенд arm-core — по `../docs/dev/qa-guide.md` §4 (ядро на `localhost:8000`, `DEBUG=true`, `make seed-dev`); для +1. `npm install` (из `web/`). +2. Стенд arm-core — по `../../docs/dev/qa-guide.md` §4 (ядро на `localhost:8000`, `DEBUG=true`, `make seed-dev`); для распознавания PDF — профиль `services` (§6.8: tabular-parser, scan-gateway, scan-emulator). -3. `make start` — dev-сервер rsbuild (сам ставит `REACT_APP_ROOT_PATH=/`; без этого приложение ждёт префикс +3. `REACT_APP_ROOT_PATH=/ npm run start` — dev-сервер rsbuild (без `REACT_APP_ROOT_PATH=/` приложение ждёт префикс `/aurora/apps/fastapi-dkb-armka` и показывает белый экран, см. `qa-guide` §4.3). Запросы `/api` проксируются на `ARM_CORE_URL` (по умолчанию `http://localhost:8000`), `REACT_APP_API_URL` в dev не нужен. 4. Вход — через dev-форму (`POST /dev/token`), например `ka_go@armka.local`. ## Форматирование и линтеры -**Перед PR — `npm run format`** (или `make format`): `eslint --fix` → `biome check --write` (импорты, безопасные +**Перед PR — `npm run format`**: `eslint --fix` → `biome check --write` (импорты, безопасные исправления) → `prettier --write`. Команда приводит `src/` к единому виду; повторный запуск ничего не меняет. - Prettier (`.prettierrc.json`) — единственный форматтер: табы, ширина 140, одинарные кавычки (в CSS — двойные), `>` тега JSX на той же строке. Форматтер biome выключен, чтобы два инструмента не спорили о пробелах. -- ESLint (`eslint.config.js`) — правила, повторяющие `biome.json`; biome остаётся линтером в `make lint`/`make check`. +- ESLint (`eslint.config.js`) — правила, повторяющие `biome.json`; biome остаётся линтером в `make web-check` ядра. - `npm run lint` — `eslint` + `prettier --check` без исправлений: ошибки валят команду, предупреждения (`any`, `console`, зависимости хуков) — нет. - В редакторе: расширения Prettier и ESLint, «Format on Save» с Prettier — результат совпадёт с `npm run format`. ## Проверка -`make check` — install, biome + ESLint + Prettier (`make lint`), `tsc --noEmit`, vitest, `rsbuild build`. Зелёным -считается всё вместе. +Из корня arm-core — `make web-check` (install, biome, `tsc --noEmit`, `rsbuild build`; входит в `check-full`), из `web/` — +`npm test` (vitest) и `npm run lint` (ESLint + Prettier). Зелёным считается всё вместе. ## Демо-сценарий @@ -43,9 +44,9 @@ SPA кредитного аналитика поверх API `arm-core` (`/api/v `CONSOLIDATION_EXISTS`) → члены ГСК отмечены → «Создать» → открывается страница группы с новой версией. 2. Дальше работаем на подготовленной версии 2024 Q3 (`/groups/?version=0437f8be-019c-4dbb-9776-08c306aa38cc`): панель «Организации» → ЮЛ → «Файлы» → документы ОСВ в статусе «Загружен». Загрузка ОСВ вручную — - `../fixtures/osv/{rb,schastl}/2024-Q{1,2,3}/*`; для новой версии быстро — `scripts/demo-prepare.sh [email]` - (каталог фикстур — `FIXTURES_DIR`, по умолчанию `../../fixtures` относительно репозитория; в конце печатает сводку). -3. ББ/ОФР: открыть уже загруженный ББ Счастливочной (или загрузить `../fixtures/ocr/aep_6.pdf` РБ) → скан слева, форма справа, + `../../fixtures/osv/{rb,schastl}/2024-Q{1,2,3}/*`; для новой версии быстро — `../../docs/scripts/demo-prepare.sh [email]` + (каталог фикстур — `FIXTURES_DIR`, по умолчанию `fixtures` workspace; в конце печатает сводку). +3. ББ/ОФР: открыть уже загруженный ББ Счастливочной (или загрузить `../../fixtures/ocr/aep_6.pdf` РБ) → скан слева, форма справа, исправить ячейку. ИНН и дата отчёта в aep_6 не распознаются: в шапке ввести дату строго `2024-09-30` (ГГГГ-ММ-ДД) и нажать «Сохранить», иначе «Подтвердить данные» даст 409 `PERIOD_REQUIRED`. Принять нарушения с комментарием (если есть), подтвердить. 4. «К отчётности» → сводная ОСВ; фильтр «Счастливочная» + «бисквит» → строка `60.01` (сальдо нач. Кт 4 454 151.93, @@ -62,13 +63,11 @@ SPA кредитного аналитика поверх API `arm-core` (`/api/v («Показать все»); в режиме правки можно назначить код строке, пометить её расшифровкой и подтвердить значение, код или дату колонки — всё уходит одним `PATCH`; кнопка «Подтвердить данные» заблокирована, пока есть строки без кода (ссылка «Разберите строки без кода: N» ведёт к первой); панель файлов ЮЛ показывает счётчик предупреждений файла и документа. -Карта модулей — в `CLAUDE.md`, раздел «Архитектура». +Карта модулей — `ARCHITECTURE.md`. -## Ограничения прототипа +## Ограничения - Нет блокировки версии («Взять в работу»), сопоставления контрагентов, экрана чек-листа, комментариев, удаления файлов, смены периметра и ручных переходов статусов. - Нет правки строк ОСВ (в API нет), картинок страниц и координат ячеек в скане (в API нет). - Нет генерации типов из OpenAPI и автотестов компонентов (vitest — только чистые функции). -- Нет сборки под контур и переноса в `arm-core/web` — отдельной задачей после демо. -- Изменений arm-core / scan-gateway нет: найденные пробелы — отдельные issue в тех репозиториях. -- 2.47.2 From a2b0a58fd0454a3fa02f797506332260f0c5a292 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 21 Oct 2026 09:58:02 +0400 Subject: [PATCH 3/4] =?UTF-8?q?docs(openspec):=20=D1=81=D0=BF=D0=B5=D0=BA?= =?UTF-8?q?=D0=B8=20=D1=8D=D0=BA=D1=80=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=B8?= =?UTF-8?q?=D0=B7=20arm-web@de4e477=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D1=81=D0=B5=D0=BD=D1=8B=20=D0=B2=20arm-core=20(#148)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Спеки consolidated-osv-ui, consolidation-setup, document-review-ui, primary-files-ui и архив changes demo-prototype, statements-v2. Каталоги архива statement-template-lines и console-files в arm-core уже заняты другими изменениями и не переносились. Ссылки на ../arm-web/openspec в CLAUDE.md и web/CLAUDE.md заменены на openspec/specs/*-ui. Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 4 +- .../2026-10-08-demo-prototype/.openspec.yaml | 2 + .../2026-10-08-demo-prototype/design.md | 158 +++++++++++++++ .../2026-10-08-demo-prototype/proposal.md | 57 ++++++ .../specs/consolidated-osv-ui/spec.md | 39 ++++ .../specs/consolidation-setup/spec.md | 39 ++++ .../specs/document-review-ui/spec.md | 64 ++++++ .../specs/primary-files-ui/spec.md | 38 ++++ .../2026-10-19-statements-v2/.openspec.yaml | 2 + .../2026-10-19-statements-v2/design.md | 90 +++++++++ .../2026-10-19-statements-v2/proposal.md | 34 ++++ .../specs/document-review-ui/spec.md | 109 +++++++++++ .../specs/primary-files-ui/spec.md | 11 ++ openspec/specs/consolidated-osv-ui/spec.md | 81 ++++++++ openspec/specs/consolidation-setup/spec.md | 44 +++++ openspec/specs/document-review-ui/spec.md | 185 ++++++++++++++++++ openspec/specs/primary-files-ui/spec.md | 77 ++++++++ web/CLAUDE.md | 4 +- 18 files changed, 1034 insertions(+), 4 deletions(-) create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/.openspec.yaml create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/design.md create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/proposal.md create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidated-osv-ui/spec.md create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidation-setup/spec.md create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/specs/document-review-ui/spec.md create mode 100644 openspec/changes/archive/2026-10-08-demo-prototype/specs/primary-files-ui/spec.md create mode 100644 openspec/changes/archive/2026-10-19-statements-v2/.openspec.yaml create mode 100644 openspec/changes/archive/2026-10-19-statements-v2/design.md create mode 100644 openspec/changes/archive/2026-10-19-statements-v2/proposal.md create mode 100644 openspec/changes/archive/2026-10-19-statements-v2/specs/document-review-ui/spec.md create mode 100644 openspec/changes/archive/2026-10-19-statements-v2/specs/primary-files-ui/spec.md create mode 100644 openspec/specs/consolidated-osv-ui/spec.md create mode 100644 openspec/specs/consolidation-setup/spec.md create mode 100644 openspec/specs/document-review-ui/spec.md create mode 100644 openspec/specs/primary-files-ui/spec.md diff --git a/CLAUDE.md b/CLAUDE.md index 68934db..15bec43 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -182,8 +182,8 @@ бэкенд. Отдельный репозиторий `RSHB/arm-web` заморожен на `test` `de4e477` (= arm-core `3157a15`), синхронизация `make -C ../docs sync-web` больше не используется; правило «`web/` напрямую не править» отменено. Проверки фронта — `make web-check` (biome + tsc + build, входит в `check-full`) и из `web/`: `npm test` (vitest), `npm run lint` - (ESLint + Prettier), форматирование — `npm run format`. Спеки экранов (`*-ui`) пока лежат в `../arm-web/openspec/specs/`; - новые и изменённые требования к экранам — в `openspec/` этого репозитория. + (ESLint + Prettier), форматирование — `npm run format`. Спеки экранов — `openspec/specs/*-ui` (перенесены из arm-web@de4e477); + новые и изменённые требования к экранам — в `openspec/changes/` этого репозитория. - Фронт: пользователь слаб во фронте — для TS/React изменений делай ревью сам и объясняй решения в PR. - `api/arm_statements/` — копия пакета `arm-statements`, напрямую не править: обновление — `../docs/scripts/sync-statements.sh` (`--in-place` в PR фичи), свежесть — `make statements-check` (в `check-full`). - OpenSpec: `openspec/` здесь; сквозные изменения — change в `../docs`. diff --git a/openspec/changes/archive/2026-10-08-demo-prototype/.openspec.yaml b/openspec/changes/archive/2026-10-08-demo-prototype/.openspec.yaml new file mode 100644 index 0000000..01660ba --- /dev/null +++ b/openspec/changes/archive/2026-10-08-demo-prototype/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-10-08 diff --git a/openspec/changes/archive/2026-10-08-demo-prototype/design.md b/openspec/changes/archive/2026-10-08-demo-prototype/design.md new file mode 100644 index 0000000..e536333 --- /dev/null +++ b/openspec/changes/archive/2026-10-08-demo-prototype/design.md @@ -0,0 +1,158 @@ +## Context + +arm-web выделен из `arm-core/web` командой фронта (3 коммита 06–07.10.2026) и дополнен экранами групп, консолидаций и +загрузки. Обзор 08.10.2026: список консолидаций и карточка версии работают с arm-core; загрузка теряет ошибки (нет +`await`, лишние поля формы); проверка документов (`PDFResultViewer`, `FileViewer`, `FileUploaderModel`) скопирована из +старого АРМ и ходит в `/fsl/...`, `/osv/by-file-id`, `POST /files` мимо клиента API; сводной ОСВ нет; `tsc` — 185 ошибок, +biome — 276. + +Демо — 09.10.2026 на локальном стенде; затем прототип уходит в контур на тестирование заказчику и переезжает в +`arm-core/web`, где развивается дальше. Поэтому код держится соглашений шаблона `arm-core/web`. + +Источник контракта — `../docs/dev/frontend-api-guide.md` (§5.5–§5.7) и схемы `arm-core/api/src/schemas/`. + +## Goals / Non-Goals + +**Goals:** аналитик на стенде проходит путь «создание консолидации → загрузка ОСВ и PDF → проверка и подтверждение → +сводная ОСВ» без сбоев и консоли разработчика; `make check` зелёный; все запросы — к API arm-core. + +**Non-Goals:** см. proposal.md («Non-goals»). + +## Decisions + +### D-1. Чинить на месте, новое — по образцу arm-core/web (согласовано 08.10.2026) +Оставляем `api/client.ts`, `auth/*`, список консолидаций, карточку версии, модалку создания (с правками), Redux-слайсы +(типизируем). Новые экраны держат состояние в локальных хуках (`useStatement`, `useDocumentEntries`, +`useConsolidatedOsv`) как `arm-core/web/src/widgets/Admin/hooks.ts`. Альтернативы — генерация типов из OpenAPI (новая +dev-зависимость, доступность в Nexus не проверена) и переписывание с нуля (не успеть) — отклонены владельцем. + +### D-2. Типы DTO руками +`src/types/` повторяют схемы arm-core только для используемых эндпоинтов: `Page`, `UploadResult`, `FileOut`, +`DocumentBrief`, `DocumentOut`, `StatementOut` (`HeaderOut`, `ColumnOut`, `LineOut`, `ValueOut`, `ChecksOut`), +`EntryOut`, `ConsolidatedRowOut`, `OsvSummaryOut`, `VersionCard` (исправления: `is_head_entity: boolean`, +`entity_type: 'ЮЛ' | 'ИП' | null`, `osv_accounts: string[]`, `changed_by` — UUID). `Decimal` и даты приходят строками — +в типах `string`. + +### D-3. Деньги — строки +Суммы не превращаются в `number`. Чистые функции `src/utils/money.ts`: `formatAmount(s)` — разделители разрядов и два +знака без арифметики над float; `parseAmountInput(s)` — нормализация ввода (пробелы, запятая → точка) и проверка +`^-?\d+(\.\d{1,2})?$`, пустое — `null`. Единицы ББ/ОФР — из `header.units`, ОСВ — рубли. + +### D-4. Бинарные ответы — `apiFetchBlob` +`src/api/client.ts` получает `apiFetchBlob(path) → {blob, filename | null}` с той же обработкой токена, 401 и ошибок +(тело ошибки — JSON). Используется для скана (`blob.arrayBuffer()` → pdf.js) и экспорта (сохранение через +`URL.createObjectURL` + ``). Имя экспорта — из `Content-Disposition` (`filename*=UTF-8''…` или `filename=`), +иначе `exportFilename(group, year, quarter)`. + +### D-5. Dev-proxy вместо CORS +`rsbuild.config.ts`: `server.proxy['/api'] → process.env.ARM_CORE_URL ?? 'http://localhost:8000'`; в dev +`REACT_APP_API_URL` пустой. Запросы идут с того же источника: нет CORS и читается `Content-Disposition` (follow-up +docs#58 O-1 на фронте обходится). В контуре SPA отдаёт сам arm-core — тот же источник, код не меняется. Гайд фронта §2 +(где `REACT_APP_API_URL=http://localhost:8000`) остаётся верным для варианта без proxy. + +### D-6. Просмотр PDF +Из `widgets/PDFResultViewer/IFrameBlock.tsx` сохраняется только постраничный рендер pdf.js (canvas, масштаб, листание); +загрузка — `apiFetchBlob('/files/{id}/content?disposition=inline')` → `arrayBuffer`. Компонент переименовывается в +`widgets/DocumentReview/PdfPages.tsx`. Worker pdf.js подключается из пакета `pdfjs-dist` сборкой (без CDN — в контуре +внешнего интернета нет). `PDFDataViewer.tsx`, `types.ts`, `styles.module.css` старого АРМ удаляются. + +### D-7. Экран документа +`layouts/DocumentPage.tsx` (`/documents/:document_id`) → `GET /documents/{id}` → `widgets/DocumentReview/StatementReview` +(BALANCE/INCOME) или `widgets/DocumentReview/OsvDocument` (OSV). Чистые функции: `buildStatementGrid(statement)` — +матрица строк × колонок по `column_id` (не по индексу), `buildEntryTree(entries)` — дерево по `parent_entry_id` с +сохранением `row_number`. Правка ячейки — локальный черновик ячеек и «Сохранить» одним `PATCH` со всеми изменёнными +ячейками; ответ сервера заменяет состояние (сервер пересчитывает проверки и сбрасывает акцепт). + +### D-8. Панель файлов +`widgets/FilesDrawer` переписывается: `UploadDocumentsModal` → один запрос со всеми файлами, итог из +`summarizeUpload(result)`; список — `FilesList` с вложенными документами; подписи — `fileStatusLabel`, +`documentTypeLabel`, `periodLabel`, `documentStatusLabel` (чистые функции). Опрос — `useDocumentsPolling` с остановкой, +когда нет `UPLOADED`/`PROCESSING`. Слайс `files` типизируется или заменяется локальным хуком (решает исполнитель по +месту, без смены поведения). + +### D-9. Сводная ОСВ +`layouts/ConsolidatedOsvPage.tsx` + `widgets/ConsolidatedOsv/` (`useConsolidatedOsv`, `OsvFilters`, `OsvTable`, +`OsvGaps`). Таблица — antd `Table` с серверной пагинацией (`limit` 500). Фильтры — query-параметры как в API; ЮЛ — +из `VersionCard.members`. + +### D-10. Тесты — vitest на чистых функциях +`vitest` (devDependency), `npm test` → `vitest run`, цель `make test` входит в `make check`. Покрытие по TDD: money, +`summarizeUpload`, подписи статусов/типов/периодов, `normalizeData` карточки версии, `exportFilename` и разбор +`Content-Disposition`, `buildStatementGrid`, `buildEntryTree`. Компоненты — ручной демо-сценарий. + +## Демо-сценарий (приёмка) + +Стенд по `../docs/dev/qa-guide.md` §4 и §6.8 (профиль `services`: tabular-parser, scan-gateway, scan-emulator), +`make seed-dev`, вход `ka_rf@armka.local` (или пользователь из гайда с правами EDIT на ГК «Русский бисквит»). + +Данные стенда уже подготовлены: консолидация РБ ГСК 2024 Q3 создана (версия `0437f8be-019c-4dbb-9776-08c306aa38cc`), +`aep_6.pdf` уже загружен Счастливочной; повторы дают штатные 409 `CONSOLIDATION_EXISTS` / `DUPLICATE_FILE`. + +1. Кнопка «Новая консолидация» — в боковом меню (действует на всё приложение); ГК «Русский бисквит» выбирается в модалке: + ГСК, период 2024 Q2 или 2025 Q3 (для 2024 Q3 — показать 409 как штатную ошибку) → члены ГСК отмечены → «Создать». +2. Шаги 2–4 — на подготовленной версии `0437f8be-…`. Панель «Организации» → РБ → «Файлы»: ОСВ + `fixtures/osv/rb/2024-Q{1,2,3}/*` и Счастливочной (`fixtures/osv/schastl/2024-Q{1,2,3}/*`) загружены, документы + подтверждены (на новой версии — загрузить и подтвердить на экране ОСВ). +3. ББ/ОФР: открыть уже загруженный ББ Счастливочной (или загрузить `fixtures/ocr/aep_6.pdf` РБ) → скан слева, форма справа, + исправить ячейку; ИНН и дата отчёта не распознаны — ввести в шапке дату `2024-09-30` (ГГГГ-ММ-ДД) и «Сохранить», иначе + 409 `PERIOD_REQUIRED`; принять нарушения с комментарием (если есть), подтвердить. +4. «К отчётности» → сводная ОСВ: 1385 строк, 22 документа, 7 пробелов; фильтр Счастливочная + «бисквит» → строка `60.01` + по `qa-guide` §7.2; «Скачать xlsx». + +Шаги API (2–4) перед браузерным прогоном проверяются curl-скриптом; браузерный прогон — владелец. + +## Risks / Trade-offs + +- [Круг «ядро + scan-gateway + эмулятор» на стенде целиком не прогонялся (`qa-guide` §6.8: «сервис проверяется + отдельно»)] → Задача 1 плана — прогон до кода. Если сломан: issue в arm-core/scan-gateway, а форма ББ/ОФР на демо — + из xlsx (`fixtures/statements-xlsx/mezheninovskaya`, `qa-guide` §6.9), скан — заглушка «превью недоступно». +- [Объём к завтра] → порядок задач от критичного к желательному; экспорт и пробелы — последними. +- [Ручные типы расходятся с API] → типы только по используемым полям, сверка со схемами при ревью. +- [Подтверждение 22 ОСВ кликами долго на демо] → в README — скрипт подтверждения из `qa-guide` §7.1; на демо можно + показать подтверждение одного документа, остальные подготовить заранее. + +## Migration Plan + +Один PR `feat/3-demo-prototype` → `test`. Откат — revert PR. Перенос в `arm-core/web` — отдельная задача после демо. + +## Open Questions + +- Какой ЮЛ «владеет» `aep_6.pdf` в фикстурах (ИНН в шапке) — влияет только на `counterparty_check` (не блокирует + подтверждение); выясняется в задаче 1. + +## Decisions made without discussion + +- 08.10.2026 — D-5 dev-proxy `/api` вместо `REACT_APP_API_URL=http://localhost:8000`. Обоснование: снимает CORS и + нечитаемый `Content-Disposition` без правок arm-core. Цена ошибки: низкая — переменная `REACT_APP_API_URL` продолжает + работать, proxy только в dev. +- 08.10.2026 — D-6 worker pdf.js из пакета, без CDN. Обоснование: в контуре нет внешнего интернета. Цена ошибки: низкая. +- 08.10.2026 — D-7 правка ячеек пакетом по «Сохранить», а не по каждой ячейке. Обоснование: меньше запросов, сервер + принимает до 5000 ячеек и пересчитывает проверки один раз. Цена ошибки: низкая — поведение меняется в одном хуке. +- 08.10.2026 — D-8: слайс Redux `files` заменён локальным хуком `useLegalEntityFiles` (список нужен только открытой панели). Цена ошибки: низкая. +- 08.10.2026 — R-1: Task 1 (проверка стенда, без записи в worktree) и Task 2 запущены параллельно. Обоснование: срок демо. Цена ошибки: нулевая. +- 08.10.2026 — R-2: замечание T4.I1 (частичный успех загрузки не обновляет список) отложено в Task 6, где модалка переписывалась; закрыто в Task 6. Цена ошибки: нулевая. +- 08.10.2026 — R-3, R-4: scoped re-review однострочного фикса T5.I1 и фикса T7.I1 (чистая функция с тестами) заменены проверкой контроллера по коду. Цена ошибки: низкая. +- 08.10.2026 — R-5: все находки финального ревью ветки исправлены одной fix-волной (384301e, 0f734e3, 67bc2c8), M-5 (тосты после 401) отложена. Цена ошибки: низкая. +- 08.10.2026 — R-6: `make start` задаёт `REACT_APP_ROOT_PATH=/` (иначе белый экран на dev-сервере, C-1). Цена ошибки: низкая — в контуре переменную задаёт платформа. +- 08.10.2026 — R-7: по замечаниям владельца (H-1, H-2) и сверке всех экранов с PNG макета (`docs/mockup/screens/`) экраны + [03], [30], [34], [39], [40], [41], [42] приведены к макету в той же ветке. Цена ошибки: низкая — только вёрстка. +- 08.10.2026 — R-8: суммы — запятая и разделители разрядов (`12 275,68`); в своде и ОСВ ноль показывается «—», в формах + ББ/ОФР — без копеек и «-» для пустых (как в макете). Цена ошибки: низкая — одна функция `formatAmount`. +- 08.10.2026 — R-9: даты загрузки и создания показываются по Москве (`Europe/Moscow`), а не по UTC-строке. Цена: низкая. +- 08.10.2026 — R-10: [34] «Дата верификации» — «—» (в `VersionBrief` нет поля, до маршрута согласования), «ГСК» — «—» + (П-3). Цена: низкая. +- 08.10.2026 — R-11: [30] вкладки Шахматка/КФО/… показаны неактивными (Срезы 5–6); фильтры свода — в заголовках колонок, + признак контрагента — в фильтре «Контрагенты». Цена: низкая. +- 08.10.2026 — R-12: [41] заголовок колонки формы без распознанной подписи — «На <дата периода>» или «Колонка N»; длинный + список нарушений — с прокруткой (120 px). Цена: низкая. +- 08.10.2026 — R-13 (согласовано с владельцем в чате): форма ББ/ОФР [41] раскладывается «как на бумаге» на фронте — + порядок строк и заголовки разделов восстанавливаются по соотношениям §7 (`formLayout.ts`), итоги XX00 жирные (кроме 2900), + строки вне формы — «Прочие строки»; приклеенные OCR заголовки разделов срезаются только при показе (полное имя — в + подсказке). ИНН — только в рамке кодов; ОКУД — по типу формы, если не распознан; длинное название — 2 строки. Причина: + сервер отдаёт строки по коду и без строк-разделов (§12, OQ-36). Цена ошибки: низкая — только показ, данные не меняются; + при появлении порядка строк в API (issue arm-core) раскладку можно упростить. +- 08.10.2026 — R-14 (по замечанию владельца H-5): шапка формы [41] — как в старом АРМ (`reference-old-arm` + `PDFResultViewer`): компактная таблица ИНН / Дата отчёта / Единица измерения (подсветка уверенности и правки, правка в + режиме «Редактировать»), затем «Бухгалтерский баланс на …». Реквизиты бумажной шапки макета (ОКПО, ОКОПФ, ОКФС, адрес, + название организации) не показываются: распознавание их не отдаёт или отдаёт мусор (arm-scan-gateway#15). Заменяет + шапку из R-13. Цена ошибки: низкая — один компонент `StatementHeaderBlock`. diff --git a/openspec/changes/archive/2026-10-08-demo-prototype/proposal.md b/openspec/changes/archive/2026-10-08-demo-prototype/proposal.md new file mode 100644 index 0000000..7e2033d --- /dev/null +++ b/openspec/changes/archive/2026-10-08-demo-prototype/proposal.md @@ -0,0 +1,57 @@ +## Why + +В пятницу 09.10.2026 — демо владельцу и бизнесу, затем прототип уходит в контур банка на тестирование заказчику +(и переезжает внутрь `arm-core/web`). Сейчас arm-web не проводит аналитика по пути «консолидация → первичка → +проверка → сводная ОСВ»: загрузка теряет ошибки, проверка документов ходит в эндпоинты старого АРМ, экрана сводной ОСВ +нет, `make check` красный (tsc — 185 ошибок, biome — 276). + +## What Changes + +- Модалка «Новая консолидация» [42]: предотметка членов ГСК, догрузка всех ЮЛ ГК, ошибки API, переход к новой версии. +- Панель «Файлы ЮЛ» [39]/[40] переписана: загрузка в контексте версии с итогом «принято / отклонено», файлы со + вложенными документами, переход к документу, опрос до окончания распознавания. +- Новый экран документа `/documents/:document_id`: для ББ/ОФР [41]/[41-02] — скан PDF рядом с формой, правка ячеек, + проверки и их акцепт, подтверждение; для ОСВ — дерево строк только для чтения и подтверждение. +- Новый экран «Сводная ОСВ» [30] `/groups/:group_id/versions/:version_id/osv`: таблица, фильтры, пробелы, счётчик + несопоставленных, экспорт xlsx. +- `api/client.ts`: `apiFetchBlob` для бинарных ответов (скан, xlsx); dev-proxy `/api` в `rsbuild.config.ts`. +- **BREAKING (внутреннее):** удалены `layouts/FileViewer.tsx`, `components/FileUploaderModel.tsx`, + `widgets/PDFResultViewer/PDFDataViewer.tsx`, `services/api/mocks.ts`; маршрут `/files/:file_id` заменён на + `/documents/:document_id`. +- `make check` зелёный: biome + tsc + vitest + build; добавлен `vitest` (dev) для чистых функций. + +## Capabilities + +### New Capabilities +- `consolidation-setup`: создание консолидации ГК за период из модалки и переход к её версии. +- `primary-files-ui`: загрузка первичных файлов ЮЛ в контексте версии и список файлов/документов со статусами. +- `document-review-ui`: проверка и подтверждение документа — форма ББ/ОФР со сканом PDF, ОСВ-документ. +- `consolidated-osv-ui`: сводная ОСВ версии — просмотр, фильтры, пробелы, экспорт. + +### Modified Capabilities +(нет — `openspec/specs/` пуст) + +## Impact + +- Экраны макета: [03], [34], [39], [40], [41], [41-02], [42], [30]. +- Эндпоинты arm-core (`/api/v1`), только существующие: + `GET /directories/company-groups`, `GET /directories/company-groups/{id}/related-groups`, + `GET /directories/related-groups/{id}`, `GET /directories/legal-entities`, `POST /consolidations`, + `GET /company-groups/{id}/consolidations`, `GET /consolidations/versions/{id}`, + `POST /legal-entities/{id}/files`, `GET /legal-entities/{id}/files`, `GET /files/{id}/content`, + `GET /documents/{id}`, `GET /documents/{id}/entries`, `POST /documents/{id}/confirm`, + `GET|PATCH /documents/{id}/statement`, `POST /documents/{id}/statement/checks/accept`, + `GET /consolidations/versions/{id}/osv`, `GET …/osv/summary`, `GET …/osv/export`. +- Зависимости: `vitest` (devDependency). +- Код: `src/api/`, `src/services/api/`, `src/types/`, `src/widgets/{NewConsoleModal,FilesDrawer,ConsoleTable,…}`, + новые `src/widgets/DocumentReview/`, `src/widgets/ConsolidatedOsv/`, `src/layouts/`, `src/App.tsx`, `rsbuild.config.ts`, + `Makefile`, `README.md`. + +## Non-goals + +- Блокировка версии («Взять в работу»), сопоставление контрагентов [32-*], экран чек-листа [37], комментарии, + удаление файлов, смена периметра и ручные переходы статусов. +- Правка строк ОСВ (в API нет), картинки страниц и координаты ячеек в скане (в API нет). +- Генерация типов из OpenAPI; автотесты компонентов. +- Перенос в `arm-core/web` и сборка под контур — отдельной задачей после демо. +- Изменения arm-core / scan-gateway: найденный пробел — отдельная issue в том репозитории. diff --git a/openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidated-osv-ui/spec.md b/openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidated-osv-ui/spec.md new file mode 100644 index 0000000..9c52797 --- /dev/null +++ b/openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidated-osv-ui/spec.md @@ -0,0 +1,39 @@ +## ADDED Requirements + +### Requirement: Сводка версии +Экран «Сводная ОСВ» [30] SHALL показывать шапку версии (ГК, период, номер, статус) и сводку +`GET /consolidations/versions/{id}/osv/summary`: строк всего, документов, несопоставленных (`unmapped_total` — счётчик +«Осталось N» без перехода к сопоставлению), автоматически сопоставленных. + +#### Scenario: Контрольные цифры РБ 2024 Q3 +- **WHEN** открыт свод версии РБ 2024 Q3 после подтверждения 22 ОСВ из `fixtures/osv/{rb,schastl}/2024-Q{1,2,3}` +- **THEN** «строк» = 1385, «документов» = 22, «несопоставленных» = 1381 + +### Requirement: Таблица свода и фильтры +Экран SHALL показывать строки `GET /consolidations/versions/{id}/osv` постранично (размер страницы ≤ 2000): ЮЛ, счёт, +контрагент, ИНН контрагента, признак контрагента (ГСК/ГК/Внешний), способ сопоставления, сальдо на начало Дт/Кт, +обороты Дт/Кт, сальдо на конец Дт/Кт (суммы — строками с разделителями разрядов). Фильтры: ЮЛ (`legal_entity_id`), +корень счёта (`account_root`), признак контрагента (`counterparty_type`), только несопоставленные (`unmapped`), поиск по +контрагенту (`q`, ≤ 500 символов). Смена фильтра SHALL перечитывать первую страницу. + +#### Scenario: Строка из контрольных цифр +- **WHEN** фильтр ЮЛ «Пекарня Счастливочная» и поиск «бисквит» +- **THEN** строка `60.01` показывает сальдо нач. Кт 4 454 151.93, обороты Дт 128 058 143.65, Кт 125 950 450.77, + сальдо кон. Кт 2 346 459.05, признак «ГСК» + +### Requirement: Пробелы +Экран SHALL показывать `gaps[]` сводки списком «ЮЛ — счёт — недостающие кварталы» с пояснением, что строки этих пар в +своде отсутствуют. + +#### Scenario: Пробелы РБ 2024 Q3 +- **WHEN** открыт свод версии РБ 2024 Q3 +- **THEN** показано 7 пробелов, у каждого недостающие кварталы «Q1, Q2» + +### Requirement: Экспорт +Кнопка «Скачать xlsx» SHALL получать `GET /consolidations/versions/{id}/osv/export` с текущими фильтрами через клиент API +с токеном и сохранять файл; имя — из `Content-Disposition`, а если заголовок недоступен — +`Сводная_ОСВ_<ГК>_<год>_<квартал>.xlsx`. + +#### Scenario: Экспорт с фильтром +- **WHEN** аналитик скачивает свод с фильтром по ЮЛ +- **THEN** сохраняется xlsx, а ошибка сервера показывается текстом, а не скачивается diff --git a/openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidation-setup/spec.md b/openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidation-setup/spec.md new file mode 100644 index 0000000..37df316 --- /dev/null +++ b/openspec/changes/archive/2026-10-08-demo-prototype/specs/consolidation-setup/spec.md @@ -0,0 +1,39 @@ +## ADDED Requirements + +### Requirement: Состав модалки «Новая консолидация» +Модалка [42] SHALL предлагать выбор ГК (`GET /directories/company-groups`), ГСК этой ГК с `kind = gsk` +(`GET /directories/company-groups/{id}/related-groups`), года и квартала, и показывать **все** незакрытые ЮЛ ГК +(`GET /directories/legal-entities?company_group_id=&closed=false`, страницы дочитываются по `offset`, пока не получены +все `total`). Члены выбранной ГСК (`GET /directories/related-groups/{id}` → `members[]`) SHALL быть отмечены +автоматически; пользователь может снять или добавить отметки. + +#### Scenario: Выбор ГСК отмечает её членов +- **WHEN** аналитик выбирает ГК «Русский бисквит» и её ГСК +- **THEN** в списке ЮЛ видны все ЮЛ ГК, а члены ГСК («АО "Русский бисквит"», «ООО "Пекарня Счастливочная"») отмечены + +#### Scenario: ЮЛ больше одной страницы +- **WHEN** у ГК больше ЮЛ, чем `limit` одной страницы +- **THEN** модалка показывает все ЮЛ ГК, а не первую страницу + +### Requirement: Создание и переход к версии +По «Создать» модалка SHALL отправить `POST /consolidations {company_group_id, related_group_id, year, quarter, +legal_entity_ids}` с отмеченными ЮЛ. При 201 модалка SHALL закрыться, список консолидаций ГК — перечитаться, а созданная +версия (`VersionCard.id`) — открыться в карточке. При ошибке модалка SHALL остаться открытой и показать `message` из +`ApiError` (коды `CONSOLIDATION_EXISTS`, `RELATED_GROUP_MISMATCH`, `ENTITY_NOT_IN_GROUP`, `PERIMETER_TOO_SMALL` и 422 +валидации). + +#### Scenario: Успешное создание +- **WHEN** аналитик создаёт консолидацию 2024 Q3 с периметром из ГСК +- **THEN** открыта карточка версии №1 со статусом «Инициация» и двумя ЮЛ в панели «Организации» + +#### Scenario: Консолидация за период уже есть +- **WHEN** сервер отвечает 409 `CONSOLIDATION_EXISTS` +- **THEN** модалка не закрывается и показывает текст ошибки сервера + +### Requirement: Переход к сводной ОСВ из карточки +Кнопка «К отчётности» карточки версии SHALL вести на `/groups/:group_id/versions/:version_id/osv` и быть доступна в +любом статусе версии. + +#### Scenario: Переход к своду +- **WHEN** аналитик нажимает «К отчётности» у версии +- **THEN** открывается экран сводной ОСВ этой версии diff --git a/openspec/changes/archive/2026-10-08-demo-prototype/specs/document-review-ui/spec.md b/openspec/changes/archive/2026-10-08-demo-prototype/specs/document-review-ui/spec.md new file mode 100644 index 0000000..98ca25f --- /dev/null +++ b/openspec/changes/archive/2026-10-08-demo-prototype/specs/document-review-ui/spec.md @@ -0,0 +1,64 @@ +## ADDED Requirements + +### Requirement: Экран документа +Маршрут `/documents/:document_id` SHALL загрузить `GET /documents/{id}` и показать вид по `document_type`: `BALANCE` и +`INCOME` — проверка формы, `OSV` — просмотр ОСВ; для прочих типов — карточку документа без данных. Шапка экрана SHALL +показывать тип, ЮЛ-владельца, период и статус документа, кнопку «Назад». + +#### Scenario: Открытие формы баланса +- **WHEN** аналитик открывает документ `BALANCE` +- **THEN** показан экран проверки формы + +### Requirement: Скан рядом с формой +Для ББ/ОФР экран SHALL показывать исходный файл документа: PDF — постранично через pdf.js из байт +`GET /files/{file_id}/content?disposition=inline`, полученных клиентом API с токеном (не через `