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

GET /api/v1/developers/lookup/{banks,hoteliers} — Lookup справочников банков/отельеров

Назначение

Консолидированный документ 4 read-only lookup-операций над платформенными справочниками BankEntity и HotelierEntity: список и карточка по id на каждый справочник. Даёт застройщику (area developers) и агенту (area agents) справочники для подстановки при оформлении финансирования проекта (эскроу/ипотечные банки в ProjectFinancingDocument, INV-PRJ-7) и сделок (банк эскроу-счёта в crm; отельер апарт-отеля в карточке проекта). Только чтение активных записей (название + лого) с поиском по имени и пагинацией. Наполнение справочников — Admin API (banks-crud.md, hoteliers-crud.md), не здесь.

Зеркалирование area

Area developers и agents обслуживаются одной и той же логикой: различие — только маршрут (/developers/… vs /agents/…) и авторизационная policy эндпойнта (см. «Актор и доступ»).

Metadata

ПолеЗначение
Сервис/контекстchessboard
API areadevelopers (зеркалируется в agents)
Feature groupreferences
Статусdraft
Документdocs/06-services/chessboard/api/developers/references-lookup.md

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

ПроверкаЗначение
Actor typeUser — менеджер застройщика (developers area) или агент (agents area)
Auth policy / Permissionschessboard.references.lookup (единый permission для обеих area; policy эндпойнта различает area — permission.md)
Scope (RBAC)платформа — справочники платформенные, видимость решается permission-ом, не tenant-scope
Tenant isolationне применяется — BankEntity/HotelierEntity платформенные (ADR-0052 п.3); tenant актора на выборку не влияет
Auditread (не sensitive) — публичные данные (название/лого), access-audit не пишется

HTTP-контракт

ПолеЗначение
MethodGET (все 4)
Routes (developers)/api/v1/developers/lookup/banks, /api/v1/developers/lookup/banks/{bankId}, /api/v1/developers/lookup/hoteliers, /api/v1/developers/lookup/hoteliers/{hotelierId}
Routes (agents mirror)те же пути с префиксом /api/v1/agents/lookup/…
Success status200 (список — всегда 200, в т.ч. пустой; by-id — 200 при найденной активной записи)
Correlationсквозной trace через заголовок traceparent

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

Списочные запросы (banks / hoteliers):

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
Searchquerystring?Нетtrim; 0..256; фильтр по Name (case-insensitive contains)
PagingqueryPagingQueryДаPage >= 1 (default 1); PageSize 1..100 (default 20)

By-id запросы (bank / hotelier):

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
BankId / HotelierIdrouteGuidДа!= Guid.Empty (иначе VALIDATION_FAILED); существование и активность — на выборке
Ограничения параметров

TenantId в запрос не входит (платформенный справочник). Сортировка списков — по Name (возр.), фиксирована на сервере (клиент порядок не задаёт).

Модель ответа ReferenceLookupItem

Проекция сущности справочника; дом полей — bank.md / hotelier.md, здесь только выдаваемая дельта.

ПолеТипОбязательностьИсточникMaskingОписание
IdGuidДаBankEntity.Id / HotelierEntity.IdИдентификатор записи справочника (подставляется в Financing/сделку).
NamestringДа.NameНазвание банка/отельера.
LogoFileIdGuid?Нет.LogoFileIdФайл логотипа; выдача presign-ссылки — граница storage/CDN (здесь только FileId).

Списочный контейнер — постраничный: Items: IReadOnlyList<ReferenceLookupItem>, TotalCount: long, Page: int, PageSize: int. Служебные поля (CreatedAt, Version, DeletedAt, аудит) наружу не выдаются.

Предусловия

  • Пользователь авторизован (developers или agents area); у актора есть permission chessboard.references.lookup.
  • Справочники BankEntity/HotelierEntity наполняются администратором платформы (Admin API); lookup только читает активные (DeletedAt == null) записи.
  • Полученный Id используется вызывающими сценариями как ссылка: банк — в ProjectFinancingDocument (INV-PRJ-7) и в эскроу-счёте сделки crm; отельер — в Project.HotelierId. Актуальность имени/лого на стороне потребителя обеспечивается повторным lookup (справочник меняется редко).

