Перейти к основному содержимому

GET /api/investors/me/referral-links/lookup — Пагинированный lookup своих ссылок

Назначение

Облегчённый постраничный список собственных реферальных ссылок для наполнения выпадающих списков выбора реф-ссылки (SharePopover подборок, форма выбора ссылки при шаринге объекта, /profile/partner). В отличие от get-my-referral-links.md — без дорогих производных (registrationsCount не считается): только идентификатор, slug, описание и признак default, достаточные, чтобы отрисовать пункт списка и подставить slug в cookie.

Metadata

ПолеЗначение
Сервис/контекстreferral
API areapublic
Feature groupreferral-links
Статусdraft

Актор и доступ

ПроверкаЗначение
Actor typeUser (авторизованный пользователь)
Auth policy / Permissionsreferral.links.view-self
Scopeself (роль не требуется)
Record-levelфильтр OwnerUserId = UserId актора — чужие ссылки в выборку не попадают (нет user enumeration)
Tenant isolationне применяется (record-level по владельцу, ADR-0052)
Auditnone (несенситивное чтение собственных данных)

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/investors/me/referral-links/lookup?Offset&Take
Success status200
Idempotencyне применяется (safe GET)
CorrelationOpenTelemetry trace (traceparent)

Маршрутизация: статический сегмент lookup имеет приоритет над route-параметром {id} того же уровня — конфликта с lookup/{id} (lookup-referral-link-by-id.md) нет.

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
UserIdidentity claims (sub)GuidДавалидный JWT (подпись, exp, notBefore)401 при отсутствии/просрочке
OffsetqueryintДаmin 0, max 2147483647
TakequeryintДаmin 1, max 1000ограничение размера выдачи

Ограничения Offset/Take — единый дом paging-параметров README.md.

Модель ответа ReferralLinkLookupEntryPagingResult

Контейнер-страница с коллекцией и метаданными пагинации (дом paging-моделей — README.md).

ПолеТипОбязательностьИсточникMaskingОписание
itemsReferralLinkLookupEntry[]ДаprojectionПункты страницы (может быть пустым).
metaPagingResultMetaДаcomputedtotal/take/offsetREADME.md.

Модель ReferralLinkLookupEntry (дом item-модели)

Первая операция-владелец lookup-семейства; переиспользуется lookup-referral-link-by-id.md (одиночная выдача) и get-or-create-default-referral-link.md (одиночная entry). Поля — проекция агрегата referral-link.md.

ПолеТипОбязательностьИсточникMaskingОписание
idstring (Guid)ДаReferralLinkEntity.IdИдентификатор ссылки (значение выпадающего пункта).
urlstringДаReferralLinkEntity.UrlSlug (lowercase); полный URL собирает фронт.
descriptionstring?НетReferralLinkEntity.DescriptionОписание канала — подпись пункта списка.
isDefaultboolДаReferralLinkEntity.IsDefaultСсылка «по умолчанию» (для преселекта пункта).
channelReferralChannelНетReferralLinkEntity.ChannelКанал (enum строкой); additive optional.

Предусловия и постусловия

  • Предусловия. Пользователь авторизован. В выборку попадают только действующие (не удалённые) собственные ссылки.
  • Постусловия. Состояние не меняется (чтение); VisitsCount не растёт; события не публикуются.

Алгоритм

  1. Контекст и доступ. Операцию выполняет авторизованный пользователь; UserId — из claim sub (иначе 401); требуется право referral.links.view-self.
  2. Проверка входа. Offset >= 0, 1 <= Take <= 1000 — иначе ValidationError.
  3. Что читаем. Страницу собственных ссылок владельца (OwnerUserId = UserId, не удалённых); без подсчёта регистраций. Порядок: default-ссылка сверху (IsDefault desc), далее свежие (CreatedAt desc), при равенстве — по Id (детерминированный tie-break: устойчивая пагинация без пропусков/дублей на границах страниц) — удобный преселект в выпадающем списке. meta.total — общее число ссылок владельца по тому же условию.
  4. Маппинг. Пункт страницы — поле-в-поле по таблице ReferralLinkLookupEntry; meta = {total, take, offset} (эхо запроса + подсчёт).
  5. Результат. ReferralLinkLookupEntryPagingResult → HTTP 200; items упорядочены (default → свежие). Инкремент VisitsCount здесь не выполняется (перехода по ссылке нет — счётчик растит только validate-referral-link.md). Консистентность — read-your-writes.

Диаграмма

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
— (auth)401Нет/просрочен/невалиден JWTбез тела схемыre-login
ValidationError400Offset/Take вне диапазонасписок ошибок полейисправить параметры

Доменных REFERRAL_* ошибок нет: фильтрованное чтение собственных записей — пустая страница, не ошибка.

Критерии приёмки

  • Given владелец с несколькими ссылками, одна из которых default, When запрос страницы, Then 200, default-ссылка первой (IsDefault desc), далее свежие (CreatedAt desc); meta.total = число не удалённых ссылок владельца.
  • Given у владельца нет ссылок, When запрос, Then 200 с пустым items и meta.total = 0 (не 404).
  • Given Offset >= meta.total, When запрос, Then 200 с пустым items и корректным meta.total.
  • Given несколько ссылок с одинаковым IsDefault/createdAt, When последовательный обход страниц, Then каждая ссылка встречается ровно один раз (tie-break по Id).
  • Given Offset < 0 или Take вне 1..1000, When запрос, Then ValidationError (400).
  • Given soft-deleted собственная ссылка, When запрос, Then она в выборку не входит.
  • Given отсутствует/просрочен токен, When запрос, Then 401.

Совместимость и наблюдаемость

  • Контракт стабилен; additive: channel (ReferralChannel, enum строкой) у ReferralLinkLookupEntry — без breaking change. Unknown enum при чтении — fallback Other + warning (referral-link.md). Удаление/переименование/смена типа полей — breaking (migration + rollout).
  • Logs: UserId, размер страницы (take/offset) — без PII; metrics: referral_links_lookup_requests_total, latency p95; traces — OpenTelemetry. Dashboard — referral-overview; алерт на p95 > 300 мс (SLO public API, README.md); операция дешевле get-my-referral-links.md — регистрации не считаются.

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы