arm-ka-docs/dev/contour-transfer-guide.md
Andrey Epifancev 6a3da7c376 docs(dev): контур — GitLab платформы, merge request вместо PR
Refs #34

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
2026-10-06 16:01:05 +04:00

17 KiB
Raw Blame History

Перенос сервисов АРМ КА в контур банка: гайд для разработчика

Разработка ведётся снаружи (workspace awp-ca, Gitea проекта). В контур банка (GitLab платформы РАИСА и его CI/CD; Gitea в контуре нет) уезжают только три сервисных репозитория — arm-core, tabular-parser, scan-gateway — снимками дерева, без истории. Репозитории docs и fixtures в контур не переносятся: решение владельца 06.10.2026. Этот документ — что именно уезжает, чего в платформе нет, как подготовить снимок скриптом и как его положить в контур.

Соглашения платформы, от которых всё отталкивается, — context/03-architecture.md, разделы «Соглашения шаблона команды» и «Что ожидаем от платформы». Проверки качества — dev/checks.md.

1. Что переносится и что нет

Что В контур Почему
api/ (код, тесты, contracts/, rules/, alembic/, scripts/), web/ (arm-core), README.md, Makefile, setup/, raisa_config.yml, api/.env.example, api/.env.test да это и есть сервис по шаблону платформы
openspec/specs/, openspec/changes/archive/, openspec/config.yaml да спецификация системы и журнал решений (design.md); без них код в контуре нечем объяснять
.claude/, CLAUDE.md нет инструкции и skills AI-агента, инструментарий внешней разработки
docs/superpowers/ (планы, ledger) нет рабочие артефакты процесса, содержат локальные пути разработчика
Dockerfile, .dockerignore нет образ для локального make check-full; в контуре образ собирает платформа своим CI (шаблон держит Dockerfile в .gitignore)
История коммитов нет снимок одним коммитом; в истории снаружи — трейлеры Co-Authored-By: Claude …, Claude-Session, ссылки на внешний Gitea
Репозиторий docs нет контекст, модель, контракты, экспорт ТЗ — остаются снаружи; копия контракта лежит в api/contracts/ каждого сервиса
Репозиторий fixtures нет реальная отчётность для регрессии парсера; тесты с маркером fixtures в контуре пропускаются
reference-old-arm нет старый репозиторий банка, читался только для справки

Снимок получает файл SNAPSHOT.md с хешем коммита-источника и датой: по нему потом сверяется, что уже перенесено.

2. Чего в платформе нет и что есть

Нет в контуре (всё это скрипт вырезает или заменяет):

  • uv — make venv снаружи ставит окружение через uv venv --python 3.11 и uv pip. В снимке цель venv переписана на python3.11 -m venv + pip с setup/pip.conf (Nexus), как делает setup/setup.sh шаблона.
  • Docker и docker compose — локальная инфраструктура (docs/dev/docker-compose.yml) живёт в docs, которого в контуре нет. Цели make up, test-integration, check-full в контуре не запускаются; docker-build удалена из Makefile.
  • docs и fixtures рядом с сервисом — тесты идентичности контракта и тесты на реальных данных пропускаются (раздел 5), сверка ORM с DBML (make dbml-check в arm-core) не выполняется.
  • tea, codegraph, openspec (CLI), хуки .claude/hooks — инструментарий процесса; в снимке только их следы в openspec/config.yaml (контекст для агента, безвреден).
  • Внешний Gitea git.aepif.ru — ссылки вида https://git.aepif.ru/RSHB/arm-core/pulls/19 в архивах change'ей скрипт превращает в RSHB/arm-core#19 (номера относятся к внешнему Gitea, в контуре их нет).

Есть только в контуре (снаружи заменено заглушками, в снимке остаётся как есть):

  • Nexus nexus.dev.raisa.go.rshbank.ru (setup/pip.conf, setup/.npmrc) и пакеты raisa_fastapi_protected_api (api/requirements.txt arm-core), raisa-fastapi-protected-web, raisa-ui (web/package.json, optionalDependencies). Снаружи make venv их пропускает (grep -v '^raisa_'), импорт raisa_fastapi_protected_api условный — только при DEBUG=false. В контуре всё ставится штатно.
  • Запуск платформой: api/run_server.py, SERVER__HOST/SERVER__PORT, ресурсы raisa_config.yml, секреты OPENBAO__* из OpenBao, Python 3.11 в базовом образе.
  • PostgreSQL 16 (схема dkb), NATS без JetStream (nkeys/JWT), S3-совместимое хранилище, JWT РАИСА для входа.

