UC-OVR-001. Запрос консультации у агента недвижимости
Назначение
Cross-service сценарий: инвестор с публичной витрины (или по реферальной ссылке агента) просит консультацию/
презентацию, и заявка превращается в лид в воронке конкретного агента. Оркеструет crm (публичный вход),
identity (lazy-регистрация), referral (привязка агента), catalog/selections (контекст объекта),
notifications (уведомление агенту). Альтернативный вход — самозапись на конкретный свободный слот агента
через calendar (см. альтернативный сценарий ниже): лид создаётся асинхронно по событию
pin.calendar.appointment-created.v1.
Metadata
| Поле | Значение |
|---|---|
| Статус | draft |
| Owning team | crm |
| Primary capability | consultation-lead-intake |
| Risk level | medium |
Scope И Участники
| Участник | Роль |
|---|---|
| Инвестор / Гость | Актор: отправляет форму «ФИО + телефон» + опц. контекст (подборка/объект/время) |
catalog / selections | Источник контекста заявки (PropertyObjectId, SelectionId) — подсказки для агента |
crm (public) | Оркестратор: приём заявки, get-or-create Client/Lead, событие ленты ConsultationRequested |
identity (internal) | Lazy-регистрация инвестора по телефону → InvestorUserId |
referral | Правила привязки: реф-ссылка агента → AgentUserId + TenantId = AgencyCompanyId |
calendar | Альтернативный вход: витрина свободных слотов агента и бронирование (UC-CAL-003) — лид создаётся по событию appointment-created |
notifications | Consumer lead-created → пуш/СМС агенту «новый лид» |
Preconditions
- Витрина доступна анонимно или под JWT инвестора; при переходе по реф-ссылке в cookie лежит
referralUrl. - У агента есть активная реф-ссылка (см. UC-REF-001).
- Для слотового входа: агент опубликовал слоты самозаписи (UC-CAL-002).
Основной Сценарий
- Инвестор на карточке объекта/подборки жмёт «Получить консультацию» и заполняет форму ФИО + телефон.
- Фронт вызывает
POST /api/public/crm/consultation-requests(create-consultation-request.md), передаёт опц.SelectionId/PropertyObjectId/PreferredAtи cookiereferralUrl. crmвыполняет дубль-детект по телефону в окне (при повторе в окне —409 DUPLICATE_PHONE).crm→identityinternal «get-or-create user by phone» (lazy-регистрация) →InvestorUserId.crmопределяет агентскую сторону через правила привязкиreferral: валидная реф-ссылка агента →AgentUserId= владелец,TenantId = AgencyCompanyId. (Ссылки нет / ссылка инвестора → маршрут UC-OVR-002.)- get-or-create
Client(уникальность по паре tenant + телефон) и активногоLead(инвариант «один активный лид на пару агент↔инвестор»); лид фиксирует событие лентыConsultationRequested— см. UC-CRM-001. - В одном согласованном изменении сохраняются клиент, лид и событие ленты; для нового лида публикуется
pin.crm.lead-created.v1(lead-created.md). notifications(consumerlead-created) уведомляет агента; агент видит лид в CRM и берёт в работу.
Sequence
Постусловие
После успешного сценария (нового лида) гарантированно:
- в
identityсуществуетUserEntityинвестора (InvestorUserId), созданный/найденный lazy-регистрацией по телефону; - в
crmестьClient(уникален по пареtenant + телефон) и ровно один активныйLeadпары агент↔инвестор со снапшотамиAgentUserId= владелец реф-ссылки иTenantId = AgencyCompanyId(иммутабельны); - зафиксировано событие ленты
ConsultationRequestedв истории лида; - опубликовано
pin.crm.lead-created.v1(Source = ConsultationRequest, key =LeadId) — ровно один раз на новый лид; агент получит уведомление в пределах окна обработкиnotifications(< 5 мин); - инвестору немедленно возвращён
201 {requestId, receivedAt}— заявка принята.
Если активный лид пары уже был — новые сущности не создаются, интеграционное событие не публикуется;
добавляется только новое событие ленты ConsultationRequested (повторное обращение того же инвестора).
Альтернативные Сценарии И Отказы
| Ситуация | Поведение |
|---|---|
| Реф-ссылки нет или ссылка инвестора | Маршрут переходит в UC-OVR-002 (агент ПИН) |
Реф-cookie просрочена/невалидна (код не найден в referral) | Привязка не даётся → fallback на ПИН-маршрут (UC-OVR-002); подделка cookie не должна давать чужую атрибуцию |
| Пустые/некорректные ФИО или телефон (формат) | 400 VALIDATION до дубль-детекта и lazy-регистрации; сущности не создаются |
| Повторная заявка тем же телефоном в окне | 409 DUPLICATE_PHONE (дедуп по телефону в окне); повтор идемпотентен для пользователя — новых лидов/событий нет |
identity недоступен | 503 IDENTITY_UNAVAILABLE, форма предлагает повтор; лид не создаётся (нет InvestorUserId) |
| Активный лид пары агент↔инвестор уже есть | Переиспользуется (один активный лид на пару агент↔инвестор), интеграционных событий нет — новое событие ленты |
Указанный SelectionId/PropertyObjectId не существует/снят | Контекст-подсказка отбрасывается (деградация), заявка принимается без контекста — не блокирует лид |
| Инвестор хочет конкретное время (не «время обсудим») | Слотовый вход: бронирование свободного слота агента — см. альтернативный сценарий ниже |
Альтернативный Сценарий: Инвестор Выбирает Свободный Слот Агента
Тот же бизнес-результат — лид в воронке конкретного агента — достигается самозаписью на конкретное время вместо формы «время обсудим»:
- Инвестор на странице агента / проекта / объекта открывает витрину свободных слотов
(list-available-slots, доступно
анониму) и выбирает слот нужного вида (
Showing/Consultation). - Бронирование слота (book-slot; детально —
UC-CAL-003): lazy-регистрация
анонима по телефону через
identity(как в основном сценарии), слотAvailable → Booked, запись (PendingилиConfirmedпоAutoConfirm) и календарное событие агента — в одном согласованном изменении; публикуетсяpin.calendar.appointment-created.v1(appointment-created.md). crm(consumerdocs/06-services/crm/consumers/calendar-appointments.md) поappointment-createdасинхронно (< 1 мин) делает get-or-createClient/Leadв tenant компании агента и пишет ленту лида (вид/время встречи,Commentинвестора); для нового лида публикуетсяpin.crm.lead-created.v1— дальше как шаг 8 основного сценария.- Привязка агента задаётся выбранным слотом (
AgentUserId/TenantIdиз события) — правилаreferralне участвуют. Дубль-детект окнаDUPLICATE_PHONEне применяется: антиспам живёт на стороне календаря (не более 1 активной записи на пару «инвестор + агент + вид», ≤ 3 активных записей суммарно —APPOINTMENT_DUPLICATE). Pending-запись ждёт решения агента (UC-CAL-004). Оба входа воронки — слотовый и no-slot — сходятся в одном клиенте/лиде (get-or-create по телефону инвестора).
Согласованность И Идемпотентность
- Атомарность записи. Клиент, лид и событие ленты сохраняются в одном согласованном изменении; событие
lead-createdуходит только после фиксации (иначе не уходит совсем). - Идемпотентность входа. Lazy-регистрация в
identityидемпотентна по телефону; дубль-детект в окне отсекает повторные формы (409 DUPLICATE_PHONE). Инвариант «один активный лид на пару агент↔инвестор» делает повторную заявку no-op для интеграционных потребителей. - Порядок и доставка.
pin.crm.lead-created.v1: key =LeadId, at-least-once. Потребительnotificationsдедуплицирует поMessageId; событие append-only (version-guard не требуется). - Окно eventual-consistency. Между
201инвестору и появлением лида у агента — задержка обработкиnotifications(< 5 мин). В этом окне инвестор уже видит «заявка принята», агент — ещё нет. - Слотовый вход — событийный. При бронировании слота лид появляется в CRM асинхронно по
appointment-created(окно < 1 мин); запись в календаре агента видна сразу. Идемпотентность консюмера —MessageId+ business keyAppointmentId; инвариант «один активный лид на пару агент↔инвестор» сводит слотовый и no-slot входы к одному лиду.
Acceptance Criteria (Given/When/Then)
- Happy (новый лид у агента). Дано: анонимный инвестор пришёл по валидной реф-ссылке агента (cookie
referralUrl), активного лида пары нет. Когда: отправляет форму ФИО + телефон с карточки объекта. Тогда: создаютсяClientи активныйLead(AgentUserId= владелец ссылки,TenantId = AgencyCompanyId), фиксируетсяConsultationRequested, публикуетсяpin.crm.lead-created.v1, агент получает уведомление, инвестор —201. - Повторное обращение (реюз лида). Дано: активный лид этой пары уже есть. Когда: инвестор снова
отправляет форму. Тогда: новый лид не создаётся, интеграционное событие не публикуется, добавляется только
событие ленты
ConsultationRequested; ответ201. - Дубль по телефону. Дано: заявка с тем же телефоном в окне дедупликации. Когда: форма отправлена
повторно. Тогда:
409 DUPLICATE_PHONE, новые сущности и события не создаются. - Нет привязки к агенту. Дано: реф-cookie отсутствует/невалидна/указывает на инвестора. Когда: форма отправлена. Тогда: сценарий переходит на ПИН-маршрут (UC-OVR-002).
identityнедоступен. Дано: сервис identity не отвечает. Когда: форма отправлена. Тогда:503 IDENTITY_UNAVAILABLE, лид не создан, форма предлагает повтор.- Слотовый вход (самозапись). Дано: агент опубликовал слоты, активного лида пары нет. Когда: инвестор
бронирует свободный слот агента с витрины. Тогда: создана запись и календарное событие агента, по
appointment-createdCRM создаётClientи активныйLeadв tenant компании агента с событием ленты о встрече; последующая no-slot заявка того же телефона переиспользует этот лид.
Source Of Truth И Данные
| Данные | Владелец | Consistency rule |
|---|---|---|
Client / Lead / LeadEvent | crm | В одном согласованном изменении; уникальность клиента по паре tenant + телефон; один активный лид на пару агент↔инвестор |
UserEntity (инвестор) | identity | Lazy-регистрация идемпотентна по телефону |
| Привязка агента | referral | Правила R1/R2/R6 (attach-rules.md) |
Контракты И Зависимости
- API: create-consultation-request.md; слотовый вход — list-available-slots.md, book-slot.md.
- Events: lead-created.md, appointment-created.md.
- UC сервисов: UC-CRM-001, UC-REF-001, UC-CAL-003, UC-CAL-004.
- ADR: 0052 tenancy, 0056 simplicity-first, 0064 calendar.
Наблюдаемость
- critical metrics:
crm_consultation_requests_total{result}, доля привязанных к агенту vs ПИН. - trace path: витрина →
crm.public→identity.internal→ шина событий →notifications. - alerts: рост
409 DUPLICATE_PHONE/503 IDENTITY_UNAVAILABLE.
Риски И Guardrails
- Риск: PII формы в логах. Control: телефон маской
+7***NNNN, ФИО не логируется. - Риск: неверная привязка агента при поддельной реф-cookie. Control: валидация кода в
referral, fallback на ПИН.
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (2): UC-CAL-003. Инвестор бронирует слот с витрины, US-реестр контекста calendar (US-CAL)
- scenarios (6): Кросс-сервисные сценарии PIN (OVR), UC-OVR-002. Запрос консультации у инвест-консультанта ПИН (+2a), UC-OVR-003. Бронирование объекта у агента (+3a), UC-OVR-004. От реферальной ссылки до объекта у собственника, UC-OVR-005. От лида до сделки (4 фазы), UC-OVR-011. Самозапись инвестора: от слота до исхода встречи и лида в воронке
- index.md (1): Calendar Service
- registries (1): Реестр use cases и user stories PIN