Срез 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
8.7 KiB
8.7 KiB
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.jsonraisa-uiиraisa-fastapi-protected-web→optionalDependencies. - Модель данных: ORM 1:1 с
../docs/model/data-model-v5.13.dbml— 43 таблицы, 27 enum'ов, все FK, уникальные и частичные индексы (related_group_memberWHERE is_current,consolidation_lockWHERE released_at IS NULL,documentNULLS 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_rulev1 для ББ (§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 grouparm-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/afterjsonb). - Проверки качества (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).
- Любые экраны фронта.