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

API контекста selections — индекс

Дом полей — ../domain/selection.md и ../domain/selection-snapshot.md; карта областей — ../README.md.

Public (мутации — владелец по JWT; чтение по коду — любой актор, включая гостя)

ОперацияМетод и routeДокумент
Мои подборкиGET /api/v1/selectionslist-my-selections.md
Создать вручнуюPOST /api/v1/selectionscreate-selection.md
Создать из текущего избранногоPOST /api/v1/selections/from-favoritescreate-selection-from-favorites.md
Открыть по публичному кодуGET /api/v1/selections/{publicCode}get-selection-by-code.md
Название/описаниеPUT /api/v1/selections/{id}update-selection.md
Состав и порядок целикомPUT /api/v1/selections/{id}/itemsset-selection-items.md
Удалить (soft)DELETE /api/v1/selections/{id}delete-selection.md

Internal (m2m: news, crm)

ОперацияМетод и routeДокумент
Снять snapshot для поста (news)POST /api/v1/internal/selections/{id}/snapshotscreate-selection-snapshot.md
Отвязать snapshot — замена блока целиком / удаление поста (news, INV-SEL-001)POST /api/v1/internal/snapshots/{id}/detachdetach-selection-snapshot.md
Контент snapshot-а для рендера поста (news)GET /api/v1/internal/snapshots/{id}get-selection-snapshot.md
Подборка для карточки клиента/сделки (crm)GET /api/v1/internal/selections/{id}get-selection.md
Свои подборки инвестора для карточки клиента (crm)GET /api/v1/internal/selections/by-owner/{ownerUserId}list-selections-by-owner.md

Admin-области нет (модерация публичных подборок отложена — ../README.md). Callbacks — not applicable.

Матрица операций (актор · идемпотентность · публикуемые события)

ОперацияАкторSuccessИдемпотентностьПубликует
GET /selectionsвладелец (JWT)200безопасный read
POST /selectionsвладелец (JWT)201нет (повтор → 2-я подборка; лимит INV-SEL-007)selection-created
POST /selections/from-favoritesвладелец (JWT)201нет (повтор → независимая копия)selection-created + N× selection-item-added
GET /selections/{publicCode}любой (guest/JWT)200безопасный read
PUT /selections/{id}владелец (JWT)200семантически (полная замена метаданных)selection-updated (только при изменении)
PUT /selections/{id}/itemsвладелец (JWT)200семантически (replace-all)selection-updated + N× selection-item-added (при изменении)
DELETE /selections/{id}владелец (JWT)204повтор → 404 (клиент трактует как успех)selection-deleted
POST /internal/selections/{id}/snapshotsm2m news201/200бизнес-ключ (PostId, SourceSelectionId, Active)— (синхронный ответ)
POST /internal/snapshots/{id}/detachm2m news200переход Active → Detached однократен (INV-SNP-005)
GET /internal/snapshots/{id}m2m news200безопасный read
GET /internal/selections/{id}m2m crm200безопасный read
GET /internal/selections/by-owner/{ownerUserId}m2m crm200безопасный read

Все интеграционные события — key = SelectionId (порядок событий одной подборки сохраняется); selection-item-added дополнительно несёт монотонный Version. Дом контрактов событий — ../events/; дом инвариантов — ../domain/selection.md, ../domain/selection-snapshot.md.

Сквозные правила записи (какие инварианты проверяет каждая мутация)

  • Владение (INV-SEL-002): все мутации подборки — только OwnerUserId == actor.UserId; чужая/ несуществующая/удалённая → SELECTIONS_NOT_FOUND (существование чужой не раскрывается).
  • Состав: дедупликация PropertyObjectId (INV-SEL-003), лимит ≤ 200 (INV-SEL-004), нормализация SortOrder 0..N-1 (INV-SEL-006) — при создании с начальным списком, from-favorites, замене состава.
  • Лимит владельца (INV-SEL-007): ≤ 100 не удалённых подборок — при создании (POST, from-favorites).
  • PublicCode (INV-SEL-005): генерируется при создании, неизменяем; коллизия → регенерация (≤ 3).
  • Удаление (INV-SEL-009): soft delete; удалённая невидима публично и не редактируется; snapshot-ы и ссылки CRM остаются разрешимыми.
  • Snapshot (INV-SNP-002/004/005/006, INV-SEL-001): снятие только из активной непустой подборки; контент иммутабелен; detach однократен; snapshot не удаляется.
  • Конкурентность: правки одной подборки сериализуются оптимистической блокировкой — проигравший получает SELECTIONS_CONCURRENCY_CONFLICT (409) и перечитывает.

Общие правила области

  • Подборки — вне tenant (ADR-0052 п.2); изоляция мутаций — record-level по OwnerUserId (INV-SEL-002).
  • Ошибки — ProblemDetails с кодом SELECTIONS_*.
  • {publicCode} и {id} в одном сегменте роутинга разводятся route-constraint-ом: {id:guid} — приоритетный маршрут, всё остальное (12 символов base62) — publicCode.
  • Feature flag selections.public-open.enabled действует только на публичное чтение по коду.