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

POST /api/v1/platform/commission-terms/{termsId}/activate — Активация условий платформенной комиссии

Перевод условий Draft → Active: с этого момента условия участвуют в резолюции удержания при создании начислений (с учётом периода EffectiveFrom/EffectiveTo, резолюция по asOf = CompletedAt сделки). При активации проверяется непересечение периодов активных условий одной специфичности (INV-PT-2) — гарантия детерминированной резолюции — domain/platform-commission-terms.md.

Назначение

Менеджер ПИН вводит условия удержания в действие. Активация не архивирует предыдущие условия: активные условия одной специфичности сосуществуют с непересекающимися периодами (текущие + будущая акция). Плановая смена условий — это досрочное завершение текущих через EffectiveTo (update-platform-terms.md) и активация новых на смежный период. Owning-контекст — rewards. Feature group — platform-terms.

Metadata

ПолеЗначение
Сервис/контекстrewards
API areaplatform
Feature groupplatform-terms
Статусdraft
Документdocs/06-services/rewards/api/platform/activate-platform-terms.md

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

ПроверкаЗначение
Actor typeUser (Менеджер ПИН)
Auth policy / Permissionsrewards.platform-terms.manage
Scope (RBAC)платформа
Tenant isolationвне tenant-модели — платформенная сущность (ADR-0052)
Auditupdate: UpdatedByUserId, Version + 1, доменное событие PlatformTermsActivatedEvent

HTTP-контракт

ПолеЗначение
MethodPOST
Route/api/v1/platform/commission-terms/{termsId}/activate
Success status200
Idempotency headerне применяется (повтор из ActiveREWARDS_PLATFORM_TERMS_INVALID_STATUS_TRANSITION)
Correlationсквозной trace через заголовок traceparent

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

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
ActorUserIdidentity claims (sub)GuidДаRequired
TermsIdroute {termsId}GuidДаRequired, непустой
ExpectedVersionbodylongДа>= 1; сверка с Versionoptimistic concurrency

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

ПолеТипОбязательностьИсточникMaskingОписание
TermsPlatformCommissionTermsModelДаобновлённый агрегатПроекция после активации (Status = Active); модель — list-platform-terms.md.

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

  • Предусловия. Актор — Менеджер ПИН с rewards.platform-terms.manage; условия существуют в статусе Draft; период не истёк; среди активных условий той же специфичности нет пересечения периодов; клиент передаёт актуальный ExpectedVersion.
  • Постусловия (успех). Условия в статусе Active, Version увеличен, актор зафиксирован; условия участвуют в резолюции удержания для начислений, чей asOf = CompletedAt попадает в [EffectiveFrom, EffectiveTo|∞); внутри специфичности на любой момент — не более одного активного кандидата (INV-PT-2, детерминированность). Уже созданные начисления не пересчитываются — в них зафиксирован снапшот (PlatformRetentionPercentagePoints, AppliedPlatformTermsIddomain/commission-accrual.md).
  • Постусловия (отказ). Условия остаются в исходном статусе, версия не меняется.
  • Граница «активны, но ещё не действуют». Условия с EffectiveFrom в будущем после активации в резолюцию попадают только с наступлением EffectiveFrom — механизм заблаговременной подготовки акций.

Алгоритм

  1. Контекст и доступ. Операцию выполняет Менеджер ПИН в платформенном scope; требуется право rewards.platform-terms.manage.
  2. Проверка входа и предусловий. TermsId непустой, ExpectedVersion >= 1. Условия существуют — иначе REWARDS_PLATFORM_TERMS_NOT_FOUND. Статус = Draft (единственный допустимый исходный) — иначе REWARDS_PLATFORM_TERMS_INVALID_STATUS_TRANSITION. Version совпадает с ExpectedVersion — иначе REWARDS_CONCURRENCY_CONFLICT. Если EffectiveTo задан и уже в прошлом — REWARDS_PLATFORM_TERMS_PERIOD_INVALID (нельзя активировать истёкшие условия).
  3. Непересечение периодов (INV-PT-2). Активные условия с тем же набором заполненных измерений (AgencyCompanyId, DeveloperCompanyId, ProjectId, LayoutGroupId), включая null-значения, читаются под блокировкой; если период [EffectiveFrom, EffectiveTo|∞) активируемых условий пересекается хотя бы с одним из них — отказ REWARDS_PLATFORM_TERMS_OVERLAP (id конфликтующих условий — в metadata ошибки; менеджер либо досрочно завершает действующие через update-platform-terms.md, либо правит период черновика). Пересечение проверяется только внутри одной комбинации измерений: условия разных уровней специфичности пересекаться могут — конфликт разрешает порядок «специфичное побеждает».
  4. Переход и запись. Условия переходят Draft → Active; фиксируются актор и новая версия. Переход сохраняется в одном согласованном изменении с проверкой п.3 (гонка двух активаций пересекающихся черновиков одной комбинации — под блокировкой активных условий комбинации: победитель активируется, проигравший получает REWARDS_PLATFORM_TERMS_OVERLAP).
  5. Результат. Проекция активированных условий (PlatformCommissionTermsModel, Status = Active) → 200. Интеграционные события не публикуются — условия применяются только внутри rewards при создании начисления.

