# Proposal: Срез 0 — скелет ядра arm-core **Срез:** 0 «Скелет» (`../docs/context/09-delivery-plan.md`). **Репозиторий:** arm-core. **Issue:** RSHB/arm-core#1. **Родительский change:** `../docs/openspec/changes/slice-0-skeleton` (контракт v1.0, compose, проверки качества). **Соседние:** `../tabular-parser/openspec/changes/slice-0-skeleton`, `../scan-gateway/openspec/changes/slice-0-skeleton`. ## Why Ядро — единственный писатель в PostgreSQL и единственная точка обмена с сервисами распознавания. Пока нет схемы БД по DBML v5.13, прав как данных и работающего outbox/inbox, ни один следующий срез (справочники, загрузка файлов, парсер) не может начаться: каждому нужны таблицы, пользователь с правами и канал в NATS. Срез 0 делает всё это один раз, без бизнес-логики, и доказывает end-to-end тестом на пустых обработчиках. ## What Changes - **Инструменты шаблона**: `api/pyproject.toml` (ruff — формат, совместимый с black, и lint; mypy), `requirements-dev.txt` переписан как `-r requirements.txt` + dev-инструменты (пины шаблона были рассинхронизированы), `Dockerfile` (`python:3.11-slim` — версия платформы; строка `Dockerfile` убрана из `.gitignore`), `Makefile` с общими целями `up / test / test-integration / lint / check / check-full` и своими `venv / migrate / seed`, `.env.example`, `.env.test`; `Settings` читает путь к env-файлу из `ENV_FILE` (шаблонный `pytest.ini` уже задаёт его, но `config.py` игнорировал). Без Nexus: `make venv` ставит `requirements.txt` без строк `raisa_*`; в `web/package.json` `raisa-ui` и `raisa-fastapi-protected-web` → `optionalDependencies`. - **Модель данных**: ORM 1:1 с `../docs/model/data-model-v5.13.dbml` — 43 таблицы, 27 enum'ов, все FK, уникальные и частичные индексы (`related_group_member` WHERE is_current, `consolidation_lock` WHERE released_at IS NULL, `document` NULLS NOT DISTINCT), схема `dkb`. Миграция `0001_dbml_v5_13` создаёт всё с нуля и полностью откатывается. `api/scripts/check_dbml_vs_orm.py` сравнивает DBML и ORM-метаданные; расхождение — ошибка CI. - **Seed** (`api/seed/`, идемпотентный `python -m scripts.seed`): `regional_office` (ГО), `role` (7 ролей ТЗ 8.1), `permission` (16 сочетаний объект × действие из §10), `role_permission` по §10 (ASSUMPTION(OQ-16)), `chart_of_account` (План счетов 94н + субсчета типовой 1С, упомянутые в §4/§6), `elimination_rule` v1 для ББ (§4, 8 правил) с `elimination_rule_account`, `required_document_rule` для BASIC и EXTENDED (ASSUMPTION(OQ-46)); `--dev`: примеры РФ и по одному `app_user` на роль. - **Аутентификация и права**: `core/auth.py` — проверка JWT (`TokenVerifier`: dev HS256-эмитент за флагом `AUTH_DEV_ISSUER`; каркас `RaisaVerifier` под JWKS/публичный ключ, параметры — вопрос к человеку), поиск `app_user` по email, зависимости `current_user` и `require(permission_code)`, `GET /api/v1/me`, `POST /api/v1/dev/token` (только при включённом флаге). Policy-слой (филиал/ЗО/статус) — не здесь (Срез 1+). - **Обмен через `recognition_job`** (DECISION-4, **NATS без JetStream**): вендоренные схемы контракта `api/contracts/` + pydantic-модели `src/contract/`; outbox-паблишер (`queued` → NATS → `published`, `Nats-Msg-Id = :`); подписка queue group `arm-core` на `recognition.result`: ack сервиса (`status = processing`) → `processing`/`started_at`, результат → дедуп по `result_msg_id`, обновление статуса/метрик, регистрация файла результата в `s3_object`; повторная публикация запроса без ack (`ACK_TIMEOUT_SECONDS` = 30, до `OUTBOX_MAX_REPUBLISH` = 3 раз) → затем `dlq`; вахтёр `reply_deadline` → `timeout`. Маппинг документов — точка расширения, реализуется в Срезе 2. - **Аудит**: `services/audit.py` — единственный способ записать `audit_event` (append-only, `before/after` jsonb). - **Проверки качества** (CI в Gitea нет, пайплайн платформы вне репозитория): `make check` — ruff, mypy, pytest без Docker, идентичность контракта; `make check-full` — плюс интеграционные тесты против compose, миграции upgrade → downgrade → upgrade, `check_dbml_vs_orm`, сборка образа, `web`: biome, tsc, rsbuild build. - **Документация репозитория**: `README.md` заменяется описанием сервиса (команды, env, как поднять), `CLAUDE.md` — раздел «Соглашения шаблона» (уже в ветке). ## Capabilities ### New Capabilities - `data-model`: схема БД = DBML v5.13; миграции применяются с нуля и откатываются; сверка ORM ↔ DBML. - `reference-data-seed`: идемпотентная загрузка справочников продукта (роли, права, матрица, план счетов, правила элиминации, чек-лист) и dev-данных. - `authn-authz`: вход по JWT, пользователь по email, эффективные права, зависимость `require(permission)`, `/api/v1/me`. - `recognition-job-exchange`: outbox/inbox через `recognition_job`, идемпотентность, таймауты, DLQ, регистрация результата в `s3_object`. - `audit-trail`: append-only запись событий `audit_event` через единый сервис. ### Modified Capabilities ## Impact - **Таблицы DBML v5.13:** все 43 (ORM и миграция); данными заполняются `regional_office`, `role`, `permission`, `role_permission`, `chart_of_account`, `elimination_rule`, `elimination_rule_account`, `required_document_rule`, `app_user` (dev), `user_role` (dev); в рантайме Среза 0 изменяются `recognition_job`, `s3_object`, `audit_event`. Новых полей и таблиц нет. - **Параграфы правил:** §4 (seed правил элиминации), §9.4 (жизненный цикл `recognition_status`), §10 (матрица прав). - **Зависимости (новые):** `PyJWT[crypto]`, `pydbml` (dev, сверка DBML), `ruff`, `mypy`, `pytest-cov`, `types-*`; `nats-py` уже есть (core NATS, заголовки), `miniopy-async` уже есть. - **Внешние системы:** NATS без JetStream (subjects `recognition.*`), MinIO/S3 (бакет `arm-ka`), PostgreSQL 16 (`CREATE SCHEMA dkb`, `CREATE TYPE`). - **Фронт:** код не меняется; `raisa-*` в `package.json` → `optionalDependencies`; проверки `web` входят в `make check-full`. ## Non-goals - Загрузка файлов, `stored_file`/`document` жизненный цикл и маппинг результата в `osv_entry`/`financial_statement_*` (Срез 2). - CRUD справочников и экраны администратора (Срез 1); policy-слой по филиалу/ЗО/статусу (Срез 1+). - Реальная проверка JWT РАИСА (нужны параметры — Open Questions родительского change'а); в Срезе 0 — только dev-эмитент и конфигурируемый каркас. - Авто-элиминация ОФР (OQ-09) — правила ОФР в seed не входят. - Полный план счетов конкретного клиента — только стандартный 94н + типовые субсчета 1С; остальное добавляет администратор (ARCH-004). - Любые экраны фронта.