# Окружение разработки АРМ КА (`docs/dev/`) Локальная инфраструктура workspace одной командой: PostgreSQL 16, NATS 2.10 без JetStream и MinIO с бакетом `arm-ka`. **Статус (фаза 1):** в compose сейчас только инфраструктура (`postgres`, `nats`, `minio`, `minio-init`). Профиль `services` (контейнеры `arm-core`, `tabular-parser`, `scan-gateway`, `scan-emulator`) **планируется** — добавляется позже (задача 5.3), здесь не описан. До этого сервисы запускаются из venv против этой инфраструктуры (см. ниже). ## Предварительные требования - Docker и compose v2 (проверено на docker 28 / compose 2.34). - `uv` и Python 3.11 — для запуска сервисов из venv (версия Python — как на платформе). - Свободные порты хоста: 5432 (PostgreSQL), 4222 и 8222 (NATS и его мониторинг), 9000 и 9001 (MinIO API и консоль). Занятые порты меняются в `.env` (см. «Типичные проблемы»). ## Запуск инфраструктуры Команды — из каталога `docs/dev/`: ```bash cp .env.example .env # .env в git не попадает docker compose up -d # вернётся сразу; healthy — примерно через 6 с ``` Ожидание готовности (для скриптов и `Makefile`): ```bash docker compose up -d && docker compose up -d --wait postgres nats minio ``` Голый `docker compose up -d --wait` **возвращает код 1**: одноразовый `minio-init` (создаёт бакет и завершается с кодом 0) compose 2.34 считает сбоем (`container arm-ka-minio-init-1 exited (0)`). Поэтому `--wait` нужно давать со списком долгоживущих сервисов — как выше. Проверка: ```bash docker compose ps # postgres, nats, minio — Up (healthy); minio-init — Exited (0) docker compose exec postgres psql -U armka -d armka -c 'select version()' curl -s localhost:8222/healthz # {"status":"ok"} curl -s localhost:8222/varz | grep -A1 jetstream # "jetstream": {} — JetStream не включён docker compose run --rm --entrypoint sh minio-init -c 'mc alias set local http://minio:9000 minioadmin minioadmin >/dev/null && mc ls local' # [...] 0B arm-ka/ ``` Консоль MinIO — (по умолчанию `minioadmin` / `minioadmin`); S3 API — `localhost:9000`. Схема БД (`dkb`) создаётся миграциями `arm-core`, не compose. ## Переменные `.env` Файл читают `docker compose` (из этого каталога) и, вторым блоком, сервисы при запуске из venv. Значения по умолчанию — только для dev. Блок compose: | Переменная | По умолчанию | Для чего | |---|---|---| | `POSTGRES_DB` | `armka` | имя БД | | `POSTGRES_USER` | `armka` | пользователь БД | | `POSTGRES_PASSWORD` | `armka` | пароль БД | | `POSTGRES_PORT` | `5432` | порт PostgreSQL на хосте | | `NATS_PORT` | `4222` | клиентский порт NATS на хосте | | `NATS_MONITOR_PORT` | `8222` | порт мониторинга NATS (`/varz`, `/healthz`) | | `MINIO_ROOT_USER` | `minioadmin` | администратор MinIO | | `MINIO_ROOT_PASSWORD` | `minioadmin` | пароль администратора MinIO | | `MINIO_API_PORT` | `9000` | порт S3 API на хосте | | `MINIO_CONSOLE_PORT` | `9001` | порт консоли MinIO на хосте | | `MINIO_BUCKET` | `arm-ka` | единственный бакет, создаётся `minio-init` | Блок сервисов (запуск из venv против compose по `localhost`, формат шаблона команды): | Переменная | По умолчанию | Для чего | |---|---|---| | `DEBUG` | `true` | dev-режим: пакеты `raisa_*` импортируются условно | | `OPENBAO__DATABASE__DATABASE_URL` | `postgresql+asyncpg://armka:armka@localhost:5432/armka` | подключение к PostgreSQL (asyncpg) | | `OPENBAO__MINIO__MINIO_URL` | `localhost:9000` | адрес MinIO без схемы (`host:port`, так ждёт `miniopy-async`) | | `OPENBAO__MINIO__MINIO_ADMIN_LOGIN` | `minioadmin` | логин MinIO | | `OPENBAO__MINIO__MINIO_ADMIN_PASSWORD` | `minioadmin` | пароль MinIO | | `OPENBAO__MINIO__MINIO_BUCKET` | `arm-ka` | бакет | | `OPENBAO__NATS__NATS_URL` | `nats://localhost:4222` | адрес NATS | | `OPENBAO__NATS__NATS_SEED` | пусто | nkey seed; пусто — подключение без nkeys | | `OPENBAO__NATS__NATS_JWT` | пусто | JWT NATS; пусто — подключение без nkeys | | `OPENBAO__SMB__SMB_HOST` | `localhost` | заглушка SMB (в Срезе 0 не используется); блок обязателен для `Settings` arm-core | | `OPENBAO__SMB__SMB_PATH` | `share` | заглушка SMB | | `OPENBAO__SMB__SMB_LOGIN` | `user` | заглушка SMB | | `OPENBAO__SMB__SMB_PASSWORD` | `password` | заглушка SMB | | `NATS_ENABLED` | `true` | включает подключение arm-core к NATS; без него `/healthcheck` показывает `nats=off` | Два блока описывают одни и те же ресурсы: **при смене порта, пароля, пользователя или бакета меняйте обе части.** ## Сброс окружения ```bash docker compose down # останавливает контейнеры; тома postgres-data и minio-data сохраняются docker compose down -v # полный сброс: удаляет тома postgres-data и minio-data (БД и бакет — с нуля) ``` Имя проекта compose фиксировано (`name: arm-ka`), поэтому тома общие для любого worktree (`.wt/<срез>/docs/dev`): сброс из одного worktree затрагивает все. ## Запуск сервисов из venv без Nexus (черновик) > Черновик: будет дописан и проверен вручную в задаче 5.4 (сквозная проверка). `make venv` и `make test-integration` > в `tabular-parser` и `scan-gateway` будут доступны после задач этих сервисов; сейчас они есть в `arm-core`. Пакеты `raisa_*` из Nexus банка вне банка недоступны (D-10). Поэтому `make venv` ставит `requirements.txt` без строк `raisa_*` (фильтр `grep -v '^raisa_'`), код импортирует `raisa_*` условно (при `DEBUG=true`), а npm-пакеты `raisa-*` в `web/package.json` вынесены в `optionalDependencies`. Шаги для сервиса (пути — относительно каталога его репозитория; в workspace `docs/` лежит рядом, `../docs/dev/`): ```bash # 1. поднять инфраструктуру (из docs/dev/, см. выше) # 2. из корня репозитория сервиса: cp ../docs/dev/.env.example api/.env make venv # api/.venv: Python 3.11 + зависимости без raisa_* cd api && .venv/bin/python run_server.py # сервис подключается к PostgreSQL/NATS/MinIO по localhost # 3. в другом терминале: curl -s localhost:<порт сервиса>/healthcheck ``` Порт сервиса задаётся его настройками; в профиле `services` по spec это 8000 (`arm-core`), 8001 (`tabular-parser`), 8002 (`scan-gateway`). Для `arm-core` в ответе `/healthcheck` ожидаются `version` и `nats = ok` — при `NATS_ENABLED=true` (задан в `.env.example`; без него `nats = off`). Для `tabular-parser` и `scan-gateway` ожидаемые поля и переменные зависят от их настроек — будет уточнено в задачах 5.x. ## Интеграционные тесты сервисов против compose (черновик) > Черновик: уточняется после задач 3.x и 5.x. **Сейчас.** Makefile есть только у `arm-core`: `make test-integration` (`pytest -m integration`), `make check` = `lint` + `test` (ruff, mypy, `pytest -m "not integration"`), `make check-full` = `check` + `test-integration`. У `tabular-parser` и `scan-gateway` Makefile пока нет. **Планируется** (spec `quality-checks`, реализуется в задачах 3.x/4.x/5.x): одинаковый набор целей во всех сервисных репозиториях со следующей семантикой: - `make test-integration` — `pytest -m integration` против инфраструктуры из этого compose; - `make check` — быстрые проверки без Docker (ruff, mypy, `pytest -m "not integration"`, идентичность контракта); - `make check-full` — `make check` + интеграционные тесты; для `arm-core` — ещё «`alembic upgrade head` → `downgrade base` → `upgrade head`» и `scripts/check_dbml_vs_orm.py` (этих шагов и скрипта пока нет). Выполняется перед созданием PR. Интеграционные тесты **требуют поднятой инфраструктуры**: сначала `docker compose up -d && docker compose up -d --wait postgres nats minio`, затем `make test-integration` (или `make check-full`) в репозитории сервиса. Для `scan-gateway` дополнительно нужен эмулятор ИС Сканирование (появится вместе с профилем `services`). Общее описание проверок — `docs/dev/checks.md` (будет добавлено). ## Проверка контракта Из корня репозитория `docs`: `python scripts/validate_contracts.py` — валидирует примеры в [`contracts/examples/`](../contracts/examples/) тремя схемами из [`contracts/`](../contracts/) (3 схемы, 8 примеров; нужен `jsonschema`). ## Примечания - **Образы MinIO неофициальные.** Официальные `minio/minio` и `minio/mc` недоступны (Docker Hub — denied, на quay.io нет нужных тегов), поэтому в compose стоят `alpine/minio:RELEASE.2025-10-15T17-29-55Z` и `bitnamilegacy/minio-client:2025.7.21`, а сервис `minio` запущен с `user: "0:0"` (иначе образ не пишет в свежий том) — только для dev. Решения R-5/R-6: [`design.md`](../openspec/changes/slice-0-skeleton/design.md), раздел «Decisions made without discussion», решения №16–17. Замена на официальные образы — две строки `image:` в `docker-compose.yml` (и удаление `user: "0:0"`). - **Безопасность.** Порты публикуются на `0.0.0.0` с паролями по умолчанию: это dev-окружение, не запускайте его в недоверенной сети. ## Типичные проблемы - **Порт занят** (`address already in use`): измените `*_PORT` в `.env` и одновременно соответствующий порт в `OPENBAO__*` (`DATABASE_URL`, `MINIO_URL`, `NATS_URL`); перезапустите `docker compose up -d`. - **`minio-init` завис или завершился с ошибкой:** `docker compose logs minio-init`; чаще всего `minio` не стал healthy — `docker compose logs minio`. Повторный `docker compose up -d` идемпотентен. - **Остаточные тома от прошлых запусков** (старый пароль БД, бакет не тот): `docker compose down -v` и запуск заново. - **`up -d --wait` возвращает код 1:** см. раздел «Запуск инфраструктуры» — указывайте сервисы явно.