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

Referral API — реестр операций и общие контрактные модели

Индекс HTTP-операций сервиса referral (public / admin / internal) и единственный дом общих контрактных моделей: формат ответа/ошибок, paging-модели, FullName-проекция. Файлы операций описывают только свою дельту и ссылаются сюда.

Metadata

ПолеЗначение
Сервис/контекстreferral
Owning teamкоманда referral
Область действияPublic API area (self-service ссылки/журнал/реферер/статистика + анонимная валидация), Admin API area (журнал всех, коррекции связей), Internal API area (m2m-резолв slug для identity/crm)
Зависимостиdomain/referral-link.md, domain/referral-registration.md, domain/referral-bond.md, domain/attach-rules.md

Реестр операций

Public — self-service

#ОперацияHTTPRouteАкторPermissionДокумент
1getOrCreateDefaultReferralLinkPOST/api/investors/me/referral-links/defaultUserreferral.links.manage-selfget-or-create-default-referral-link.md
2createReferralLinkPOST/api/v1/referral-linksUserreferral.links.manage-selfcreate-referral-link.md
3updateReferralLinkPUT/api/investors/me/referral-links/{id}Userreferral.links.manage-selfupdate-referral-link.md
4deleteReferralLinkDELETE/api/investors/me/referral-links/{id}Userreferral.links.manage-selfdelete-referral-link.md
5getMyReferralLinksGET/api/investors/me/referral-linksUserreferral.links.view-selfget-my-referral-links.md
6getMyReferrerGET/api/investors/me/referrerUserreferral.links.view-selfget-my-referrer.md
7lookupReferralLinkByIdGET/api/investors/me/referral-links/lookup/{id}Userreferral.links.view-selflookup-referral-link-by-id.md
8lookupReferralLinksGET/api/investors/me/referral-links/lookupUserreferral.links.view-selflookup-referral-links.md
9validateReferralLinkGET/api/investors/referral-links/{url}/validateAnonymousnonevalidate-referral-link.md
10getLinkRegistrationsGET/api/investors/me/referral-links/{id}/registrationsUserreferral.registrations.view-selfget-link-registrations.md
11getAllRegistrationsGET/api/investors/me/referral-links/registrationsUserreferral.registrations.view-selfget-all-registrations.md
12getPartnerStatsGET/api/v1/partner/statsUserreferral.links.view-selfget-partner-stats.md
13getLinkStatsGET/api/v1/referral-links/{referralLinkId}/statsUserreferral.links.view-selfget-link-stats.md

Маршрутизация: статические сегменты default, lookup, registrations имеют приоритет над route-параметром {id} того же уровня (правило приоритета статических сегментов маршрута) — конфликтов /{id}/registrations/default/lookup нет.

Admin — администратор платформы

#ОперацияHTTPRouteАкторPermissionДокумент
14getReferralLinksGET/api/admin/referrals/linksOperator(Admin)referral.registrations.view-allget-referral-links.md
15getReferralLinkByIdGET/api/admin/referrals/links/{linkId}Operator(Admin)referral.registrations.view-allget-referral-link-by-id.md
16getLinkRegistrations (admin)GET/api/admin/referrals/links/{linkId}/registrationsOperator(Admin)referral.registrations.view-allget-link-registrations.md
17getInvestorReferralsGET/api/admin/referrals/investors/{investorId}/referralsOperator(Admin)referral.registrations.view-allget-investor-referrals.md
18adminRebindBondPOST/api/admin/referrals/bonds/{bondId}/rebindOperator(Admin)referral.registrations.view-allrebind-bond.md
19adminRevokeBondPOST/api/admin/referrals/bonds/{bondId}/revokeOperator(Admin)referral.registrations.view-allrevoke-bond.md

Internal — m2m

#ОперацияHTTPRouteАкторPermissionДокумент
20resolveReferralLinkGET/internal/v1/referral-links/resolveSystempolicy internal-servicesresolve-referral-link.md

Межконтекстные мутации остаются событийными; internal-area — единственный синхронный read-only резолв slug для identity/crm (владелец, тип/статус, lead-eligible; PII не отдаёт).

Формат ответа и ошибок

  • Успех: тело = типизированный результат операции (<Operation>Result); статус — 200/201/204 по HTTP-контракту операции.
  • Ошибка валидации: 400 с перечнем полей.
  • Доступ: 401 (нет/невалиден токен), 403 (нет требуемого permission).
  • Корреляция — сквозной trace через заголовок traceparent.

Кросс-сервисные (общие) коды ошибок

Коды, повторяющиеся в нескольких операциях; доменно-специфические (REFERRAL_LINK_*, REFERRAL_BOND_*) — в файлах операций-владельцев. Статусы фиксированы контрактом и одинаковы во всех операциях, где код применим.

