UC-REF-005. Авторизация: «Имя заполнено И регистрация ≥ 4 ч» → только лид, без связи (правило R3)
Назначение
Авторизация инвестора с реферальной ссылкой, когда пользователь уже зарегистрировался сам: имя
заполнено И дата регистрации более 4 часов назад. Реферальная связь НЕ создаётся (вознаграждение рефереру
не положено — пользователь пришёл в систему самостоятельно, INV-REF-003), но лид между агентом и
инвестором создаётся на основе этой ссылки. Правило R3 AuthorizationSelfRegistered матрицы
attach-rules.md. Связан с контекстом referral.
Metadata
| Поле | Значение |
|---|---|
| ID | UC-REF-005 |
| Контекст | referral (см. docs/06-services/referral/) |
| Тип | альтернативный (ветка триггера T2; основная ветка — UC-REF-004) |
| Статус | draft |
Актор
| Поле | Значение |
|---|---|
| Роль | System (обработка события входа; m2m ACL Kafka на топик pin.identity.sign-ins.v1); инициатор — Инвестор с давно завершённой регистрацией |
| Permissions / scope | permission не применяется (system actor); доступ — ACL топика |
| Tenant | лид-событие несёт AgentCompanyId = link.TenantId (ADR-0052); записей в referral не создаётся |
| Record-level | не применяется |
Предусловие
- Учётка инвестора существует; в реплике
ReferralUserReplica:IsNameFilled = trueИnow() - RegisteredAt >= Referral:LazyRegistrationWindow(default 4 ч) — либоRegisteredAt = null(fail-closed, альтернатива A1). - Инвестор открыл реферальную ссылку агента/застройщика — cookie
referralUrlжива (UC-REF-002). - Поле
ReferrerUrl?вUserSignedInKafkaEventдоступно (решение 4 README.md). - Guard-ы G1–G4 attach-rules.md выполнены; владелец ссылки —
Agent/DeveloperManagerсоStatus = Active(иначе полный no-op, альтернатива A2).
Триггер
| Поле | Значение |
|---|---|
| Источник | Kafka event |
| Триггерящий элемент | Событие UserSignedInKafkaEvent (топик pin.identity.sign-ins.v1), ReferrerUrl != null (триггер T2, ветка R3 attach-rules.md) |
Основной Поток
Ниже — дельта R3 к общему алгоритму привязки (дом — attach-rules.md): связь и журнал не пишутся.
- Давно зарегистрированный инвестор (имя заполнено) открывает ссылку агента и входит в систему;
identityпубликуетUserSignedInKafkaEventсReferrerUrl = slug(user-signed-in.md). - Контекст и идемпотентность. Повтор отсекается по
MessageId(записей вreferralэтот сценарий не делает, дедуп лида — на стороне CRM). Формат slug валиден; ссылка резолвится и не удалена (G1). Читаются: реплика пользователя (Type = Investor[G2],Status[G4],IsNameFilled,RegisteredAt); владелец ссылки; наличие активной связи — только для телеметрии выбора ветки (связь в R3 всё равно не создаётся). - Выбор правила.
IsNameFilled = trueИвремя события - RegisteredAt >= Referral:LazyRegistrationWindow→ правило R3 (INV-REF-003 SelfRegisteredNoBond: «пользователь зарегистрировался уже сам»). Связь НЕ создаётся; проверка INV-REF-002: владелец —Agent/DeveloperManager,owner.Status = Active→ лид требуется. - Без записей. Правило R3 ничего не пишет в
referral— ни связь, ни журнал (в матрице «Журнал: нет»); след лида живёт в карточке CRM (referral-registration.md, раздел «Назначение»). - Интеграционное событие. Публикуется только
ReferralLeadAttachRequestedKafkaEvent(pin.referral.lead-attachments.v1, key =InvestorUserId; payload:InvestorUserId = event.UserId,AgentUserId = link.OwnerUserId,AgentCompanyId = link.TenantId,ReferralLinkId = link.Id,Channel = link.Channel,AppliedRule = R3,BondId = null— связи нет,RequestedAt = now()). Событие фиксируется согласованно; затем подтверждается (ack). - Downstream.
crmсоздаёт карточку лида «агент ↔ инвестор» (дедуп активной пары на стороне CRM — у пары одновременно один активный лид);rewardsсобытия НЕ получает — основания для выплат нет.
Альтернативные Потоки
A1. RegisteredAt = null в реплике (пользователь без RegisteredAt)
- Дата регистрации неизвестна (first-seen пришёл с
Version > 1до backfill) → окно 4 ч считается истёкшим (fail-closed, решение 5 README.md): работает то же правило R3. Поток не меняется.
A2. Владелец ссылки — не агент/застройщик
- INV-REF-002 не выполнен (модификатор R5): лид не запрашивается; связи по R3 тоже нет → полный no-op (structured log с исходом guard-а). Событие подтверждается. Завершение.
A3. У инвестора уже есть активная связь с другим агентом
- R3 связь всё равно не создаёт, активная связь с агентом A не трогается (INV-REF-001).
- Лид агенту B запрашивается — несколько агентов могут отслеживать одного инвестора. Поток не меняется.
A4. Повторный вход с той же cookie (30 дней живёт)
- Каждый вход с
ReferrerUrlснова публикует lead-событие с тем же бизнес-ключом (InvestorUserId,AgentUserId); CRM дедуплицирует — активная пара одна, дубль карточки не создаётся (attach-rules.md, «Дедупликация лидов»). Событие подтверждается.
Постусловие
- В
referralНЕ появилось ниReferralBondEntity, ни записи журнала (getMyReferrerинвестора по-прежнемуhasReferrer = false, если связи не было). - В CRM запрошена (или дедуплицирована) карточка лида «агент ↔ инвестор» с
AppliedRule = R3,BondId = null. rewardsникаких событий не получил — выплат по этому сценарию не будет (INV-REF-003).
Возможные Ошибки
| Код | HTTP | Условие | Поведение |
|---|---|---|---|
| — (no-op, warning) | — (Kafka consumer, HTTP нет) | Guard G1–G4: битый slug, не инвестор, self-attach, blocked | Метрика no-op guard-ов |
| — (полный no-op) | — | Владелец не агент/застройщик (A2, R5/INV-REF-002) | Событие подтверждается |
| retry consumer-а | — | Реплика пользователя/владельца отсутствует | Retry |
| DLQ после исчерпания retry | — | Инфраструктурный сбой | Runbook referral-consumer-lag (README.md) |
Доменные События
| Событие | Когда поднимается | Subscribers |
|---|---|---|
| — | Не поднимаются: агрегаты referral в этом сценарии не создаются и не мутируются | — |
Kafka Интеграционные События
| Событие | Topic | Когда публикуется | Consumers |
|---|---|---|---|
ReferralLeadAttachRequestedKafkaEvent | pin.referral.lead-attachments.v1 | Правило R3: владелец — Agent/DeveloperManager (шаг 5); BondId = null | crm (карточка лида, дедуп активной пары) |
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Вход с ReferrerUrl при IsNameFilled = true и регистрации 5 ч назад → связь НЕ создана, журнал пуст, lead-событие с AppliedRule = R3, BondId = null | интеграционный тест |
| AC2 | getMyReferrer инвестора после сценария → hasReferrer = false | API-тест |
| AC3 | RegisteredAt = null → тот же исход R3 (fail-closed) | тест реплики без RegisteredAt |
| AC4 | Владелец-инвестор → полный no-op: ни события, ни записей | негативный тест (см. также UC-REF-006) |
| AC5 | Повторный вход → повторное lead-событие; в CRM активная пара одна (дедуп) | e2e с crm-стабом |
| AC6 | rewards не получает событий по R3 | проверка топика pin.referral.bonds.v1 пуст |
| AC7 | Активная связь с агентом A не изменяется при лиде агенту B | тест A3 (INV-REF-001) |
| AC8 | Владелец-агент со Status ∈ {Blocked, Archived} → лид не запрашивается (guard owner.Status = Active): полный no-op, связи по R3 всё равно нет | тест заблокированного владельца-агента |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (3): UC-REF-002. Аноним открыл реферальную ссылку (cookie 30 дней, validateReferralLink), UC-REF-004. Авторизация со ссылкой в окне lazy-регистрации → связь + лид (правило R2), UC-REF-006. Ссылка от инвестора (не агента/застройщика) → связь без лида (модификатор R5)
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- Правила привязки (дом): ../domain/attach-rules.md — правило R3,
INV-REF-003, «Дедупликация лидов», уточнение
RegisteredAt = null. - Consumer: ../consumers/user-signed-in.md.
- Событие: ../events/lead-attach-requested.md; входное — user-signed-in.md.
- Соседний контекст: crm/README.md (жизненный цикл карточки лида, единственность активной пары).
- Связанные UC: UC-REF-004 (R2 — когда связь создаётся), UC-REF-006 (зеркальный кейс: связь без лида).