ADR: Search Intelligence Layer MVP
ADR: Search Intelligence Layer MVP
Status: Proposed
Date: 2026-06-26
Context: В Яндекс.Директе накоплено ~6 500 уникальных ключевых слов из 16 архивных кампаний. В Яндекс.Метрике — ежедневно ~1 000 поисковых фраз от реальных посетителей. Необходимо создать слой, который переводит разрозненные поисковые сигналы в связку «кластер → JTBD → оффер → поверхность размещения» и даёт управленческие рекомендации.
Decision
1. Search Intelligence Layer — не отдельный модуль, а cross-domain слой
SIL не живёт сам по себе. Он — связующий контур между:
- коннекторами (raw data)
- словарём фраз (normalization)
- семантическим слоем (clustering)
- бизнес-сущностями (JTBD, Offer, Product)
- поверхностями размещения (Campaign, Landing, TrafficSource)
- action layer (Opportunity Cards)
Архитектурная цепочка:
raw phrase → canonical phrase → search_cluster → JTBD / buyer stage → offer → placement surface
2. Cluster-first, не phrase-first
Основная единица принятия решений — search_cluster, не отдельная фраза.
Правила:
- Прямая связь phrase → entity — только override/high-confidence
- Основные связи — на уровне кластеров:
- cluster → JTBD
- cluster → buyer stage
- cluster → offer fit
- cluster → placement recommendation
3. FastAPI как backend source of truth
- Бизнес-логика — только в FastAPI
- Next.js API routes — только BFF (прокси/агрегация для UI)
- Sync-воркфлоу — batch через cron внутри FastAPI (или n8n)
4. Две отдельные сущности: buyer stage и CRM pipeline stage
| Сущность | Назначение |
|---|---|
buyer_stage | Стадия принятия решения пользователем |
crm_pipeline_stage | Стадия движения лида в воронке |
Маппинг на buyer_stage: search_cluster → intent_classification
Связь с CRM: через аналитику конверсий
5. Placement surface — нормализованная сущность
placement_surface— таблица-справочник- Связь с LandingVariant/Campaign/TrafficSource — через существующие link-таблицы
- Не хранить как TEXT[]
6. Opportunity Score → Opportunity Cards
search_opportunity_score— аналитический расчётный слой (веса, нормализация)opportunity_cards— управленческий action-слойopportunity_cardsрасширяем: source='search_intelligence', search_score_id FK
7. Строгая таксономия каналов
direct_traffic≠yandex_direct_ads- Единый словарь
traffic_channelна уровне домена
8. Wordstat — deferred dependency
- Доступа к Search API v2 / Wordstat нет
- Модель учитывает Wordstat (search_fact_wordstat)
- MVP не блокируется
- На старте: Директ history + Forecast + Метрика
9. AI-автоматизация — позже
Условия запуска:
- data quality стабильна
- taxonomy зафиксирована
- buyer stages проходят валидацию
- opportunity score работает
MVP: batch-кластеризация + ручная валидация. AI = Phase 6.
10. Технологический стек на MVP
| Компонент | Решение |
|---|---|
| DB | PostgreSQL 16 (существующий) |
| Vector search | pgvector (уже включён) |
| Text search | gin_trgm_ops |
| Backend | FastAPI (существующий) |
| Sync | Batch cron (1×/сутки) |
| Raw storage | PostgreSQL → object storage после 30 дней |
| Embedding | VECTOR(384) (как в research_clusters) |
Alternatives Considered
A1. Отдельный Vector DB (Qdrant/Milvus)
Отклонено. 1 млн записей за год — pgvector справится. Отдельный сервис = лишняя сложность на старте.
A2. Real-time sync
Отклонено. Ежедневного batch достаточно для аналитики и рекомендаций. Real-time добавит цену без пропорциональной пользы.
A3. AI-first: сразу ML-кластеризация
Отклонено. Без валидированной taxonomy и качественных данных ML будет генерировать шум. Сначала — ручная разметка топ-кластеров.
A4. Phrase-first: каждая фраза ко всем сущностям
Отклонено. Приведёт к N×M связям и мусору. Cluster-first — чище и полезнее.
A5. Использовать research_clusters как основу
Отклонено. ResearchCluster жёстко привязан к research_queries. Создаём отдельные search_clusters.
Consequences
Positive
- Модуль не дублирует существующие сущности
- Cluster-first даёт меньше мусора и больше полезных решений
- FastAPI-first сохраняет единый backend
- Retention policy не даёт БД раздуваться
- Quick Wins видны уже через 2-4 дня
Negative
- Нужна миграция для расширения opportunity_cards
- Search clusters — новые таблицы (миграции 0022+)
- Sync jobs нужно писать с нуля (или через n8n)
- Wordstat отложен — не будет сезонности и related queries на MVP
Risks
- Дублирование: search_clusters ≠ research_clusters, задокументировать связь
- Перегрузка: 7 000+ фраз × 16 кампаний = ~100 000 фактов. Индексы решают
- Multi-tenant: workspace_id пронести во все новые сущности
Deferred Items
| Фича | Причина откладывания | План |
|---|---|---|
| Wordstat API | Нет доступа к Yandex Cloud Search API | Когда появится сервис-аккаунт |
| ML-автокластеризация | Нет quality данных и валидированной taxonomy | Phase 6 |
| AI-рекомендации офферов | Зависит от ML-кластеризации | Phase 6 |
| Real-time sync | Не нужно для MVP | Отложено |
| Отдельный vector DB | pgvector достаточно | Если > 10 млн записей |
References
docs/search-intelligence/01-repo-gap-analysis.mddocs/search-intelligence/02-architecture-dna-corrections.mddocs/search-intelligence/03-domain-taxonomy.mddocs/search-intelligence/04-data-model-v2.mddocs/search-intelligence/05-roadmap-v2.mddocs/search-intelligence/06-implementation-backlog.mddocs/search-intelligence/07-open-questions-for-architect.mddocs/adr/ADR-direct-ecospros-campaign-integration.mdapps/api/app/domain/direct.py— direct_keywordsapps/api/app/domain/research.py— research_clustersapps/api/app/domain/opportunity.py— opportunity_cardsapps/api/app/domain/activation.py— campaigns, landing_variants, traffic_sources