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

GET /api/v1/investor/calendar/appointments/{appointmentId} — Карточка моей записи

Назначение

Отдаёт инвестору карточку одной его записи (appointment.md): статус, время и место встречи, агента и — главное — действующие правила отмены/переноса (echo cutoff), чтобы клиент показал кнопки «Отменить»/«Перенести» ровно тогда, когда операции реально доступны. Чужая запись неотличима от несуществующей (fail-closed 404).

Metadata

ПолеЗначение
Сервис/контекстcalendar
API areainvestor
Feature groupappointments
Статусdraft
Документdocs/06-services/calendar/api/investor/get-my-appointment.md

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

ПроверкаЗначение
Actor typeUser (Инвестор с JWT)
Auth policy / Permissionsnone (достаточно аутентификации инвестора)
Scope (RBAC)не применяется — инвестор вне tenant (ADR-0052)
Record-levelзапись доступна только при InvestorUserId = ActorUserId из токена; иначе — 404 (без раскрытия существования)
Auditread: актор и AppointmentId фиксируются в trace; Comment в логи не пишется

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/v1/investor/calendar/appointments/{appointmentId}
Success status200
Idempotency headerнет (безопасное чтение)
Correlationсквозной trace через заголовок traceparent

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

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
ActorUserIdтокен (sub)GuidДаRequiredrecord-level фильтр InvestorUserId
AppointmentIdrouteGuidДаRequired, валидный Guid

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

Модель и все её поля — по дому list-my-appointments.md. Для карточки существенны echo-поля правил отмены:

  • CancellationCutoffMinutes — параметр слота (INV-APT-3);
  • CancellableUntil = StartAt − CancellationCutoffMinutes — до этого момента инвестору доступны cancel-my-appointment.md и reschedule-my-appointment.md;
  • отмена/перенос возможны только для активной записи (Pending/Confirmed) и пока now ≤ CancellableUntil; после cutoff обе операции вернут 409 APPOINTMENT_CUTOFF_PASSED, а по терминальной записи — 409 APPOINTMENT_INVALID_STATE;
  • PendingExpiresAt (для Pending) — до какого момента агент примет решение; после — запись автоматически истечёт (Expired), слот освободится.

Алгоритм

Тривиальное чтение: найти запись по AppointmentId с условием InvestorUserId = actor; не найдена или принадлежит другому инвестору → APPOINTMENT_NOT_FOUND (404, fail-closed). Найденная запись дополняется display-именем агента (реплика identity) и местом встречи из слота и возвращается как MyAppointmentModel → HTTP 200. Данные — из source of truth calendar, актуальны на момент чтения.

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
VALIDATION_FAILED400AppointmentId — не валидный Guid«Некорректный идентификатор»no retry
UNAUTHORIZED401нет/просрочен JWTno retry
APPOINTMENT_NOT_FOUND404запись не существует или принадлежит другому инвестору«Запись не найдена»no retry

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

  • Контракт модели — по дому list-my-appointments.md: новые поля — additive optional; удаление/переименование/смена типа — breaking.
  • Logs: InvestorUserId, AppointmentId, результат (без Comment); metrics: calendar_api_request_duration_seconds{route}; traces — сквозной traceparent.

Acceptance Criteria

  • AC-1 (happy). Дано: активная запись инвестора, до StartAt далеко. Когда: GET карточки. Тогда: 200, CancellableUntil > now — клиент показывает «Отменить»/«Перенести».
  • AC-2 (после cutoff). Дано: Confirmed-запись, now > StartAt − CancellationCutoffMinutes. Тогда: 200, CancellableUntil < now — клиент скрывает кнопки; попытка отмены вернёт 409 APPOINTMENT_CUTOFF_PASSED.
  • AC-3 (чужая запись). Дано: AppointmentId записи другого инвестора. Тогда: 404 APPOINTMENT_NOT_FOUND — ответ неотличим от несуществующей записи.
  • AC-4 (перенесённая). Дано: запись, отменённая переносом. Тогда: 200, Status = Cancelled, RescheduledToAppointmentId указывает на новую запись.

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

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

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