# Развёртывание

## 1. WordPress

1. Сделать резервную копию сайта.
2. Скопировать `wordpress-plugin/tft-miniapp-api` в `wp-content/plugins`.
3. Активировать плагин.
4. Проверить:

```text
https://thaifortravel.ru/wp-json/tft-miniapp/v1/health
https://thaifortravel.ru/wp-json/tft-miniapp/v1/tours?city=pattaya&per_page=2
```

5. Назначить категории Mini App сначала десяти популярным экскурсиям и проверить fallback-классификацию остальных.
6. Добавить URL очистки backend-кэша и одинаковый sync secret в `wp-config.php` и backend ENV.

Плагин не меняет публичные шаблоны и не удаляет существующие ACF-поля.

## 2. Backend host

Требования:

- Node.js 22 или 24;
- PostgreSQL 16+;
- Redis 7+;
- HTTPS reverse proxy;
- отдельные процессы API и worker.

Для Docker:

```bash
docker build -t thaifortravel-miniapp-api .
docker compose -f docker-compose.production.example.yml up -d
```

Перед запуском заменить example image и создать `.env.production`.

Для защищённой админ-панели обязательно задать:

```text
ADMIN_USERNAME=owner
ADMIN_PASSWORD=<отдельный длинный пароль>
ADMIN_EMAIL=<email владельца>
ADMIN_SESSION_SECRET=<случайная строка минимум 32 символа>
ADMIN_SESSION_TTL_HOURS=12
ADMIN_PASSWORD_RESET_TTL_MINUTES=45
ADMIN_PUBLIC_URL=https://api.thaifortravel.ru/admin/
SMTP_HOST=<SMTP-сервер>
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=<SMTP-логин>
SMTP_PASSWORD=<SMTP-пароль приложения>
SMTP_FROM_EMAIL=<адрес отправителя>
SMTP_FROM_NAME=ThaiForTravel
```

При первом запуске API создаёт владельца из `ADMIN_USERNAME`,
`ADMIN_PASSWORD` и `ADMIN_EMAIL`, только если такого администратора ещё нет.
Дальше пароль хранится в PostgreSQL в виде scrypt-хеша и не перезаписывается
значением ENV. Ссылка восстановления действует 45 минут, одноразовая, а после
смены пароля завершает все ранее открытые сессии.

После миграции и перезапуска панель открывается по адресу
`https://<backend-domain>/admin/`. Суммы бронирований и платежи начинают
учитываться после их заполнения менеджером; исторические суммы автоматически не
восстанавливаются.

## 3. Telegram

- Использовать токен того же seller-бота, из которого запускается Mini App.
- В рабочем режиме `TELEGRAM_UPDATE_OWNER=backend`: единственный Telegram
  webhook указывает на backend Mini App. Он обрабатывает `/start`, запрашивает
  собственный контакт пользователя и фиксирует согласие.
- Текущий webhook Telegram-интеграции OkoCRM хранится только в production ENV
  `TELEGRAM_FORWARD_WEBHOOK_URL`. Передача запрещена без отдельного
  `TELEGRAM_FORWARD_WEBHOOK_SECRET` длиной не менее 16 символов. Секрет всегда
  передаётся в `X-Telegram-Bot-Api-Secret-Token`. Если принимающая сторона не
  проверяет этот заголовок, relay необходимо отключить до исправления OkoCRM.
- `TELEGRAM_MANAGER_USER_IDS` содержит Telegram ID менеджеров, которым разрешено
  отвечать клиентам через резервную группу. Ответ принимается только как reply
  на сообщение, идентификатор которого ранее сохранил backend.
- `TELEGRAM_INIT_DATA_MAX_AGE_SECONDS` для production устанавливается в `900`.
- Обновления для OkoCRM сначала фиксируются в outbox PostgreSQL, а затем
  отправляются worker-процессом с повторами. Поэтому медленный ответ OkoCRM не
  задерживает Telegram webhook и не вызывает повторную доставку одного Update.
- Если OkoCRM временно отклоняет сообщение, текстовое обращение передаётся
  менеджерам через резервный Telegram-топик, чтобы обращение не потерялось.