КодHTTPУсловиеГде применяется
ValidationError400Формат/диапазон входных полей нарушен (slug, paging, enum, длины)все операции
UNAUTHORIZED401Нет/просрочен/невалиден токенвсе аутентифицированные операции
FORBIDDEN / REFERRAL_ADMIN_FORBIDDEN / REFERRAL_FORBIDDEN403Нет требуемого permission (self или referral.registrations.view-all)self- и admin-операции
REFERRAL_LINK_NOT_FOUND404 (public delete — 400)Ссылка не существует / чужая / удалена (без раскрытия чужого id)операции по linkId
REFERRAL_BOND_NOT_FOUND404Связь по bondId не существуетadmin-коррекции связей
CONCURRENCY_CONFLICT / REFERRAL_BOND_CONCURRENCY_CONFLICT409 (public delete — 400)Конкурентная правка (потеря обновления); проигравший перечитывает и повторяетмутации ссылок/связей
IDEMPOTENCY_CONFLICT409Тот же Idempotency-Key, иной payload / операция в процессепривилегированные мутации связей (rebind/revoke)

Paging-модели (дом; используются списочными операциями 5, 8, 10, 11, 14, 16, 17)

Все списочные выдачи — offset-paging контейнером <Item>PagingResult. Коллекция всегда живёт в именованной container-модели.

Модель PagingResult (базовая)

ПолеТипОбязательностьОписание
metaPagingResultMetaДаМетаданные страницы.

Модель PagingResultMeta

ПолеТипОбязательностьОграниченияОписание
totalnumber (int64)Да>= 0Полное число записей под фильтром.
takenumber (int32)Да0..1000Фактический размер страницы (эхо запроса).
offsetnumber (int32)Да0..2147483647Фактическое смещение (эхо запроса).

Query-параметры paging (единые ограничения)

ПараметрТипОбязательностьОграниченияОписание
OffsetintДаmin 0, max 2147483647Смещение от начала выборки.
TakeintPublic: Да / Admin: Нетmin 1, max 1000Размер страницы. В admin-области параметр опционален (клиент передаёт Take явно).

Контейнеры

КонтейнерItemОперации
ReferralLinkListItemPagingResultReferralLinkListItemgetMyReferralLinks
ReferralLinkLookupEntryPagingResultReferralLinkLookupEntrylookupReferralLinks
ReferralRegistrationItemPagingResultReferralRegistrationItemgetLinkRegistrations, getAllRegistrations
AdminReferralLinkEntryPagingResultAdminReferralLinkEntryadmin getReferralLinks
AdminReferralRegistrationEntryPagingResultAdminReferralRegistrationEntryadmin getLinkRegistrations
AdminReferredInvestorEntryPagingResultAdminReferredInvestorEntryadmin getInvestorReferrals

Item-модели — дома в файлах операций (первая операция-владелец), проекции полей — из сущностей referral-link.md, referral-registration.md, referral-bond.md.

Консистентность и стабильность страницы (единое правило списочных операций)

Правило для всех списочных выдач (5, 8, 10, 11, 14, 16, 17); операции ссылаются сюда и не переописывают.

  • Детерминированный порядок. Сортировка — по основному ключу (дата: RegisteredAt для журналов, BoundAt для связей, CreatedAt для ссылок — desc, свежие сверху), при равных значениях даты — вторичный ключ Id (стабильный tie-break). Без вторичного ключа записи с одинаковой датой могли бы «перепрыгивать» между страницами; с ним постраничный обход детерминирован.
  • Снимок offset-paging. Между запросами соседних страниц выборка не транзакционно-снимочна: конкурентная вставка (новая регистрация/ссылка) или смена статуса связи (Active → Replaced/Revoked) сдвигает offset — на границе страниц запись может продублироваться или быть пропущена. Для append-only журналов это затрагивает только «голову» ленты (новые записи сверху); исторические страницы стабильны. Клиенту, которому нужна точная лента, следует дочитывать до meta.total за один непрерывный проход.
  • Свежесть. Выдача отражает только зафиксированные (committed) данные referral. PII-поля из реплики ReferralUserReplica (ФИО/телефон) могут отставать на лаг consumer-а pin.identity.users.v1: при отсутствии реплики запись всё равно возвращается с пустым FullName и phoneNumber = null (graceful degradation, не ошибка).
  • meta.total. Полное число записей под фильтром на момент запроса; при активной конкурентной записи может незначительно отличаться от фактически перечисленных на всех страницах (то же окно, что и выше).

Модель FullName (admin-проекции)

Проекция имени владельца/приглашённого из реплики ReferralUserReplica (исходный дом — identity/domain/user.md):

ПолеТипОбязательностьОграниченияОписание
firstNamestringДаmax 128Имя (может быть пустой строкой — lazy-регистрация).
lastNamestringДаmax 128Фамилия (может быть пустой строкой).
middleNamestring?Нетmax 128Отчество.

Общие правила безопасности (все операции)

ПравилоЗначение
Record-level selfВсе me-операции фильтруют по OwnerUserId/ReferrerUserId/ReferredUserId = UserId из claim sub; чужая/несуществующая запись неотличима от отсутствующей (нет user enumeration по id ссылок)
Tenant isolationИнвесторы обслуживаются с TenantId = null; изоляция self-выдач — record-level; admin — платформенный permission
PIIPublic-выдачи журнала обезличены (только referredInvestorId); ФИО/телефон/email — только admin-выдачи (permission referral.registrations.view-all); телефоны в логах маскируются +7***1234
Untrusted inputSlug из route и форм — untrusted: нормализация lowercase + формат ^[a-z0-9][a-z0-9-]{2,63}$ (INV-REF-L3) до обращения к данным
AuditМутации ссылок — actor-stamping + доменные события; чтения с PII (admin) — access-audit

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