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

Favorites API — индекс операций

Карта HTTP-операций контекста favorites. Дом полей сущностей — domain/favorite.md и domain/merge-strategy.md.

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

  • Определение владельца (actor) едино для всех public-операций: авторизованный пользователь — UserId из JWT-claim sub; гость — AnonymousId из заголовка X-Anonymous-Id (выдаёт user-activity, ADR-0054). При наличии обоих приоритет у JWT. Нет ни того ни другого → FAVORITES_OWNER_UNRESOLVED.
  • Сущности вне tenant (ADR-0052 п.2): обязательный record-level фильтр по UserId/AnonymousId в каждой операции (INV-FAV-005).
  • Display-данные объектов недвижимости (цена, название, фото) этот сервис не отдаёт — фронт добирает их батч-запросом в catalog по списку PropertyObjectId (будущий док docs/06-services/catalog/README.md).
  • Все мутирующие операции публикуют интеграционные события атомарно со сменой состояния.
  • Note — приватные данные владельца: не логируется, не попадает в Kafka-события и internal-ответы.

Сквозные ошибки области

Единые коды, повторяющиеся в public-операциях (дом условий — таблицы «Ошибки» каждой операции и инварианты domain/favorite.md / domain/merge-strategy.md):

КодHTTPУсловиеГде применяется
FAVORITES_OWNER_UNRESOLVED400Нет ни JWT, ни валидного X-Anonymous-Idвсе public-операции self-scope
FAVORITES_NOTE_TOO_LONG400Note после trim > 4000 символов (INV-FAV-003)add, update-note
FAVORITES_NOT_FOUND404Записи владельца нет / чужая (не различаются, INV-FAV-005)update-note
FAVORITES_CONCURRENCY_CONFLICT409Версия записи изменилась между чтением и фиксациейupdate-note
FAVORITES_SESSION_NOT_LINKED403Сессия не связана с пользователем в user-activity (INV-FAV-102)merge-preview, merge
FAVORITES_MERGE_UNAVAILABLE503user-activity недоступен (internal API связи сессии)merge-preview, merge

DELETE/GET-операции возврата 404 избегают намеренно (существование чужой записи не раскрывается) — удаление отсутствующей записи и пустой список суть валидные успехи.

Идемпотентность операций (сводка)

ОперацияКлюч идемпотентностиПоведение при повторе
POST /favoritesпара «владелец + PropertyObjectId» (INV-FAV-002)200, WasCreated = false, без второго события
DELETE /favorites/{id}естественная (удаление отсутствующей записи)204, без события
PUT …/noteцелевое значение = текущему200, no-op
POST /favorites/importпара «владелец + объект» на каждый элемент200, ImportedCount = 0, без событий
POST /favorites/mergeпара (UserId, AnonymousId) (INV-FAV-101)200, сохранённые счётчики, WasAlreadyApplied = true

Окно согласованности слияния и порядок вызовов

Слияние после входа опирается на асинхронную связь сессии в user-activity (pin.identity.sign-ins.v1 → связывание AnonymousIdUserId). Пока связь не установлена, merge-preview/merge возвращают FAVORITES_SESSION_NOT_LINKED — фронт повторяет после короткой паузы. Обязательный порядок клиентского флоу: importmerge-previewmerge (импорт с устройства должен предшествовать превью — иначе локальные лайки не попадут в слияние). Обычные операции add/remove/ list/note от этого окна не зависят.

Операции

ОбластьМетод и маршрутОперацияФайл
publicGET /api/v1/favoritesСписок избранного владельца (user или гостевая сессия)get-my-favorites.md
publicPOST /api/v1/favoritesДобавить объект недвижимости в избранное (идемпотентно, опц. заметка)add-favorite.md
publicDELETE /api/v1/favorites/{propertyObjectId}Удалить объект недвижимости из избранного (идемпотентно)remove-favorite.md
publicPUT /api/v1/favorites/{propertyObjectId}/noteУстановить/очистить заметку (≤ 4000)update-favorite-note.md
publicPOST /api/v1/favorites/importBulk-импорт propertyObjectId[] с устройстваimport-favorites.md
publicGET /api/v1/favorites/merge-previewСчётчики/конфликты сторон перед слиянием после входаget-merge-preview.md
publicPOST /api/v1/favorites/mergeПрименить стратегию слияния (DeviceWins / AccountWins / Merge)merge-favorites.md
internalGET /internal/favorites?userId=Чтение избранного пользователя контекстом selections (m2m)internal/list-favorites.md
internalPOST /internal/favorites/statusПакетный 3-state статус избранного (агент+инвестор × объекты) контекстом crm (m2m)internal/get-favorite-status.md

Admin-области нет (модерация заметок не требуется; заметки приватны). Callbacks — не применяется.

Клиентский флоу авторизации (страница избранного)

  1. Первый заход клиента: если на устройстве есть накопленный локально набор избранного — один вызов POST /api/v1/favorites/import, при успехе локальный набор очищается.
  2. Обычная работа: GET /favorites, POST /favorites, DELETE /favorites/{propertyObjectId}, PUT /favorites/{propertyObjectId}/note — гость по X-Anonymous-Id, пользователь по JWT.
  3. После входа (JWT получен, X-Anonymous-Id продолжает передаваться): GET /favorites/merge-preview → при RequiresChoice = true диалог трёх стратегий (предвыбран Merge) → POST /favorites/merge.

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