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

Catalog Admin API — реестр методов и общие правила области

Реестр admin-методов каталога (контекст catalog, сервис Pin.Catalog.Api, area admin) и общие правила этой области: модель актора администратора платформы (m2m), policy AdminSystemOnly, обязательные заголовки, deep audit мутаций, соответствие permission-каталогу, общий формат ответа и общий поток admin-мутации. Документы методов ссылаются сюда и описывают только свою дельту. Дома полей — ../../domain/.

Metadata

ПолеЗначение
Сервис/контекстcatalog
API areaadmin (m2m, ADR-0053)
Тип документаapi (area-registry, не единичная операция)
Статусdraft
OwnerPIN Marketplace
Область действияadmin-оверрайды витрины (объекты недвижимости/корпуса), операционный rebuild проекций; public- и developers-области — отдельные реестры (../README.md, ../developers/); CRUD пакетов продвижения — admin-область контекста promotion (ADR-0060)
Assumptionsадминистратор платформы (через admin API) — единственный клиент области; permission-каталог — ../../../identity/domain/permission.md

Реестр методов

Route-префикс области — /api/admin/v1/. Все permission-проверки — каталожное соответствие поверх policy AdminSystemOnly (см. ниже).

МетодRoutePermissionДокумент
GET/api/admin/v1/lots/{propertyObjectId}/overridecatalog.overrides.viewget-property-object-override.md
PUT · DELETE/api/admin/v1/lots/{propertyObjectId}/overridecatalog.overrides.manageput-property-object-override.md (DELETE — дельта снятия)
GET/api/admin/v1/buildings/{buildingId}/overridecatalog.overrides.viewget-building-override.md
PUT · DELETE/api/admin/v1/buildings/{buildingId}/overridecatalog.overrides.manageput-building-override.md (DELETE — дельта снятия)
POST/api/admin/v1/projections/rebuildcatalog.overrides.managerebuild-projections.md (runbook расхождений)

CRUD пакетов продвижения (PromotionPackage) — admin-область контекста promotion (permission promotion.packages.admin, ADR-0060); в каталоге его нет.

Feature groups: admin-overrides (оверрайды), admin-operations (rebuild).

Модель актора и доступ

Область обслуживает один класс актора — систему, не человека. Актор определяется до выполнения бизнес-логики.

ПроверкаЗначение
Actor typeExternalSystem — администратор платформы через admin API
AuthOAuth2 client-credentials (m2m), клиент pin-admin-system — ADR-0053
Auth policyAdminSystemOnly: токен выдан клиенту pin-admin-system; иначе 403
Scope (RBAC)платформа — данные не tenanted (ADR-0052 п.3), см. ниже
Записи о вызывающем пользователенет: identity знает систему, конкретного администратора несёт заголовок X-Admin-User-Id (actor-stamping)

Соответствие permission-каталогу

Поверх AdminSystemOnly каждый метод сверяет каталожный permission (../../../identity/domain/permission.md); для администратора платформы каталог permission — справочное соответствие возможностей.

PermissionЧто разрешает
catalog.overrides.viewЧтение оверрайдов объекта недвижимости/корпуса (get-*-override).
catalog.overrides.manageМутации оверрайдов (PUT/DELETE) и операционный rebuild проекций.

Обязательные заголовки области

ЗаголовокГде обязателенНазначение
X-Admin-User-Idвсе методыGuid администратора-инициатора внутри admin API. Actor-stamping (CreatedByUserId/UpdatedByUserId/DeletedByUserId) и subject deep audit: m2m-токен идентифицирует систему, заголовок — человека. Пустой/отсутствует → ValidationError/401.
Idempotency-Keyмутации (POST/PUT/DELETE)Guid; администратор платформы ретраит по таймауту. Повтор с тем же ключом → сохранённый результат (replay), шаги мутации не повторяются. Ключ бизнес-идемпотентности — admin:<operation>:{Idempotency-Key}.
traceparentвсеСквозной trace (correlation).

Чтения (GET) идемпотентны по природе — Idempotency-Key к ним не применяется.

Правила идемпотентности и конкурентности мутаций:

  • Повтор с тем же ключом и тем же телом → сохранённый результат (replay), шаги мутации и пересчёт не выполняются повторно; ответ идентичен первому (включая Version/Effective).
  • Тот же ключ с иным телом запроса → отказ CONCURRENCY_CONFLICT (409): ключ уже связан с другим запросом, повторно использовать его для другой правки нельзя (защита от случайного «двойного смысла» одного ключа).
  • Окно хранения отметок идемпотентности — ограниченное (envelope: сутки); по истечении повтор с тем же ключом трактуется как новый запрос. Ретраить по таймауту следует в пределах окна.
  • Конкурентный доступ (два администратора либо администратор против консюмера источников, правящих те же карточки): при заданном ExpectedVersion проигравший по версии получает CONCURRENCY_CONFLICT и перечитывает форму; без ExpectedVersion побеждает последняя запись override-полей, но пересчёт эффективных полей карточек остаётся согласованным (пересчёт детерминирован и атомарен). Ретрай — с тем же Idempotency-Key после перечитки.

Deep audit admin-мутаций

