Перейти к содержанию

OTA Integration Backlog — connectivity-партнёрства (peer-OTA модель)

Дата: 2026-06-01 Контекст: Decisions/decision_arkhyz_as_ota_peer.md — Архыз.CLUB = OTA-peer, а не клиент-отельер. Связано: PLAN_OTA_DETAILED.md (карточки каналов + архитектура), services/booking-svc/app/integrations/ota/.

Этот документ — бэклог интеграционных задач для подключения Архыз.CLUB к другим OTA как connectivity-партнёра (передаём им ARI наших ~120 отелей) и как affiliate (перепродаём их inventory нашим гостям).


0. Что уже есть и чего не хватает (gap-анализ)

✅ Сделано (код)

  • Контракт канала OtaChannel (Protocol, base.py): healthcheck, pull_bookings, push_availability, push_rates, confirm_booking, cancel_booking, verify_webhook.
  • 11 коннекторов: ostrovok, yandex_partner, bronevik, hotels101, sutochno, tvil, travelline_cm, bnovo_cm, channex_cm, ical_generic, google_hotel (XML-feed).
  • Воркеры: ota_sync_worker, ota_inbound_worker, ota_push_availability_worker, ota_rate_parity_monitor, ota_tech_fee_biller.
  • Роутеры: ota_admin (CRUD credentials/mappings/sync), ota_admin_overview, ota_webhooks.
  • БД: таблицы ota_* (применены на прод 2026-06-01), pgsodium-шифрование, RLS.
  • Хотельерский UI: /hotelier/ota-channels (подключение каналов, маппинг, sync).

❌ Чего не хватает для peer-модели

  1. Portfolio-уровень. Весь код — per-credential (один отель ↔ один канал). Как OTA-провайдер мы должны отдавать партнёру единый агрегированный фид всех наших отелей под одним partner-account, а не 120 отдельных подключений.
  2. Сертификация. Ни один канал не прошёл sandbox-сертификацию партнёра → ни одного боевого подключения. Коннекторы написаны «по докам», но не верифицированы.
  3. Приём броней как провайдер (booking ingestion + ack) с гарантиями идемпотентности и atomic-инвентаря на portfolio-масштабе.
  4. Affiliate / inbound (перепродажа чужого inventory) — кода нет вообще.
  5. Партнёрская операционка: per-connection SLA-мониторинг, reconciliation, payout, parity как OTA, content-pipeline (наши отели ↔ их property/room IDs).
  6. Известный баг: OTA-воркеры падают (prepared statement does not exist, asyncpg) — вынесен в отдельную задачу, блокирует любой боевой sync.

Легенда статусов задач

  • 🟢 внутренняя — можем делать сразу, не ждём партнёра.
  • 🟡 нужен sandbox — заблокировано доступом партнёра (NDA / sandbox-креды).
  • 🔴 блокер — без этого боевой запуск невозможен.
  • Размер: S (≤1 дн), M (2-4 дн), L (неделя+).

1. Cross-cutting — общие задачи (нужны для ЛЮБОГО партнёра)

INT-0 🔴🟢 S — Починить asyncpg-краш OTA-воркеров

  • Проблема: ota_push_availability_worker / ota_inbound_worker падают в цикле prepared statement "__asyncpg_stmt_X__" does not exist.
  • Фикс: statement_cache_size=0 на пуле воркеров (или per-connection reset).
  • Файлы: workers/ota_*, пул в notify.py/db.
  • DoD: docker logs booking-svc без crash/prepared 1 час под нагрузкой sync.
  • Блокирует все остальные boevые задачи — делать первым.

INT-1 🟢 L — Portfolio Mapping Pipeline (наши отели ↔ partner IDs)

  • Зачем: партнёру нужен маппинг наш hotel_id/room_type_id → их property_id/room_id/rate_plan. Сейчас маппинг ручной per-credential — для 120 отелей не масштабируется.
  • Scope: таблица ota_portfolio_mappings (provider × our_hotel × our_room × external_ids, content-статус), импорт их property-каталога, авто-матчинг по гео+названию+вместимости, ручная доводка в админке.
  • Файлы: новая миграция; integrations/ota/<provider>.py::fetch_property_catalog(); UI в admin (раздел «OTA Connectivity»).
  • DoD: для тест-партнёра 10 отелей замаплены и прошли content-валидацию.

INT-2 🔴🟢 L — Portfolio ARI Push Engine (агрегированный фид)

  • Зачем: ядро connectivity-провайдера — push Availability/Rates/Inventory всех наших отелей в партнёра одним каналом, дельтами, по событиям inventory.
  • Scope: надстройка над push_availability/push_rates: батчинг по partner-account, дельта-детект (только изменения), очередь с ретраями/backoff, dedupe, rate-limit под лимиты партнёра, full-refresh по расписанию + delta по booking/price-change.
  • Файлы: новый workers/ota_portfolio_push_worker.py; расширить OtaChannel методом push_ari_batch (или переиспользовать существующие).
  • DoD: изменение цены/стоп-сейла у отеля долетает в sandbox-партнёра ≤60с, идемпотентно, без дублей.

