# Spec Delta: dev-environment ## Purpose Локальное окружение разработки всего workspace одной командой: инфраструктура (PostgreSQL, NATS JetStream, MinIO), эмулятор внешней ИС Сканирование и три сервиса системы, собранные из соседних каталогов workspace. ## ADDED Requirements ### Requirement: Инфраструктура поднимается одной командой `docker compose -f docs/dev/docker-compose.yml up -d` без профилей SHALL поднять PostgreSQL 15 (БД `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`, `nats stream ls` отвечает (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/S3; stream `RECOGNITION` существует #### Scenario: Запуск из venv против compose - **WHEN** разработчик поднял только инфраструктуру и запускает `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` за одну сессию