Files
han-app/architectory/arch-05-agent-development-process.md
T

138 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# arch-05. Правила разработки модулей отдельными агентами
> Термины — в [`arch-00-glossary.md`](arch-00-glossary.md). Безопасность VM и production-деплоя — в [`arch-06-service-hosting-security.md`](arch-06-service-hosting-security.md). Настоящий документ описывает процесс разработки и не переопределяет архитектуру. Иерархия приоритета — в [`README.md`](README.md), раздел «Разрешение конфликтов».
## Цель
Этот документ задает единый процесс разработки, чтобы отдельные агенты создавали совместимые части приложения без расхождения архитектуры.
## Общие правила
- Каждый агент работает только в границах назначенного модуля.
- Перед разработкой агент читает [`README.md`](README.md), архитектурные документы и профильный документ назначенного модуля.
- Любое изменение публичного API сопровождается обновлением OpenAPI.
- Любое изменение структуры данных сопровождается миграцией.
- Все **бизнес-параметры** — в таблице `app_settings`; несекретная **infra** — в `.env`; production-секреты — только через механизм arch-06.
- Нельзя hardcode-ить телефоны, лимиты, тексты, mime types, feature flags и параметры Битрикс24.
- Модули, принимающие пользовательский ввод, должны учитывать rate limits и security/safety проверки.
## Размещение и production-деплой
- Изменение deployment, VM topology, network exposure, volumes, Linux capabilities, OS/sudo-прав или способа доставки секретов требует impact analysis по arch-06.
- Агент не добавляет `deploy` в группу `docker` и не расширяет sudo wildcard-командами. Новое право оформляется как конкретная операция над конкретным systemd-unit с review и rollback.
- Production compose, systemd-units, deploy scripts и secret mappings остаются root-owned и недоступны `deploy` на запись.
- Release содержит version-controlled manifest owner/group/mode; blanket
`F644` sync запрещён, executable scripts/hooks/preflight сохраняют `+x`.
- Изменение image digest повторяет runtime-проверки exact image: UID/GID,
entrypoint, writable paths, healthcheck binaries и one-shot init jobs.
- Изменение bind permissions, feature flag/edge allow-list, published ports
или systemd oneshot helper требует positive/negative production-like test,
а не только review YAML/shell.
- Для private/no-egress VM допустим временный bootstrap с SSH из trusted ops CIDR и ограниченным egress для пакетов/образов.
- Раскатка private/no-egress VM считается незавершённой, пока не выполнен lockdown: public ingress/SSH и общий egress закрыты, private access проверен, а недоступность снаружи зафиксирована.
- Повторное открытие ingress/egress после lockdown — документированная break-glass операция с обязательным возвратом в lockdown, а не штатный способ деплоя.
## Правила базы данных
- Перечень таблиц, полей, индексов и миграций **определяет модуль-владелец** (`database`, `api-backend`, `bitrix-sync`, `message-safety`, `bitrix-local-app`), а не arch-*.
- Архитектура фиксирует **разделение схем** и общие подходы к ведению баз данных, которые должны соблюдаться при проработке модулей.
- У каждой основной **прикладной** сущности должен быть `record_status`. Базовые статусы: `A` — active, `D` — deleted.
- `record_status` выражает только административное наличие строки. Доменное завершение (например `Notification.lifecycle_status='closed'`) хранится отдельно и не переводит запись в `D`.
- Физическое удаление строк прикладных сущностей запрещено. Если нужно удалить сущность, сервис меняет `record_status` с `A` на `D`.
- При смене статуса на `D` сервис обязан заполнить `status_changed_at` и `status_change_reason`.
- Все сервисы при чтении бизнес-данных по умолчанию запрашивают только `record_status = 'A'`.
- Исключения допускаются только для аудита, админки, технического восстановления и миграций.
- Прикладные сущности, имеют `id`, `created_at`, `updated_at`, `updater_user_id`.
- Системные таблицы (`app_settings`, `text_resources`, `popular_questions`, `sync_queue`, audit, справочники) могут использовать `user_id = NULL` или отдельное поле `actor_type` — по спецификации `module-01-api-backend` и migrations схемы `han_app`.
- Для **строковых enum из arch-00** (`Dialog.status`, `Message.safety_status`, `Message.delivery_status`, `sender_type`, `scan_status` и т.п.) справочник sequence **не** обязателен: значения фиксированы контрактом API.
- Для больших/изменяемых списков (типы документов post-MVP, причины, классификаторы UI) — справочники с ID (sequence) и расшифровкой.
- Для часто используемых фильтров добавляются индексы.
- Миграции не должны удалять данные без отдельного согласования.
- Все юзеры должны иметь ИД, которое указывается в `updater_user_id` которое они меняют.
- При создании миграций учитывать, что asyncpg допускает один top-level SQL statement на один execute.
## API
Правила:
- endpoint naming должен следовать `arch-02-api-contracts.md`;
- cross-VM contract test обязан запускать caller и callee как разные network zones: private DNS, verified internal CA, service token, timeout/circuit и запрет plaintext; Docker hostname вынесенного сервиса не считается валидным remote test;
- response schema не должна раскрывать внутренние поля;
- ошибки возвращаются в едином формате;
- для пользовательских данных всегда используется текущий user context из JWT;
- frontend не передает `client_profile_id` для доступа к своим данным;
- профиль в MVP не редактируется через `PATCH /me`;
- сообщения оператора должны приходить в frontend через realtime или polling fallback.
## Логирование и OTP
Каждый модуль должен:
- использовать общий формат JSON-логов из [`arch-07-observability.md`](arch-07-observability.md);
- добавлять `module`, `event`, `request_id`, `trace_id`;
- для `api-backend` добавлять **`ux_session_id`** в JSON-логи, если передан заголовок `X-Ux-Session-Id`;
- не логировать access token, refresh token, raw OTP, документы, полные PII;
- хранить факт отправки OTP через `provider_message_id`, `sent_at`, `destination_masked`, `otp_hash`, попытки и итог проверки.
Raw OTP запрещено хранить в открытом виде: это временный секрет. Доказательство отправки и проверки строится на аудите, delivery id провайдера и hash-проверке.
## Тесты
Минимум для каждого модуля:
- happy path;
- ошибки авторизации и доступа;
- rate limits, если модуль принимает пользовательский ввод;
- soft delete и фильтрация `record_status = 'A'`, если модуль работает с БД;
- idempotency, если операция может повториться;
- отсутствие секретов и PII в логах.
Дополнительно для модулей с async/worker:
- идемпотентность обработки задач очереди;
- поведение при повторной доставке webhook;
- таймауты и retry/backoff.
Для Notification Center обязательны contract tests каталога без ветвления по виду, бессрочной дедупликации `(source, external_id)`, изоляции producer tokens, TTL с сохранением существующего `date_expired`, первого скачивания любого связанного документа и открытия instruction только в новой вкладке.
## Definition of Done
Модуль считается готовым, если:
- реализованы сценарии из задачи;
- обновлен `{service}/openapi.yaml`, если менялся HTTP API;
- обновлены каталог ошибок в `arch-02` и contract tests, если менялась публичная или internal HTTP-семантика;
- созданы миграции, если менялась БД;
- обновлены seed `app_settings` и `.env.example`, если добавлялись настройки, service tokens, лимиты или feature flags;
- secret value не добавлен в `.env.example`; новый секрет включён только в runtime secret catalog и выдан минимальному набору сервисов;
- добавлены тесты;
- сервис запускается в root Docker Compose своей VM; CI отдельно валидирует оба projects и отсутствие cross-host `depends_on`/Docker DNS;
- remote Message Safety contract tests покрывают v2 `202 + Location + Retry-After`, sticky final result, terminal failed `503`, `409` invariant mapping и legacy v1 migration adapter;
- container проверен по arch-06: non-root, `no-new-privileges`, capabilities, read-only filesystem/writable paths, volumes, networks и resource limits;
- release manifest проверяет executable modes; bind files читаются реальным
container UID/GID, named volumes подготовлены ограниченным init-job;
- healthcheck выполнен внутри exact pinned digest, без несуществующих
вспомогательных binaries;
- published Docker ports проверены через live `DOCKER-USER` counters с учётом
DNAT; обновлённый active oneshot helper применён explicit restart;
- hooks/timers имеют корректный exit code и пустой stderr при успехе;
- feature flags, edge allow-lists и service readiness согласованы fail-closed;
- изменение embedded seed/schema выпущено как совместимая пара нового image
digest и новой монотонной config version с проверенным rollback;
- изменение прав `deploy`, systemd, network exposure, capabilities, volumes или secret delivery отражено в arch-06 и deployment runbook;
- для private/no-egress VM выполнен и зафиксирован bootstrap→lockdown checklist;
- worker, указанный в Compose/runbook, имеет реально зарегистрированный entrypoint в image; deployment не может заранее выдумывать имя команды;
- все изменяемые параметры вынесены из кода;
- логи содержат `request_id`, `trace_id` и **`ux_session_id`** (если передан в запросе);
- нет секретов, raw OTP и PII в логах;
- soft delete соблюден;
- агент указал, какие документы архитектуры были затронуты.
## Правила изменения архитектуры
Если агент видит, что текущая архитектура мешает задаче, он должен:
1. описать проблему;
2. предложить минимальное изменение;
3. указать затронутые документы;
4. не делать широкий рефакторинг без подтверждения.