# Spec Delta: dev-environment ## Purpose Локальное окружение разработки всего workspace одной командой: инфраструктура (PostgreSQL 16, NATS без JetStream, MinIO), эмулятор внешней ИС Сканирование и три сервиса системы, собранные из соседних каталогов workspace. ## ADDED Requirements ### Requirement: Инфраструктура поднимается одной командой `docker compose -f docs/dev/docker-compose.yml up -d` без профилей SHALL поднять PostgreSQL 16 (БД `armka`, пользователь `armka`, порт 5432), NATS 2.10 **без JetStream** (как на платформе; порты 4222, мониторинг 8222) и MinIO (API 9000, консоль 9001) с уже созданным бакетом `arm-ka`. Все учётные данные — в `docs/dev/.env.example`, копируемом в `docs/dev/.env`. #### Scenario: Чистый старт - **WHEN** разработчик выполняет `cp .env.example .env && docker compose up -d` в `docs/dev/` на машине без томов - **THEN** в течение 60 с все три контейнера проходят healthcheck, `psql` подключается к `armka`, `curl :8222/varz` отвечает и `jetstream` в нём отсутствует/выключен, `mc ls local/arm-ka` возвращает пустой бакет ### Requirement: Профиль сервисов собирает приложения из workspace Профиль `services` SHALL добавить контейнеры `arm-core`, `tabular-parser`, `scan-gateway` и `scan-emulator`, собранные из `../../arm-core`, `../../tabular-parser`, `../../scan-gateway` относительно `docs/dev/` (работает и из зеркального workspace `.wt/<срез>/`). Сервисы читают настройки через переменные `OPENBAO__*` шаблона, `DEBUG=true`, и получают `fixtures/ocr` смонтированным только для чтения в эмулятор. #### Scenario: Сервисы стартуют против инфраструктуры compose - **WHEN** выполняется `docker compose --profile services up -d --build` - **THEN** `GET http://localhost:8000/healthcheck` (arm-core), `:8001/healthcheck` (tabular-parser), `:8002/healthcheck` (scan-gateway) отвечают 200 с `version` и `nats = ok`; в логах нет ошибок подключения к NATS/S3 #### Scenario: Запуск из venv против compose без Nexus - **WHEN** разработчик поднял только инфраструктуру, создал venv командой `make venv` (ставит `requirements.txt` без строк `raisa_*`) и запускает `python run_server.py` из `api/` любого сервиса с `.env`, скопированным из `docs/dev/.env.example` - **THEN** сервис подключается к тем же PostgreSQL/NATS/MinIO по `localhost` и проходит healthcheck ### Requirement: Эмулятор ИС Сканирование воспроизводит горячие папки Контейнер `scan-emulator` SHALL следить за каталогом `Input/` общего тома `hotfolder`; для файла `UUID_имя.ext` он SHALL через настраиваемую задержку (по умолчанию 2 с) создать `Output/UUID/UUID.json` с содержимым `fixtures/ocr/<имя без расширения>.json`, если такая пара есть; иначе — JSON ошибки в формате Content AI (`error.code = INVALID_DOCUMENT`). #### Scenario: Известная пара - **WHEN** в `Input/` появляется `3f1c…_aep_5.pdf` - **THEN** через ≤ 5 с в `Output/3f1c…/3f1c….json` лежит содержимое `fixtures/ocr/aep_5.json` #### Scenario: Неизвестное имя - **WHEN** в `Input/` появляется `…_unknown.pdf` - **THEN** в `Output/…/….json` лежит ответ с `error.code = INVALID_DOCUMENT` и пустым `data_ocr` ### Requirement: Окружение документировано `docs/dev/README.md` SHALL описывать: предварительные требования, команды запуска инфраструктуры и профиля сервисов, переменные `.env`, как запустить интеграционные тесты каждого сервиса против compose, как сбросить тома. #### Scenario: Новый разработчик - **WHEN** разработчик следует README без помощи - **THEN** он получает работающее окружение и зелёные интеграционные тесты `arm-core` за одну сессию