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

POST /api/v1/property-objects/{propertyObjectId}/analytics-report — PDF-отчёт «Скачать расчёт» (реализация отложена)

Статус реализации: отложена. Настоящим документом фиксируется контракт (route, вход, формат ответа, ошибки); до реализации endpoint отвечает 501 INVEST_ANALYTICS_REPORT_NOT_IMPLEMENTED. Формирование файла — средствами отчётного модуля платформы; выбор PDF-библиотеки — при реализации, отдельным решением.

Назначение

Скачивание PDF-файла с расчётом доходности объекта недвижимости: параметры расчёта, сводка выбранного месяца (AsideMetrics), три графика и помесячная таблица (InvestorMonth[]) — тот же расчёт, что ../public/get-property-object-investor-series.md, отрендеренный в документ. Вызывается аутентифицированным пользователем портала (инвестор/агент/менеджер); реф-гость отчёт скачивать не может.

Metadata

ПолеЗначение
Сервис/контекстinvest-analytics
API areadevelopers (аутентифицированный портал; реф-гость исключён)
Feature groupinvestor-series
Статусdraft (контракт зафиксирован; реализация отложена)
Документdocs/06-services/invest-analytics/api/developers/create-analytics-report.md

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

ПроверкаЗначение
Actor typeUser (Bearer JWT) — только аутентифицированный; реф-гость readOnly скачивать отчёт не может → 403
Auth policy / Permissionsauthenticated + permission invest-analytics.series.view (отчёт — проекция серии, отдельная permission не заводится)
Scope (RBAC)платформа
Tenant isolationне применяется (вход платформенный); request не tenanted
Auditфакт выгрузки — лог analytics-report-downloaded (userId, propertyObjectId); audit-записи БД нет

HTTP-контракт

ПолеЗначение
MethodPOST (генерация файла с телом параметров; не safe)
Route/api/v1/property-objects/{propertyObjectId}/analytics-report
Success status200, Content-Type: application/pdf, Content-Disposition: attachment; filename="pin-analytics-{propertyObjectId}-{yyyyMMdd}.pdf"
Idempotency headerне применяется (генерация детерминирована — INV-CALC-6, побочных эффектов в данных нет)
Correlationсквозной trace через traceparent

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

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
PropertyObjectIdrouteGuidДа!= Guid.Empty; существование — через chessboard (как в серии)
Entitybody entityEntityKindНетwire legal / individual, default legal; unknown → ValidationError
Taxbody taxTaxRegimeНетwire usn-6 / usn-15 / osno, default usn-6
MonthIndexbody monthIndexint?Нет0..360; выбранный слайдером месяц для секции сводки; default — последний месяц серии (HorizonMonths); значение за пределами фактической серии → ValidationError
UserIdidentity claims (sub)GuidДавалидный JWT — 401 до расчётадля лога выгрузки

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

ПолеТипОбязательностьИсточникMaskingОписание
FileNamestringДаpin-analytics-{propertyObjectId}-{yyyyMMdd}.pdfИмя файла (в Content-Disposition).
ContentTypestringДаконстанта application/pdfMIME-тип.
Contentbyte[]Дарендер отчётного модуляБинарное содержимое PDF (отдаётся как файл-стрим).

Состав PDF (контракт содержимого)

СекцияСодержимоеИсточник
ШапкаНазвание/номер объекта недвижимости, проект, дата формирования, параметры (entity, tax — человекочитаемо)chessboard analytics-params + вход
Сводка выбранного месяцаВсе 21 поле AsideMetrics выбранного MonthIndex (прогнозная стоимость, ROI, EBITDA, налоги, ипотечный платёж…)MetricsByMonth[MonthIndex]
ГрафикиТри серии gross-profit / ebitda / price-per-meter (растровый рендер)AnalyticsSeries
Помесячная таблицаInvestorMonth[] — 18 колонок по месяцам горизонтаMonths
Дисклеймер«Расчёт не является налоговой/инвестиционной консультацией; ставки — модельные допущения платформы» (../../domain/tax-entity-params.md, Безопасность)константа

Алгоритм

