GET /api/v1/platform/referral-rate-rules — Реестр ставок реферального вознаграждения
Постраничный реестр ставок реферального вознаграждения с фильтрами по специфичности, партнёру,
застройщику, проекту, группе планировок, статусу и срезу «действуют на момент». Дом модели элемента
ReferralRateRuleModel — здесь; операции правки/активации ссылаются сюда.
Назначение
Менеджер ПИН просматривает таблицу ставок: какие персональные, акционные и глобальные ставки действуют
и запланированы, какова история ставок партнёра или застройщика. Owning-контекст — rewards, дом полей
— domain/referral-rate-rule.md. Feature group — referral-rates.
| Поле | Значение |
|---|
| Сервис/контекст | rewards |
| API area | platform |
| Feature group | referral-rates |
| Статус | draft |
| Документ | docs/06-services/rewards/api/platform/list-referral-rate-rules.md |
Актор и доступ
| Проверка | Значение |
|---|
| Actor type | User (Менеджер ПИН) |
| Auth policy / Permissions | rewards.referral-rates.manage (управление и чтение реестра — единый permission, domain/referral-rate-rule.md) |
| Scope (RBAC) | платформа |
| Tenant isolation | вне tenant-модели — платформенные сущности (ADR-0052); выдача не фильтруется по tenant |
| Audit | none (read; партнёру реестр недоступен — применённый процент он видит в снапшоте своего начисления, rewards.referral.view-own) |
HTTP-контракт
| Поле | Значение |
|---|
| Method | GET |
| Route | /api/v1/platform/referral-rate-rules |
| Success status | 200 |
| Idempotency header | не применяется (read) |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|
Status | query | ReferralRateRuleStatus? | Нет | enum Draft/Active/Archived; unknown-значение → ValidationError | — |
Scope | query | ReferralRateScope? | Нет | enum — 8 уровней от PartnerDeveloperProjectLayoutGroup до Global — фильтр по заполненности измерений (не хранимое поле) | — |
PartnerUserId | query | Guid? | Нет | точное совпадение измерения PartnerUserId (ставки с PartnerUserId = null под фильтр не попадают) | — |
DeveloperCompanyId | query | Guid? | Нет | точное совпадение измерения DeveloperCompanyId (ставки с null под фильтр не попадают) | — |
ProjectId | query | Guid? | Нет | точное совпадение измерения ProjectId (ставки с null под фильтр не попадают) | — |
LayoutGroupId | query | Guid? | Нет | точное совпадение измерения LayoutGroupId (ставки с null под фильтр не попадают) | — |
ActiveAsOf | query | DateTimeOffset? | Нет | срез «действуют на момент»: Status = Active + период покрывает момент (EffectiveFrom <= ActiveAsOf и (EffectiveTo is null или EffectiveTo > ActiveAsOf)) — семантика резолюции; если Status не задан — применяется неявно Status = Active; если задан Status ≠ Active — параметр игнорируется (период применим только к действующим ставкам) | — |
Page / PageSize | query | int | Нет | paging-конвенция — README.md | — |
Модель ответа ListReferralRateRulesResult
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|
Items | IReadOnlyList<ReferralRateRuleModel> | Да | projection | — | Страница ставок. |
Page / PageSize | int | Да | echo запроса | — | Параметры страницы. |
TotalCount | long | Да | COUNT(*) по фильтру | — | Всего ставок под фильтром. |
ReferralRateRuleModel (полная проекция ReferralRateRuleEntity — дом полей: domain/referral-rate-rule.md)
| Поле | Тип | Обязательность | Источник | Описание |
|---|
Id | Guid | Да | Id | Id ставки. |
PartnerUserId | Guid? | Нет | PartnerUserId | Партнёр; null — любой. |
DeveloperCompanyId | Guid? | Нет | DeveloperCompanyId | Застройщик; null — любой. |
ProjectId | Guid? | Нет | ProjectId | Проект застройщика; null — любой (требует заданного DeveloperCompanyId). |
LayoutGroupId | Guid? | Нет | LayoutGroupId | Группа планировок проекта; null — любая (требует заданного ProjectId). |
Scope | string (enum ReferralRateScope) | Да | computed из измерений | 8 уровней от PartnerDeveloperProjectLayoutGroup до Global — уровень специфичности. |
Percent | decimal | Да | Percent | Процент вознаграждения от FinalPrice сделки. |
EffectiveFrom | DateTimeOffset | Да | EffectiveFrom | Начало периода действия. |
EffectiveTo | DateTimeOffset? | Нет | EffectiveTo | Конец периода (исключительно); null — бессрочно. |
Comment | string? | Нет | Comment | Комментарий Менеджера ПИН. |
Status | string (enum ReferralRateRuleStatus) | Да | Status | Draft/Active/Archived. |
CreatedAt | DateTimeOffset | Да | CreatedAt | Момент создания. |
CreatedByUserId | Guid? | Нет | CreatedByUserId | Автор. |
UpdatedAt | DateTimeOffset | Да | UpdatedAt | Момент последнего изменения. |
UpdatedByUserId | Guid? | Нет | UpdatedByUserId | Последний изменивший. |
Version | long | Да | Version | Версия — для ExpectedVersion операций правки. |
Алгоритм
- Контекст и доступ. Операцию выполняет Менеджер ПИН в платформенном scope; требуется право
rewards.referral-rates.manage.
- Проверка входа. Enum
Status/Scope, диапазоны paging — иначе ValidationError.
- Выборка. Постранично отбираются ставки с фильтрами:
Status; Scope (по заполненности
партнёрской и объектной осей: напр. PartnerDeveloperProjectLayoutGroup — заданы все четыре,
DeveloperProject — заданы застройщик и проект без партнёра и группы, Global — все null); точные
совпадения PartnerUserId/DeveloperCompanyId/ProjectId/LayoutGroupId; срез ActiveAsOf
(семантика резолюции: активные с покрывающим периодом). Сортировка — EffectiveFrom DESC, CreatedAt DESC.
- Результат. Страница
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 мс.
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные документы