diff --git a/backlog.md b/backlog.md
index c117631..0b2c434 100644
--- a/backlog.md
+++ b/backlog.md
@@ -5,12 +5,12 @@
~~4. Добавить параметр, ограничивающих кол-во неуспешных попыток ввода смс.~~
~~5. Поправить чтение сообщений от Битрикса. Сейчас они выглядят так: "[b]Антон Пичугин:[/b] [br]опять ты?" Надо убрать из текста сообщения Отправителя в битриксе~~
6. Кнопка "Войти" для авторизации
-7. Если неавторизованный пользователь вводит сообщение, после отправки идет на регистрацию, после окончания регистрации его сообщение пропадает. Надо чтобы сохранялось и отправлялось (по аналогии с нажатием на кнопку из раздела "Популярные вопросы")
+~~7. Если неавторизованный пользователь вводит сообщение, после отправки идет на регистрацию, после окончания регистрации его сообщение пропадает. Надо чтобы сохранялось и отправлялось (по аналогии с нажатием на кнопку из раздела "Популярные вопросы")~~
~~8. Изменение в БД по аудитам (заполнение IP, сквозное заполнение UserSession)~~
9. Кнопка "Позвонить оператору" (ссылка tel:+74999591007)
10. Отправлять на UI информацию разные ошибки при попытках авторизации в зависимости от события: код неверен, истёк или уже использован, превышен лимит попыток авторизации, попробуйте через 24 часа (в случаях превышения otp.phone.max_send_attempts_per_24h), превышен лимит неуспешных авторизаций, начните процедуру заново (в случае превышения otp.phone.max_verify_attempts).
11. После интеграции с смс провайдером, реализовать debounce механизм при авторизации - каждая след. смс можно отправить через все большее окно.
-12. Яндекс.капчу добавить
+~~12. Яндекс.капчу добавить~~
13. На экране профиля в гостевом режиме добавить "Авторизоваться"
14. Проверить повторную отправку СМС (меня перенесло на главный экран)
15. При выходе из профиля надо бы сбрасывать cookies Keycloack (Классический OIDC front-channel logout (redirect на end-session → браузер сам сбрасывает cookies Keycloak))
@@ -19,6 +19,9 @@
~~18. При повторном запросе OTP кода при авторизации не нужно указывать ошибку "Новый код заказан. Предыдущий код больше не действует."~~
19. Хранить историю устройств, с которых пользователь входил в ЛК (Ид юзера, идентификатор устройства, дата последнего входа, способ входа - веб\приложение)
20. Убрать с экрана при запросе OTP тексты согласий (внизу экрана)
+21. UX-дефект: frontend показывает «Не удалось завершить вход» при ошибке отправки отложенного сообщения, хотя вход завершён. Это следует исправить: завершать экран авторизации после bootstrap, а ошибку Bitrix показывать уже в чате.
+22. Веб-пуши для PWA
+23. На кнопке Чат отображать значок наличия непрочитанных уведомлений. Требуется синхронизация между устройствами (решение, например через Dialog.client_last_opened_at)
На будущее (после доработки отдельных функциональностей):
1. Разработка message-safety
@@ -26,7 +29,7 @@
~~3. Интеграция с СМС-провайдером — спецификация и план rollout зафиксированы в `modules/module-11-idgtl-sms.md`; пункт не закрыт до реализации `sms-service`/worker, Keycloak lifecycle, schema `sms`, callback/nginx, env validation, observability и общего DoD. Production prerequisites: согласованные sender/template, Direct `TOKEN_1`, callback credentials/подтверждённый source IP и статический egress IP.~~
3. Определение итогового перечня мнемоник, перевод фронтенда на мнемоники, seed заливка мнемоник в БД (?)
4. Моделирование профиля клиента/
-5. Моделирование уведомлений.
+5. Моделирование уведомлений — постановка согласована v3 (G/P; D1–D13 закрыты): `busines_tasks/notification-requirements.md` → arch-00/01/02/04.
На анализ:
debounce на отправку СМС (сейчас есть Фиксированный cooldownmin_seconds_between_attempts)
\ No newline at end of file
diff --git a/busines_tasks/notification-requirements.md b/busines_tasks/notification-requirements.md
new file mode 100644
index 0000000..4eda9de
--- /dev/null
+++ b/busines_tasks/notification-requirements.md
@@ -0,0 +1,493 @@
+# Бизнес-постановка: Уведомления (Notification Center)
+
+**Статус:** бизнес-постановка согласована (v3: D1–D13 закрыты) → вход в проектирование arch / OpenAPI / модули
+**Продукт:** HAN Chat (клиентское приложение + `api-backend`)
+**Источники:** макет Figma (**не канон** — только визуализация элементов UI, где применимо; при расхождении приоритет у этого ТЗ), черновик требований, архитектура `HAN_chat_specification`
+**Связанный backlog:** «Моделирование уведомлений»; смежно — кнопка «Позвонить оператору», кнопка «Войти»; **отдельно** — индикатор непрочитанных сообщений чата (не в scope этого ТЗ)
+
+---
+
+## 1. Цель
+
+Дать клиенту единый канал сервисных и маркетинговых коммуникаций вне чата: срочные напоминания, статусы услуг, документы, оплаты, акции, а также подсказки в гостевой зоне (авторизация, установка PWA).
+
+Чат остаётся каналом диалога с оператором; уведомления — канал «компания → клиент» с действиями (переход, оплата, загрузка/скачивание документов, переход в чат по акции). Непрочитанные ответы оператора в чате **не** моделируются как уведомления (см. §3.2).
+
+Гостевые `ads`/`promo` — не персонализированная реклама на клиента; отдельное маркетинговое согласие не требуется. Функционал описывается в Пользовательском соглашении.
+
+---
+
+## 2. Два контура показа
+
+| Контур | Кто видит | Источник данных | Frontend |
+|---|---|---|---|
+| **G. Гостевые уведомления** | Только гость | Таблица гостевых уведомлений в App DB → **public API** | Единственный источник в гостевом режиме |
+| **P. Персональные уведомления** | Только авторизованный | Таблица персональных (`user_id` NOT NULL) → **JWT API** | Единственный источник в ЛК |
+
+Правила:
+
+1. До авторизации: только контур **G** (ответ public API as-is).
+2. После авторизации: только контур **P**. Гостевые **не** показываются и **не** переносятся в персональные.
+3. Смешивать G и P в одной таблице / через `user_id IS NULL` — **запрещено**.
+4. В v1 **нет** клиентских условий показа (ОС / PWA / прочие фильтры): фронт показывает список из API в рамках лимита и сортировки. Локальная генерация карточек на устройстве **запрещена**.
+5. У фронта всегда ровно один источник: public API **или** JWT API.
+
+Дубли тематики `ads`/`promo` в G и P допустимы; после входа виден только P.
+
+---
+
+## 3. Границы релиза
+
+### 3.1. В scope
+
+- Контуры G и P (§2); персональный жизненный цикл: `lifecycle_status` / `visibility` / `is_read` / `close_reason` + `record_status` (arch-05).
+- UI: карусель на главной, Центр уведомлений, деталка (где применимо).
+- Каталог типов; публичный id — **UUID v7** (генерация в приложении).
+- Клиентские действия (ЛК): крестик, CTA, деталка/оплата, done/got it, документы (`chat.attachments.*`).
+- Internal API: **Create**, **Cancel** (без upsert / без update content) — §7.4.
+- Константы `notification.*` в `app_settings`; вложения — reuse `chat.attachments.*`.
+- Кнопки **Чат** + **Оператор** (`tel:` ← `operator.call.phone`).
+- Готовность модели к Web Push (UUID, события); реализация push — out of scope.
+
+### 3.2. Вне scope
+
+- Тип `message` / непрочитанный чат (отдельная фича).
+- Push / Web Push / deep link из push.
+- Админ-UI для гостевых уведомлений (v1: insert/SQL).
+- Жёсткая привязка «тип ↔ upstream-сервис».
+- Профиль «Документы» / архив оплат — не заменяются уведомлениями.
+- Запись в `sync_queue` из application-кода: только **триггер БД** + новый `task_type`; куда в Bitrix — ТЗ `bitrix-sync`.
+- SMS/email поверх ЛК.
+- История чатов как UI-раздел — deprecated; backend API диалогов этим ТЗ не удаляется.
+- **Архив `lifecycle_status = N` в UI v1 — нет.**
+- Поле `opened` / impression — **не моделируем** (CTA → `is_read`).
+
+---
+
+## 4. Изменения UI
+
+| Место | Было | Стало |
+|---|---|---|
+| Под полем чата | (см. текущий UI) | **Чат** + **Оператор** (`operator.call.phone`) |
+| Верхнее меню | История чата | Центр уведомлений (колокольчик; бейдж только в ЛК) |
+| Главная | — | Карусель (лимит/сортировка §6.1) |
+| Центр | — | ЛК — список; гость — auth-gate + «Авторизоваться» |
+| Деталка | — | Для типов с деталкой; гостевые `ads`/`promo` — **без** деталки |
+
+Визуал типов — по Figma, где применимо. Figma не канон поведения.
+
+---
+
+## 5. Бизнес-модель
+
+### 5.1. Слои контента
+
+1. **Краткий** — баннер и строка списка: `header`, `text`, цена, CTA.
+2. **Детальный** — `details.*`, документы, кнопки. Только если у типа есть деталка.
+
+### 5.2. Справочник типов (**принято**)
+
+| Слой | Где | Содержимое |
+|---|---|---|
+| Структурный | App DB `notification_types` | `code`, `priority`, `countable`, признак «есть деталка», `record_status` |
+| Визуал | Frontend (тема/константы), сверка с Figma | Цвет, иконка, оформление |
+| Тексты по умолчанию | `text_resources` | `label`, дефолтный CTA, empty states |
+
+В экземпляре **не** дублируются label/цвет/icon/countable/priority/action — только `notification_type` (FK/code).
+
+### 5.3. Каталог типов
+
+| type | label | priority | countable | Action по CTA | Контур |
+|---|---|---|---|---|---|
+| `authorize` | Гостевой режим | 2 | нет | Сценарий авторизации | G |
+| `install_app` | Приложение | 2 | нет | Адаптивная установка PWA (§5.7) | G |
+| `urgent` | Срочно | **1** | да | Детальный просмотр | P |
+| `reminder` | Напоминание | 2 | да | Детальный просмотр | P |
+| `news` | Новость | 2 | да | Детальный просмотр | P |
+| `ads` | Предложение | 2 | да* | G: чат после auth; P: чат + закрытие (§7.2) | G и/или P |
+| `promo` | Акция | 2 | да* | G: чат после auth; P: чат + закрытие (§7.2) | G и/или P |
+| `docs_required` | Требуются документы | 2 | да | Деталка (+ загрузка) | P |
+| `docs_ready` | Документы готовы | 2 | да | Деталка (+ скачивание) | P |
+| `status_changed` | Статус | 2 | да | Детальный просмотр | P |
+| `payment_pending` | Оплата | 2 | да | Переход по `payment_url` | P |
+
+\* Countable/read применяются только в контуре **P**. В **G** read-state нет.
+
+Типы `install_Android` / `install_IOS-HarmonyOS` / `message` — **отсутствуют**.
+
+`priority`: меньше = важнее. Seed: `urgent = 1`, остальные = `2`.
+
+CTA по умолчанию:
+
+- `authorize` — «Войти →»
+- `install_app` — «Установить →» (на UI инструкции текст может быть «Как установить →»)
+- `urgent` / `reminder` / `news` / `status_changed` — «Подробнее →»
+- `ads` / `promo` — «Узнать подробнее →»
+- `docs_required` — «Загрузить документы →»
+- `docs_ready` — «Скачать →»
+- `payment_pending` — «Оплатить →»
+
+**Инвариант:** CTA у `docs_required` / `docs_ready` открывает **карточку**; upload/download — на карточке.
+**Инвариант:** жёсткой привязки «сервис X → тип Y» нет.
+
+### 5.4. Поля экземпляра (контур P)
+
+| Поле | Обяз. | Описание |
+|---|---|---|
+| `id` | да | UUID v7 (api-backend при Create) |
+| `user_id` | да | `UserIdentity.id` NOT NULL |
+| `notification_type` | да | Код из справочника |
+| `notification_datetime` | да | UTC |
+| `header` | да | Заголовок |
+| `text` | нет | Подзаголовок |
+
+Опционально:
+
+| Поле | Описание |
+|---|---|
+| `date_expired` | → `lifecycle_status=N`, `close_reason=expired` |
+| `price` | Текущая цена (₽), опционально. Может быть без `old_price` |
+| `old_price` | Старая цена (₽), опционально. Имеет смысл только вместе с `price` (зачёркнутая «было») |
+| `payment_url` | Обязателен для `payment_pending` |
+| `details` / `details.*` | Деталка (если нужна) |
+| `details.deadline` | Срок на карточке |
+| `send_documents` | UI загрузки клиентом |
+| `documents[]` | Вложения компании в бакете **`han-chat-attachments`** (id объектов working S3) |
+| `chat_message_text` | Текст в чат при CTA (`ads`/`promo` P — **обязателен**) |
+| `button_done` / `button_gotit` / `button_gotit_text` | Кнопки деталки |
+| `external_id` + `source` | Идемпотентность Create (§8) |
+
+### 5.5. Состояние экземпляра (контур P)
+
+| Атрибут | Значения | Семантика |
+|---|---|---|
+| `record_status` | `A` / `D` | Soft-delete строки (arch-05) |
+| `lifecycle_status` | `A` / `N` | `N` — нет в UI; в БД для аудита |
+| `visibility` | `V` / `I` | `I` — нет на главной, есть в Центре (пока `lifecycle_status=A`) |
+| `is_read` | да / нет | Для countable; бейдж = `A` ∧ countable ∧ ¬is_read |
+| `close_reason` | см. ниже | При `A` → `N` |
+
+| `close_reason` | Когда |
+|---|---|
+| `user_done` | «Выполнено»; успех upload `docs_required`; Cancel после успешной оплаты |
+| `expired` | `date_expired` |
+| `cancelled` | Cancel (отзыв системой) |
+
+**`is_read` ≠ `visibility`:** прочтение → бейдж; видимость → главная. Правила — §7.1.
+
+Контур G: per-user lifecycle / visibility / is_read **нет**.
+
+### 5.6. Константы и мнемоники
+
+`notification.*` в `app_settings`. Вложения — ключи чата:
+
+- `chat.attachments.allowed_extensions`
+- `chat.attachments.allowed_mime_types`
+- `chat.attachments.disallowed_extensions`
+- `chat.attachments.max_size_mb`
+- `chat.attachments.presigned_upload_ttl_seconds`
+
+Оператор: **`operator.call.phone`**.
+
+Seed `notification.*`:
+
+| Ключ | Смысл | Default |
+|---|---|---|
+| `notification.gotit.default_ttl_days` | Got it без `date_expired` → now+N дней | `3` |
+| `notification.docs_ready.default_ttl_days` | После скачивания документов, если `date_expired` пуст → now+N дней | `3` |
+| `notification.home.max_items` | Лимит карусели | `15` |
+| `notification.center.max_items` | Лимит Центра (ЛК) | `15` |
+| `notification.carousel.autoplay_enabled` | `Y`/`N` | `N` |
+| `notification.carousel.autoplay_interval_ms` | Интервал | `5000` |
+
+Мнемоники UI (`text_resources`) — **принято**:
+
+- `notification.center.empty.title` / `.text` — пустой Центр (ЛК)
+- `notification.guest_center.title` / `.text` / `.cta` — гостевой Центр
+- `notification.detail.not_found.title` / `.text` — 404 деталки («На главную»)
+
+API при чужом/`N`/отсутствии → **404**; UI — нейтрально «Уведомление недоступно».
+
+### 5.7. Гостевые уведомления (контур G)
+
+- Одна таблица гостевых уведомлений; `record_status` + актуальность **`A`/`N`** (без per-user state).
+- Public API отдаёт все активные (`A`); фронт **не фильтрует** по ОС/PWA в v1.
+- Наполнение v1 — insert/SQL; public API — read-only.
+- Типы в G: `authorize`, `install_app`, `ads`, `promo` (и при необходимости другие broadcast-типы позже).
+- Крестика нет. Деталки у `ads`/`promo` в G **нет**.
+
+**`install_app` — один тип, адаптивный CTA (принято, технически возможно):**
+
+1. Пользователь нажал CTA.
+2. Если среда поддерживает установку PWA (`beforeinstallprompt` / эквивалент) — запускаем установку.
+3. Иначе — показываем инструкцию установки (локальный экран/модалка на фронте; отдельный тип в API не нужен).
+
+Fallback (если адаптивный CTA окажется нереализуем на конкретной платформе сборки): две записи в G (`install` для Android-потока и для iOS/Harmony) — только как запасной план реализации, не целевая модель данных.
+
+**CTA прочих G:**
+
+- `authorize` → сценарий авторизации.
+- `ads` / `promo` → как «популярные вопросы»: старт auth; после успеха в чат уходит `chat_message_text` кампании от лица клиента. Кампания для других гостей остаётся `A`.
+
+### 5.8. Персональные (контур P) — кратко
+
+Создаются Internal **Create**; полная модель §5.4–5.5. Поведение CTA — §7.
+
+---
+
+## 6. Поведение UI
+
+### 6.1. Главная (карусель)
+
+**ЛК (P):**
+
+- Выборка: `record_status=A`, `lifecycle_status=A`, `visibility=V`.
+- Лимит `notification.home.max_items` (15).
+- Сортировка: `priority` ↑, затем `notification_datetime` ↓.
+- Крестик → `visibility=I` (синхрон на все устройства).
+- Карусель: свайп; автопрокрутка по settings.
+- CTA → action типа + эффекты §7.1.
+
+**Гость (G):**
+
+- Список = ответ public API; лимит 15; сортировка: `priority` ↑, затем datetime ↓ (поля сортировки — в таблице G / типе).
+- Крестика нет. Один источник — public API.
+
+### 6.2. Центр
+
+**Гость:** колокольчик без бейджа; экран auth-gate + «Авторизоваться» (мнемоники §5.6). Списка нет.
+
+**ЛК:**
+
+- `record_status=A`, `lifecycle_status=A` (в т.ч. `visibility=I`), лимит 15, без архива `N`.
+- Точка на непрочитанных countable.
+- Сортировка: `priority` ↑ → непрочитанные выше → datetime ↓.
+- Бейдж = непрочитанные countable (`lifecycle_status=A`); sync через бэкенд.
+- Empty state — мнемоники §5.6.
+
+### 6.3. Деталка (контур P; инструкция `install_app` — локальный UI)
+
+- SPA: `/notification/{uuid}`.
+- Чужой / `N` / deleted → **404** (не 403).
+- Upload: quarantine → Message Safety → working (`han-chat-attachments`) → **триггер БД** → `sync_queue`.
+- Company `documents[]`: тот же бакет **`han-chat-attachments`**; preview/download + audit как в чате.
+- `button_done` → `lifecycle_status=N`, `close_reason=user_done`.
+- `button_gotit` → `visibility=I`; при пустом `date_expired` — now + `notification.gotit.default_ttl_days`; `is_read=true` (got it = действие пользователя, см. §7.1).
+- Обе кнопки допустимы одновременно; исход по нажатой. Обе false → только back.
+
+### 6.4. Завершение по типам (P)
+
+| Тип | → `lifecycle_status=N` |
+|---|---|
+| `payment_pending` | Cancel после callback оплаты, `close_reason=user_done` |
+| `docs_required` | Успешный upload → `user_done` |
+| Другой тип с `send_documents` | Upload сам не закрывает |
+| `ads` / `promo` | CTA → `N` (§7.2) |
+| `status_changed` | «Выполнено»; с главной уходит уже по CTA (`visibility=I`) |
+| `docs_ready` | После скачивания — `I` + TTL/`date_expired` (§7.1); в `N` уходит по expire (или Cancel/done) |
+| Прочие | done / expired / cancelled |
+
+---
+
+## 7. Матрицы поведения (контур P)
+
+### 7.1. `is_read` и `visibility` — раздельно
+
+**Правило прочтения (единое):**
+
+> Любое **CTA** → `is_read = true` (идемпотентно).
+
+CTA = первичное действие карточки: кнопка CTA на баннере, тап по строке Центра ведущий к action типа, «Оплатить», переход в деталку по CTA, отправка в чат по ads/promo.
+Не CTA: системный back, крестик (крестик не ставит `is_read`).
+
+**Матрица `visibility` / `lifecycle` (избирательно):**
+
+| Тип | Событие | `is_read` | `visibility` | `lifecycle_status` |
+|---|---|---|---|---|
+| любой | Крестик на главной | — | `I` | — |
+| любой с `button_gotit` | Got it | `true` | `I` (+ TTL если нужно) | — |
+| любой с `button_done` | «Выполнено» | `true` | — | `N` / `user_done` |
+| `urgent` | CTA → деталка | `true` | — | — |
+| `reminder` | CTA → деталка | `true` | — | — |
+| `status_changed` | CTA → деталка | `true` | `I` | — |
+| `news` | CTA → деталка | `true` | `I` | — |
+| `ads` / `promo` | CTA (чат) | `true` | `I` | `N` (+ сообщение в чат) |
+| `docs_required` | CTA → деталка | `true` | — | — |
+| `docs_required` | Успешный upload | `true` | — | `N` / `user_done` |
+| `docs_ready` | CTA → деталка | `true` | — | — |
+| `docs_ready` | Скачивание документов | `true` | `I` | — (+ TTL, см. ниже) |
+| `payment_pending` | CTA «Оплатить» | `true` | `I` | — (далее Cancel→`N` при оплате) |
+
+Пояснения:
+
+- Прочерк «—» = поле этим событием не меняется.
+- Для `ads`/`promo`: одновременно `is_read`, `visibility=I` и `lifecycle_status=N`. В UI запись исчезает из-за `N`; `I` фиксирует намерение «убрать с главной» на случай гонок/аудита.
+- Открытие деталки из Центра по тапу строки = CTA → всегда `is_read=true`; `visibility` меняется только если тип/событие есть в матрице выше.
+- `status_changed`: CTA → деталка сразу уводит карточку с главной (`visibility=I`); в Центре остаётся, пока `lifecycle_status=A`.
+- `docs_ready`, скачивание документов: `is_read=true`, `visibility=I`; если `date_expired` пуст — выставить `date_expired = now + notification.docs_ready.default_ttl_days` (default 3). Если `date_expired` уже задан продюсером — **не перезаписывать**. Далее сработает общий expired-job → `lifecycle_status=N`, `close_reason=expired`.
+
+### 7.2. `ads` / `promo` (P)
+
+1. CTA отправляет в чат `chat_message_text` (обязательное поле).
+2. `is_read=true`, `visibility=I`, `lifecycle_status=N`.
+3. Деталки у персональных ads/promo на MVP **нет** (симметрично G).
+
+### 7.3. Валидация Internal Create (**принято**)
+
+| Тип | Обязательно | Не ожидается | Примечания |
+|---|---|---|---|
+| `urgent`, `reminder`, `news`, `status_changed` | `header`; `details` если нужна деталка | `payment_url` | `button_*` по необходимости |
+| `ads`, `promo` | `header`; **`chat_message_text`** | `payment_url` | `price` и `old_price` — разные опц. поля; `price` без `old_price` допустим; `old_price` без `price` — нет; деталки нет |
+| `docs_required` | `header`; `send_documents=true` | `payment_url` | |
+| `docs_ready` | `header`; `documents[]` ≥1 | `payment_url` | |
+| `payment_pending` | `header`; `payment_url` | — | `price` **не** обязателен; `details` **разрешены** |
+| любой | `user_id`, `notification_type`, `source`, `external_id` | неизвестный тип / user | |
+
+Ошибка валидации → `400` (OpenAPI).
+
+Типы контура G через Internal Create **не** создаются (только insert/public table).
+
+### 7.4. Контракт продюсера
+
+| Операция | Семантика |
+|---|---|
+| **Create** | Создать новое уведомление. Ключ `source`+`external_id`: если уже есть активная (`lifecycle_status=A`) запись с той же парой → **409 Conflict** (контент не обновляется). |
+| **Cancel** | `lifecycle_status=N` + `close_reason` (`cancelled` \| `user_done`). |
+| **Смена контента** | Upsert / update content **нет**. Сценарий: **Cancel** старого → **Create** нового (новый `external_id` или та же пара после `N` — допустим Create, т.к. активной записи с ключом больше нет; политика ключа после `N` — в OpenAPI: разрешить Create с тем же ключом только если нет активной). |
+
+Кто закрывает:
+
+| Сценарий | Кто | reason |
+|---|---|---|
+| Оплата успешна | Внешний → Cancel | `user_done` |
+| Upload `docs_required` | api-backend | `user_done` |
+| CTA ads/promo | api-backend по действию клиента | (закрытие как `user_done` или отдельный reason — по OpenAPI; default `user_done`) |
+| «Выполнено» | Клиент | `user_done` |
+| Отзыв | Внешний → Cancel | `cancelled` |
+| TTL | Scheduler | `expired` |
+
+---
+
+## 8. Идентификация
+
+- Id P и G — **UUID v7** (генерация приложением / seed-скриптом, не клиентом).
+- SPA: `/notification/{uuid}` (только P; гостевая инструкция install — локальный роут без обязательного id в API).
+- Deep link — с push (later).
+- Идемпотентность Create — §7.4 (без upsert).
+
+---
+
+## 9. API
+
+### 9.1. Клиентские (JWT) — контур P
+
+Список / get one / hide / mark-read·done·gotit / upload / counter — по §6–§7.
+Владелец = `user_id` из JWT. Чужое/`N` → 404.
+
+### 9.2. Public — контур G
+
+`GET` списка активных гостевых уведомлений (без JWT).
+
+### 9.3. Internal
+
+- Path: **`/internal/notifications/v1/...`**
+- Service token — как у прочих internal (arch-02).
+- Callers: сервисы приватной сети облака (в т.ч. другие ВМ). Интернет — нельзя.
+- Операции: **Create**, **Cancel** только.
+
+### 9.4. Realtime (**подписка**)
+
+Желательно в релизе, иначе polling.
+
+После connect на `WS /api/v1/realtime` клиент выполняет явный **`subscribe` на уведомления** (например `subscribe: { notifications: true }`), отдельно от `dialog_ids`.
+События: `notification.created` / `notification.updated` / `notification.closed`.
+Reconnect → reconciliation GET списком. Гостю WS для G не требуется.
+
+### 9.5. Готовность к Web Push
+
+Стабильный UUID v7; события жизненного цикла; `header`/`text` для текста push; path `/notification/{uuid}`. Реализация push — вне scope.
+
+---
+
+## 10. Смежные сервисы
+
+| Компонент | Изменение |
+|---|---|
+| **Frontend** | Один источник (G или P); карусель; Центр; адаптивный `install_app`; Чат/Оператор |
+| **api-backend** | Модель G+P; public/JWT/internal; scheduler expired; WS subscribe notifications; upload |
+| **App DB** | Две таблицы; types+priority; триггер → `sync_queue`; seed |
+| **nginx** | Internal не в интернет; rate limit; SPA |
+| **Redis/WS** | События notification.* по подписке |
+| **message-safety** | Как chat attachments |
+| **bitrix-sync** | Новый task_type |
+| **S3** | Бакет вложений уведомлений (клиент и компания): **`han-chat-attachments`** |
+| **settings** | `notification.*`, `chat.attachments.*`, `operator.call.phone`, мнемоники |
+
+Порядок: (1) модель + API + UI → (2) Internal Create/Cancel + seed G → (3) документы + триггер → (4) WS subscribe.
+
+---
+
+## 11. Критерии приёмки
+
+1. Колокольчик; ЛК — бейдж непрочитанных, sync `is_read`/`visibility` между устройствами; гость — без бейджа, Центр = «Авторизоваться».
+2. ЛК главная: лимит 15, sort priority→datetime, только `A`+`V`; крестик → `I`; `N` не в UI.
+3. Гость: только public API, без клиентских фильтров ОС/PWA; один тип `install_app` с адаптивным CTA.
+4. Типы каталога отличимы; `message` нет; после логина только P.
+5. Деталка/кнопки по флагам; docs_* CTA → карточка; ads/promo P: чат + `is_read`+`I`+`N`.
+6. Internal только Create/Cancel; дубликат активного `source`+`external_id` → 409; смена контента = Cancel+Create.
+7. Expired → `N`, UI исчезает.
+8. Upload → quarantine → working → триггер → `sync_queue`; company docs в `han-chat-attachments`.
+9. Оператор — только `operator.call.phone`.
+10. Константы из `app_settings`; UUID v7; 404 на чужое/`N`.
+11. Валидация Create по §7.3.
+12. WS: события после `subscribe` на notifications.
+13. Push не обязателен; модель push-ready.
+14. Архива `N` нет; поля `opened` нет.
+
+---
+
+## 12. Решения D1–D13 (закрыты)
+
+| # | Решение |
+|---|---|
+| **D1** | Два контура: **G** (всё через public API) и **P** (JWT). Без локальных карточек и без условий показа в v1. `install_app` — один тип, адаптивный CTA (установка / инструкция). Fallback — два баннера в данных, не целевая модель. |
+| **D2** | Схема справочника §5.2 принята. |
+| **D3** | Мнемоники empty/404 и поведение 404 приняты (§5.6). |
+| **D4** | ads/promo CTA: `is_read` + `visibility=I` + `lifecycle_status=N` + чат. |
+| **D5** | Любое CTA → `is_read=true`. `visibility` — только по матрице §7.1. |
+| **D6** | Валидация §7.3: `chat_message_text` обязателен для ads/promo; `price` у payment необязателен; `details` у payment разрешены. |
+| **D7** | `/internal/notifications/v1/...` + service token. |
+| **D8** | WS: явная подписка на notifications. |
+| **D9** | Бакет company/client файлов уведомлений: `han-chat-attachments`. |
+| **D10** | `opened` / impression удалены; достаточно `is_read` от CTA. |
+| **D11** | Upsert нет; механика **Cancel + Create**; конфликт активного ключа → 409. |
+| **D12** | IDOR: единый 404. |
+| **D13** | Одновременные done+gotit допустимы без доп. правил продюсеру. |
+
+---
+
+## 13. История решений (Q)
+
+| # | Решение |
+|---|---|
+| **Q1** | Непрочитанный чат / `message` — вне ТЗ. |
+| **Q2** | `N` в БД, не в UI; архива v1 нет. |
+| **Q3** | `payment_pending`: CTA «Оплатить» → `is_read`+`I`; деталка не обязательна. |
+| **Q4** | Гостевые — отдельная таблица; insert v1. |
+| **Q5** | Документы через S3; клиент quarantine→working. |
+| **Q6** | `sync_queue` только триггером БД. |
+| **Q7** | Лимит 15; sort priority→datetime. |
+| **Q8** | Подсказки установки/входа — в контуре G через API (не локальный FE). |
+| **Q9** | UUID v7; `/notification/{uuid}`. |
+| **Q10** | `message` исключён. |
+| **Q11** | Владелец = `user_id`. |
+| **Q12** | `record_status` ≠ `lifecycle_status`. |
+| **Q13** | `operator.call.phone`. |
+| **Q14** | Got it = `I` (+TTL), не обязательно `N`. |
+| **Q15** | Два контура G/P (вместо A/B/C). |
+| **Q16** | Гостевой Центр = auth-gate. |
+| **Q17** | Reuse `chat.attachments.*`. |
+| **Q18** | Поле `opened` снято (D10). |
+| **Q19** | Модель push-ready; push вне scope. |
+
+---
diff --git a/figma/Main page specification.zip b/figma/Main page specification.zip
index 815c584..205b49b 100644
Binary files a/figma/Main page specification.zip and b/figma/Main page specification.zip differ
diff --git a/figma/src/app/App.tsx b/figma/src/app/App.tsx
index 2040ce9..3140497 100644
--- a/figma/src/app/App.tsx
+++ b/figma/src/app/App.tsx
@@ -1,6 +1,34 @@
-import { RouterProvider } from 'react-router';
-import { router } from './routes';
+import { MemoryRouter, Routes, Route, Navigate, Outlet } from 'react-router';
+import { Home } from './pages/Home';
+import { History } from './pages/History';
+import { Profile } from './pages/Profile';
+import { Chat } from './pages/Chat';
+import { Calendar } from './pages/Calendar';
+import { NotificationDetail } from './pages/NotificationDetail';
+import { AuthPhone } from './pages/AuthPhone';
+import { AuthOtp } from './pages/AuthOtp';
+import { AuthLoading } from './pages/AuthLoading';
+import { AuthConsent } from './pages/AuthConsent';
+import { Root } from './pages/Root';
export default function App() {
- return
+ Нажимая «Получить код», вы соглашаетесь с{' '} + условиями использования + {' '}и{' '} + политикой конфиденциальности +
+