INT-3 🔴🟢 M — Booking Ingestion + Acknowledgement

  • Зачем: бронь от партнёра → atomic-резерв нашего инвентаря → ack/reject партнёру.
  • Scope: webhook + pull fallback → book_room_atomicconfirm_booking/cancel_booking обратно партнёру; идемпотентность по external_booking_id; обработка overbooking (reject с причиной); запись в ota_bookings + наш booking.
  • Файлы: ota_inbound_worker, routers/ota_webhooks.py, book_room_atomic.
  • DoD: sandbox-бронь партнёра создаёт нашу бронь и возвращает ack; гонка двух броней на последний номер → одна confirmed, вторая rejected.

INT-4 🟢 M — Modify / Cancel / No-show flow

  • Scope: входящие modify/cancel от партнёра → пересчёт нашей брони + инвентаря; исходящие (отель отменил у нас) → push отмены партнёру; no-show/charge-policy.
  • Файлы: ota_inbound_worker, <provider>.py::cancel_booking.
  • DoD: modify дат и cancel из sandbox корректно отражаются с обеих сторон.

INT-5 🟢 M — Rate Parity как OTA

  • Зачем: мы обязаны держать parity по договору с отелем И отслеживать demp-цены партнёров.
  • Scope: расширить ota_rate_parity_monitor: сравнение наша-цена vs цена-у-партнёра, алерт при нарушении, отчёт хотельеру/нам.
  • Файлы: workers/ota_rate_parity_monitor.py, ota_parity_violations.
  • DoD: искусственное расхождение ловится и попадает в отчёт + Sentry.

INT-6 🟢 M — Reconciliation & Financials

  • Scope: сверка партнёрских броней с нашими; расчёт комиссии (наши 7% + комиссия партнёра), tech-fee биллинг, payout-репорт; месячная выгрузка для бухгалтерии.
  • Файлы: ota_tech_fee_biller, новый reconciliation-репорт.
  • DoD: месячный отчёт сходится по числу броней и суммам с sandbox-данными.

INT-7 🟡 M — Certification Harness (sandbox test-runner)

  • Зачем: каждый партнёр требует прогон их test-кейсов (booking, modify, cancel, overbooking, ARI-update) перед прод-доступом.
  • Scope: прогон сценариев сертификации против sandbox, чек-лист, отчёт «готов к prod».
  • Файлы: tests/ota/cert_<provider>.py, фикстуры.
  • DoD: для целевого партнёра все обязательные cert-кейсы зелёные.

INT-8 🟢 S — Credential Vault & Rotation (расширение)

  • Scope: pgsodium уже шифрует креды; добавить ротацию по событию OtaAuthError, алерт на истечение, audit-trail доступа. Партнёр-аккаунт (не отельный) — отдельный scope.
  • Файлы: credentials_service.py, secrets.py, ota_credentials_audit.
  • DoD: ротация при 401 без даунтайма sync.

INT-9 🟢 M — Per-connection Monitoring / SLA / Alerting

  • Scope: health-стейты (healthy/degraded/broken) на уровне partner-connection, дашборд «OTA Connectivity», алерты (degraded→Sentry, broken→нам+отельеру), метрики latency/ошибок push/pull в Prometheus.
  • Файлы: ota_admin_overview, Grafana-дашборд, Prometheus-правила.
  • DoD: падение sandbox-партнёра → алерт ≤5 мин, дашборд показывает broken.

2. Per-partner tracks (sandbox → certification → prod)

Каждый трек = повторяемый чек-лист. Большинство задач 🟡 нужен sandbox — блокируются партнёрским action (NDA + выдача sandbox-доступа). Эти пункты в разделе «Следующие шаги» pivot-документа.

Шаблон трека (для любого партнёра)

# Задача Статус Кто
P-1 Отправить peer-connectivity письмо в Connectivity Partnerships team 🟡 бизнес
P-2 Подписать NDA / partner-agreement 🟡 бизнес/юр
P-3 Получить sandbox-credentials + спецификацию API 🟡 партнёр
P-4 Верифицировать коннектор против sandbox (healthcheck, auth) 🟢 eng
P-5 Импорт property-каталога + маппинг 5-10 пилот-отелей (INT-1) 🟢 eng
P-6 ARI push пилот-отелей в sandbox (INT-2) 🟢 eng
P-7 Прогон cert-кейсов: booking/modify/cancel/overbooking (INT-7) 🟡 eng
P-8 Получить prod-доступ + go-live пилота (5-10 отелей) 🟡 партнёр
P-9 Раскатка на весь portfolio (120 отелей) + мониторинг (INT-9) 🟢 eng

2.1 Островок Connectivity Switch — приоритет №1

  • Коннектор: ostrovok.py (✓ написан, не верифицирован).
  • Письмо: Knowledge/ota_letter_templates/ru/peer_connectivity_ostrovok.md.
  • Главный аргумент: ~40% наших отелей — эксклюзив (мелкие гостевые дома).
  • Специфика: REST, Островок Partner Hub; уточнить лимиты ARI push и формат rate-plans.
  • Все P-1…P-9.

