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

GET /api/v1/platform/referral-rate-rules — Реестр ставок реферального вознаграждения

Постраничный реестр ставок реферального вознаграждения с фильтрами по специфичности, партнёру, застройщику, проекту, группе планировок, статусу и срезу «действуют на момент». Дом модели элемента ReferralRateRuleModel — здесь; операции правки/активации ссылаются сюда.

Назначение

Менеджер ПИН просматривает таблицу ставок: какие персональные, акционные и глобальные ставки действуют и запланированы, какова история ставок партнёра или застройщика. Owning-контекст — rewards, дом полей — domain/referral-rate-rule.md. Feature group — referral-rates.

Metadata

ПолеЗначение
Сервис/контекстrewards
API areaplatform
Feature groupreferral-rates
Статусdraft
Документdocs/06-services/rewards/api/platform/list-referral-rate-rules.md

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

ПроверкаЗначение
Actor typeUser (Менеджер ПИН)
Auth policy / Permissionsrewards.referral-rates.manage (управление и чтение реестра — единый permission, domain/referral-rate-rule.md)
Scope (RBAC)платформа
Tenant isolationвне tenant-модели — платформенные сущности (ADR-0052); выдача не фильтруется по tenant
Auditnone (read; партнёру реестр недоступен — применённый процент он видит в снапшоте своего начисления, rewards.referral.view-own)

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/v1/platform/referral-rate-rules
Success status200
Idempotency headerне применяется (read)
Correlationсквозной trace через заголовок traceparent

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

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
StatusqueryReferralRateRuleStatus?Нетenum Draft/Active/Archived; unknown-значение → ValidationError
ScopequeryReferralRateScope?Нетenum — 8 уровней от PartnerDeveloperProjectLayoutGroup до Global — фильтр по заполненности измерений (не хранимое поле)
PartnerUserIdqueryGuid?Нетточное совпадение измерения PartnerUserId (ставки с PartnerUserId = null под фильтр не попадают)
DeveloperCompanyIdqueryGuid?Нетточное совпадение измерения DeveloperCompanyId (ставки с null под фильтр не попадают)
ProjectIdqueryGuid?Нетточное совпадение измерения ProjectId (ставки с null под фильтр не попадают)
LayoutGroupIdqueryGuid?Нетточное совпадение измерения LayoutGroupId (ставки с null под фильтр не попадают)
ActiveAsOfqueryDateTimeOffset?Нетсрез «действуют на момент»: Status = Active + период покрывает момент (EffectiveFrom <= ActiveAsOf и (EffectiveTo is null или EffectiveTo > ActiveAsOf)) — семантика резолюции; если Status не задан — применяется неявно Status = Active; если задан Status ≠ Active — параметр игнорируется (период применим только к действующим ставкам)
Page / PageSizequeryintНетpaging-конвенция — README.md

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

ПолеТипОбязательностьИсточникMaskingОписание
ItemsIReadOnlyList<ReferralRateRuleModel>ДаprojectionСтраница ставок.
Page / PageSizeintДаecho запросаПараметры страницы.
TotalCountlongДаCOUNT(*) по фильтруВсего ставок под фильтром.

ReferralRateRuleModel (полная проекция ReferralRateRuleEntity — дом полей: domain/referral-rate-rule.md)

ПолеТипОбязательностьИсточникОписание
IdGuidДаIdId ставки.
PartnerUserIdGuid?НетPartnerUserIdПартнёр; null — любой.
DeveloperCompanyIdGuid?НетDeveloperCompanyIdЗастройщик; null — любой.
ProjectIdGuid?НетProjectIdПроект застройщика; null — любой (требует заданного DeveloperCompanyId).
LayoutGroupIdGuid?НетLayoutGroupIdГруппа планировок проекта; null — любая (требует заданного ProjectId).
Scopestring (enum ReferralRateScope)Даcomputed из измерений8 уровней от PartnerDeveloperProjectLayoutGroup до Global — уровень специфичности.
PercentdecimalДаPercentПроцент вознаграждения от FinalPrice сделки.
EffectiveFromDateTimeOffsetДаEffectiveFromНачало периода действия.
EffectiveToDateTimeOffset?НетEffectiveToКонец периода (исключительно); null — бессрочно.
Commentstring?НетCommentКомментарий Менеджера ПИН.
Statusstring (enum ReferralRateRuleStatus)ДаStatusDraft/Active/Archived.
CreatedAtDateTimeOffsetДаCreatedAtМомент создания.
CreatedByUserIdGuid?НетCreatedByUserIdАвтор.
UpdatedAtDateTimeOffsetДаUpdatedAtМомент последнего изменения.
UpdatedByUserIdGuid?НетUpdatedByUserIdПоследний изменивший.
VersionlongДаVersionВерсия — для ExpectedVersion операций правки.