Каждая мутация области попадает в deep audit — оверрайды/ранжирование помечены как чувствительные (README сервиса, «Безопасность»):

  • actorX-Admin-User-Id (+ m2m-клиент pin-admin-system);
  • объект — сущность и Id (PropertyObjectDisplayOverride/BuildingDisplayOverride);
  • диф полей — before/after изменённых полей (значения цен в plain-логах маскируются, в audit — полностью);
  • Comment — служебный комментарий администратора «зачем правка» (internal, в public-ответы не попадает);
  • результат — success либо код ошибки.

Запись audit фиксируется в том же согласованном изменении, что и мутация. Чтения управленческих списков логируются как admin-доступ, но deep audit не требуют. Audit не tenanted (платформенные данные).

Tenancy: область не tenanted

Оверрайды — платформенные данные (ADR-0052 п.3): tenant-изоляция к области не применяется; при необходимости кросс-tenant агрегаты читаются в системном scope. Пакеты/покупки продвижения — контекст promotion (ADR-0060), в admin-области каталога их нет.

Общий формат ответа и ProblemDetails

  • Успех — коды 200/201 (create — 201 + Location).
  • Списки — всегда пагинированный контейнер (Items, TotalCount, Page, PageSize), не сырой массив.
  • Ошибка — ProblemDetails с машинным полем code и traceId; enum сериализуются строкой; голых object/json в контрактах нет.

Общий поток admin-мутации

Скелет, общий для всех мутаций области (метод описывает только дельту):

  1. Контекст и доступ. Policy AdminSystemOnly подтверждает m2m-клиента pin-admin-system (401/403 до бизнес-логики); заголовки X-Admin-User-Id (actor) и Idempotency-Key. Повтор по ключу admin:<operation>:{key} → сохранённый результат (replay).
  2. Проверка входа. Диапазоны/enum/длины/пустой X-Admin-User-IdValidationError. Существование цели в проекциях (property_object_cards/project_cards) → CATALOG_*_NOT_FOUND; допустимость состояния (цель Delisted → отказ); optimistic-check ExpectedVersionCONCURRENCY_CONFLICT.
  3. Что читаем. Целевой агрегат и затрагиваемые карточки (батч при каскаде); область не tenanted.
  4. Правила и маппинг. Создание/замена/архивация оверрайда, маппинг поле-в-поле, actor-stamping (CreatedByUserId/UpdatedByUserId = X-Admin-User-Id), Version++; пересчёт эффективных полей карточек (Effective = Override ?? SourceSnapshot, INV-6 display-override).
  5. Что меняется. Создание/обновление/снятие (soft-delete) оверрайда и пересчёт затронутых карточек в порядке логических связей; правка не должна затирать чужую (конкурентный доступ) — конфликт → CONCURRENCY_CONFLICT.
  6. Согласованность. Агрегат + пересчитанные карточки + отметка идемпотентности + deep audit фиксируются в одном согласованном изменении (simplicity-first, ADR-0056: один контекст, одна БД). Интеграционные события область не публикует: оверрайды в Kafka не эмитятся.
  7. Результат. Успех → 200/201; отказ → ProblemDetails с кодом.

Диаграмма (общий поток мутации)

Чтения области следуют тем же шагам без записи (шаги 4–6 не применяются).

Общие коды ошибок области

Сквозные коды (детали и method-specific CATALOG_* — в документах методов):

КодHTTPУсловиеRetry
ValidationError400Синтаксис/диапазоны/enum; пустой X-Admin-User-Id/Idempotency-Keyno retry
UNAUTHORIZED401Нет/просрочен m2m client-credentials токенno retry
FORBIDDEN403Клиент не pin-admin-system либо нет требуемого permissionno retry
CONCURRENCY_CONFLICT409ExpectedVersion не совпал / гонка с консюмером или вторым админом / тот же Idempotency-Key с иным телом запросаretry с тем же Idempotency-Key после перечитки

Method-specific коды (CATALOG_*): оверрайды — CATALOG_OVERRIDE_*, CATALOG_PROPERTY_OBJECT_NOT_FOUND, CATALOG_BUILDING_NOT_FOUND. Дом каждого — документ соответствующего метода и раздел «Инварианты» дома сущности.

Наблюдаемость и совместимость (общие правила area)

  • Logs: admin-<entity>-<action> (id, adminUserId, изменённые поля без значений цен в plain-логе). Metrics: catalog_admin_operations_total{operation}, duration histogram, catalog_projection_recompute_total{trigger="override"}. Traces: span приёма → span обработки → span обращения к хранилищу, correlation — сквозной trace через traceparent. Каждая мутация — в deep audit. Dashboard catalog-overview; runbook — rebuild проекций по id при расхождении SourceSnapshot.ChessboardVersion.
  • Совместимость: новые optional-поля запросов/ответов — additive; удаление/переименование/смена типа поля, изменение route/permission, ужесточение валидации — breaking (migration + rollout). Неизвестное значение enum в теле/query → ValidationError (строгий разбор).

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

  • Дома полей: ../../domain/display-override.md (INV-1..6 оверрайдов); пакеты продвижения — контекст promotion.
  • Решения: ADR-0053 (m2m client-credentials, deep audit), ADR-0052 (платформенная витрина, не tenanted), ADR-0056 (simplicity-first, пересчёт в транзакции).
  • Соседние реестры: ../README.md (public), ../developers/ (ранжирование застройщика); продвижение — promotion/; README сервиса — ../../README.md.