From 4d9e81c04bda05db858b57b17db8e4d5b7e1307a Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Tue, 13 Oct 2026 12:31:45 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20subject'=D1=8B=20=D0=B8=20JWT=20NATS=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8E=20=E2=80=94=20=D0=B0=D1=80=D1=85=D0=B8=D1=82=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D1=83=D1=80=D0=B0,=20=D0=BE=D0=BA=D1=80=D1=83=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5,=20OQ-83=20(#80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- context/03-architecture.md | 17 +++++++++++---- context/07-open-questions.md | 2 +- dev/.env.example | 5 +++++ dev/README.md | 26 +++++++++++------------ dev/contour-transfer-guide.md | 11 +++++++--- dev/frontend-api-guide.md | 2 +- dev/qa-guide.md | 1 + openspec/changes/nats-env-config/tasks.md | 6 +++--- 8 files changed, 45 insertions(+), 25 deletions(-) diff --git a/context/03-architecture.md b/context/03-architecture.md index 42c5046..86d6f8c 100644 --- a/context/03-architecture.md +++ b/context/03-architecture.md @@ -64,9 +64,13 @@ | Поток | Subject | Кто пишет | Полезная нагрузка | `Nats-Msg-Id` | Схема | |---|---|---|---|---|---| -| запрос | `files.tabular_uploaded` / `files.img_uploaded` | arm-core (outbox из `recognition_job`) | `schema_version`, `job_id`, `file_id`, `pipeline`, `file_type`, `original_name`, `s3 {bucket, key}` исходника, `reply_deadline`, `attempt` | `:` | [request](../contracts/recognition-request.schema.json) | -| ack | `files.tabular_parsed` | tabular-parser / scan-gateway | конверт со `schema_version`, `status = processing`, `job_id`, `file_id`, `service {name, version}` | `ack::` | [message](../contracts/recognition-result-message.schema.json) | -| результат | `files.tabular_parsed` | tabular-parser / scan-gateway | `schema_version`, `job_id`, `file_id`, `status` (done / needs_check / error), `service {name, version}`, `metrics` (опц.), `raw_s3_key` (опц., только scan-gateway); при `done` / `needs_check` обязательны `result_s3 {bucket, key}` и `result_schema_version`, при `error` — `error {code, message}` | `result::` | [message](../contracts/recognition-result-message.schema.json); файл в S3 — [result](../contracts/recognition-result.schema.json) | +| запрос | `files.tabular_uploaded` / `files.img_uploaded` (умолчания) | arm-core (outbox из `recognition_job`) | `schema_version`, `job_id`, `file_id`, `pipeline`, `file_type`, `original_name`, `s3 {bucket, key}` исходника, `reply_deadline`, `attempt` | `:` | [request](../contracts/recognition-request.schema.json) | +| ack | `files.tabular_parsed` (умолчание) | tabular-parser / scan-gateway | конверт со `schema_version`, `status = processing`, `job_id`, `file_id`, `service {name, version}` | `ack::` | [message](../contracts/recognition-result-message.schema.json) | +| результат | `files.tabular_parsed` (умолчание) | tabular-parser / scan-gateway | `schema_version`, `job_id`, `file_id`, `status` (done / needs_check / error), `service {name, version}`, `metrics` (опц.), `raw_s3_key` (опц., только scan-gateway); при `done` / `needs_check` обязательны `result_s3 {bucket, key}` и `result_schema_version`, при `error` — `error {code, message}` | `result::` | [message](../contracts/recognition-result-message.schema.json); файл в S3 — [result](../contracts/recognition-result.schema.json) | + +Имена `files.*` на схеме и в таблице выше — умолчания: subject'ы являются настройками окружения +`OPENBAO__NATS__NATS_{TABULAR_REQUEST,IMAGE_REQUEST,RESULT}_SUBJECT` (`files.tabular_uploaded`, `files.img_uploaded`, +`files.tabular_parsed`), одинаковыми у всех трёх сервисов. Queue group'ы — константы. `group_schema` в конверт не входит — ядро берёт его из `documents[].group_schema` файла результата при маппинге. @@ -303,7 +307,9 @@ FastAPI» платформы РАИСА/aurora): дерево импортиро - `pydantic-settings`, файл `api/.env`, вложенность через `__`, лишние переменные игнорируются. Все инфраструктурные секреты — под префиксом `OPENBAO` (в проде заполняет OpenBao): `OPENBAO__DATABASE__DATABASE_URL`, `OPENBAO__MINIO__{MINIO_URL, MINIO_ADMIN_LOGIN, MINIO_ADMIN_PASSWORD, MINIO_BUCKET}`, - `OPENBAO__NATS__{NATS_URL, NATS_SEED, NATS_JWT}`, `OPENBAO__SMB__{SMB_HOST, SMB_PATH, SMB_LOGIN, SMB_PASSWORD}`. + `OPENBAO__NATS__{NATS_URL, NATS_SEED, NATS_JWT, NATS_TABULAR_REQUEST_SUBJECT, NATS_IMAGE_REQUEST_SUBJECT, + NATS_RESULT_SUBJECT}` (во всех трёх сервисах; `NATS_SEED` и `NATS_JWT` — `SecretStr`, три subject'а — настройки + с умолчаниями `files.*`), `OPENBAO__SMB__{SMB_HOST, SMB_PATH, SMB_LOGIN, SMB_PASSWORD}`. Прочее: `DEBUG`, `ROOT_PATH`, `VERSION`, `SERVER__HOST`, `SERVER__PORT`. - Платформа РАИСА передаёт в под только секреты OpenBao, поэтому любая настройка верхнего уровня `Settings` в контуре задаётся как `OPENBAO__APP__<ИМЯ>` (приоритет: обычный env → `OPENBAO__APP__*` → `.env` → умолчание; неизвестное @@ -334,6 +340,9 @@ FastAPI» платформы РАИСА/aurora): дерево импортиро `files.img_uploaded`, `files.tabular_parsed`, `files.img_parsed`; используем три — запросы в `files.tabular_uploaded` и `files.img_uploaded`, ack и результаты обоих сервисов в общий `files.tabular_parsed`; `files.img_parsed` не используется. Старый АРМ гасится, общих подписчиков на этих subject'ах у нас с ним не будет. + Прод и тест — свои наборы: JWT, seed и три subject'а окружения задаются одинаково всем трём сервисам; JWT окружения + должен давать publish/subscribe на эти subject'ы. Разъехавшиеся настройки — тишина на шине (dlq по NO_ACK); сверять + `/healthcheck.subjects` ядра и сервисов (решение владельца 12.10.2026). - **SMB** (горячие папки ИС Сканирование) — `smbprotocol`/`smbclient`, сессия регистрируется в lifespan; нужен только `scan-gateway`. - **Внешняя аутентификация** — пакет `raisa_fastapi_protected_api` из внутреннего Nexus (`AuthorizationMiddleware`, `ProtectedSettings`, …), импортируется только при `DEBUG=false` (в контуре временно `DEBUG=true`, см. «Аутентификация и авторизация», п. 6); фронтовая пара — `raisa-fastapi-protected-web`. diff --git a/context/07-open-questions.md b/context/07-open-questions.md index 11632cb..7249380 100644 --- a/context/07-open-questions.md +++ b/context/07-open-questions.md @@ -88,7 +88,7 @@ | OQ-80 | `make up` расходится с эталоном (scan-gateway и `dev/Makefile.common`): в `tabular-parser` нет `minio-init` — на свежем томе бакета `arm-ka` нет, `test_s3_integration` даёт `NoSuchBucket`, хотя README сервиса обещает бакет; в `arm-core` `up -d` без `--wait` и без `--project-name` (имя в compose фиксировано, безвредно). Также `check-full` в arm-core и tabular-parser — через пререквизиты (порядок при `make -j` не гарантирован), в scan-gateway — через `$(MAKE)`; `lint` arm-core включает `mypy scripts`. Подключить `include ../docs/dev/Makefile.common` в сервисах? | tabular-parser: `Makefile` (цель `up`); scan-gateway: п. 18 таблицы предложений (I-1); docs: O-1 и O-2 (задача 1 фазы 2), O-4 и O-5 (задача 2 фазы 2), `dev/checks.md`, `dev/Makefile.common` | срез 0 (процесс), все сервисы | допущение принято: эталон — scan-gateway, расхождения описаны в `dev/checks.md`, Makefile сервисов не правились (design #22, #24); выровнять — правкой Makefile сервисов (follow-up) | | OQ-81 | Переменные `ARM_KA_DOCS` / `ARM_KA_FIXTURES` поддержаны неравномерно: `arm-core` — обе; `tabular-parser` — только `ARM_KA_DOCS`; `scan-gateway` — ни одной (жёстко `../docs`, `../../fixtures/ocr`). Текст причины skip («fixtures недоступен: положите репозиторий…») не содержит строки «ARM_KA_FIXTURES недоступен» из сценария «Нет фикстур» spec `quality-checks`; для docs-теста текст тоже без `ARM_KA_DOCS`. Нарушение spec — править сервисы? | scan-gateway и tabular-parser (тесты, Makefile); docs: O-3 (задача 1 фазы 2), `dev/checks.md`; spec `quality-checks` | срез 0 (процесс), все сервисы | допущение принято: расхождение описано в `dev/checks.md`; правка тестов и Makefile в scan-gateway и tabular-parser — follow-up человеку (сервисы не правились); **частично закрыт (Срез 2a, tabular-parser):** хелпер `tests/fixtures_helpers.py` поддерживает `ARM_KA_FIXTURES` (текст skip называет переменную и путь), `ARM_KA_DOCS` поддержан в тесте идентичности контракта; `scan-gateway` — по-прежнему ни одной переменной, остаётся follow-up человеку | | OQ-82 | `.dockerignore` в `arm-core` не исключает `api/.env.test`: файл попадает в образ (у `tabular-parser` и `scan-gateway` исключён). Исправлять? | arm-core `.dockerignore`; docs: T3.2 (задача 3 фазы 2) | срез 0 (образы), прод-сборка | **закрыт реализацией (arm-core PR #10, техдолг Среза 1, 05.10.2026):** `.dockerignore` исключает `api/.env.*` (включая `.env.test` и `.env.example`); настройки контейнера — только из окружения | -| OQ-83 | Контейнеры профиля `services` подписаны на те же subject и queue group общего NATS, что и экземпляры в интеграционных тестах сервисов (`recognition.result` / `arm-core`, `*.request`): NATS может отдать сообщение теста контейнеру и наоборот; интеграционные тесты `scan-gateway` и `arm-core` одновременно тоже делят NATS. Сделать queue group и subject-префикс настраиваемыми для тестов (например `NATS_TEST_PREFIX`) или поднимать отдельный NATS на тесты? | scan-gateway: п. 11 таблицы предложений (T14.1, T11.8); docs: O-11 (задача 3 фазы 2; подтверждено ревью для tabular-parser и scan-gateway), `dev/README.md` | срез 0 (процесс), интеграционные тесты | допущение принято: в `dev/README.md` предупреждение и команда `stop` для контейнеров профиля; не гонять `make test-integration` двух сервисов одновременно | +| OQ-83 | Контейнеры профиля `services` подписаны на те же subject и queue group общего NATS, что и экземпляры в интеграционных тестах сервисов (`recognition.result` / `arm-core`, `*.request`): NATS может отдать сообщение теста контейнеру и наоборот; интеграционные тесты `scan-gateway` и `arm-core` одновременно тоже делят NATS. Сделать queue group и subject-префикс настраиваемыми для тестов (например `NATS_TEST_PREFIX`) или поднимать отдельный NATS на тесты? | scan-gateway: п. 11 таблицы предложений (T14.1, T11.8); docs: O-11 (задача 3 фазы 2; подтверждено ревью для tabular-parser и scan-gateway), `dev/README.md` | срез 0 (процесс), интеграционные тесты | допущение принято: в `dev/README.md` предупреждение и команда `stop` для контейнеров профиля; не гонять `make test-integration` двух сервисов одновременно. 13.10.2026 (nats-env-config): subject'ы — настройки; интеграционные тесты tabular-parser и scan-gateway идут на уникальных subject'ах прогона и не пересекаются со стендом. Для `make e2e` ядра вопрос остаётся: ему нужен контейнер tabular-parser стенда на умолчаниях, конфликт — общая queue group `arm-core` (design R-7). Статус: открыт (частично) | | OQ-84 | Запуск сервисов из venv без Nexus (`make venv` + `python run_server.py` из `api/` с `.env` из `docs/dev/.env.example`, healthcheck по `localhost`) в Срезе 0 не проверялся ни в одном из трёх сервисов. Известно по чтению конфигов (design #44): `.env.example` в нынешнем виде отвергнут `scan-gateway` (`OPENBAO__DATABASE__*`) и `tabular-parser` (`OPENBAO__DATABASE__*`, `OPENBAO__SMB__*` — `extra_forbidden`), в нём нет `OPENBAO__MINIO__MINIO_SECURE=false` (по умолчанию `true` — https к http-MinIO). Прогнать сценарий, зафиксировать набор переменных и портов (`SERVER__PORT`, `SCAN_HOTFOLDER_PATH` для `scan-gateway`), решить, нужен ли отдельный `.env.example` на сервис, и снять пометку «черновик» с раздела `dev/README.md`? | spec `dev-environment`, сценарий «Запуск из venv против compose без Nexus»; docs: design #43, `dev/README.md` («Запуск сервисов из venv без Nexus»); финальное ревью фазы 2: I-1 | срез 0 (процесс, окружение разработки); кандидат в follow-up issue | вопрос: допущение Среза 0 — раздел README остаётся черновиком, сценарий не подтверждён (проверка требовала `.venv` внутри сервисных репозиториев, в фазе 2 доступных только для чтения) | | OQ-85 | **Возможен ли JetStream на платформе** (серверный дедуп по `Nats-Msg-Id`, durable consumer'ы, redelivery вместо ack и повторной публикации на уровне приложения)? Сейчас NATS без JetStream (ответ платформы 03.10.2026); Срез 0 строит доставку на ack `processing`, повторной публикации ядром и дедупе по `recognition_job.result_msg_id`. Если JetStream подключить можно — меняются только publisher/subscriber (`core/nats.py` в трёх сервисах), outbox/inbox и контракт остаются; исчезают потеря результата при простое ядра и риск повторной обработки. | решение человека 04.10.2026: «узнать у платформы и проверить позже»; `design.md` slice-0-skeleton (D-3, Open Questions п. 4); OQ-72, OQ-73 | инфраструктура NATS (платформа); `core/nats.py`, воркеры сервисов | **вопрос к платформе (поставить напоминание, проверить после ревью Среза 0 / до Среза 3)**: допущение — без JetStream. 06.10.2026: `RSHB/armka_file_worker` (PDFWorker старого АРМ, проверен в контуре) тоже работает на core NATS (`subscribe`/`publish` + `flush`, без `jetstream()`), один JWT на все сервисы АРМ с правами по subject'ам; возможность включить JetStream по-прежнему не выяснена | | OQ-86 | Фильтр видимости по ЗО (`business_segment`): сегмент есть только у `app_user`, у ГК/ЮЛ поля нет (DBML v5.14). Откуда брать сегмент ГК (из ЕЦП CRM? из РФ?), нужен ли вообще фильтр по ЗО в первой очереди? | §10.1 правил; DBML v5.14 | срез 1 (policy), DBML v5.15 | допущение: в Срезе 1 ЗО не фильтрует; видимость — только по филиалу (ГО видит всё) | diff --git a/dev/.env.example b/dev/.env.example index c50f3ff..66d4208 100644 --- a/dev/.env.example +++ b/dev/.env.example @@ -47,6 +47,11 @@ OPENBAO__MINIO__MINIO_BUCKET=arm-ka OPENBAO__NATS__NATS_URL=nats://localhost:4222 OPENBAO__NATS__NATS_SEED= OPENBAO__NATS__NATS_JWT= +# Subject'ы окружения — одинаковые у arm-core, tabular-parser и scan-gateway (значения ниже — умолчания). +# Прод и тест имеют свои наборы; JWT должен давать publish/subscribe на эти subject'ы. +OPENBAO__NATS__NATS_TABULAR_REQUEST_SUBJECT=files.tabular_uploaded +OPENBAO__NATS__NATS_IMAGE_REQUEST_SUBJECT=files.img_uploaded +OPENBAO__NATS__NATS_RESULT_SUBJECT=files.tabular_parsed # SMB — заглушки (в Срезе 0 не используется); блок необязателен для arm-core и scan-gateway (режим local). # Блок OPENBAO__DATABASE__* знает только arm-core: scan-gateway и tabular-parser неизвестные ключи OPENBAO__* отвергают diff --git a/dev/README.md b/dev/README.md index 410dd44..e3e0adf 100644 --- a/dev/README.md +++ b/dev/README.md @@ -323,12 +323,17 @@ MinIO; полная очистка — `docker compose --profile services down - | `OPENBAO__NATS__NATS_URL` | `nats://localhost:4222` | адрес NATS | | `OPENBAO__NATS__NATS_SEED` | пусто | nkey seed; пусто — подключение без nkeys | | `OPENBAO__NATS__NATS_JWT` | пусто | JWT NATS; пусто — подключение без nkeys | +| `OPENBAO__NATS__NATS_TABULAR_REQUEST_SUBJECT` | `files.tabular_uploaded` | subject запросов на разбор таблиц (ядро публикует, tabular-parser слушает) | +| `OPENBAO__NATS__NATS_IMAGE_REQUEST_SUBJECT` | `files.img_uploaded` | subject запросов на распознавание сканов (ядро публикует, scan-gateway слушает) | +| `OPENBAO__NATS__NATS_RESULT_SUBJECT` | `files.tabular_parsed` | subject ack и результатов обоих сервисов (слушает ядро) | | `OPENBAO__SMB__SMB_HOST` | `localhost` | заглушка SMB (в Срезе 0 не используется); блок необязателен для `arm-core` и для `scan-gateway` в режиме `SCAN_HOTFOLDER_MODE=local` (по умолчанию); `tabular-parser` его не знает и отвергнет (см. ниже) | | `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` | +Три subject'а одинаковы у всех трёх сервисов (непустые, без пробелов, `*`, `>` и пустых токенов, попарно различны; `NATS_JWT` и `NATS_SEED` — `SecretStr`). Прод и тест — свои наборы; разъехавшиеся настройки дают тишину на шине, сверяйте `/healthcheck.subjects`. + Два блока описывают одни и те же ресурсы: **при смене порта, пароля, пользователя или бакета меняйте обе части.** ## Сброс окружения @@ -374,7 +379,7 @@ curl -s localhost:<порт сервиса>/healthcheck одновременно или сервис из venv рядом с профилем `services` требуют разных `SERVER__PORT`. Для `arm-core` в ответе `/healthcheck` ожидаются `version` и `nats = ok` — при `NATS_ENABLED=true` (задан в `.env.example`; без него `nats = off`). Поля `/healthcheck` в контейнерах: `tabular-parser` — `uptime`, `version`, `nats`; `scan-gateway` — ещё -`hotfolder` (шлюзу нужен `SCAN_HOTFOLDER_PATH`). Набор переменных сервисов для запуска из venv не проверялся (см. черновик выше и OQ-84). По чтению конфигов: `scan-gateway` и `tabular-parser` отвергают неизвестные ключи `OPENBAO__*`, а поле DATABASE есть только у `arm-core`. Поэтому в `.env` `scan-gateway` нужно удалить строки `OPENBAO__DATABASE__*` (SMB в режиме `local` допустим), а в `.env` `tabular-parser` — `OPENBAO__DATABASE__*` и `OPENBAO__SMB__*`; для MinIO по `http` нужен `OPENBAO__MINIO__MINIO_SECURE=false` (в `.env.example` его нет, по умолчанию `true`). +`hotfolder` (шлюзу нужен `SCAN_HOTFOLDER_PATH`). Во всех трёх ответах есть объект `subjects` с фактическими subject'ами сервиса (при любом состоянии NATS): `arm-core` — `{tabular_request, image_request, result}`, `tabular-parser` — `{tabular_request, result}`, `scan-gateway` — `{image_request, result}`. Набор переменных сервисов для запуска из venv не проверялся (см. черновик выше и OQ-84). По чтению конфигов: `scan-gateway` и `tabular-parser` отвергают неизвестные ключи `OPENBAO__*`, а поле DATABASE есть только у `arm-core`. Поэтому в `.env` `scan-gateway` нужно удалить строки `OPENBAO__DATABASE__*` (SMB в режиме `local` допустим), а в `.env` `tabular-parser` — `OPENBAO__DATABASE__*` и `OPENBAO__SMB__*`; для MinIO по `http` нужен `OPENBAO__MINIO__MINIO_SECURE=false` (в `.env.example` его нет, по умолчанию `true`). ## Интеграционные тесты сервисов против compose (черновик) @@ -392,18 +397,13 @@ postgres nats minio`, затем `make test-integration` (или `make check-ful эмулятор ИС Сканирование поднимается в процессе интеграционного теста; контейнер `scan-emulator` профиля `services` тестами не используется. Общее описание проверок — [`checks.md`](checks.md). -> **Не запускайте интеграционные тесты `tabular-parser` и `scan-gateway` при поднятом профиле `services`.** Их -> сквозные тесты (`api/tests/integration/test_roundtrip.py`, у `scan-gateway` ещё `test_nats_minio_integration.py`) -> публикуют запросы в боевые `files.tabular_uploaded` / `files.img_uploaded`, а экземпляр сервиса из теста -> подписан в ту же queue group (`tabular-parser` / `scan-gateway`), что и контейнер. NATS отдаёт каждое сообщение группы -> одному подписчику — запрос теста может уйти контейнеру, и тест упадёт по таймауту ожидания ack (так прямо сказано в -> docstring теста `scan-gateway`). Риск подтверждён чтением кода тестов, тесты при поднятом профиле не запускались. -> Интеграционные тесты `arm-core` от контейнеров изолированы: временная БД на сессию (рабочая `armka` не используется) -> и уникальный subject результатов на тест. Перед тестами сервисов: -> `docker compose --profile services stop tabular-parser scan-gateway scan-emulator`; проверить, что чужих подписчиков -> нет: `curl -s 'http://127.0.0.1:8222/subsz?subs=1' | grep -o '"subject": *"recognition[^"]*"'` — строк -> `files.tabular_uploaded` / `files.img_uploaded` быть не должно (`files.tabular_parsed` — подписка контейнера -> `arm-core`, тестам `arm-core` не мешает). +> Интеграционные тесты `tabular-parser` и `scan-gateway` (`api/tests/integration/`) идут на уникальных subject'ах +> прогона (префиксы `itest.` / `test-.`), поэтому не пересекаются с контейнерами профиля `services` и друг с +> другом: **останавливать контейнеры стенда больше не нужно.** Интеграционные тесты `arm-core` от контейнеров +> изолированы: временная БД на сессию и уникальный subject результатов на тест. Исключение — `make e2e` ядра +> (`tests/e2e/`): он идёт на subject'ах по умолчанию (design R-7, OQ-83), поэтому ядро стенда (`arm-core` на +> `:8000`) на время прогона нужно остановить — общая queue group `arm-core`; контейнер `tabular-parser` стенда на +> умолчаниях ему, наоборот, нужен. ## Проверка контракта diff --git a/dev/contour-transfer-guide.md b/dev/contour-transfer-guide.md index 367f1c7..169acdd 100644 --- a/dev/contour-transfer-guide.md +++ b/dev/contour-transfer-guide.md @@ -183,9 +183,14 @@ issue #22; файл `api/src/core/settings_sources.py` одинаков в тр | Сервис | Секреты `OPENBAO__<ГРУППА>__*` | Настройки `OPENBAO__APP__*` | |---|---|---| -| 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}` | `NATS_ENABLED=true` (по умолчанию `false`: без него NATS не подключается и обмен с сервисами распознавания не работает), `DEBUG=true`, `AUTH_DEV_ISSUER=true`, `AUTH_DEV_SECRET=<случайная строка от 32 байт>` (поле верхнего уровня `Settings`, поэтому тоже через `OPENBAO__APP__`), `FORWARDED_ALLOW_IPS=<адреса прокси платформы>` (иначе IP в аудите — адрес прокси); `CORS_ORIGINS` при `DEBUG=true` не нужен. `SERVER__HOST` не задавать (платформа задаёт сама). **Временно, на период тестов:** `CONSOLIDATION_PERIOD_FROM_VERSION=true` — ОСВ, загруженная в консолидацию, берёт её период (arm-core#103, OQ-161; `qa-guide.md` §7.4); после тестов убрать | -| scan-gateway | `OPENBAO__MINIO__*`, `OPENBAO__NATS__*`, `OPENBAO__SMB__{SMB_HOST, SMB_PATH, SMB_LOGIN, SMB_PASSWORD}` | `SCAN_HOTFOLDER_MODE=smb` (`NATS_ENABLED` по умолчанию `true`, задавать не нужно). `SCAN_HOTFOLDER_PATH` в контуре не нужен (только режим `local`; режим `local` и эмулятор `make emulator` — для разработки) | -| tabular-parser | `OPENBAO__MINIO__*`, `OPENBAO__NATS__*` | сверх секретов ничего (`NATS_ENABLED` по умолчанию `true`); при необходимости `PARSE_TIMEOUT_SECONDS` (и `PARSE_MAX_BYTES`) | +| 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, NATS_TABULAR_REQUEST_SUBJECT, NATS_IMAGE_REQUEST_SUBJECT, NATS_RESULT_SUBJECT}` | `NATS_ENABLED=true` (по умолчанию `false`: без него NATS не подключается и обмен с сервисами распознавания не работает), `DEBUG=true`, `AUTH_DEV_ISSUER=true`, `AUTH_DEV_SECRET=<случайная строка от 32 байт>` (поле верхнего уровня `Settings`, поэтому тоже через `OPENBAO__APP__`), `FORWARDED_ALLOW_IPS=<адреса прокси платформы>` (иначе IP в аудите — адрес прокси); `CORS_ORIGINS` при `DEBUG=true` не нужен. `SERVER__HOST` не задавать (платформа задаёт сама). **Временно, на период тестов:** `CONSOLIDATION_PERIOD_FROM_VERSION=true` — ОСВ, загруженная в консолидацию, берёт её период (arm-core#103, OQ-161; `qa-guide.md` §7.4); после тестов убрать | +| scan-gateway | `OPENBAO__MINIO__*`, `OPENBAO__NATS__*` (включая три subject'а), `OPENBAO__SMB__{SMB_HOST, SMB_PATH, SMB_LOGIN, SMB_PASSWORD}` | `SCAN_HOTFOLDER_MODE=smb` (`NATS_ENABLED` по умолчанию `true`, задавать не нужно). `SCAN_HOTFOLDER_PATH` в контуре не нужен (только режим `local`; режим `local` и эмулятор `make emulator` — для разработки) | +| tabular-parser | `OPENBAO__MINIO__*`, `OPENBAO__NATS__*` (включая три subject'а) | сверх секретов ничего (`NATS_ENABLED` по умолчанию `true`); при необходимости `PARSE_TIMEOUT_SECONDS` (и `PARSE_MAX_BYTES`) | + +Для тестового контура — свой набор JWT, seed и трёх subject'ов (`NATS_TABULAR_REQUEST_SUBJECT` по умолчанию +`files.tabular_uploaded`, `NATS_IMAGE_REQUEST_SUBJECT` — `files.img_uploaded`, `NATS_RESULT_SUBJECT` — +`files.tabular_parsed`): одинаковый у всех трёх сервисов; JWT должен давать publish/subscribe на эти subject'ы. +Разъехавшиеся настройки — тишина на шине (dlq по NO_ACK); сверяйте `/healthcheck.subjects`. В отличие от arm-core, в `scan-gateway` и `tabular-parser` `NATS_ENABLED=true` по умолчанию, а `DEBUG` влияет только на уровень логов; платформенной аутентификации у них нет (внутренние сервисы без HTTP-входа для пользователей). diff --git a/dev/frontend-api-guide.md b/dev/frontend-api-guide.md index 08eff45..5cb1cf8 100644 --- a/dev/frontend-api-guide.md +++ b/dev/frontend-api-guide.md @@ -68,7 +68,7 @@ | Токен в проде | SSO РАИСА; параметры неизвестны (OQ-54) — держите слой «получить токен» отдельно от слоя «использовать токен» | | Dev-пользователи | `admin@`, `ka_go@`, `curator_go@`, `expert@`, `ka_rf@`, `rka@`, `client_manager@armka.local` — по одному на роль (таблица — `frontend-auth-guide.md` §3.1) | | Схема и Swagger | `/openapi.json`, `/docs`, `/redoc` — **только** при `DEBUG=true`; в проде 404 | -| Живость | `GET /healthcheck` (без префикса и без токена) → `{"uptime": "<время старта процесса, ISO>", "version": "1.0.0", "nats": "ok" \| "down" \| "off"}` — это не признак «вошёл» | +| Живость | `GET /healthcheck` (без префикса и без токена) → `{"uptime": "<время старта процесса, ISO>", "version": "1.0.0", "nats": "ok" \| "down" \| "off", "subjects": {"tabular_request": "…", "image_request": "…", "result": "…"}}` (`subjects` — служебное поле для диагностики, фронту не нужно) — это не признак «вошёл» | | CORS | при `DEBUG=true` — `*` без credentials; в проде — источники из `CORS_ORIGINS` | | Стенд целиком | `qa-guide.md` (docker compose, сиды, запуск бэка и фронта) | diff --git a/dev/qa-guide.md b/dev/qa-guide.md index 90503fe..048a973 100644 --- a/dev/qa-guide.md +++ b/dev/qa-guide.md @@ -952,6 +952,7 @@ Gitea: бэкенд и API — `RSHB/arm-core`, экраны — `RSHB/arm-web`, | PDF завис в «Обработка» | не запущены `scan-gateway`/`scan-emulator` (раздел 8, предусловия) | | PDF в статусе «Ошибка» (подсказка `INVALID_DOCUMENT`) | эмулятор знает только PDF из `fixtures/ocr` с JSON-ответом (6.8); свой PDF так и должен падать | | Импорт падает на записи файла в S3 | MinIO не поднят или не создан бакет: `docker compose logs minio-init` | +| `/healthcheck.subjects` ядра и сервиса различаются (или файл зависает в `UPLOADED` при `nats: ok`) | у сервисов разные `OPENBAO__NATS__NATS_*_SUBJECT`; выровняйте настройки у всех трёх | | `/healthcheck` показывает `nats: down` | NATS не поднят; на сценарии Среза 1 не влияет, но загрузка ОСВ (6.6) без NATS не дойдёт до парсера | | Файл завис в `UPLOADED`/`PROCESSING` | не запущен tabular-parser (`curl localhost:8001/healthcheck`) или ядро запущено без `NATS_ENABLED=true`; без ack файл через ~2 мин станет `ERROR` | diff --git a/openspec/changes/nats-env-config/tasks.md b/openspec/changes/nats-env-config/tasks.md index 4f8d767..0719fba 100644 --- a/openspec/changes/nats-env-config/tasks.md +++ b/openspec/changes/nats-env-config/tasks.md @@ -17,10 +17,10 @@ ## 3. Документы контекста -- [ ] 3.1 `context/03-architecture.md`: subject'ы — настройки окружения (таблица потоков, NATS платформы), перечень +- [x] 3.1 `context/03-architecture.md`: subject'ы — настройки окружения (таблица потоков, NATS платформы), перечень секретов `OPENBAO__NATS__*` по сервисам, требование одинакового набора для всех трёх сервисов -- [ ] 3.2 `dev/README.md` (таблица переменных, `/healthcheck`, интеграционные тесты), `dev/.env.example`, +- [x] 3.2 `dev/README.md` (таблица переменных, `/healthcheck`, интеграционные тесты), `dev/.env.example`, `dev/contour-transfer-guide.md` (секреты окружения), `dev/qa-guide.md` и `dev/frontend-api-guide.md` (ответ `/healthcheck`, если описан), `repo-templates/*.CLAUDE.md` при упоминании констант subject'ов -- [ ] 3.3 `context/07-open-questions.md`: OQ-83 — интеграционные тесты `tabular-parser`/`scan-gateway` на своих +- [x] 3.3 `context/07-open-questions.md`: OQ-83 — интеграционные тесты `tabular-parser`/`scan-gateway` на своих subject'ах; для e2e ядра вопрос остаётся (общая queue group `arm-core`, design R-7)