Диаграмма

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
REWARDS_PLATFORM_TERMS_NOT_FOUND404Условия не существуют«Условия не найдены»no retry
REWARDS_PLATFORM_TERMS_INVALID_STATUS_TRANSITION409Status != Draft (уже Active / Archived)«Активировать можно только черновик»no retry
REWARDS_PLATFORM_TERMS_OVERLAP409Период пересекается с активными условиями той же специфичности (INV-PT-2)«Период пересекается с действующими условиями» + id конфликтующих в metadatano retry (сначала завершить/поправить конфликтующие)
REWARDS_PLATFORM_TERMS_PERIOD_INVALID400EffectiveTo уже в прошлом«Период действия уже истёк»no retry
REWARDS_CONCURRENCY_CONFLICT409ExpectedVersion устарел«Условия изменены другим пользователем»retry после refresh

Общие коды — README.md.

Acceptance-критерии

  • Happy path. Дано: черновик условий уровня AgencyProject, период не пересекается с активными условиями той же комбинации измерений, ExpectedVersion актуален. Когда: POST .../activate. Тогда: 200, Status = Active, Version + 1; начисления с CompletedAt внутри периода применяют эти условия.
  • Первая активация комбинации. Дано: активных условий этой комбинации измерений нет. Когда: POST .../activate. Тогда: 200; до этого момента резолюция комбинации падала на менее специфичный уровень / fallback 0 п.п.
  • Пересечение периодов. Дано: активные условия той же комбинации с периодом [t0, ∞); черновик с EffectiveFrom = t0 + 30дней. Когда: POST .../activate. Тогда: 409 REWARDS_PLATFORM_TERMS_OVERLAP с id конфликтующих условий; после досрочного завершения действующих (EffectiveTo = t0 + 30дней) повторная активация проходит — периоды смыкаются без пересечения.
  • Разные специфичности пересекаются свободно. Дано: активные Global-условия на [t0, ∞); черновик AgencyLayoutGroup с периодом внутри. Когда: POST .../activate. Тогда: 200 — уровни разные, резолюция выбирает более специфичный (INV-PT-2 действует внутри комбинации измерений).
  • Будущая акция. Дано: черновик с EffectiveFrom в будущем, пересечений нет. Когда: POST .../activate. Тогда: 200, Status = Active; в резолюцию условия попадут с наступлением EffectiveFrom.
  • Истёкший период. Дано: EffectiveTo уже в прошлом. Когда: POST .../activate. Тогда: 400 REWARDS_PLATFORM_TERMS_PERIOD_INVALID.
  • Не черновик. Дано: условия уже Active или Archived. Когда: POST .../activate. Тогда: 409 REWARDS_PLATFORM_TERMS_INVALID_STATUS_TRANSITION.
  • Существующие начисления не пересчитываются. Дано: начисление со снапшотом прежних условий. Когда: активация новых условий той же комбинации на смежный период. Тогда: снапшот начисления (PlatformRetentionPercentagePoints, AppliedPlatformTermsId) не меняется.
  • Гонка двух активаций. Дано: два черновика одной комбинации измерений с пересекающимися периодами. Когда: одновременный POST .../activate обоих. Тогда: один — 200, другой — 409 REWARDS_PLATFORM_TERMS_OVERLAP (проверка под блокировкой активных условий комбинации).
  • Конкурентная версия. Дано: ExpectedVersion устарел. Когда: POST. Тогда: 409 REWARDS_CONCURRENCY_CONFLICT.

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

  • Проверка INV-PT-2 — app-level под блокировкой (записей единицы, ADR-0056), db-индекса непересечения нет — блокировка активных условий комбинации обязательна.
  • Guard INV-PT-4 (RetentionPercentagePoints < CommissionPercent применённого правила застройщика) проверяется не при активации, а при создании начисления — ставки застройщиков различны и заранее неизвестны; нарушение уводит событие сделки в DLQ (REWARDS_PLATFORM_RETENTION_EXCEEDS_RULE, domain/platform-commission-terms.md).
  • Logs: ActorUserId, TermsId, Scope, период; metrics: rewards_platform_terms_activate_total{result}; traces: OTel; dashboard rewards-overview.

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

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

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