POST /api/v1/platform/referral-rate-rules/{rateRuleId}/activate — Активация ставки реферального вознаграждения
Перевод ставки Draft → Active: с этого момента ставка участвует в резолюции при создании реферальных
начислений (с учётом периода EffectiveFrom/EffectiveTo). При активации проверяется непересечение
периодов активных ставок одной комбинации измерений (INV-RR-2) — гарантия детерминированной резолюции —
domain/referral-rate-rule.md.
Назначение
Менеджер ПИН вводит ставку в действие. В отличие от условий платформенной комиссии активация не
архивирует предыдущие ставки: активные ставки одной комбинации измерений сосуществуют с
непересекающимися периодами (текущая + будущая акция). Owning-контекст — rewards. Feature group —
referral-rates.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | rewards |
| API area | platform |
| Feature group | referral-rates |
| Статус | draft |
| Документ | docs/06-services/rewards/api/platform/activate-referral-rate-rule.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | User (Менеджер ПИН) |
| Auth policy / Permissions | rewards.referral-rates.manage |
| Scope (RBAC) | платформа |
| Tenant isolation | вне tenant-модели — платформенная сущность (ADR-0052) |
| Audit | update: UpdatedByUserId, Version + 1, доменное событие ReferralRateRuleActivatedEvent |
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | POST |
| Route | /api/v1/platform/referral-rate-rules/{rateRuleId}/activate |
| Success status | 200 |
| Idempotency header | не применяется (повтор из Active → REWARDS_REFERRAL_RATE_INVALID_STATUS_TRANSITION) |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
ActorUserId | identity claims (sub) | Guid | Да | Required | — |
RateRuleId | route {rateRuleId} | Guid | Да | Required, непустой | — |
ExpectedVersion | body | long | Да | >= 1; сверка с Version | optimistic concurrency |
Модель ответа ActivateReferralRateRuleResult
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
Rule | ReferralRateRuleModel | Да | обновлённый агрегат | — | Проекция после активации (Status = Active); модель — list-referral-rate-rules.md. |
Предусловия и постусловия
- Предусловия. Актор — Менеджер ПИН с
rewards.referral-rates.manage; ставка существует в статусеDraft; период не истёк; среди активных ставок той же комбинации измерений нет пересечения периодов; клиент передаёт актуальныйExpectedVersion. - Постусловия (успех). Ставка в статусе
Active,Versionувеличен, актор зафиксирован; ставка участвует в резолюции для реферальных начислений, чейasOf = CompletedAtпопадает в[EffectiveFrom, EffectiveTo|∞); внутри одной комбинации измерений на любой момент — не более одного активного кандидата (INV-RR-2, детерминированность). Уже созданные начисления не пересчитываются. - Постусловия (отказ). Ставка остаётся в исходном статусе, версия не меняется.
- Граница «активна, но ещё не действует». Ставка с
EffectiveFromв будущем после активации в резолюцию попадает только с наступлениемEffectiveFrom— механизм заблаговременной подготовки акций.
Алгоритм
- Контекст и доступ. Операцию выполняет Менеджер ПИН в платформенном scope; требуется право
rewards.referral-rates.manage. - Проверка входа и предусловий.
RateRuleIdнепустой,ExpectedVersion >= 1. Ставка существует — иначеREWARDS_REFERRAL_RATE_NOT_FOUND. Статус =Draft(единственный допустимый исходный) — иначеREWARDS_REFERRAL_RATE_INVALID_STATUS_TRANSITION.Versionсовпадает сExpectedVersion— иначеREWARDS_CONCURRENCY_CONFLICT. ЕслиEffectiveToзадан и уже в прошлом —REWARDS_REFERRAL_RATE_PERIOD_INVALID(нельзя активировать истёкшую ставку). - Непересечение периодов (INV-RR-2). Активные ставки с той же комбинацией значений
(
PartnerUserId,DeveloperCompanyId,ProjectId,LayoutGroupId), включаяnull-значения, читаются под блокировкой; если период[EffectiveFrom, EffectiveTo|∞)активируемой ставки пересекается хотя бы с одним из них — отказREWARDS_REFERRAL_RATE_OVERLAP(id конфликтующих ставок — в metadata ошибки; менеджер либо досрочно завершает действующую ставку через update-referral-rate-rule.md, либо правит период черновика). Пересечение проверяется только внутри одной комбинации измерений: ставки разных уровней специфичности пересекаться могут — конфликт разрешает порядок «специфичное побеждает». - Переход и запись. Ставка переходит
Draft → Active; фиксируются актор и новая версия. Переход сохраняется в одном согласованном изменении с проверкой п.3 (гонка двух активаций пересекающихся черновиков одной комбинации — под блокировкой активных ставок комбинации: победитель активируется, проигравший получаетREWARDS_REFERRAL_RATE_OVERLAP). - Результат. Проекция активированной ставки (
ReferralRateRuleModel,Status = Active) →200. Интеграционные события не публикуются — ставка применяется только внутриrewardsпри создании реферального начисления.
Диаграмма
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
REWARDS_REFERRAL_RATE_NOT_FOUND | 404 | Ставка не существует | «Ставка не найдена» | no retry |
REWARDS_REFERRAL_RATE_INVALID_STATUS_TRANSITION | 409 | Status != Draft (уже Active / Archived) | «Активировать можно только черновик» | no retry |
REWARDS_REFERRAL_RATE_OVERLAP | 409 | Период пересекается с активной ставкой той же комбинации измерений (INV-RR-2) | «Период пересекается с действующей ставкой» + id конфликтующих ставок в metadata | no retry (сначала завершить/поправить конфликтующую) |
REWARDS_REFERRAL_RATE_PERIOD_INVALID | 400 | EffectiveTo уже в прошлом | «Период действия уже истёк» | no retry |
REWARDS_CONCURRENCY_CONFLICT | 409 | ExpectedVersion устарел | «Ставка изменена другим пользователем» | retry после refresh |
Общие коды — README.md.
Acceptance-критерии
- Happy path. Дано: черновик ставки
Partner-специфичности, период не пересекается с активными ставками того же партнёра (без застройщика),ExpectedVersionактуален. Когда:POST .../activate. Тогда:200,Status = Active,Version + 1; начисления сCompletedAtвнутри периода применяют эту ставку. - Пересечение периодов. Дано: активная ставка той же комбинации измерений с периодом
[t0, ∞); черновик сEffectiveFrom = t0 + 30дней. Когда:POST .../activate. Тогда:409REWARDS_REFERRAL_RATE_OVERLAPс id конфликтующей ставки; после досрочного завершения действующей (EffectiveTo = t0 + 30дней) повторная активация проходит — периоды смыкаются без пересечения. - Разные специфичности пересекаются свободно. Дано: активная
DeveloperProject-ставка на[t0, ∞); черновикDeveloperProjectLayoutGroup(тот же застройщик и проект, но задана группа планировок) с периодом внутри. Когда:POST .../activate. Тогда:200— комбинации измерений разные, резолюция выбирает более специфичный уровень (INV-RR-2 действует внутри одной комбинации). - Будущая акция. Дано: черновик с
EffectiveFromв будущем, пересечений нет. Когда:POST .../activate. Тогда:200,Status = Active; в резолюцию ставка попадёт с наступлениемEffectiveFrom. - Истёкший период. Дано:
EffectiveToуже в прошлом. Когда:POST .../activate. Тогда:400REWARDS_REFERRAL_RATE_PERIOD_INVALID. - Не черновик. Дано: ставка уже
ActiveилиArchived. Когда:POST .../activate. Тогда:409REWARDS_REFERRAL_RATE_INVALID_STATUS_TRANSITION. - Гонка двух активаций. Дано: два черновика одной комбинации измерений с пересекающимися периодами.
Когда: одновременный
POST .../activateобоих. Тогда: один —200, другой —409REWARDS_REFERRAL_RATE_OVERLAP(проверка под блокировкой активных ставок комбинации). - Конкурентная версия. Дано:
ExpectedVersionустарел. Когда:POST. Тогда:409REWARDS_CONCURRENCY_CONFLICT.
Совместимость и наблюдаемость
- Проверка INV-RR-2 — app-level под блокировкой (ставок единицы–десятки, ADR-0056), db-индекса непересечения нет — блокировка активных ставок комбинации измерений обязательна.
- Logs:
ActorUserId,RateRuleId,Scope, период; metrics:rewards_referral_rate_activate_total{result}; traces: OTel; dashboardrewards-overview.
Обратные ссылки
Автоссылки: где используется этот документ.
- API (5): GET /api/v1/platform/referral-rate-rules — Реестр ставок реферального вознаграждения, POST /api/v1/platform/referral-rate-rules — Создание ставки реферального вознаграждения (черновик), POST /api/v1/platform/referral-rate-rules/{rateRuleId}/archive — Архивирование ставки реферального вознаграждения, PUT /api/v1/platform/referral-rate-rules/{rateRuleId} — Изменение ставки реферального вознаграждения, Rewards API — реестр операций и общие контрактные модели
- Use Cases (2): UC-RWD-008. Платформа настраивает ставки реферального вознаграждения, US-реестр: Финансовый блок ПИН (US-FIN)
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущность: domain/referral-rate-rule.md (INV-RR-2, «Резолюция ставки», stateDiagram).
- Досрочное завершение действующей ставки: update-referral-rate-rule.md; архив: archive-referral-rate-rule.md.
- Точка применения: domain/referral-accrual.md, consumer — ../../consumers/crm-deal-completed.md.
- ADR-0066,
ADR-0068
(объектная ось
Developer → Project → LayoutGroup).