Внешнее архитектурное ревью платформы (30.04.2026) и постатейные ответы
Версия: 1.0 Дата: 30.04.2026 Статус: Готов к обсуждению
Назначение документа
Документ фиксирует внешнее архитектурное ревью, полученное по абстрактному техническому заданию платформы 30.04.2026, и постатейные ответы главного архитектора по каждому пункту: согласие или несогласие с тезисом, предлагаемые изменения в документации платформы, приоритетность правок.
Документ создан как audit trail архитектурного процесса — каждое серьёзное внешнее замечание должно оставлять след: получено, проанализировано, отвечено, последующие документы обновлены или мотивированно не обновлены.
Источник ревью
Ревью получено от внешнего эксперта на основе абстрактного технического задания. Эксперт оценивал архитектурный замысел, оси платформы, логические связи, gap'ы и зрелость документации.
Полный текст ревью
1. Общий вердикт: «Промышленный радикализм»
Концепция Vitiana — это попытка построить Stripe в мире Travel. Вы отказываетесь от модели «агрегатора-посредника» в пользу «платформы-инфраструктуры».
Главный успех концепта: Выход за рамки «отельной выдачи». Платформа мыслит Офферами и Квотами, а не «комнатами». Это позволяет строить Tour Builder как ядро, а не как надстройку.
2. Анализ Осей и Логических Связей
Ось 1: Каноническая доменная модель (Domain Spine)
Сила: Четкое разделение на Master Truth (стабильное), Operational Truth (быстрое/волатильное) и Transactional Truth (неизменное). Это защищает систему от «отравления» кэшами.
Логический разрыв: В Booking State Machine (14 состояний) состояние unknown_external_state (8-е) заявлено как «first-class категория». Это смело, но опасно. Если этот статус не имеет жесткого автоматического тайм-аута с переходом в Failed или Manual_Intervention, система накопит «зависшие» деньги. В финансовом блоке (partner-finance-and-clearing) не до конца прописано, блокируется ли баланс партнера «навсегда» при этом статусе.
Пропуск: Не детализирована модель Inventory для не-отельных сегментов (перелеты, страховки). Отели прописаны глубоко, остальное — декларативно. Для Tour Builder это критично: логика Quote для авиабилета (где цена живет секунды) принципиально иная, чем для отеля.
Ось 2: Поверхности (Surfaces)
Сила: Принцип «API-as-a-Product» и отказ от «одного API для всех». Visibility Matrix — отличный инструмент.
Логический конфликт: Вы заявляете Partner Machine Surface и Partner UI/SDK как равноправные. Однако в SDK часто зашивают логику, которая в «чистом» API может отсутствовать. Есть риск, что партнеры на чистом API будут «гражданами второго сорта» по сравнению с теми, кто использует ваш SDK.
Связанность: Связь Surface → Capability Set → ActorContext прописана идеально. Это база для безопасности.
Ось 3: Платформа как продукт (Monetization)
Сила: Динамическая тарификация за труд платформы (сложность поиска, нагрузка на поставщиков). Это отвязывает ваш доход от маржи отеля и привязывает к вашим затратам на инфраструктуру. Гениально с точки зрения Unit-экономики.
Риск: Поймет ли рынок плату за «сложность запроса»? Большинство B2B привыкло к комиссии. Вам понадобится очень прозрачный Usage Dashboard, чтобы партнер не чувствовал, что его «грабят» за тяжелые фильтры.
Ось 4: Данные и Интеллект
Сила: Событийная модель с 6 классами гарантий. Разделение Domain и Analytical событий на уровне шины — это стандарт High-load, который вы закладываете с нулевого дня.
Критика: ML-платформа описана как «first-class», но в Stage 1-2 она фактически отсутствует. Есть риск, что вы накопите данные в DWH в формате, который потом потребует мучительного ре-инжиниринга для обучения моделей ранжирования.
3. Критические Gaps (Пропуски)
Ingestion Bottleneck (Бутылочное горлышко приема): Правило 00000 (Платформа доминирует) возлагает на Ingestion Layer колоссальную нагрузку. Нормализация данных от 50 поставщиков в единую модель Property — это не только техническая, но и лингвистическая/географическая проблема. В документах не описан механизм Conflict Resolution, когда два доверенных поставщика дают противоречивые данные (например, разные координаты одного отеля). Кто «правее» в автоматическом режиме?
Дрейф цен в Tour Builder (The Drift Problem):
В tour-builder-operational-model описан DriftEvent. Но как быть с «каскадным дрейфом»? Если в туре из 5 элементов изменилась цена одного, это может сделать невыгодным весь тур. Не хватает логики автоматического переподбора (Auto-replace) при дрифте, которая была бы бесшовной для агента.
Settlement при частичных отказах: Saga в Tour Builder — отличное решение. Но финансовая модель Refund при отмене одного элемента из пакета (Package Travel Directive) прописана сложно. Нужно четко разделить: что возвращает поставщик и что обязана вернуть платформа (insolvency protection).
5. Резюме по архитектурным правилам
- Правило 00000: Соблюдено на 100%. Это фундамент, который выстоит.
- Развитие без деградации: Соблюдено. Отсутствие «заглушек» в тексте радует, вы честно фиксируете «развилки».
- Тезисное обоснование: Имеется почти везде. Это делает ТЗ понятным для Senior-подрядчика.
Финальный вывод
Архитектура готова к реализации Stage 1. Она избыточна для простого сайта, но адекватна для глобальной платформы.
Главный совет: Сфокусируйтесь на Governance данных (матчинг и дедупликация). Если на старте каноническая модель наполнится дублями и мусором от поставщиков, все остальные оси (ML, Search, Tour Builder) потеряют смысл, так как будут работать на гнилом фундаменте.
Постатейные ответы главного архитектора
Ответ 1: «Промышленный радикализм» — принимаю формулировку
Согласен полностью. «Stripe в travel» — короткая ёмкая формулировка, объясняющая партнёрам и подрядчикам в одной фразе суть архитектуры.
Действие: добавить эту формулировку в overview/architectural-anchor-and-business-model.md как краткий elevator pitch в начале документа.
Ответ 2.1: unknown_external_state без жёсткого timeout — критическая правка
Согласен полностью. Это реальный пробел архитектуры. У нас есть reference/booking-state-machine.md с 14 состояниями, и unknown_external_state действительно first-class. Но timeout-эскалация в нём задокументирована недостаточно жёстко.
Действие: усилить документацию явными правилами:
- Жёсткий timeout перед автоматическим переходом из
unknown_external_state:- search-флоу — 15 минут;
- booking-флоу — 4 часа;
- после timeout — переход в
failed(если есть подтверждение неудачи) илиmanual_intervention(если поставщик молчит).
- Состояние никогда не остаётся в
unknown_external_stateнавсегда. - В reference/partner-finance-and-clearing.md явное правило: средства на партнёрском балансе не блокируются дольше N часов; по истечении timeout — либо list_failed_charge, либо escalation.
- Метрика
unknown_external_state_shareуже зафиксирована как один из 10 SLI в operations/sla-and-on-call-model.md — связать с runbook'ом инцидента «доля > 1%».
Приоритет: Block 1 (критично к Stage 1).
Ответ 2.2: Inventory не-отельных сегментов — закладываем сразу
Согласен. Известный пробел — в reference/tour-builder-domain.md и reference/domain-model.md отели проработаны вглубь, а flights / transfers / insurance / activities — на уровне «то же самое, только с поправкой».
Ревьюер прав в важном: семантика Quote для авиабилета принципиально иная — цена живёт секунды, не минуты; pricing engine внешний (GDS/IATA); refund-семантика жёстко регулируется (IATA fare rules); quote-revalidation должна быть встроена в чек-аут.
Действие: создать новый документ reference/inventory-non-accommodation-domains.md, описывающий 4 не-отельных segment-типа с явным тезисом «у каждого segment-типа своя Quote-семантика», и перекрёстные ссылки из tour-builder-domain.md.
Не блокирует Stage 1 (отели сначала), но закладывает каноничную модель сразу, чтобы потом не переделывать ядро.
Приоритет: Block 2 (закладка для Stage 2-3).
Ответ 2.3: SDK как тонкая обёртка — наше решение жёстче ревьюера
Замечание правильное, но решение иное. Ревьюер боится что партнёры на чистом API будут «гражданами второго сорта», если в SDK зашивается логика которой нет в API.
Наше каноничное решение наоборот: SDK не должен ничего добавлять сверх API. SDK — это тонкая обёртка с типизированными моделями, retry, idempotency. Любая бизнес-логика — на стороне API. Если в SDK появилось правило, которого нет в API — это баг SDK, не фича.
Так делает Stripe: Stripe SDK ничего не знает, чего не знает Stripe API.
Действие: добавить в reference/api-as-product.md явный тезис «SDK как тонкая обёртка»:
- SDK не содержит бизнес-логики.
- Любая валидация, идемпотентность, политика — на API-стороне.
- Каждый SDK-метод имеет точное соответствие одному API-запросу.
- Партнёры на raw API получают тот же функционал с той же надёжностью, просто без удобств типизации.
Приоритет: Block 1 (критично к Stage 1 — это формирует культуру разработки SDK).
Ответ 2.4: Динамическая тарификация — согласен с риском, корректирую фокус
Ревьюер боится что партнёры не поймут «плату за сложность запроса». Корректирую: мы не платим за сложность — мы платим за потребление (метрики: количество search, количество quote, количество booking, количество supplier-вызовов). Это не «оценщик субъективной сложности», это «счётчик ресурсов».
Действие: зафиксировать в reference/economic-model.md:
- Пунктовое explanation тарификации без эзотерических слов «сложность».
- 3-4 примера типичных профилей потребления (стартующее агентство, активный B2B, enterprise).
- Каждый платный объект (search, quote, booking, supplier-call) — с явной ценой и ставкой.
Usage Dashboard ревьюер правильно подсветил — он должен показывать партнёру в реальном времени что и за что начисляется. У нас это есть в reference/api-metering-and-usage-governance.md, но возможно стоит вытащить mockup-дашборд в отдельный раздел.
Приоритет: Block 4 (коммуникационное).
Ответ 2.5: ML-платформа в Stage 1-2 — частично согласен
Действительно, в Stage 1 ML-платформа физически отсутствует — есть только обязательство к event format, чтобы потом не переписывать collectors.
Что у нас уже зафиксировано: аналитические события с самого начала имеют схемы, готовые для ML (hashed user_id, generalized geo, exposure tracking, conversion events); DWH с partition'ами по дате и user_id; feature naming convention.
Что стоит сделать сильнее:
- Добавить в reference/ml-platform.md раздел «Stage 1 minimum» — какие именно поля в каких events обязательны с нулевого дня для будущих ML-моделей (даже если сами модели появятся в Stage 3).
- Список 3-5 «MVP-моделей» которые мы планируем (ranking, dynamic pricing, fraud detection, recommendation, demand forecasting) — для каждой указать какие поля events критичны на Stage 1.
- Принцип: «накапливай данные в правильной схеме, даже если ещё не используешь».
Приоритет: Block 2 (закладка для Stage 2-3).
Ответ 3.1: Conflict Resolution в Ingestion — самый важный пункт ревью
Согласен полностью, критическая правка. В reference/data-governance-and-matching.md есть матчинг (когда две записи об одном объекте — это один объект), но не conflict resolution для противоречивых данных (когда один объект, но supplier'ы дают разные значения).
Конкретные сценарии без решения:
- Два supplier'а вернули разные координаты одного отеля.
- Два supplier'а вернули разные
star_rating. - Supplier поменял координаты — это поправка ошибки или новая локация?
- Три источника, два говорят X, один Y — большинство выигрывает или есть приоритет?
Действие: расширить data-governance-and-matching.md разделом «Conflict Resolution Policy»:
- Source priority rules — у каких полей какой supplier канонический (координаты — Google Places, цены — supplier который продаёт, описание — наш редактор).
- Voting mechanism — для полей без явного приоритета, большинство из последних N источников.
- Confidence scoring — каждое поле имеет confidence в зависимости от источника и согласованности.
- Manual review queue — при low confidence или явном расхождении — модератору.
- Audit trail — каждое изменение поля канонической модели хранит provenance: какой источник, когда, какой confidence.
Это must-have перед Stage 1 production. Без этого получим именно «гнилой фундамент» о котором говорит ревьюер в финальном выводе.
Приоритет: Block 1, наивысший в блоке.
Ответ 3.2: Каскадный дрейф в Tour Builder — согласен
В reference/tour-builder-operational-model.md есть DriftEvent, но auto-replace только декларативно упомянут.
Действие: дописать:
- Каскадный анализ влияния: при дрифте одного элемента — пересчёт всего тура (новая полная цена, новые комиссии, новые комбинации).
- Replacement candidates: для каждого элемента тура хранить ranked-список альтернатив (cheaper hotel, alternative airline, similar tour) на случай дрифта.
- Threshold rules: total drift < 5% — auto-accept; 5-15% — auto-replace с уведомлением партнёра; > 15% — manual review партнёром.
- Bundle integrity: проверка что замена не нарушает связи (например, замена отеля не должна нарушить расстояние до точки трансфера).
Сложная фича, но проектировать сразу нужно. Иначе при first production-tour drift'е партнёр получит «вы должны переделать всё руками» — и доверие потеряно.
Приоритет: Block 2.
Ответ 3.3: Settlement при частичных отказах — согласен
В reference/partner-finance-and-clearing.md финансовая модель refund'ов прописана, но разделение ответственности между supplier-refund и платформенным refund размыто.
Действие: явно зафиксировать:
- Supplier portion: сколько вернёт поставщик (по контракту с нами).
- Platform portion: сколько мы возвращаем партнёру даже если supplier не вернул (insolvency protection per Package Travel Directive).
- Customer portion: что возвращается end-customer'у через нашего партнёра.
- Loss accounting: разница между supplier-portion и platform-obligation — это наш убыток (ML может прогнозировать риск, partner-tier может покрывать через premium fee, или амортизация через резерв).
Связано с insurance product который сейчас декларативный — может быть стоит сразу проектировать opt-in расширенную страховку для партнёра.
Приоритет: Block 3.
Дополнение от архитектора — gap, не замеченный ревьюером
Long-running idempotency для Tour Builder
У нас есть idempotency keys для синхронных вызовов. Но Tour Builder может минутами собирать тур (саги через несколько supplier'ов). Если партнёр повторяет запрос с тем же idempotency-key через 30 секунд:
- Возвращаем cached partial result?
- Возвращаем error «in_progress»?
- Игнорируем повтор?
В нашей документации это не прописано чётко.
Действие: добавить раздел «Long-running idempotency semantics» в reference/eventing-and-queue-baseline.md.
Приоритет: Block 3.
План интеграции замечаний
Block 1 — критичное к Stage 1 (срочно)
- Conflict Resolution Policy в data-governance-and-matching.md — самый важный gap.
- Timeout-эскалация для unknown_external_state в booking-state-machine.md + связь с finance.
- «SDK как тонкая обёртка» в api-as-product.md — снимает риск раздвоения surfaces.
Block 2 — закладка для Stage 2-3 (зафиксировать сейчас, реализовать позже)
- Inventory non-accommodation новый документ — закладывает семантику flights/transfers/insurance.
- Stage 1 minimum для ML в ml-platform.md — какие поля events обязательны с нулевого дня.
- Tour Builder cascading drift + auto-replace в tour-builder-operational-model.md.
Block 3 — финансовые уточнения
- Settlement split (supplier/platform/customer portions) в partner-finance-and-clearing.md.
- Long-running idempotency в eventing-and-queue-baseline.md.
Block 4 — коммуникационные
- «Stripe в travel» формулировка в architectural-anchor-and-business-model.md.
- Прозрачность тарификации в economic-model.md с примерами и mockup'ом дашборда.
Резюме
Внешнее ревью признаёт архитектуру готовой к Stage 1 при условии закрытия 3 критических gap'ов в Block 1. Все замечания по существу приняты, по двум вопросам (SDK-граждане первого сорта, тарификация за «сложность») архитекторская позиция уточнена, не отвергнута.
Главный совет ревьюера — «сфокусируйтесь на Governance данных» — соответствует Block 1 нашего плана интеграции (пункт 1: Conflict Resolution Policy).
Связанная документация
Документы, которые будут обновлены или созданы по итогам ревью:
- reference/data-governance-and-matching.md — расширение разделом Conflict Resolution Policy.
- reference/booking-state-machine.md — усиление timeout-эскалации.
- reference/api-as-product.md — тезис «SDK как тонкая обёртка».
- reference/inventory-non-accommodation-domains.md — новый документ.
- reference/ml-platform.md — Stage 1 minimum раздел.
- reference/tour-builder-operational-model.md — cascading drift + auto-replace.
- reference/partner-finance-and-clearing.md — settlement split.
- reference/eventing-and-queue-baseline.md — long-running idempotency.
- overview/architectural-anchor-and-business-model.md — Stripe-в-travel формулировка.
- reference/economic-model.md — прозрачность тарификации.
- development/abstract-platform-summary-for-external-evaluation.md — источник, на котором было сделано ревью.