Шаги описывают целевую (отложенную) реализацию; до неё выполняются только шаги 1–2, затем возвращается ошибка INVEST_ANALYTICS_REPORT_NOT_IMPLEMENTED → 501.

  1. Контекст и доступ. Actor = User по Bearer JWT (реф-гость → 403 FORBIDDEN); только аутентифицированный пользователь портала.
  2. Проверка входа. PropertyObjectId != Guid.Empty; entity/tax — как в ../public/get-property-object-investor-series.md (unknown → INVEST_ANALYTICS_INVALID_TAX_PARAMS); MonthIndex0..360. Существование объекта недвижимости и допустимость состояния — при загрузке (chessboard, как в серии).
  3. Что читаем. Полностью переиспользует загрузку алгоритма серии (объект недвижимости из chessboard, платформенная модель, тип объекта, помесячные оверрайды, ипотека crm с fallback 21 %/240, история ClickHouse с synthetic-fallback) — общий расчётный компонент.
  4. Правила и расчёт. Тот же детерминированный расчёт (каскад коэффициентов → помесячный цикл → AsideMetrics → серии) → серии доходности. Дополнительно: MonthIndex = min(MonthIndex ?? HorizonMonths, HorizonMonths); рендер PDF: маппинг секций по таблице «Состав PDF».
  5. Результат. Файл-стрим application/pdf (Content-Disposition: attachment); ошибки → ProblemDetails (JSON). До реализации — 501. Файл не сохраняется (генерация на лету; персист/повторное скачивание по ссылке — вне v1).

Диаграмма

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

ТипДетали
Внешние вызовыкак у ../public/get-property-object-investor-series.md (chessboard / crm / ClickHouse)

Интеграционных и доменных событий метод не публикует.

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
INVEST_ANALYTICS_REPORT_NOT_IMPLEMENTED501Реализация отложена (текущее поведение всех запросов после валидации)Формирование отчёта пока недоступноno retry
ValidationError400Невалидные monthIndex/телоОшибка валидации запросаno retry
INVEST_ANALYTICS_INVALID_TAX_PARAMS400Неизвестное entity/taxНедопустимые параметры расчётаno retry
UNAUTHORIZED401Нет/просрочен JWTТребуется авторизацияno retry
FORBIDDEN403Реф-гость (readOnly)Скачивание доступно после входаno retry
INVEST_ANALYTICS_PROPERTY_OBJECT_NOT_FOUND404Объект недвижимости не найден в chessboardОбъект не найденno retry
INVEST_ANALYTICS_PROPERTY_OBJECT_SOURCE_UNAVAILABLE503chessboard недоступенПараметры объекта временно недоступныretry с backoff

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

  • Контракт зафиксирован до реализации: route/вход/формат не меняются при включении генерации (замена 501 на 200 — не breaking). Состав секций PDF — additive (новые секции добавляются без версии); смена формата файла (PDF → иной) — breaking.
  • Logs: analytics-report-downloaded (userId, propertyObjectId, entity, tax, monthIndex, размер файла, elapsed); до реализации — analytics-report-requested-not-implemented (счётчик спроса на фичу). Metrics: invest_analytics_report_requests_total{implemented}, duration рендера. Traces — сквозной trace через traceparent.

Acceptance Criteria

  • Given реализация отложена, When аутентифицированный пользователь шлёт валидный запрос, Then после прохождения валидации возвращается 501 INVEST_ANALYTICS_REPORT_NOT_IMPLEMENTED; фиксируется счётчик спроса analytics-report-requested-not-implemented.
  • Given актор — реф-гость (readOnly, без Bearer JWT), When POST, Then 403 FORBIDDEN (до генерации; скачивание доступно только после входа).
  • Given неизвестное значение entity/tax, When POST, Then 400 INVEST_ANALYTICS_INVALID_TAX_PARAMS.
  • Given monthIndex вне 0..360 или за пределами фактической серии, When POST, Then 400 ValidationError.
  • Given объект недвижимости не найден в chessboard, When POST, Then 404 INVEST_ANALYTICS_PROPERTY_OBJECT_NOT_FOUND; chessboard недоступен → 503 INVEST_ANALYTICS_PROPERTY_OBJECT_SOURCE_UNAVAILABLE.
  • Given целевая (включённая) реализация и существующий объект, When аутентифицированный пользователь шлёт POST, Then 200 application/pdf (Content-Disposition: attachment) с секциями по таблице «Состав PDF»; route/вход/формат не меняются (замена 501 → 200 — не breaking), файл не персистится.

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

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

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