arm-ka-docs/dev/contour-transfer-guide.md
Andrey Epifancev 6edb62c592 docs(dev): снимок для контура вырезает openspec/config.yaml
Вопрос разработчика при переносе в контур: .claude/ и CLAUDE.md
вырезаются, а openspec/config.yaml с контекстом агента остаётся.
Решение владельца 06.10.2026: вырезать, как CLAUDE.md. Блоки
context/rules — инструкции агенту с путями ../docs и ../fixtures,
которые в контуре никуда не ведут; openspec CLI в контуре нет,
specs/ и design.md читаются без него.

- prepare-contour-snapshot.sh: rm, проверка раздела 5, SNAPSHOT.md
- contour-transfer-guide.md: таблица раздела 1, разделы 2, 3, 9

Проверено прогоном скрипта на tabular-parser@3b32462.

Closes #36

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-06 16:52:00 +04:00

180 lines
17 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.

# Перенос сервисов АРМ КА в контур банка: гайд для разработчика
Разработка ведётся **снаружи** (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/` | да | спецификация системы и журнал решений (`design.md`); без них код в контуре нечем объяснять |
| `.claude/`, `CLAUDE.md`, `openspec/config.yaml` | **нет** | инструкции и контекст AI-агента (в `config.yaml` — блоки `context`/`rules` с путями `../docs`, `../fixtures`), инструментарий внешней разработки; `openspec` CLI в контуре нет, `specs/` и `design.md` читаются без него |
| `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` — инструментарий процесса; его конфигурация
(`.claude/`, `CLAUDE.md`, `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, по одному репозиторию:
```bash
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`, `openspec/config.yaml`, `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`/`openspec/config.yaml`/планов/`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 тот же):
```bash
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
```bash
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`) возвращается наружу до следующей синхронизации:
```bash
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, в контуре они никуда не ведут.
- Тесты, которые снаружи пропускаются без `fixtures`, в контуре не выполняются никогда. Поэтому перед каждым снимком снаружи
обязателен `make check-full` с доступными `docs` и `fixtures` (`dev/checks.md`, раздел «Порядок перед PR»).