Files
han-app/architectory/arch-00-glossary.md
T

206 lines
17 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-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` | Получен финальный `allow`, сообщение и durable-намерение доставки зафиксированы, но Open Lines ещё не подтвердил приём |
| `processing` | Сообщение принято API, Safety ещё выполняется (включая sync-wait `202 pending`); клиенту на `POST .../messages` не отдаётся как финальный ответ |
| `delivered` | Финальный `allow`, сообщение ушло в Open Lines (или входящее от оператора сохранено) |
| `rejected` | Финальный `deny` от Message Safety |
| `failed` | Инфраструктурная ошибка доставки (Bitrix/S3), не safety-deny |
Для исходящего сообщения успешный lifecycle строго следует порядку: Safety `allow``accepted` → приём в Open Lines → `delivered`. Статус `accepted` не означает незавершённую Safety-проверку.
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 |