2.2 Яндекс.Путешествия Partner API — приоритет №2

  • Коннектор: yandex_partner.py (✓) + ical_generic.py (уже есть iCal-связка как база).
  • Письмо: ru/peer_connectivity_yandex.md.
  • Специфика: эскалация существующей iCal до полноценного Partner API; трафик из Карт/Поиска.
  • Все P-1…P-9; P-4 частично закрыт (iCal работает).

2.3 Booking Connectivity Partner Program — приоритет №3 (англ.)

  • Коннектор: пока нет отдельного Booking-провайдера → задача: написать (REST, OTA-XML/JSON).
  • Письмо: en/peer_connectivity_booking.md, контакт connectivitypartners@booking.com.
  • Специфика: позиционирование как resort-specific OTA (аналог Riu/Iberostar); РФ-доступ может быть ограничен санкциями — трекать.
  • Доп. задача BKG-0 🟢 L: реализовать booking_connectivity.py по их XML-спеке.

2.4 Bronevik — корпоративный сегмент

  • Коннектор: bronevik.py (✓). Отдельный B2B-контур (командировки).
  • Письмо: ru/a_direct_bronevik.md (переписать в peer-тон при необходимости).

2.5 Airbnb / generic iCal — гостевые дома (самый простой)

  • Коннектор: ical_generic.py (✓). Только availability (без rates/instant-book).
  • Задача ICAL-1 🟢 S: UI «добавить iCal-ссылку» для гостевых домов в хотельерском кабинете.
  • DoD: импорт ICS закрывает даты у нас, экспорт нашего ICS — у них.

2.6 TravelLine / Bnovo — sub-connectivity (backup, НЕ платим)

  • Коннекторы: travelline_cm.py, bnovo_cm.py (✓).
  • Модель: для отелей, которые уже на этих PMS и не дают нам direct-ключи — подключаемся как connectivity-партнёр (backup-канал), без подписки.
  • Задача: верифицировать sub-connectivity-доступ (не reseller-тариф).

3. Affiliate / Inbound Distribution (перепродаём чужой inventory)

Применять в Phase D, когда наш гость ищет соседние регионы (Домбай, Эльбрус, КМВ, Сочи) — закрываем спрос чужим inventory, получаем 25-40% их комиссии.

AFF-1 🟢 L — Affiliate feed ingestion слой

  • Scope: обратный коннектор — тянем search/availability/booking из affiliate-API, показываем в нашем UI как «дополнительные направления», бронь идёт через партнёра, фиксируем нашу комиссию.
  • Кандидаты API: Booking Demand API v3 (без NDA, partner.booking.com/affiliate), Expedia EPS Rapid (developers.expediagroup.com/rapid), Островок Affiliate, Trip.com.
  • DoD: поиск по «Сочи» в нашем UI возвращает affiliate-результаты, тест-бронь трекается с нашим affiliate-id.

AFF-2 🟢 M — UI «Дополнительные направления» в гостевом приложении

  • Отдельная вкладка/раздел, явная пометка «бронирование у партнёра».

4. White-Label / Cross-Distribution (Phase E — отложено)

  • WL-1: «Архыз на Островке/Яндексе» под их брендом (наш inventory). Реальность: нужно 1-2 года работы + 1000+ броней/мес. Заглушка, не делаем сейчас.
  • XD-1: взаимозачёт inventory с нишевыми OTA (TVIL, авито-аналоги) на overlap-supply.

5. Последовательность и зависимости

INT-0 (фикс воркеров) ──┬─> INT-1 (mapping) ─> INT-2 (ARI push) ─┬─> Островок P-4..P-9
                        │                                          ├─> Яндекс P-4..P-9
                        ├─> INT-3 (booking ingest) ────────────────┘
                        ├─> INT-8 (vault) ─> INT-9 (monitoring)
                        └─> INT-7 (cert harness) ─> [блокируется sandbox каждого партнёра]

Параллельно (бизнес): P-1..P-3 для Островок+Яндекс+Booking (письма + NDA + sandbox).
Phase D: AFF-1/AFF-2.  Phase E: WL/XD.

Критический путь к первому боевому подключению (Островок): INT-0 → INT-1 → INT-2 → INT-3 → INT-7 + параллельно бизнес P-1..P-3 → P-8 go-live.

6. Definition of Done (общее для интеграционных задач)

  1. Код + тесты (unit + cert-сценарий) зелёные.
  2. Верифицировано против sandbox партнёра (где применимо).
  3. Идемпотентность и atomic-инвентарь подтверждены (гонка-тест).
  4. Мониторинг/алерты заведены (INT-9).
  5. Документация канала обновлена в PLAN_OTA_DETAILED.md (карточка партнёра).

7. Вне инженерной зоны (бизнес/юр — из pivot-документа)

  1. Заполнить Knowledge/ota_letter_templates/shared_vars.md (ИНН/ОГРН/ФИО подписанта).
  2. Отправить 3 peer-письма одновременно: Островок + Яндекс + Booking.
  3. Tech-deck (5 слайдов): 120 отелей, ~50k room-nights/год, 40% эксклюзив, готовность к sandbox.
  4. По получении sandbox — активировать треки P-4…P-9.