Andrey Epifancev db7df33517 chore(openspec): архив change slice-0-skeleton
Срез 0 реализован и влит (PR #3), change перенесён в openspec/changes/archive, спеки — в openspec/specs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-04 19:44:37 +04:00

8.7 KiB
Raw Blame History

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 = <job_id>:<attempt>); подписка 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).
  • Любые экраны фронта.