# arch-00. Глоссарий и единый словарь терминов ## Назначение Канонические **имена** сущностей, полей, идентификаторов, enum-значений, бакетов S3, env-переменных и терминов проекта. При расхождении имён приоритет у настоящего словаря. ## Bucket Selectel S3 | Логическое имя | env-переменная | Пример физического бакета | |---|---|---| | **S3-quarantine** | `SELECTEL_S3_BUCKET_QUARANTINE` | `han-chat-quarantine` | | **S3-data** (attachments) | `SELECTEL_S3_BUCKET_ATTACHMENTS` | `han-chat-attachments` | | **S3-data** (documents) | `SELECTEL_S3_BUCKET_DOCUMENTS` | `han-chat-documents` | В тексте: **S3-quarantine** — временное хранилище до вердикта Message Safety; **S3-data** — проверенные файлы (attachments и documents — два физических бакета). ## Сущности App DB (основные) | Имя | Схема | Назначение (кратко) | |---|---|---| | `UserIdentity` | `han_app` | Локальный пользователь, связь с Keycloak | | `UxSession` | `han_app` | Аналитическая UX-сессия (период активности пользователя) | | `UserConsent` | `han_app` | Запись о принятии согласий (после OTP, привязка к `user_id`) | | `ClientProfile` | `han_app` | Кэш профиля для UI | | `Dialog` | `han_app` | Диалог клиента с Open Lines | | `Message` | `han_app` | Сообщение в диалоге | | `MessageAttachment` | `han_app` | Вложение к сообщению | | `sync_queue` | `han_app` | Durable очередь бизнес-намерений App → Bitrix24 с lease/fencing | | `safety_tasks` | `han_app` | Checkpoint sync-wait Message Safety (`task_id`) для recovery | | `app_settings` | `han_app` | Бизнес-настройки | | `text_resources` | `han_app` | Тексты UI по мнемоникам | | `popular_questions` | `han_app` | Популярные вопросы главного экрана | | `Notification` / `GuestNotification` | `han_app` | Персональное уведомление / общая гостевая кампания | | `NotificationType` | `han_app` | Вид уведомления как данные: контур, приоритет, CTA, кнопки и оформление | | `NotificationCtaAction` / `NotificationButton` / `NotificationColorToken` | `han_app` | Реестры реализованных механик CTA, кнопок и семантической палитры | | `NotificationSource` | `han_app` | Продюсер Internal Notifications API; хранит hash индивидуального токена, не секрет | | `ClientDocument` | `han_app` | Отправленный клиентом проверенный документ; создаёт `document.client_uploaded` в `sync_queue` | | `dialog_sessions` | `bitrix_local` | Маппинг чата Open Lines | | `entity_external_mapping` | `bitrix_sync` | Каноническая active/closed/broken история `user_id` ↔ Bitrix Contact | | `workflow_instances` / `crm_commands` | `bitrix_sync` | Persisted сценарии CRM sync и конкретные Bitrix batch subcommands | | `webhook_inbox` | `bitrix_sync` | Durable inbox событий Contact/smart process от Битрикс24 | | `business_alerts` | `bitrix_sync` | Локальное состояние конфликтов, связанных со smart process Битрикс24 | | `sms_template` | `sms` | Версионируемый согласованный SMS-шаблон; active-версия уникальна для `code`+`channel`+`locale` | | `sms_setting` | `sms` | Технические runtime-настройки `sms-service`, не секреты и не OTP product settings | | `sms_outbound_message` | `sms` | Бессрочный журнал заказа, отправки и доставки SMS; источник истины provider status | ## Идентификаторы | Имя | Где используется | |---|---| | `dialog_id` | UUID диалога в приложении; **равен** `external_chat_id` в Open Lines | | `external_chat_id` | Идентификатор чата для `bitrix-local-app` / `imconnector` | | `keycloak_sub` | Subject JWT Keycloak (`sub`); ключ `UserIdentity` | | `phone_number` | Auth-телефон пользователя; master — Keycloak; в App DB пишется из JWT claims при `bootstrap`, не из body клиента | | `guest_session_id` | Опциональный локальный UUID на устройстве (UI); **не** auth и **не** открывает write API | | `ux_session_id` | UUID **аналитической UX-сессии**; заголовок `X-Ux-Session-Id` | | `b24_id` | ID Contact в Bitrix24 CRM; хранится только в schema `bitrix_sync` | | `bitrix_chat_id` | ID чата Open Lines в Bitrix24 | | `session_id` | ID сессии Open Lines (поле `dialog_sessions`; не путать с `ux_session_id`) | | `task_id` | ID async-проверки Message Safety | | `request_id` | Корреляция HTTP-запроса (заголовок `X-Request-ID`) | | `sms_message_id` | UUID `sms.sms_outbound_message.id`; логическая ссылка из Keycloak challenge/event, межсхемного FK нет | | `notification_id` | UUID v7 персонального или гостевого уведомления; генерирует приложение/seed | | `external_id` уведомления | Бессрочный бизнес-ключ продюсера в паре с `source` | | `provider_message_id` | `messageUuid` i-Digital Direct; хранится только в `sms-service` | | `provider_external_id` | `externalMessageId`; в v1 равен `sms_message_id` и является корреляцией, а не доказанной идемпотентностью Direct | Публичные id сущностей — **UUID**. ## `UxSession` (аналитическая UX-сессия) ### Определение **`UxSession`** — период **непрерывной активности** пользователя в приложении (web / iOS / Android) для **аналитики** и **сквозной корреляции** логов и событий. - Идентификатор периода — **`ux_session_id`** (UUID). - Начало периода фиксируется событием **`session_start`** (**ровно один раз** на период). - Запись создаётся в App DB при `POST /api/v1/analytics/session-start` (**только с JWT**, см. arch-02). - Frontend передаёт **`X-Ux-Session-Id`** во всех JWT-запросах к backend, пока сессия активна. **`UxSession` не является механизмом авторизации.** Отсутствие или неизвестный `ux_session_id` **не** блокирует API (кроме endpoint, где id обязателен по контракту). Сам endpoint `session-start` без JWT недоступен. ### Когда начинается **новая** `UxSession` Новый **`ux_session_id`** + событие **`session_start`** — **только** если: 1. **`first_launch`** — приложение открыто, в памяти **нет** `ux_session_id`. 2. **`cold_start`** — после kill app или закрытия вкладки браузера (память очищена). 3. **`idle_timeout`** — возврат спустя **более N минут** (`ux.session.idle_timeout_minutes` в `app_settings`, default **30**). ### Когда **та же** `UxSession` продолжается - возврат из фона **в пределах** idle timeout (напр. через 5 минут — **без** нового `session_start`); - успешный refresh access token, если `ux_session_id` уже создан и idle timeout не превышен; - успешный OTP внутри уже активной UX-сессии, если повторная авторизация не очистила память приложения; - навигация между экранами внутри приложения. При первом JWT-входе после гостевого режима или после cold start, когда в памяти нет активного `ux_session_id`, frontend создаёт новую UX-сессию через `POST /api/v1/analytics/session-start`. ## `Dialog.status` | Значение | Смысл | |---|---| | `open` | Диалог создан, сообщений ещё нет (сразу после `POST /dialogs`) | | `waiting_for_company` | Последнее значимое событие — исходящее от клиента; ждём оператора | | `waiting_for_client` | Последнее значимое событие — входящее от оператора; ждём клиента | | `closed` | Диалог закрыт в Open Lines (`dialog.closed` / `ONIMCONNECTORDIALOGFINISH`) | Переходы задаёт `api-backend` (см. arch-01, потоки чата). Значения — **строковые enum** в API и App DB (не sequence-справочник). ## `Message` — enum и поля | Имя | Допустимые значения | |---|---| | `Message.sender_type` | `client`, `company` | | `Message.safety_status` | `pending`, `allowed`, `blocked` (`needs_review` — зарезервирован, MVP не используется) | | `Message.safety_processing_mode` | `standard`, `mock`; internal/audit field, не public DTO | | `Message.safety_config_version` | версия service-owned Message Safety config, internal/audit field | | `Message.delivery_status` | `accepted`, `processing`, `delivered`, `rejected`, `failed` | | `Message.text` | текст сообщения; пустая строка для файлового сообщения | | `content_kind` (логическое) | `text`, `file` — тип исходящего сообщения клиента (MVP) | Семантика `allow` / `deny` / `pending` в target Message Safety v2: `200` / `403` / `202 Accepted`; internal `202` скрыт api-backend от public API. `/internal/safety/v1/*`, `203` и `stub_final_error` — только legacy test stub до cutover. Полный контракт — [`arch-02-api-contracts.md`](arch-02-api-contracts.md). ### `Message.delivery_status` (смысл) | Значение | Когда | |---|---| | `accepted` | Сообщение принято API, safety ещё не завершена или только начата | | `processing` | Внутренний/transient на время sync-wait safety; клиенту на `POST .../messages` не отдаётся как финальный ответ | | `delivered` | Финальный `allow`, сообщение ушло в Open Lines (или входящее от оператора сохранено) | | `rejected` | Финальный `deny` от Message Safety | | `failed` | Инфраструктурная ошибка доставки (Bitrix/S3), не safety-deny | Realtime-событие `message.status` передаёт актуальные `safety_status` и/или `delivery_status`. ## `MessageAttachment.scan_status` | Значение | Смысл | |---|---| | `pending` | Файл в S3-quarantine, проверка не завершена | | `clean` | Проверка завершена, allow | | `bypassed` | Forced allow в emergency MOCK; файл не проверялся | | `infected` | Проверка завершена, deny | | `failed` | Ошибка инфраструктуры проверки | ## Строковые enum vs справочники - **Строковые enum** (значения в API/контрактах): `Dialog.status`, `Message.sender_type`, `Message.safety_status`, `Message.delivery_status`, `MessageAttachment.scan_status`, `content_kind`, `start_reason`, SMS `send_status`, SMS `delivery_status`, OTP `challenge_status`. - **Справочники (sequence ID)** — для больших/изменяемых списков UI и доменных классификаторов (типы документов post-MVP, причины и т.п.); правило — [`arch-05-agent-development-process.md`](arch-05-agent-development-process.md). ### SMS и OTP статусы - `sms_outbound_message.send_status`: `pending`, `accepted`, `rejected`, `failed`, `uncertain`, `skipped`. - `sms_outbound_message.delivery_status`: `unknown`, `sent`, `delivered`, `undelivered`, `unsent`. - `han_otp_challenge.challenge_status`: `ordering`, `active`, `consumed`, `superseded`, `expired`, `limited`, `order_failed`. - Provider statuses принадлежат только `sms-service`: Keycloak не читает их и не использует для verify. ## Мнемоники internal API Default-префикс: **`/internal/{service_mnemonic}/v1/`**. Approved exception: target Message Safety использует **`/internal/safety/v2/`**; `/v1` остаётся legacy stub до cutover. Health: **`/health/*`**. | `{service_mnemonic}` | Сервис | |---|---| | `safety` | `message-safety` | | `openlines` | `bitrix-local-app`, приёмник inbox на `api-backend` | | `sync` | `bitrix-sync` | | `settings` | internal settings bridge на `api-backend` для Keycloak SPI | | `sms` | `sms-service`; durable order/read API во внутренней сети | | `notifications` | Internal Create/Cancel уведомлений на `api-backend`; токен отдельный для каждого `source` | Public safety deny: internal `403 reason_code=message_blocked` → public `422 message_blocked`; `rule_id` не раскрывается. Generic company-текст берётся из `text_resources` по мнемонике `safety.chat.blocked`. ## Жизненный цикл уведомления - `lifecycle_status`: `active` / `closed`; бизнес-завершение, не soft delete. - `visibility`: `visible` / `hidden`; скрытое персональное уведомление отсутствует на главной, но остаётся в Центре, пока активно. - `close_reason`: `user_done`, `docs_submitted`, `offer_accepted`, `paid`, `expired`, `cancelled`. - `record_status='D'` означает только административное удаление ошибочной записи и не заменяет `lifecycle_status`. - `cta_action` и эффекты кнопок определяются справочниками; новый вид на существующих механиках добавляется данными. ## SMS-конфигурация - Product OTP settings: `otp.phone.code_length`, `otp.phone.ttl_seconds`, `otp.phone.sms_order_timeout_ms` и лимиты — `han_app.app_settings`, выдаются Keycloak через settings bridge. - Runtime SMS settings: `provider.idgtl.*` и `worker.*` — `sms.sms_setting`. - Infra/secrets env: `KEYCLOAK_SMS_SERVICE_URL`, `SMS_DATABASE_URL`, парные `KEYCLOAK_SMS_SERVICE_TOKEN`/`SMS_SERVICE_TOKEN`, `IDGTL_SMS_BASE_URL`, `IDGTL_SMS_API_KEY`, `IDGTL_SMS_CALLBACK_PUBLIC_URL`, `IDGTL_SMS_CALLBACK_USERNAME`, `IDGTL_SMS_CALLBACK_PASSWORD`. - Текст, placeholders и sender template не хранятся в env: они принадлежат `sms_template`; default sender — `sms_setting`. ## Bitrix24 Open Lines | Имя | Значение | |---|---| | `BITRIX_CONNECTOR_ID` / connector | `han_mobile_app` | | `BITRIX_OPEN_LINE_ID` | `8` | | Канонический URL коннектора | `https://han0107.bitrix24.ru/contact_center/connector/?ID=han_mobile_app&LINE=8` | ## Термины чата | Термин | `Message.sender_type` / направление | |---|---| | клиент | `client`; исходящее сообщение | | оператор | `company`; входящее сообщение | | сообщение пользователя | исходящее; проверяет Message Safety |