UC-SEL-002. Шаринг подборки по ссылке (SharePopover + реферальная ссылка)
Назначение
Описывает сценарий, в котором владелец делится подборкой: подборка «привязана к текущему пользователю
(владелец), но по ссылке (по ид) её может открыть кто угодно» (ТЗ.md:281). Прототип — SharePopover на
странице /collection (prototype-mapping.md, строка /collection: «подборки из избранного +
SharePopover с реф-ссылкой»): фронт комбинирует публичную ссылку подборки (PublicCode,
контекст selections) с реферальной ссылкой владельца (контекст referral, existing-net) — получатель,
перейдя по ссылке, попадает в реферальную воронку владельца (cookie referralUrl 30 дней, UC-1..3).
Со стороны selections сценарий read-only: мутаций нет, ссылка существует с момента создания
подборки (INV-SEL-005). Связан с контекстами selections и referral.
| Поле | Значение |
|---|
| ID | UC-SEL-002 |
| Контекст | selections (см. docs/06-services/selections/); интеграция — referral |
| Тип | основной |
| Статус | draft |
Актор
| Поле | Значение |
|---|
| Роль | Инвестор или Агент — владелец подборки (шаринг доступен любому владельцу; для агента это канал привлечения клиента — UC-SEL-005) |
| Permissions / scope | self-scope: список своих подборок — OwnerUserId = actor (INV-SEL-002); реф-ссылка — своя (referral, self-scope) |
| Tenant | не tenanted (ADR-0052 п.2) |
| Record-level | GET /selections фильтруется по OwnerUserId = actor.UserId; чужую подборку «пошарить» нельзя — её PublicCode знает только тот, кому её уже открыли |
Предусловие
- У владельца есть хотя бы одна активная (не удалённая) подборка —
UC-SEL-001 или создание вручную.
- Для реф-части: у владельца есть (или создаётся на лету) дефолтная реферальная ссылка —
операция
getOrCreateDefaultReferralLink (referral, existing-net —
../../referral/README.md, будущий путь по конвенции).
Триггер
| Поле | Значение |
|---|
| Источник | UI button |
| Триггерящий элемент | Страница /collection → карточка подборки → кнопка «Поделиться» (SharePopover); заглушка прототипа «Поделиться подборкой» (prototype-mapping «Заглушки фронта») |
Основной Поток
- Владелец открывает
/collection; фронт отдаёт список GET /selections (query
ListMySelectionsQuery, read-only: Filter(s => s.OwnerUserId == actor.UserId && s.DeletedAt == null, orderBy: CreatedAt desc); ответ каждой подборки содержит SelectionId, Title, PublicCode,
ItemsCount, Source, CreatedAt).
- Владелец нажимает «Поделиться» у подборки — открывается SharePopover.
- Фронт строит ссылку локально, без запроса в
selections (все данные уже есть):
- базовая публичная ссылка:
https://<host>/collection/{publicCode};
- хук
useShareReferralLink запрашивает у referral дефолтную реф-ссылку владельца
(getOrCreateDefaultReferralLink — создаёт при первом обращении) и добавляет реф-параметр:
итог https://<host>/collection/{publicCode}?ref={referralLinkId} (формат параметра — контракт
referral, дом — docs/06-services/referral/ по конвенции).
- SharePopover предлагает: копировать ссылку / системный share / QR. Владелец копирует и отправляет
получателю любым каналом (мессенджер, СМС — вне платформы).
- Получатель переходит по ссылке:
- фронт по
?ref= ставит cookie referralUrl на 30 дней и валидирует ссылку
(validateReferralLink, referral) — вход в реферальную воронку UC-1..3
(docs/02-architecture/scenarios/);
- подборка открывается публично по
publicCode — UC-SEL-003.
- Если получатель позже регистрируется/оставляет заявку — реферальная связь «кто привёл» создаётся
по правилам привязки
referral (Имя пустое / регистрация < 4 ч / владелец-агент —
glossary «Реферальная связь»); для агента-владельца это ведёт к лиду в CRM.
Альтернативные Потоки
A1. referral недоступен / реф-ссылку получить не удалось
- SharePopover деградирует до чистой публичной ссылки
/collection/{publicCode} без ?ref= —
шаринг подборки не блокируется реферальной системой; предупреждение владельцу не показывается
(реф-атрибуция — бонус, не условие).
- Возврат к основному потоку, шаг 4.
A2. Подборка удалена между открытием списка и шарингом
- Ссылку построить можно (все данные локальны), но получатель получит 404
(
SELECTIONS_NOT_FOUND — INV-SEL-009, UC-SEL-003 A1).
- Фронт владельца при обновлении списка перестаёт показывать удалённую подборку. Завершается.
A3. Получатель — уже авторизованный пользователь
- Cookie
referralUrl ставится, но реферальная связь не возникнет (правила привязки referral
отсеивают существующих пользователей вне окна); подборка открывается как обычно (UC-SEL-003 —
любой актор). Завершается.
A4. Владелец делится «живой» подборкой и продолжает её править
- Ссылка не протухает (INV-SEL-005:
PublicCode неизменяем); получатель всегда видит актуальное
состояние подборки на момент открытия — подборка живая (заморозка состава существует только для
постов, UC-SEL-004). Завершается.
A5. Реф-параметр ?ref= невалиден или чужой
- Получатель перешёл по ссылке, но
validateReferralLink (referral) отклонил referralLinkId
(устарел / отозван / не принадлежит никому): cookie referralUrl не ставится, реферальная воронка
не активируется.
- Открытие самой подборки не зависит от валидности реф-части (это параллельный параметр
selections) — подборка открывается по publicCode штатно
(UC-SEL-003). Реф-атрибуция — бонус, не условие доступа.
Завершается.
Постусловие
- Состояние
selections не изменилось (read-only сценарий; событий нет).
- У получателя: подборка открыта (UC-SEL-003), cookie
referralUrl на 30 дней (при наличии ?ref=).
- Возможная будущая реферальная связь/лид — зона
referral/crm (их UC).
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|
401 | 401 | GET /selections без JWT | Auth-модалка |
5xx от referral | — | Реф-ссылка недоступна (A1) | Деградация: ссылка без ?ref= |
SELECTIONS_NOT_FOUND | 404 | Получатель открыл удалённую подборку (A2) | Страница «подборка не найдена» |
Доменные События
Не поднимаются — read-only сценарий (изменений состояния в selections нет).
Kafka Интеграционные События
| Событие | Topic | Когда публикуется | Consumers |
|---|
| — (сценарий не публикует) | — | — | — |
Факт «поделился подборкой» как ActionEvent не трекается на бэке selections (шаринг — клиентское
действие копирования); просмотр получателем трекает user-activity при открытии (UC-SEL-003).
Acceptance Criteria
| # | Критерий | Проверка |
|---|
| AC1 | GET /selections возвращает только активные подборки актора с PublicCode в каждой | интеграционный тест + тест изоляции (чужие не видны) |
| AC2 | SharePopover строит ?ref={referralLinkId} из дефолтной реф-ссылки владельца; при первом шаринге ссылка создаётся (getOrCreateDefaultReferralLink) | e2e-тест фронта с mock referral |
| AC3 | При недоступном referral копируется ссылка без ?ref= (A1) | e2e-тест деградации |
| AC4 | Переход получателя ставит cookie referralUrl на 30 дней и открывает подборку без авторизации | сквозной тест UC-SEL-002 → UC-SEL-003 |
| AC5 | PublicCode в разосланной ссылке остаётся рабочим после переименования/правки состава подборки (A4, INV-SEL-005) | интеграционный тест |
| AC6 | Невалидный/чужой ?ref= не мешает открыть подборку по publicCode; cookie referralUrl не ставится (A5) | e2e-тест деградации реф-части |
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные Документы
- Открытие получателем: UC-SEL-003 (публичный query).
- Агентский сценарий поверх шаринга: UC-SEL-005.
- Domain entity: ../domain/selection.md (
PublicCode, INV-SEL-005).
- API метод:
../api/public/list-my-selections.md (будущий путь по конвенции).
- Реферальная система:
docs/06-services/referral/README.md (будущий путь;
getOrCreateDefaultReferralLink, validateReferralLink, правила привязки — existing-net,
prototype-mapping «valio/referrals»); сквозные сценарии UC-1..3 — docs/02-architecture/scenarios/.
- Правила: use-case-template,
cross-cutting-document-requirements.