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-модели¶
- Portfolio-уровень. Весь код —
per-credential(один отель ↔ один канал). Как OTA-провайдер мы должны отдавать партнёру единый агрегированный фид всех наших отелей под одним partner-account, а не 120 отдельных подключений. - Сертификация. Ни один канал не прошёл sandbox-сертификацию партнёра → ни одного боевого подключения. Коннекторы написаны «по докам», но не верифицированы.
- Приём броней как провайдер (booking ingestion + ack) с гарантиями идемпотентности и atomic-инвентаря на portfolio-масштабе.
- Affiliate / inbound (перепродажа чужого inventory) — кода нет вообще.
- Партнёрская операционка: per-connection SLA-мониторинг, reconciliation, payout, parity как OTA, content-pipeline (наши отели ↔ их property/room IDs).
- Известный баг: 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/prepared1 час под нагрузкой 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_atomic→confirm_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 (общее для интеграционных задач)¶
- Код + тесты (unit + cert-сценарий) зелёные.
- Верифицировано против sandbox партнёра (где применимо).
- Идемпотентность и atomic-инвентарь подтверждены (гонка-тест).
- Мониторинг/алерты заведены (INT-9).
- Документация канала обновлена в
PLAN_OTA_DETAILED.md(карточка партнёра).
7. Вне инженерной зоны (бизнес/юр — из pivot-документа)¶
- Заполнить
Knowledge/ota_letter_templates/shared_vars.md(ИНН/ОГРН/ФИО подписанта). - Отправить 3 peer-письма одновременно: Островок + Яндекс + Booking.
- Tech-deck (5 слайдов): 120 отелей, ~50k room-nights/год, 40% эксклюзив, готовность к sandbox.
- По получении sandbox — активировать треки P-4…P-9.