arm-ka-docs/context/09-delivery-plan.md
Andrey Epifancev 0c04127aec docs: OpenSpec change slice-0-skeleton — сквозной скелет Среза 0
openspec init (config с контекстом docs-репозитория) и change slice-0-skeleton: proposal, design
(11 решений без обсуждения, открытые вопросы к человеку), спеки recognition-contract,
dev-environment, ci-template, tasks в порядке зависимостей между репозиториями. 06-test-data.md §6:
справочники продукта — seed arm-core, не фикстуры. 09-delivery-plan.md: Срез 0 по факту (change'и,
compose в docs/dev, контракт копией без общего пакета, seed).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 02:44:14 +04:00

121 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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

# 09. План работ вертикальными срезами
Принцип: каждый срез — рабочий end-to-end кусок (миграции + API + минимальный UI + тесты на реальных фикстурах),
который можно показать аналитику. Порядок выбран так, чтобы самое рискованное (парсер ОСВ, матчинг ВГО) проверялось
на реальных данных как можно раньше, а внешние зависимости (ИС Сканирование, РАИСА, NATS платформы) не блокировали.
Каждый срез = OpenSpec change **в каждом затронутом репозитории** (`openspec/changes/<slug>/` с `proposal.md`, `specs/`,
`tasks.md`), сквозная часть — change в `docs/`; задачи — issues в Gitea; PR — по одному на репозиторий. Jira-эпики
пользователя маппятся на срезы (пользователь ведёт соответствие сам).
## Срез 0 — Скелет (2–3 дня, три репозитория + docs)
- Три репозитория из нулевого коммита шаблона команды; соглашения шаблона — в `03-architecture.md` и в `CLAUDE.md`
каждого репозитория. **Первая задача агента — прочитать шаблон и дополнить документы.** (Сделано: раздел «Соглашения
шаблона команды» в `03-architecture.md`; в `tabular-parser`/`scan-gateway` фронт и БД вырезаются задачами среза.)
- OpenSpec change'и среза: `docs/openspec/changes/slice-0-skeleton` (сквозной: контракт, compose, CI-шаблон, документы) и
по одному `openspec/changes/slice-0-skeleton` в `arm-core`, `tabular-parser`, `scan-gateway`; issue #1 в каждом репозитории.
- `docker-compose` workspace-уровня (`docs/dev/docker-compose.yml`): PostgreSQL 15, NATS 2.10 JetStream, MinIO (S3, один
бакет `arm-ka`), эмулятор ИС Сканирование (часть `scan-gateway`, отдаёт `fixtures/ocr/aep_N.json`), три сервиса (профиль
`services`). `Makefile` с `up/test/lint/migrate` в каждом репо (шаблон Makefile не содержит — добавляется).
- Контракт v1.0 — три схемы в `docs/contracts/`: `recognition-request`, `recognition-result-message` (конверты NATS) и
`recognition-result` (файл результата) + `examples/`. Общий пакет `arm-ka-contracts` **не публикуется**: каждый сервис
хранит копию схем в `api/contracts/` и pydantic-модели в `src/contract/`, идентичность с `docs/contracts` проверяется в CI
(решение D-1 change `slice-0-skeleton` в docs).
- Alembic: миграция 0001 — **все** таблицы и enum'ы DBML v5.13 (черновик из ORM, сверка с DBML скриптом
`api/scripts/check_dbml_vs_orm.py` — расхождение = ошибка CI).
- Seed (`arm-core/api/seed/`, идемпотентно): `regional_office` (ГО; примеры РФ — только `--dev`), `role` (7),
`permission` (16 осмысленных сочетаний объект × действие по §10), `role_permission` по §10, `chart_of_account`
(План счетов 94н + типовые субсчета 1С, OQ-47), `elimination_rule` v1 из §4 (только ББ), `required_document_rule`
для BASIC/EXTENDED (OQ-46).
- Auth: валидация JWT + dev-эмитент; `app_user` seed (по одному на роль); зависимость `require(permission)`.
- `audit_event` middleware/helper; `s3_object` клиент; outbox-паблишер и consumer `recognition.result` (пустые обработчики).
- CI: lint, mypy, pytest, миграции с нуля и обратно, сборка образов.
- DoD: `GET /api/v1/me` возвращает пользователя и его эффективные права; все миграции применяются; CI зелёный.
## Срез 1 — Справочники (ГК / ЮЛ / ГСК / ГСЗ / филиалы) + пользователи и роли
- CRUD ГК (с `code`, `crm_id` nullable, закрепление за РФ, архив, история SCD4), ЮЛ/ИП (ИНН 10/12, алиасы, перевод в
другую ГК с `legal_entity_history.event_type/effective_date`, закрытие), ГСК/ГСЗ и состав (SCD2, одна группа на ЮЛ).
- Импорт из файла (xlsx/csv) с логом ошибок и стратегией дублей; `audit_event(DIRECTORY_IMPORT)`.
- Экран администратора: пользователи, роли, матрица прав (`ROLE_PERMISSION_CHANGE`).
- Policy-слой: видимость ГК по филиалу/ЗО.
- Фикстуры: ГК «Русский бисквит» с двумя ЮЛ (+ кандидаты из OQ-25), ГСК из двух.
- UI: справочник по макету (левая панель ГК, правая — ЮЛ/ГСК/ГСЗ, модалки).
## Срез 2 — Загрузка файлов + табличный парсер (ОСВ, ББ, ОФР из Excel) — самый рискованный, делать рано
- `arm-core`: `stored_file` + `s3_object` + `recognition_job` (outbox) + дедуп по `content_hash` + замена файла (`SUPERSEDED`).
- `tabular-parser`: **динамическое** обнаружение структуры (§1.0): поиск листов с ОСВ/ББ/ОФР по содержимому, заголовка
таблицы и колонок сумм по тексту, иерархии строк каскадом стратегий (outline level → отступ → шаблон кода → суммы),
шапки регулярками; классификация по `group_schema`; контрольные суммы; ББ/ОФР из Excel по §12 в тот же
`statementDocument`; словари синонимов `rules/*.yaml`; результат по контракту; NATS request/result; S3 `results/`.
- Маппинг результата в ядре: `document` (OSV) + `osv_entry` (все строки, OQ-01) + резолв `account_id`, `account_root`,
`counterparty_id` по ИНН/имени/алиасу; `document.period_check / counterparty_check`; статусы.
- Тесты: property-тесты инвариантов на **всех** файлах `fixtures/osv/**` и `fixtures/statements-xlsx/**` («Итого» =
корень; тождество сальдо/оборотов; Σ детей = родитель; формулы §7 для форм) + синтетика для форматов, которых нет в
фикстурах (шапка вариант 2, без outline level, csv-подобный лист, Вал./Кол., xlsb, ББ+ОФР на одном листе, текстовые
числа). Снимок результатов → `fixtures/golden/expected_osv_parse/`.
- Маппинг ББ/ОФР в ядре из `statementDocument` — общий для Excel и OCR (Срез 3 его переиспользует).
- UI: панель «Первичные документы», окно загрузки, таблица ОСВ с деревом строк и подсветкой нераспознанных контрагентов.
- DoD: все реальные файлы и вся синтетика проходят **без единого правила под конкретный файл или координату**; в коде
парсера нет литералов букв колонок/номеров строк/имён листов (проверяется тестом-линтером).
## Срез 3 — ББ/ОФР: scan-gateway, маппинг форм, логические проверки, подтверждение документа
- `scan-gateway`: горячие папки (по FNR02) с заглушкой-эмулятором ИС Сканирование для dev (возвращает `aep_*.json`
по имени файла); сырой ответ → S3 `raw/`; нормализация в контракт результата; таймаут 5 мин.
- Маппинг: `financial_statement_meta/column/line/value` из JSON; числа, скобки, confidence; ИНН/имя сверка.
- Логические проверки §7 (чистые функции `domain/checks.py`), акцепт КА, «Подтвердить данные» → `CONFIRMED`,
`RECOGNIZED_DATA_EDIT` с before/after.
- Чек-лист `required_document_rule × периметр − document CONFIRMED` (API + модалка + CSV).
- UI: экран «Проверка распознавания» (исходник слева — PDF.js, результат справа, блок «Логические ошибки»).
- Тесты: пары `aep_N.pdf/json`; машиночитаемые PDF АО РБ 2024 как dev-путь без OCR (опционально pdfplumber).
## Срез 4 — Консолидация: карточка, версии, периметр, периоды, сводная ОСВ
- `consolidation` / `consolidation_version` / `consolidation_member` / `consolidation_document`; статусы INITIATED →
DOCUMENTS_PROCESSING → DATA_CORRECTION; `consolidation_lock`.
- Приведение квартальных ОСВ к нарастающим (§2) как вычисляемое представление.
- Сводная ОСВ (§3) как запрос; признак контрагента; ручное сопоставление с алиасами и автоприменением.
- UI: список консолидаций, карточка, состав, сводная ОСВ с фильтрами и экспортом xlsx.
- Тест: сводная ОСВ группы РБ за 9 мес. 2024: строки «Юг-Финанс / ПЕКАРНЯ СЧАСТЛИВОЧНАЯ» → ГСК после одного ручного
сопоставления.
## Срез 5 — ВГО: автоматическое сопоставление, шахматка, корректировки
- `elimination_rule` как данные + версия в `consolidation_version`; матчинг §5 (чистые функции на pydantic-моделях);
шахматка §6; `correction` с дочерними строками, контроль 5 %, статусы DRAFT/APPLIED/REVOKED; `ADJUSTMENT`.
- UI: шахматка (ячейки с комментариями), таблица пар (авто/ручные/несопоставленные), таблица корректировок с
импортом/экспортом xlsx.
- Тест: пара 60.01 АО РБ ↔ 62.01 Счастливочная на 30.09.2024 = 106 311 116,46 (точный матч по правилу № 6); заём
42 млн 66.03 ↔ 58.03; сверка «в т. ч. взаимные обязательства» с `Консолидация_Группа РБ.xlsx` лист `01.10.2024`.
## Срез 6 — КФО: результат, гудвилл, пороги, сравнение с клиентом
- `kfo_result(_line, _line_company)`: сумма → авто-элиминация → корректировки → гудвилл → итог; единицы (OQ-26);
пороги §8; `goodwill`; `client_kfo_line` для `CONFIRM`.
- UI: КФО (колонки как в эталонном Excel), сводка расхождений, гудвилл, подтверждение КФО клиента, экспорт xlsx.
- Тест: КФО группы РБ на 01.10.2024 vs эталонный лист (допуск на ручные правки аналитика — зафиксировать расхождения
и показать аналитику).
## Срез 7 — Маршрут согласования, ЕХ, журнал, выгрузки
- Полная машина статусов §9.1 с `consolidation_status_history`, policy по ролям/филиалам; № и дата УОБ; новая версия.
- `VERIFIED` → `ex_snapshot/_member/_item` (payload по схеме `docs/contracts/ex-payload-v1.schema.json`); read-only.
- ЛК ЕХ: дерево ГК → ГСК → организации, просмотр payload, скачивание первички, выгрузка xlsx на лету.
- Журнал действий: экран с фильтрами по разделам/объектам/полям.
- Экспорт: настраиваемые колонки, `audit_event(EXPORT)`, S3 `exports/` 7 дней.
## Срез 8 — Нефункциональные: ретеншн, архивирование, производительность, безопасность
- Lifecycle S3 и удаление по ТЗ 8.4 (5 лет), архив в data lake (ссылка), объёмы `osv_entry` (индексы, partitioning по
году при необходимости), нагрузочный тест парсера (1000-строчные ОСВ × 20 компаний), OWASP-проверка, аудит доступа.
## Поперечные правила
- Любой срез, затрагивающий модель, начинается с diff к DBML (новая версия v5.14+ с записью в changelog) и миграции.
- Вычисляемые объекты — только `domain/` + `repositories/` запросы; никаких таблиц «для ускорения» без DECISION.
- Каждый алгоритм из `05-domain-rules.md` — отдельный модуль с docstring-ссылкой на § и тестами на фикстурах.
- Открытые вопросы — только через `07-open-questions.md` с `ASSUMPTION(OQ-nn)` в коде.