Алгоритм

Обозначения

Ветвление: [L] — списочные запросы, [B] — карточка по id. Операция read-only, доменных событий не публикует.

  1. Контекст и доступ. Операцию выполняет User с permission chessboard.references.lookup (проверяется до чтения). Справочники платформенные — tenant-проверок нет.
  2. Проверка входа.
    • [L]: Search длина 0..256; Paging.Page >= 1, PageSize ∈ 1..100 — иначе VALIDATION_FAILED;
    • [B]: BankId/HotelierId != Guid.Empty; существование и активность — на выборке (шаг 3).
  3. Выборка. Архивные записи исключены фильтром DeletedAt == null (INV-BNK-2 / INV-HTL ArchiveKeepsReferences).
    • [L]: страница активных записей по фильтру имени (Search), сортировка по Name. Пустой результат — валиден (не ошибка).
    • [B]: запись по id; отсутствие (нет записи или она архивирована) — ожидаемый бизнес-исход → CHESSBOARD_BANK_NOT_FOUND / CHESSBOARD_HOTELIER_NOT_FOUND (404). Поля — Id, Name, LogoFileId.
  4. Результат. [L] — постраничный список → 200; [B] — карточка → 200 (или *_NOT_FOUND404).

Диаграмма

Побочные эффекты

ТипДетали
Кэшопц. кэширование TTL 60 c по ключу chessboard:lookup:{banks|hoteliers}:{search}:{page} (справочник меняется редко); presign логотипа — отдельный вызов storage/CDN на стороне клиента по LogoFileId

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
VALIDATION_FAILED400[L] PageSize/Page вне диапазона, Search > 256; [B] Id == Guid.Empty«Проверьте параметры запроса»no retry
CHESSBOARD_BANK_NOT_FOUND404[B] банк не найден или архивирован (DeletedAt != null)«Банк не найден»no retry
CHESSBOARD_HOTELIER_NOT_FOUND404[B] отельер не найден или архивирован«Отельер не найден»no retry
FORBIDDEN403нет permission chessboard.references.lookup«Недостаточно прав»no retry
Пустой результат — не ошибка

Пустой список — не ошибка: 200 с Items = [], TotalCount = 0.

Acceptance Criteria

  • Список банков. Given непустой активный справочник банков; When GET .../lookup/banks?search=<имя>&page=1; Then 200, постраничный список активных банков, отсортированный по Name, поля Id/Name/LogoFileId.
  • Пустой список. Given Search без совпадений или пустой справочник; When список; Then 200, Items = [], TotalCount = 0 (не ошибка).
  • Карточка по id. Given существующий активный bankId; When GET .../lookup/banks/{bankId}; Then 200 с карточкой; для отельеров симметрично.
  • Архивированная запись. Given bankId архивирован (DeletedAt != null) или не существует; When by-id; Then 404 CHESSBOARD_BANK_NOT_FOUND (для отельеров — CHESSBOARD_HOTELIER_NOT_FOUND).
  • Пустой id. Given bankId == Guid.Empty; When by-id; Then 400 VALIDATION_FAILED.
  • Agents-зеркало. Given тот же запрос по маршруту /api/v1/agents/lookup/… с агентской policy; When запрос; Then результат идентичен developers-области (общая логика).
  • Нет права. Given нет chessboard.references.lookup; When любой запрос; Then 403 FORBIDDEN.

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

  • Проекция ReferenceLookupItem минимальна (Id/Name/LogoFileId); новые optional поля — additive без breaking. Удаление/переименование/смена типа поля или маршрута — breaking (migration + rollout).
  • Agents area — контрактная копия developers: изменения проекции применяются к обеим сразу.
  • Logs: references-lookup requested (area, kind=bank|hotelier, search присутствие, resultCount); metrics: chessboard_references_lookup_total{area,kind,mode}, latency p95; traces — OTel (traceparent); dashboard chessboard-overview; runbook — не требуется (read-only, деградация = пустой/404-ответ).

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

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

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