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

GET /api/admin/v1/promotion-packages — Управленческий список пакетов (admin)

Назначение

Возвращает администратору платформы управленческий список платформенных пакетов продвижения PromotionPackage (promotion-package.md) для управления каталогом монетизации (оплата отложена — решение №10). Отличие от витрины застройщика (../developers/list-promotion-packages.md): та отдаёт только Status=Active; управленческий список отдаёт пакеты всех статусов (Draft/Active/Archived, включая архив) плюс полную аудит-проекцию и счётчик действующих покупок — чтобы админ видел черновики до публикации и последствия архивации. Чтение; создание/правка/архивация — соседние admin-операции.

Metadata

ПолеЗначение
Сервис/контекстpromotion
API areaadmin (ADR-0053, m2m)
Feature groupadmin-promotions
Статусdraft
Документdocs/06-services/promotion/api/admin/list-promotion-packages.md

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

ПроверкаЗначение
Actor typeExternalSystem (администратор платформы; машинный доступ admin API — ADR-0053)
Auth policy / Permissionspolicy AdminSystemOnly; permission promotion.packages.admin (identity/domain/permission.md)
Scope (RBAC)платформа (пакеты — платформенный каталог, не tenanted — ADR-0052 п.3)
Record-levelне применяется
Tenant isolationне применяется — PromotionPackage не привязан к tenant. Счётчик активных покупок читается по всем компаниям (cross-tenant, шаг 3)
Auditread-sensitive: чтение управленческого списка логируется; глубокий аудит мутаций — в create/update/archive

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/admin/v1/promotion-packages
Success status200
Idempotency headerне применяется (чтение)
Correlationсквозной trace через заголовок traceparent; X-Admin-User-Id (Guid админа) — обязательный заголовок admin-области

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

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
AdminUserIdheader X-Admin-User-IdGuidДа!= Guid.Emptyлог admin-доступа
Statusquerystring? (enum PromotionPackageStatus)Нет∈ {Draft, Active, Archived}; null — все не-архивные (см. шаг 3)
Kindquerystring? (enum PromotionPackageKind)Нет∈ {ProjectBoost, PropertyObjectBoost, PostBoost}; null — все
IncludeArchivedqueryboolНет (default false)true — включить soft-deleted-архив (Status=Archived); при Status=Archived подразумевается true
PagequeryintНет (default 1)>= 1
PageSizequeryintНет (default 50)1..200

Модель ответа: страница AdminPromotionPackageListItem

Постраничный список (Items, TotalCount, Page, PageSize).

Модель AdminPromotionPackageListItem (полная проекция PromotionPackage)

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаPromotionPackage.IdПакет.
CodestringДаPromotionPackage.CodeСтабильный код.
NamestringДаPromotionPackage.NameНазвание.
Descriptionstring?НетPromotionPackage.DescriptionМаркетинговый текст.
Kindstring (enum PromotionPackageKind)ДаPromotionPackage.KindProjectBoost / PropertyObjectBoost / PostBoost.
BoostWeightintДаPromotionPackage.BoostWeightВес буста (1..100).
DurationDaysintДаPromotionPackage.DurationDaysСрок действия покупки (1..365).
MaxTargetsPerPurchaseint?НетPromotionPackage.MaxTargetsPerPurchaseЛимит целей (multi-target Kind).
PriceAmountdecimalДаPromotionPackage.Price.AmountПрейскурант (информационно; оплата не требуется).
PriceCurrencyIdshortДаPromotionPackage.Price.CurrencyIdСсылка на запись справочника валют handbook (RUB — ADR-0048).
Statusstring (enum PromotionPackageStatus)ДаPromotionPackage.StatusDraft / Active / Archived.
ActivePurchasesCountintДаcomputed (шаг 3)Число покупок Status=Active, ссылающихся на пакет (последствия архивации).
CreatedAtDateTimeOffsetДаPromotionPackage.CreatedAtСоздан.
CreatedByUserIdGuid?НетPromotionPackage.CreatedByUserIdАвтор создания (admin).
UpdatedAtDateTimeOffset?НетPromotionPackage.UpdatedAtПоследняя правка.
UpdatedByUserIdGuid?НетPromotionPackage.UpdatedByUserIdАвтор последней правки.
ArchivedAtDateTimeOffset?НетPromotionPackage.DeletedAtМомент архивации (soft-delete); null — не архивирован.
VersionlongДаPromotionPackage.VersionСчётчик правок для optimistic-check в мутациях.

Алгоритм

  1. Контекст и доступ. Операцию выполняет администратор платформы через admin API; требуется permission promotion.packages.admin. Пакеты — платформенный каталог, к tenant не привязаны.
  2. Проверка входа. AdminUserId не пуст; Status/Kind ∈ соответствующих enum; Page/PageSize в границах → иначе ValidationError. Правило видимости архива: архив включается, если задан IncludeArchived или запрошен Status = Archived.
  3. Выборка. Отобрать страницу пакетов по фильтрам Status/Kind, сортировка по (Status, Kind, BoostWeight), пагинация (Page, PageSize). Архив (Archived, soft-deleted) включается только по правилу шага 2. Для каждого пакета страницы посчитать число покупок в статусе Active, ссылающихся на пакет (одним агрегатом на страницу, не по одной) — покупки принадлежат компаниям, поэтому счётчик для платформенного управленческого списка считается по всем компаниям (cross-tenant).
  4. Маппинг. Поля пакета → AdminPromotionPackageListItem (PricePriceAmount/PriceCurrencyId; DeletedAtArchivedAt); ActivePurchasesCount ← подсчёт шага 3 (0, если покупок нет).
  5. Результат. Страница AdminPromotionPackageListItem200; freshness — актуальное состояние строк (source of truth пакетов/покупок — этот контекст, лага нет).

Граничные случаи. Пустой каталог или отсутствие совпадений по фильтрам → 200 с пустым Items, TotalCount = 0. ActivePurchasesCount > 0 допустим и для Archived-пакета: архивация — soft-delete, FK restrict, действующие покупки доживают срок (это и есть сигнал «последствия архивации» для админа). ActivePurchasesCount считает только покупки Status = Active (истёкшие/отменённые не учитываются) и по всем компаниям (cross-tenant — пакет платформенный).

Диаграмма

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
ValidationError400Невалидные Status/Kind/paging/X-Admin-User-IdОшибка валидации запросаno retry
UNAUTHORIZED401Нет/просрочен m2m-токенТребуется авторизацияno retry
FORBIDDEN403Клиент не pin-admin-system / нет permission promotion.packages.adminДоступ запрещёнno retry
PROMOTION_PACKAGE_NOT_FOUND404Только для дельты get-package: пакет не существуетПакет не найденno retry

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

  • Новые optional поля item-а (будущие платёжные атрибуты) — additive; удаление/переименование/смена типа — breaking. Неизвестные значения enum Status/Kind в query → ValidationError.
  • Logs: admin-promotion-packages-listed (adminUserId, фильтры, count); metrics: promotion_admin_operations_total{operation="list-promotion-packages"}, duration; traces — сквозной trace через traceparent. Dashboard promotion-overview.

Дельта: GET /api/admin/v1/promotion-packages/{packageId} (одиночное чтение)

Та же область/доступ и та же проекция. Отличия: PackageId из route (!= Guid.Empty); отдаётся один пакет, включая архив; ActivePurchasesCount — число покупок Active по этому пакету (по всем компаниям); если пакет не найден → PROMOTION_PACKAGE_NOT_FOUND (404). Success 200; metrics promotion_admin_operations_total{operation="get-promotion-package"}.

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

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

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