3. Подготовка снимка: scripts/prepare-contour-snapshot.sh

Запуск из workspace, по одному репозиторию:

docs/scripts/prepare-contour-snapshot.sh arm-core        /tmp/contour
docs/scripts/prepare-contour-snapshot.sh tabular-parser  /tmp/contour
docs/scripts/prepare-contour-snapshot.sh scan-gateway    /tmp/contour
# третий аргумент — ref; по умолчанию origin/main (снимок всегда с сервера, не из рабочего дерева)

Что делает скрипт (репозиторий-источник не меняется):

  1. git archive <ref> → /tmp/contour/<repo>/ — дерево коммита без .git и без игнорируемых файлов.
  2. Удаляет .claude/, CLAUDE.md, docs/superpowers/, Dockerfile, .dockerignore.
  3. Правит Makefile: цель venv → python3.11 -m venv + pip install -r requirements-dev.txt с setup/pip.conf (переменная PYTHON, по умолчанию python3.11); удаляет цель docker-build и её упоминания в check-full, .PHONY, help.
  4. Заменяет ссылки на внешний Gitea на RSHB/<repo>#<n>.
  5. Пишет SNAPSHOT.md (источник, хеш, дата, что вырезано).
  6. Проверяет: нет .claude/CLAUDE.md/планов/Dockerfile, нет локальных путей (/Users/…, /home/…), нет uv и git.aepif.ru, на месте платформенные файлы (raisa_config.yml, setup/, run_server.py, requirements.txt, .env.test, contracts/). Любая проблема — код возврата 1 и список.

Проверено 06.10.2026: снимки arm-core@1d7f2c8, tabular-parser@3b32462, scan-gateway@dffc18a проходят make check без docs и fixtures (1084 / 1087 / 726 passed, пропуски только по причинам из раздела 5).

4. Как положить снимок в контур

Репозитории контура — проекты GitLab, по одному на сервис, имена как снаружи. Первый перенос и каждый следующий делаются одинаково (вместо PR в GitLab — merge request, в остальном git тот же):

git clone <url контура>/arm-core contour-arm-core
cd contour-arm-core && git switch -c sync/arm-core-1d7f2c8      # ветка по правилам контура
rsync -a --delete --exclude .git /tmp/contour/arm-core/ ./          # дерево = снимок, удалённые снаружи файлы исчезают
git status --short                                                  # прочитать diff: он должен совпадать с изменениями снаружи
git add -A
git commit -m "sync: arm-core@1d7f2c8 (2026-10-06)"                 # хеш и дата — из SNAPSHOT.md
git push -u origin sync/arm-core-1d7f2c8                           # дальше merge request и мерж по регламенту GitLab контура

--delete обязателен: иначе файлы, удалённые или переименованные снаружи, останутся в контуре. Если в контуре делали локальные правки (раздел 7), сначала вернуть их наружу, иначе rsync --delete их перезапишет.