- Backend Mini App не вызывает `getUpdates`; публикатор и другие процессы также
  не должны назначать или удалять webhook.
- Backend отправляет подтверждения заявки и напоминания только в личный чат клиента с ботом.
- Заявки менеджеров передаются в CRM через outbox; отдельное сообщение о новой заявке в Telegram-группу не создаётся.
- Для прямого создания сделок в OkoCRM используются
  `CRM_PROVIDER=okocrm`, `CRM_BASE_URL=https://api.okocrm.com/v2/`,
  пользовательский API-токен, `OKOCRM_PIPELINE_ID` и `OKOCRM_STAGE_ID`.
  При авторизации Mini App backend также синхронизирует Telegram ID из
  нативного поля контакта OkoCRM в видимое поле карточки. Имена полей
  задаются через `OKOCRM_TELEGRAM_SOURCE_FIELD` (по умолчанию `cf_13038`)
  и `OKOCRM_TELEGRAM_TARGET_FIELD` (по умолчанию `cf_15400`).
  Для webhook `client_message` задаётся отдельный случайный
  `OKOCRM_WEBHOOK_TOKEN` длиной не менее 32 символов. Webhook OkoCRM должен
  указывать на
  `https://api.thaifortravel.ru/webhook/okocrm?token=<OKOCRM_WEBHOOK_TOKEN>`.
  Для location `/webhook/okocrm` в Nginx обязательно задано `access_log off`,
  после включения правила старый токен меняется и обновляется в OkoCRM.
  Входящий `client_id` прикрепляется к найденному контакту официальным методом
  `POST /v2/unsorted/attach/`; внутренний web endpoint OkoCRM не используется.
  Режим `CRM_PROVIDER=none` считается ошибкой доставки и не помечает заявку
  синхронизированной.
- Кнопка чата возвращает deep link в тот же seller-бот.
- Ежедневный публикатор может использовать тот же токен, но только для исходящих методов `sendMessage`/`deleteMessage`. Ему нельзя вызывать `getUpdates` или `setWebhook`.
- На main должна быть включена ровно одна задача `ThaiForTravel daily Telegram availability publish` агента `publisher` в 09:00 `Asia/Bangkok`.

Если CRM или seller-bot меняют статус заявки, они вызывают:

```text
POST /v1/internal/applications/{publicId}/status
X-TFT-Sync-Secret: ...
```

Агрегированная статистика использования Mini App доступна без персональных
данных за период от 1 до 90 дней:

```bash
curl --fail-with-body \
  -H "X-TFT-Sync-Secret: $INTERNAL_ANALYTICS_SECRET" \
  "https://api.thaifortravel.ru/v1/internal/analytics/usage?days=14"
```

Endpoint возвращает число активных и новых пользователей, созданных избранных,
заявок и планов, а также разбивку заявок по типу и статусу. Ответ запрещено
кэшировать; запрос без корректного внутреннего секрета получает `401`.
Для production задаётся отдельный `INTERNAL_ANALYTICS_SECRET`, чтобы ключ
статистики не давал доступ к изменению заявок и очистке каталога.

## 4. Reverse proxy

Обязательные правила:

- TLS 1.2+;
- лимит тела запроса 256 KB;
- передавать реальный IP;
- не кэшировать пользовательские `/v1/*`;
- не кэшировать `/admin/api/*` и не проксировать `/admin/` на Mini App frontend;
- разрешать кэш только для `/v1/catalog/*`;
- readiness проверять через `/health/ready`.
- не записывать URL `/webhook/okocrm` в access log.

## 5. Порядок релиза

1. PostgreSQL и Redis.
2. Миграция.
3. API и worker.
4. WordPress plugin.
5. Проверка публичного каталога.
6. Проверка, что менеджерские события `TELEGRAM_MANAGER_APPLICATION` не создаются.
7. Тестовая заявка из служебного Telegram-аккаунта только по отдельному решению владельца.
8. Проверка личного подтверждения пользователю и CRM-синхронизации.
9. Проверка входа в `/admin/`, фильтра периода и тестового чата.
10. Включение Mini App URL в BotFather.

Секреты, реальные телефоны и Telegram initData нельзя помещать в git или обычные логи.
