Catalog Developers API — реестр методов и общие правила области
Реестр developers-методов ЛК застройщика (контекст catalog, сервис Pin.Catalog.Api, area
developers) и общие правила этой области: модель актора (менеджер застройщика), permission-модель
Scoped-RBAC, tenant isolation, общий формат ответа и общий поток обработки запроса. Документы методов
ссылаются сюда и описывают только свою дельту. Продвижение (покупка пакетов) вынесено в отдельный
контекст promotion — его developers-методы не здесь (ADR-0060). Дома
полей — ../../domain/.
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | catalog |
| API area | developers |
| Тип документа | api (area-registry, не единичная операция) |
| Статус | draft |
| Owner | PIN Marketplace |
| Область действия | ранжирование застройщика (DeveloperRankingRule) в scope компании-застройщика; витрина/поиск — ../README.md; оверрайды — ../admin/; продвижение — контекст promotion |
| Assumptions | Scoped-RBAC и claim CompanyId выдаёт identity в JWT; дом сущности — ranking-rule.md |
Реестр методов
Base path области — /api/developers/v1. Поля целей и инварианты — в доме сущности.
Ранжирование (feature group ranking)
| Метод | Route | Permission | Документ |
|---|---|---|---|
| GET | /ranking-rules | catalog.ranking.view | list-ranking-rules.md |
| POST | /ranking-rules | catalog.ranking.manage | create-ranking-rule.md |
| PUT | /ranking-rules/{ruleId}/priority | catalog.ranking.manage | update-ranking-rule-priority.md |
| POST | /ranking-rules/{ruleId}/enable (+ …/disable-дельта) | catalog.ranking.manage | enable-ranking-rule.md |
| DELETE | /ranking-rules/{ruleId} | catalog.ranking.manage | delete-ranking-rule.md |
Продвижение (покупка/отмена/список пакетов и покупок) — developers-область контекста
promotion (ADR-0060), permissions promotion.purchases.* /
promotion.packages.view; здесь его нет.
Модель актора
| Проверка | Значение |
|---|---|
| Actor type | User — менеджер застройщика (JWT identity; UserId, CompanyId, scope-претензии в claims) |
| Аутентификация | Bearer JWT (подпись, exp, notBefore); нет/просрочен → 401. Гость/реф-cookie в области недопустимы (в отличие от public-ленты) |
| Что делает | читает и правит только свои правила ранжирования в рамках компании |
| Записи о госте | не создаёт — область только для авторизованных менеджеров |
Актор и permission определяются до выполнения бизнес-логики; CompanyId становится TenantId
tenanted-запросов (см. ниже).
Permission-модель области (Scoped-RBAC)
Дом прав — identity/domain/permission.md; permission
проверяется в scope (организация → группа проектов → проект), выданном актору.
| Permission | Действие | Scope | Методы |
|---|---|---|---|
catalog.ranking.view | чтение правил ранжирования | организация и ниже | list-ranking-rules |
catalog.ranking.manage | создание/изменение/enable-disable/удаление правил | организация и ниже; при scope «проект/группа» цель обязана входить в scope-проекты актора | create/update-priority/enable/delete-ranking-rule |
Отсутствие требуемого permission в scope (или цель вне scope-проектов актора) → 403 FORBIDDEN
до выполнения бизнес-логики.
Tenant isolation
ADR-0052: DeveloperRankingRule — tenanted-сущность с TenantId = CompanyId застройщика.
- Мутирующие и списочные запросы своих данных изолированы по tenant;
TenantIdберётся из identity (claims), не из тела запроса. - К каждой выборке и мутации tenanted-сущности автоматически добавляется условие
TenantId = CompanyId: застройщик физически не видит и не правит чужие правила — чужойruleIdнеотличим от несуществующего (404). - Дополнительный record-level контроль не нужен: изоляция целиком на tenant + Scoped-RBAC.
Идемпотентность и конкурентность
Область не использует dedicated Idempotency-Key — идемпотентность естественная, своя у каждого
метода:
create— unique partial index на цель (INV-1): повтор упирается вCATALOG_RANKING_RULE_DUPLICATE.update-priority—PUTабсолютного значенияPriority: повтор устанавливает то же значение (эффект тот же).enable/disable— переход по статусу идемпотентен: повтор в целевом статусе — no-op успех (CardsRecomputed = 0).delete— soft-delete: повтор упирается в уже снятое правило (CATALOG_RANKING_RULE_NOT_FOUND).
Конкурентность. Мутации правил и пересчёт DeveloperPriority карточек защищены оптимистической
блокировкой. Конкуренты: два менеджера одной компании либо менеджер против консюмера источников
(chessboard/invest-analytics/rewards), правящего те же карточки. Проигравший по версии получает
CONCURRENCY_CONFLICT (409), перечитывает состояние и повторяет; карточки никогда не остаются в
несогласованном виде — пересчёт каскада INV-5 детерминирован и фиксируется атомарно с мутацией правила.
Гонка двух create на одну цель разрешается unique-индексом (CATALOG_RANKING_RULE_DUPLICATE
проигравшему).
Общий формат ответа и списки
- Ошибки — ProblemDetails с машинным
code(таблица ниже); correlation — сквозной trace черезtraceparent. - Списочные методы возвращают пагинированный контейнер (
Items,TotalCount,Page,PageSize) — сырой массив наружу не отдаётся. - Модели строго типизированы и именованы (item-модель на список, result-модель на команду);
enum— строкой; голыхobject/jsonнет.
Алгоритм (общий поток запроса области)
Единый поток, общий для всех методов области; документы методов описывают только дельту:
- Контекст и доступ. Актор — менеджер застройщика (Bearer JWT →
UserId,CompanyId, scope); команды области идемпотентны естественно (per-method:PUTабсолютного значения, unique-индексы, no-op-переходы); dedicated idempotency-header не применяется. - Проверка входа и доступа. Permission-policy (
catalog.ranking.*) →FORBIDDEN; форматы, enum-строки, диапазоны →ValidationError. Существование/состояние/владение целей (INV-* домена) — per-method. - Что читаем. Агрегат по id (правило), батч целей, списки — по фильтрам, сортировке, пагинации;
к выборкам tenanted-сущностей автоматически добавляется
TenantId = CompanyId. - Правила и переходы + маппинг. Инварианты и переходы
From→ToправилаDeveloperRankingRule, доменные события; маппинг поле-в-поле в result-модель — per-method. Чтение — переходов нет. - Что меняется (только записи). Создание/обновление/удаление правила; денормализация
DeveloperPriorityзатронутых карточек — в той же транзакции; правка не должна затирать чужую (конкурентный доступ). - События. Только доменные (пересчёт карточек в том же коммите; Kafka каталог по developers-области не публикует).
- Согласованность (только записи). Правило + денормализация карточек — в одном согласованном изменении.
- Результат. Модель/статус per-method (
200/201); бизнес-ошибка → ProblemDetails с кодом.
Диаграмма
Общие ошибки области
Кросс-методные коды; доменные коды правил — в доме сущности и документах методов.
| Код | HTTP status | Условие | Retry |
|---|---|---|---|
ValidationError | 400 | Невалидные форматы/enum/диапазоны запроса | no retry |
UNAUTHORIZED | 401 | Нет/просрочен Bearer JWT | no retry |
FORBIDDEN | 403 | Нет требуемого permission в scope либо цель вне scope-проектов актора | no retry |
CONCURRENCY_CONFLICT | 409 | Конфликт версий (гонка с консюмером источников или параллельной правкой) | retry |
Доменные коды: ранжирование — CATALOG_RANKING_* (ranking-rule.md,
INV-1..5).
Наблюдаемость и совместимость (общие правила area)
- Logs:
operation,tenantId(CompanyId), actoruserId, результат; PII в области нет (приоритеты — не секрет). Metrics:catalog_developers_operations_total{operation,result}, latency histogram per route,catalog_projection_recompute_total{trigger}(ranking). Traces: span на handler, correlation — сквозной trace черезtraceparent. Dashboardcatalog-overview; runbook — сверка/rebuild проекций (../../README.md, Runtime). - Совместимость: новые optional-поля моделей — additive; переименование/удаление/смена типа поля,
сужение прав — breaking (migration + rollout). Неизвестные значения enum в запросе →
ValidationError.
Связанные документы
- Реестры-соседи:
../README.md(public-витрина),../admin/README.md(оверрайды, m2m); продвижение —promotion/api/developers/. - Дом полей: ranking-rule.md (правила, формула «Рекомендованные», INV-1..5);
PromotionBoost— консюмер ../../consumers/promotion-boost.md. - Permission:
identity/domain/permission.md. - Решения: ADR-0052 (tenancy — данные компании застройщика), ADR-0053 (admin m2m),
ADR-0056 (simplicity-first), ADR-0060 (продвижение → контекст
promotion).