From 4080a8ff18e918bccc223644378a53804d5ebe39 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Sat, 3 Oct 2026 22:39:49 +0400 Subject: [PATCH] =?UTF-8?q?docs:=20README.md=20=D0=BE=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=20arm-core=20=D0=B2=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=BE=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Назначение, предварительные требования (Python 3.11, uv, Docker), быстрый старт до зелёного /api/v1/me (make venv/up/migrate/seed-dev, dev-токен), таблица env, команды make, тесты, проверка ORM и DBML, миграции, раскладка репозитория, работа без Nexus, безопасность dev-режима, ссылки на соседние документы. Co-Authored-By: Claude Fable 5.1 --- README.md | 408 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 285 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index 6b8cbb1..1714fb9 100644 --- a/README.md +++ b/README.md @@ -1,163 +1,325 @@ -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) [![linting: pylint](https://img.shields.io/badge/linting-pylint-yellowgreen)](https://github.com/pylint-dev/pylint) -__________________________________________________________________________________________________________ -# dkb_armka, v 0.0.1 -____ +# arm-core — ядро АРМ КА -| | Исполнитель | Заказчик | -|-----------|:----------------------------------------:|:----------------------------------------------:| -| Сотрудник | raykov-mse | raykov-mse | -| Отдел | aurora | aurora | -| Контакты | raykovmse@rshb.ru | raykovmse@rshb.ru | ------ -# Шаблон FastAPI +Ядро автоматизированного рабочего места кредитного аналитика Департамента крупного бизнеса (АРМ КА, АО «Россельхозбанк»): +справочники, файлы и документы, приём результатов распознавания, вычисления консолидации (КФО ГСК), маршрут +согласования, Единое хранилище (ЕХ), аудит и права. **Единственный писатель в PostgreSQL**: сервисы распознавания +(`tabular-parser`, `scan-gateway`) видят только NATS и S3. -## Описание +Монорепозиторий по шаблону команды «Шаблон FastAPI»: `api/` — бэкенд (FastAPI, SQLAlchemy 2 async, Alembic, +PostgreSQL 16, core NATS без JetStream), `web/` — фронтенд (React + TypeScript, rsbuild). -Данное шаблон предоставляет проект, в котором приложение состоит из API и UI. При использовании данного типа проекта, Вы можете разрабатывать, как отдельные API сервисы, так и WEB приложения с интерфейсом. Для построения WEB интерфейса используется React. Далее описаны основные иснтрументы предустановленные данным шаблоном: +Этот репозиторий — часть workspace АРМ КА. Общий контекст, модель данных, правила предметной области и контракты — +в соседних репозиториях: -### Подготовка к разработке +- [`../CLAUDE.md`](../CLAUDE.md) — инварианты и процесс работы всего workspace; +- [`../docs/`](../docs/) — контекст (`context/`), модель данных (`model/`), контракты (`contracts/`), окружение (`dev/`); +- [`CLAUDE.md`](CLAUDE.md) — соглашения этого репозитория. -Для удобной настройки проекта под разработку. Перейдите в каталог setup и выполните слудеющие команды: +Срез 0 («скелет ядра»): схема БД по DBML v5.13, справочники (seed), аутентификация и права, `GET /api/v1/me`, +`/healthcheck`. Спецификация — `openspec/changes/slice-0-skeleton/`. + +## Предварительные требования + +- **Python 3.11** (версия платформы) и **[`uv`](https://docs.astral.sh/uv/)** — `make venv` создаёт окружение и ставит + зависимости через `uv`; без него цель не работает. Системный `python3` другой версии не подойдёт: `uv` сам подберёт + интерпретатор 3.11. +- **Docker** и compose v2 — для PostgreSQL, NATS и MinIO (compose лежит в `../docs/dev/`). +- **Node.js** и `npm` — только для `web/`. Для запуска бэкенда не нужны. +- `make`, `curl`. + +Репозитории workspace должны лежать рядом: `arm-core/` и `docs/` — соседние каталоги (так же устроено зеркало +`.wt/<срез>/`). Пути `../docs/...` ниже и в `Makefile` рассчитаны на это. + +## Быстрый старт + +Путь «с нуля до зелёного `/api/v1/me`». Команды `make` выполняются из корня репозитория. + +### 1. Виртуальное окружение ```bash -cd setup -chmod +x setup.sh -./setup.sh +make venv ``` - По итогу успешного выполнения Вы получите сообщение следующего + +Создаёт `api/.venv` (Python 3.11) и ставит `api/requirements.txt` и `api/requirements-dev.txt`. Пакеты `raisa_*` +из Nexus банка вне банка недоступны, поэтому цель пропускает строки `raisa_*` (подробнее — «Работа без Nexus»). +Повторный запуск безопасен. + +### 2. Инфраструктура (PostgreSQL, NATS, MinIO) + +Файл `.env` compose — отдельный от `api/.env`; он создаётся один раз и в git не попадает: ```bash -complete setup web application -To start api, cd to api directory, and use venv, start run_server.py -To start api, cd to web directory, and use command npm run start! -Happy Hacking! :) +cp ../docs/dev/.env.example ../docs/dev/.env +make up # docker compose -f ../docs/dev/docker-compose.yml up -d ``` -Далее просто запускайте проекты и приступайте к разработке +`make up` поднимает `postgres` (5432), `nats` (4222, мониторинг 8222), `minio` (9000, консоль 9001) и одноразовый +`minio-init`, который создаёт бакет `arm-ka` и завершается с кодом 0. Готовность — «healthy» у трёх долгоживущих +сервисов: `docker compose -f ../docs/dev/docker-compose.yml ps`. Для скриптов, которым нужно дождаться готовности: +`docker compose -f ../docs/dev/docker-compose.yml up -d --wait postgres nats minio` (голый `--wait` возвращает код 1 +из-за завершающегося `minio-init`). Подробности, смена портов, сброс — [`../docs/dev/README.md`](../docs/dev/README.md). -### Backend - -Исходный код API находится в каталоге api. После клонирования репозитория требуется создать виртуальное окружение и установить зависимости, это достигается следующими командами: +### 3. Настройки приложения ```bash -cd api -python -m venv ./.venv -cp ./../setup/pip.conf ./.venv/pip.conf -source ./.venv/bin/python -pip install -r requirements.txt +cp api/.env.example api/.env ``` -Запуск приложения осуществляется через файл: run_server.py +Значения из `api/.env.example` уже совпадают с `../docs/dev/.env.example` (стандартные порты и учётные данные compose), +менять ничего не нужно. Менять `api/.env` придётся, только если вы изменили порты или пароли в `../docs/dev/.env` +(правьте обе части). `api/.env` в git не попадает. -В качестве фреймворка ля api используется FastAPI. (Как понятно из названия шаблона) Подробнее ознакомится с возможностями Fast API вы можете в официальной документации: [Fast API документация](https://fastapi.tiangolo.com/) - -Вы можете дополнительно устанавливать библиотеки необходимые для разработки. Настоятельно не рекомендуется изменять базовые предустановки из файла requirements.txt - -Базовый шаблон предоставляет минимальный функционал по работе с данными. Далее описаны основные моменты влияющие на работу приложения. - -#### Основная структура проекта +### 4. Миграции и справочники ```bash -api -├── requirements.txt -├── run_server.py -├── src -│ ├── app.py -│ ├── __init__.py -│ ├── settings -│ │ ├── __init__.py -│ │ ├── models.py -│ │ └── settings.py -└── web +make migrate # alembic upgrade head: схема dkb, 27 enum-типов, 43 таблицы +make seed-dev # справочники продукта + dev-пользователи (по одному на каждую роль) ``` -Вы можете придерживатся любой структуры проекта, главное, чтобы у Вас присутствовал файл run_server.py. Который запускает web сервер uvicorn или gunicorn. Также обязательно Ваш сервер должен подниматся на определенном хосте и порте. Требуемый хост и порт передаются внутрь через переменные окружения SERVER_HOST, SERVER_PORT +`make seed` загружает только справочники (роли, права, филиалы, план счетов, правила элиминации, чек-лист), без +dev-пользователей. Seed идемпотентен: повторный запуск обновляет данные и ничего не дублирует. -```python -uvicorn.run( - app, - host=settings.server.HOST, - port=settings.server.PORT, - lifespan="on" - ) -``` - -#### Отказ от ui (react) - -Если внутри вашего приложения не требуется добавлять визуальный интерфейс, а Вам требуется исключительно разработать API, то в таком случае не стоит удалять директорию web находящуюся на уровне с директорией api. ТРебуется внести небольшие правки в конфигурацию приложения, в частности в файл: /api/src/app.py, удалив следующее содержимое. В таком случае Fast API сервис не будет обрабатывать статические файлы, от web приложения. - -```python -#Подключение собранного web приложения -app.mount("/", StaticFiles(directory="web", html=True), name="web") -``` - -### Frontend - -Исходный код UI находится в каталоге web. После клонирования репозитория требуется установить зависимости, это достигается следующими командами: +### 5. Запуск ```bash -cd web -npm install +cd api && .venv/bin/python run_server.py ``` -Запуск приложения осуществляется через файл команду: +Сервер слушает `0.0.0.0:8000` (`SERVER__HOST`, `SERVER__PORT`). Дальнейшие команды — из другого терминала. + +### 6. Проверка ```bash -npm run start +curl -s localhost:8000/healthcheck ``` -В качестве фреймворка для ui используется React. Подробнее ознакомится с возможностями React вы можете в официальной документации: [React документация](https://react.dev/reference/react) +```json +{"uptime":"2026-10-03T18:37:15.121394+00:00","version":"1.0.0","nats":"ok"} +``` -Вы можете дополнительно устанавливать библиотеки необходимые для разработки. Настоятельно не рекомендуется изменять базовые предустановки из файла package.json +`nats`: `ok` — подключён, `down` — включён (`NATS_ENABLED=true`), но связи нет, `off` — выключен. -Базовый шаблон предоставляет минимальный интерфейс по работе с данными. Далее описаны основные моменты влияющие на работу web приложения. - -#### Основная структура проекта +Dev-токен по email любого dev-пользователя и профиль текущего пользователя: ```bash -web -├── biome.json -├── .npmrc -├── dist -├── package.json -├── postcss.config.cjs -├── public -│ └── index.html -├── README.md -├── rsbuild.config.ts -├── src -│ ├── App.tsx -│ ├── config.ts -│ ├── env.d.ts -│ ├── index.css -│ └── index.tsx -├── tailwind.config.js -└── tsconfig.json +curl -s -X POST localhost:8000/api/v1/dev/token \ + -H 'Content-Type: application/json' \ + -d '{"email":"ka_rf@armka.local"}' +# {"access_token":"","token_type":"bearer"} + +curl -s localhost:8000/api/v1/me -H "Authorization: Bearer " ``` -Вы можете придерживатся любой структуры проекта, внутри src. Но на верхнем уровне находятся файлы конфигурации и сборки их требуется изменять только в крайнем случае. Для сборки приложения используется [RSBuild](https://rsbuild.dev/) - -Для создания UI настоятельно рекомендуется использовать предустановленную библиотеку компонентови стилей: - -- tailwindcss -- daisy-ui -- react-daisy-ui -- raisa-ui - -!!! Важно, если внутри web приложения Вы хотите обращатся к API данного проекта, используйте следующую конструкцию: - -```javascript - -fetch(`${Config.API_URL}/api`, { - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - method: 'GET' -}) - +```json +{ + "id": "b8d7595a-787f-4bcb-8e93-7612cc8afba3", + "email": "ka_rf@armka.local", + "full_name": "Dev: Аналитик РФ", + "regional_office": { + "id": "3b38e823-e09a-47ce-a296-061948a200b0", + "name": "Ростовский региональный филиал", + "is_head_office": false + }, + "business_segment": "DKB", + "roles": ["KA_RF"], + "permissions": [ + "CONSOLIDATION_EDIT", "CONSOLIDATION_VIEW", "DIRECTORY_EDIT", "DIRECTORY_VIEW", "DOCUMENT_EDIT", + "DOCUMENT_VIEW", "EXPORT", "EX_VIEW", "KFO_EXPORT", "KFO_VIEW" + ] +} ``` -Речь идет об вызываемом эндпоинте ${Config.API_URL}/api, Обязательно используйте конструкцию данного вида т.к. при сборке приложения статический сайт обращается относительно api и вместо -запросов вида http://localhost:8000/api должно быть так: /api +(идентификаторы в вашей БД будут другими). Токен действует 8 часов. Интерактивная документация API — `/docs` +(Swagger UI), схема — `/openapi.json`. +Dev-пользователи (`api/seed/dev/users.yaml`, создаются `make seed-dev`): + +| Email | Роль | Филиал | +|---|---|---| +| `ka_rf@armka.local` | `KA_RF` | Ростовский региональный филиал | +| `rka@armka.local` | `RKA` | Ростовский региональный филиал | +| `client_manager@armka.local` | `CLIENT_MANAGER` | Краснодарский региональный филиал | +| `ka_go@armka.local` | `KA_GO` | Головной офис | +| `curator_go@armka.local` | `CURATOR_GO` | Головной офис | +| `expert@armka.local` | `EXPERT` | Головной офис | +| `admin@armka.local` | `ADMIN` | Головной офис | + +Права не зашиты в код роли: `effective_permissions(user)` — объединение прав ролей пользователя (таблицы `permission`, +`role_permission`). + +### Что вы увидите в логе при запуске + +- Предупреждение «Включён dev-эмитент токенов … только для разработки» — штатно (см. «Безопасность dev-режима»). +- Трейсбэк `ClientConnectorSSLError ... localhost:9000` при проверке бакета MinIO. Клиент S3 из шаблона ходит по + `https`, а MinIO из compose слушает `http`. Приложение стартует и работает, S3 в Срезе 0 не используется + (`app.state.storage` остаётся пустым). Недоступность S3 или NATS при старте приложение не роняет: ошибка логируется, + а состояние NATS видно в `/healthcheck`. + +### Остановка и сброс + +```bash +docker compose -f ../docs/dev/docker-compose.yml down # остановить, данные (тома) сохраняются +docker compose -f ../docs/dev/docker-compose.yml down -v # полный сброс: БД и бакет с нуля (затем снова migrate и seed-dev) +``` + +Имя проекта compose фиксировано (`arm-ka`), тома общие для всех worktree. + +## Конфигурация + +Настройки — pydantic-settings; читаются из переменных окружения и файла `api/.env`. Вложенные настройки +разделяются `__`. Файл окружения выбирается переменной `ENV_FILE` (по умолчанию `.env`, путь относительно текущего +каталога — `api/`; значение читается при импорте). Тесты используют `api/.env.test` (`pytest.ini`). +Полный пример — `api/.env.example`. + +| Переменная | По умолчанию | Назначение | +|---|---|---| +| `ENV_FILE` | `.env` | файл окружения (относительно `api/`) | +| `DEBUG` | `false` | режим разработки. `true` необходим dev-эмитенту токенов; при `false` пакеты РАИСА подгружаются условно | +| `SERVER__HOST`, `SERVER__PORT` | `0.0.0.0`, `8000` | адрес и порт сервера (`run_server.py`) | +| `ROOT_PATH` | `/` | корневой путь за прокси (должен совпадать с `REACT_APP_ROOT_PATH` фронта) | +| `VERSION` | `1.0.0` | версия в `/healthcheck` и OpenAPI | +| `OPENBAO__DATABASE__DATABASE_URL` | — (обязательно) | PostgreSQL, драйвер asyncpg: `postgresql+asyncpg://armka:armka@localhost:5432/armka` | +| `OPENBAO__MINIO__MINIO_URL` | — (обязательно) | адрес MinIO без схемы (`host:port`, так ждёт `miniopy-async`) | +| `OPENBAO__MINIO__MINIO_ADMIN_LOGIN`, `..._PASSWORD`, `..._BUCKET` | — (обязательно) | учётные данные и бакет MinIO | +| `OPENBAO__NATS__NATS_URL` | — (обязательно) | адрес NATS (`nats://localhost:4222`) | +| `OPENBAO__NATS__NATS_SEED`, `OPENBAO__NATS__NATS_JWT` | пусто | nkeys; пусто — подключение без учётных данных (compose, тесты). Задаются оба или ни одного | +| `OPENBAO__SMB__SMB_HOST`, `SMB_PATH`, `SMB_LOGIN`, `SMB_PASSWORD` | — (обязательно) | заглушки SMB (в Срезе 0 не используется, блок обязателен) | +| `NATS_ENABLED` | `false` | подключение к NATS и обмен через `recognition_job`; без него `/healthcheck` показывает `nats=off` | +| `OUTBOX_POLL_SECONDS` | `5` | период опроса outbox | +| `ACK_TIMEOUT_SECONDS` | `30` | ожидание ack сервиса распознавания до повторной публикации | +| `OUTBOX_MAX_REPUBLISH` | `3` | число повторных публикаций до перевода в `dlq` | +| `AUTH_DEV_ISSUER` | `false` | dev-эмитент токенов: работает **только** при `AUTH_DEV_ISSUER=true` **и** `DEBUG=true` | +| `AUTH_DEV_SECRET` | пусто | секрет HS256 dev-эмитента (не короче 32 байт); только для разработки | +| `AUTH_JWKS_URL` или `AUTH_PUBLIC_KEY` | пусто | проверка токенов РАИСА: JWKS по URL либо публичный ключ (PEM) | +| `AUTH_ISSUER`, `AUTH_AUDIENCE` | пусто | проверка `iss` и `aud` токена РАИСА | +| `AUTH_EMAIL_CLAIM` | `email` | claim токена с email пользователя (сопоставляется с `app_user.email`) | + +Параметры JWT РАИСА (алгоритм, claim, эмитент) пока неизвестны — это открытый вопрос +([`../docs/context/07-open-questions.md`](../docs/context/07-open-questions.md)); `AUTH_JWKS_URL`/`AUTH_PUBLIC_KEY` +и связанные поля — каркас под него. Если не настроено ни dev-эмитента, ни ключей РАИСА, токены не принимаются вовсе +(`/me` отвечает 401). + +Порты по умолчанию: приложение 8000; compose — PostgreSQL 5432, NATS 4222 (мониторинг 8222), MinIO 9000 (консоль 9001). +Порты compose меняются в `../docs/dev/.env`, тогда же — соответствующие `OPENBAO__*` в `api/.env`. + +## Команды `make` + +Все цели выполняются из корня репозитория (сами переходят в `api/`). + +| Цель | Что делает | +|---|---| +| `make venv` | `api/.venv` на Python 3.11 через `uv`, зависимости без `raisa_*` | +| `make up` | поднимает compose из `../docs/dev` (PostgreSQL, NATS, MinIO, бакет) | +| `make migrate` | `alembic upgrade head` на БД из `api/.env` | +| `make seed` | загрузка справочников продукта (идемпотентна) | +| `make seed-dev` | то же и dev-пользователи/филиалы (`--dev`) — только для разработки | +| `make lint` | `ruff check`, `ruff format --check`, `mypy src scripts` | +| `make test` | юнит-тесты: `pytest -m "not integration"`, Docker не нужен | +| `make test-integration` | интеграционные тесты: `pytest -m integration`, нужны PostgreSQL (и NATS) | +| `make dbml-check` | сверка ORM с `../docs/model/data-model-v5.13.dbml` | +| `make migration-cycle` | миграции на временной БД: `upgrade head` → `downgrade base` → `upgrade head`, пустой autogenerate | +| `make check` | быстрая проверка без Docker: `lint` + `test` | +| `make check-full` | `check` + `dbml-check` + `test-integration`; выполняется перед PR (нужна поднятая инфраструктура) | + +`make check-full` пока не включает проверки фронта, OpenAPI и откат миграций отдельным шагом (задача 25 среза). + +### Тесты + +- **Юнит-тесты** (`make test`) не обращаются ни к БД, ни к NATS, Docker не нужен. +- **Интеграционные** (`make test-integration`) требуют PostgreSQL, тесты обмена через NATS — ещё и NATS. Рабочую БД + `armka` они не трогают: на каждую сессию pytest создаётся свежая БД `armcore_pytest_`, мигрируется `alembic` + и удаляется в конце. Параметры подключения берутся из `api/.env.test` (`pytest.ini` задаёт `ENV_FILE=.env.test`). + Сейчас этот файл указывает на временную тестовую инфраструктуру (PostgreSQL `55432`, NATS `54222`, MinIO `59000`), + а не на стандартные порты compose: чтобы гонять интеграционные тесты против `make up`, поправьте порты в + `api/.env.test` на `5432`, `4222`, `9000` (не коммитьте это изменение без согласования). +- **Реальные данные** — репозиторий `../fixtures/` (путь можно задать переменной `ARM_KA_FIXTURES`). Тесты с маркером + `fixtures` без каталога пропускаются с понятной причиной. + +### Проверка ORM и DBML + +Модель данных — `../docs/model/data-model-v5.13.dbml`. ORM обязана совпадать с ней один в один: + +```bash +make dbml-check # пустой вывод и код 0 — совпадение; расхождения печатаются построчно +``` + +Другой путь к DBML: `make dbml-check DBML=<путь относительно api/>`. + +### Миграции + +```bash +make migrate # применить: alembic upgrade head +cd api && .venv/bin/alembic downgrade base # откатить до пустой БД +make migration-cycle # проверить цикл upgrade -> downgrade -> upgrade на временной БД +``` + +Ревизии лежат в `api/alembic/versions/`; автогенерация — только черновик, финал сверяется с DBML (`make dbml-check`). + +## Раскладка репозитория + +``` +api/ + run_server.py точка входа (uvicorn; хост и порт — из настроек) + alembic/ миграции (versions/0001_dbml_v5_13.py — вся модель v5.13) + seed/core/ справочники продукта (роли, права, филиалы, план счетов, правила элиминации, чек-лист) + seed/dev/ dev-данные: филиалы и пользователи по ролям + scripts/ check_dbml_vs_orm.py (ORM <-> DBML), seed.py и seed_lib/ (загрузчик справочников) + src/ + app.py FastAPI-приложение: lifespan (S3, NATS, SMB), /healthcheck, раздача SPA + api/endpoints/ эндпоинты (me.py, dev_auth.py); router.py собирает /api/v1 + api/dependencies/ зависимости FastAPI (current_user, проверка прав) + core/ config, auth (JWT), clients (S3), nats_callback, logger, exception_handlers + db/ движок и сессия (схема dkb) + models/ ORM-модели, 1:1 с DBML + repositories/ доступ к данным + schemas/ pydantic-схемы запросов и ответов + services/ бизнес-логика + common/ исключения + domain/ (появится) чистые функции по §§ правил предметной области, без ORM + tests/ pytest (юнит и integration/fixtures по маркерам) +web/ фронтенд (React 18 + TypeScript, rsbuild, antd); сборка web/dist -> api/web/ +setup/ бутстрап шаблона через Nexus банка (pip.conf, setup.sh) +openspec/ спецификации и изменения (OpenSpec) +docs/superpowers/ планы реализации +raisa_config.yml ресурсы для платформы +Dockerfile только для локального compose +``` + +Слои: `src/api/endpoints` → `services` → `repositories` → `models`. + +## Работа без Nexus + +Пакеты `raisa_*` (Python) и `raisa-*` (npm) лежат в Nexus банка и вне банка недоступны. Что с этим сделано: + +- `make venv` ставит `requirements.txt` без строк `raisa_*` (фильтр `grep -v '^raisa_'`) и поэтому требует `uv`, а не + `setup/setup.sh` (тот рассчитан на `pip.conf` с Nexus). +- Код импортирует `raisa_*` условно: пакет middleware РАИСА импортируется только при `DEBUG=false`, и `ImportError` + допустим — приложение работает без него. Аутентификация Среза 0 — собственная проверка JWT + (`api/src/core/auth.py`). +- В `web/package.json` пакеты `raisa-*` вынесены в `optionalDependencies`: `npm install` не падает, если Nexus + недоступен. Файл `.npmrc` с адресом реестра (см. `setup/setup.sh`) вне банка не нужен. + +## Безопасность dev-режима + +- `POST /api/v1/dev/token` выдаёт токен **любому**, кто знает email существующего активного пользователя: пароля нет. + Только для локальной разработки и тестовых стендов. +- Маршрут существует лишь при `AUTH_DEV_ISSUER=true` **и** `DEBUG=true`; при любом другом сочетании его нет вовсе + (404), а dev-проверяющий токенов не создаётся даже при заданном `AUTH_DEV_SECRET`. В проде `DEBUG=false`, поэтому + dev-эмитент там невозможен. +- `AUTH_DEV_SECRET` из `api/.env.example` — публичный пример, в проде не использовать. `make seed-dev` в прод не + запускать. +- Порты compose по умолчанию публикуются только на `127.0.0.1` (`BIND_ADDR`); пароли `armka`/`minioadmin` — только dev. + +## Соседние документы + +- [`CLAUDE.md`](CLAUDE.md) — соглашения этого репозитория; +- [`../CLAUDE.md`](../CLAUDE.md) — workspace: инварианты, источники истины, процесс; +- [`../docs/dev/README.md`](../docs/dev/README.md) — окружение разработки (compose), порты, типичные проблемы; +- [`../docs/context/03-architecture.md`](../docs/context/03-architecture.md) — архитектура, соглашения шаблона, NATS и S3; +- [`../docs/context/04-data-model-guide.md`](../docs/context/04-data-model-guide.md) и + [`../docs/model/data-model-v5.13.dbml`](../docs/model/data-model-v5.13.dbml) — модель данных; +- [`../docs/context/05-domain-rules.md`](../docs/context/05-domain-rules.md) — алгоритмы предметной области; +- [`../docs/context/07-open-questions.md`](../docs/context/07-open-questions.md) — открытые вопросы; +- [`../docs/context/09-delivery-plan.md`](../docs/context/09-delivery-plan.md) — план срезов; +- [`../docs/contracts/`](../docs/contracts/) — JSON-схемы обмена с сервисами распознавания; +- `openspec/changes/slice-0-skeleton/` — спецификация и решения Среза 0.