Алгоритм

  1. Контекст и доступ. Операцию выполняет Менеджер ПИН в платформенном scope; требуется право rewards.referral-rates.manage.
  2. Проверка входа. Enum Status/Scope, диапазоны paging — иначе ValidationError.
  3. Выборка. Постранично отбираются ставки с фильтрами: Status; Scope (по заполненности партнёрской и объектной осей: напр. PartnerDeveloperProjectLayoutGroup — заданы все четыре, DeveloperProject — заданы застройщик и проект без партнёра и группы, Global — все null); точные совпадения PartnerUserId/DeveloperCompanyId/ProjectId/LayoutGroupId; срез ActiveAsOf (семантика резолюции: активные с покрывающим периодом). Сортировка — EffectiveFrom DESC, CreatedAt DESC.
  4. Результат. Страница ReferralRateRuleModel (Items, Page, PageSize, TotalCount) → 200. Freshness — source of truth, без кэша.

Ошибки и failure modes

Общие коды (ValidationError, FORBIDDEN, UNAUTHORIZED) — README.md. Специфичных нет.

Acceptance-критерии

  • Happy path. Дано: ставки в разных статусах и специфичностях, актор с rewards.referral-rates.manage. Когда: GET /api/v1/platform/referral-rate-rules?page=1. Тогда: 200, страница полных ReferralRateRuleModel с вычисленным Scope, сортировка EffectiveFrom DESC, CreatedAt DESC; TotalCount — число под фильтром.
  • Фильтр по специфичности. Дано: ?scope=Global. Когда: GET. Тогда: только ставки со всеми измерениями null; ?scope=DeveloperProjectLayoutGroup — только с заданными застройщиком, проектом и группой планировок при PartnerUserId = null.
  • Ставки партнёра. Дано: ?partnerUserId=P. Когда: GET. Тогда: ставки с измерением PartnerUserId = P (все партнёрские уровни от Partner до PartnerDeveloperProjectLayoutGroup); глобальные и объектные ставки без партнёра, которые тоже применимы к партнёру P при резолюции, под фильтр не попадают — фильтр по измерению, не по применимости.
  • Ставки проекта. Дано: ?developerCompanyId=D&projectId=Pr. Когда: GET. Тогда: ставки с измерениями DeveloperCompanyId = D и ProjectId = Pr (уровни DeveloperProject, DeveloperProjectLayoutGroup и их партнёрские аналоги) — точное совпадение измерений.
  • Действуют на момент. Дано: ?activeAsOf=T без Status. Когда: GET. Тогда: только активные ставки, чей период покрывает T (неявно Status = Active) — картина резолюции на момент T; внутри каждой комбинации измерений — не более одной ставки (INV-RR-2).
  • ActiveAsOf с неактивным статусом. Дано: ?activeAsOf=T&status=Archived. Когда: GET. Тогда: ActiveAsOf игнорируется; выдача — по остальным фильтрам.
  • Пустой результат. Дано: под фильтр не подходит ни одна ставка. Когда: GET. Тогда: 200, Items = [], TotalCount = 0.
  • Неизвестный enum. Дано: ?scope=Foo. Когда: GET. Тогда: 400 ValidationError.

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

  • Новые optional фильтры/поля модели — additive; enum ReferralRateRuleStatus/ReferralRateScope расширяются только additive (клиент игнорирует unknown при чтении).
  • Logs: фильтры, TotalCount (проценты в списке не логируются); metrics: rewards_api_request_duration_seconds{route}; traces: OTel; dashboard rewards-overview.
  • НФТ (ADR-0056): ставок единицы–десятки; выборка тривиальна, p95 < 200 мс.

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

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

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