Порядок сервисов при одной синхронизации: arm-core → tabular-parser → scan-gateway (ядро — потребитель контракта, его копия схемы должна быть не старше копий сервисов). Если снаружи поднималась версия контракта (api/contracts/*.json, CONTRACT_VERSION в api/src/contract/common.py), переносить все три сервиса одним заходом.

5. Проверка в контуре перед merge request

make venv            # python3.11 -m venv + pip через Nexus (вместо setup/setup.sh; тот ставит только прод-зависимости)
make check           # ruff, mypy, pytest без интеграционных тестов

Ожидаемые пропуски (pytest -rs покажет причины), это не ошибки:

Сервис Пропускается Причина
все тест идентичности api/contracts/ с docs/contracts/ docs нет; идентичность проверена снаружи перед снимком
все тесты с маркером fixtures (golden-снимки, property-тесты на реальных ОСВ/формах, покрытие словарей) fixtures нет; регрессия на реальных данных — снаружи
arm-core сверка ORM с DBML в тестах DBML в docs
scan-gateway тесты с реальными ответами ИС Сканирование (fixtures/ocr) то же

Не запускать в контуре: make up, make test-integration, make check-full, make dbml-check, make e2e — им нужны compose из docs либо Docker. Интеграционные тесты против PostgreSQL/NATS/MinIO прогоняются снаружи перед каждым снимком; пайплайну платформы отдаётся make check.

Фронт arm-core: make web-check (npm install через .npmrc Nexus, biome, tsc, npm run build). В контуре raisa-fastapi-protected-web и raisa-ui ставятся штатно, снаружи они в optionalDependencies и пропускаются. web/package-lock.json снаружи не коммитится (OQ-63) — в контуре lock-файл появится при первом npm install, решение о его коммите за контуром.

6. Что нужно от платформы для запуска

Переменные окружения — api/.env.example каждого сервиса (имена и смысл), секреты под префиксом OPENBAO__*. Минимум для arm-core:

  • OPENBAO__DATABASE__DATABASE_URL (asyncpg, схема dkb), OPENBAO__MINIO__{MINIO_URL, MINIO_ADMIN_LOGIN, MINIO_ADMIN_PASSWORD, MINIO_BUCKET} (MINIO_SECURE=true по умолчанию), OPENBAO__NATS__{NATS_URL, NATS_SEED, NATS_JWT}.
  • DEBUG=false (включает middleware РАИСА, выключает /docs и dev-токены), CORS_ORIGINS (явный список; пусто — кросс-доменные запросы запрещены), FORWARDED_ALLOW_IPS (адреса прокси платформы, иначе IP в аудите — адрес прокси), AUTH_JWKS_URL или AUTH_PUBLIC_KEY + AUTH_ISSUER, AUTH_AUDIENCE, AUTH_EMAIL_CLAIM — параметры JWT РАИСА (открытый вопрос OQ в context/07-open-questions.md). AUTH_DEV_ISSUER/AUTH_DEV_SECRET в проде не задавать.
  • Миграции и seed при деплое: из api/ — alembic upgrade head, затем python -m scripts.seed (справочники: план счетов, правила элиминации, роли и права; --dev только для стенда разработки). Те же команды — цели make migrate и make seed (README.md arm-core, «Быстрый старт», шаг 4 «Миграции и справочники»).

tabular-parser и scan-gateway: только OPENBAO__MINIO__*, OPENBAO__NATS__*, DEBUG, NATS_ENABLED=true; у парсера PARSE_MAX_BYTES, PARSE_TIMEOUT_SECONDS; у шлюза SCAN_HOTFOLDER_MODE=smb и OPENBAO__SMB__{SMB_HOST, SMB_PATH, SMB_LOGIN, SMB_PASSWORD} (режим local и эмулятор make emulator — только для разработки). Subjects NATS, схема ключей S3 и ресурсы — context/03-architecture.md.

7. Правки внутри контура и обратный поток

Правило: источник истины — репозитории снаружи. Любая правка в контуре (чаще всего под пайплайн платформы: пути, переменные, raisa_config.yml) возвращается наружу до следующей синхронизации:

cd contour-arm-core
git diff <коммит sync> HEAD -- . ':!SNAPSHOT.md' > /tmp/contour-arm-core.patch   # база — коммит последнего sync

Патч применяется снаружи в ветку и проходит обычный PR; после его мержа следующий снимок уже содержит правку, и rsync --delete ничего не потеряет. Если правка касается только контура (например, секретов платформы), её место — вне репозитория: переменные окружения OpenBao, а не код.

8. Чек-лист одной синхронизации

  1. Снаружи: нужные PR слиты в main трёх сервисов; make check-full зелёный в каждом; контракт в docs/contracts и копии api/contracts идентичны.
  2. Правки из контура (раздел 7) возвращены наружу и слиты.
  3. prepare-contour-snapshot.sh по каждому сервису; скрипт завершился словами «снимок готов».
  4. В контуре: клон, ветка, rsync --delete, просмотр git status, коммит sync: <repo>@<hash> (<дата>), make venv, make check (пропуски — только из раздела 5), для arm-core make web-check, merge request по регламенту GitLab контура.
  5. Порядок мержа при смене версии контракта: arm-core → tabular-parser → scan-gateway.
  6. Снаружи в context/09-delivery-plan.md или в issue синхронизации отметить, какие хеши перенесены.

9. Известные неточности снимка

  • README.md сервисов описывают make venv через uv и ссылаются на ../docs, ../fixtures, docs/dev/qa-guide.md; скрипт их не переписывает. Ориентир для контура — этот документ и SNAPSHOT.md.
  • В openspec/changes/archive/*/ остаются относительные пути вида ../docs/openspec/... и ../fixtures/...: это ссылки на внешний workspace, в контуре они никуда не ведут.
  • openspec/config.yaml содержит контекст для AI-агента (упоминает ../docs, фикстуры, стек); на сборку не влияет.
  • Тесты, которые снаружи пропускаются без fixtures, в контуре не выполняются никогда. Поэтому перед каждым снимком снаружи обязателен make check-full с доступными docs и fixtures (dev/checks.md, раздел «Порядок перед PR»).