GET /api/admin/v1/model-config — Чтение платформенной экономической модели (admin)
Назначение
Отдаёт администратору платформы платформенную экономическую модель доходности — singleton-агрегат
EconomicModelConfig для таба «Глобальный дефолт». Возвращает
все девять коэффициентов, текущую ревизию (Version) и штампы последней правки (кто и когда менял
модель); ревизия нужна как expectedVersion при сохранении. Доступ — только администратор платформы
через admin API (ADR-0053).
| Поле | Значение |
|---|
| Сервис/контекст | invest-analytics |
| API area | admin (ADR-0053) |
| Feature group | admin-economic-model |
| Статус | draft |
| Документ | docs/06-services/invest-analytics/api/admin/get-model-config.md |
Актор и доступ
| Проверка | Значение |
|---|
| Actor type | Operator(Admin) — администратор платформы (доступ через admin API, m2m client-credentials) |
| Auth policy / Permissions | policy AdminSystemOnly (клиент pin-admin-system); каталожное соответствие — permission invest-analytics.model-config.view (docs/06-services/identity/domain/permissions.md; для admin API каталог permissions справочный, ADR-0053) |
| Scope (RBAC) | платформа |
| Tenant isolation | не применяется — конфигурация не tenanted (ADR-0052 п.3) |
| Audit | read: не аудируется (несекретная конфигурация, PII нет); наружу за пределы admin API модель не раскрывается |
HTTP-контракт
| Поле | Значение |
|---|
| Method | GET |
| Route | /api/admin/v1/model-config |
| Success status | 200 |
| Idempotency header | не применяется (safe GET) |
| Correlation | сквозной trace через traceparent; X-Admin-User-Id (Guid администратора) — обязательный заголовок admin-области |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|
AdminUserId | header X-Admin-User-Id | Guid | Да | != Guid.Empty | контекст admin-области (в лог) |
Параметров запроса нет — singleton читается целиком.
Модель ответа ModelConfigResult
Проекция полей дома economic-model-config.md один-в-один
(семантика/единицы/диапазоны — там):
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|
marketPremium | decimal | Да | EconomicModelConfig.MarketPremium | — | Надбавка к прайсу, доля. |
priceGrowthMonthly | decimal | Да | .PriceGrowthMonthly | — | Месячный рост цены м², доля. |
dailyRentM2 | decimal | Да | .DailyRentM2 | — | Аренда, руб/м²/сутки. |
rentGrowthMonthly | decimal | Да | .RentGrowthMonthly | — | Месячный рост аренды, доля. |
expenseShare | decimal | Да | .ExpenseShare | — | Доля расходов от выручки. |
appreciationTaxMonthly | decimal | Да | .AppreciationTaxMonthly | — | Легаси-поле (совместимость admin UI; в расчёте не участвует). |
ebitdaTaxMonthly | decimal | Да | .EbitdaTaxMonthly | — | Легаси-поле. |
occupancy | decimal | Да | .Occupancy | — | Заполняемость, доля. |
horizonMonths | int | Да | .HorizonMonths | — | Горизонт прогноза, мес. |
version | long | Да | .Version (0, если строки нет — отданы дефолты кода) | — | Ревизия модели; используется как expectedVersion при PUT. |
updatedAt | DateTimeOffset? | Нет | .UpdatedAt; null при дефолтах кода | — | Дата последнего изменения (показывается в админке). |
updatedByUserId | Guid? | Нет | .UpdatedByUserId | — | Кто последним менял (Guid администратора из X-Admin-User-Id записи). |
Алгоритм
- Контекст и доступ. Операцию выполняет администратор платформы через admin API (policy
AdminSystemOnly); scope — платформа; требуется право invest-analytics.model-config.view. Обязателен
заголовок X-Admin-User-Id.
- Проверка входа.
X-Admin-User-Id должен быть непустым, иначе — ValidationError. Параметров
запроса нет: singleton читается целиком, отсутствие строки — не ошибка (см. шаг 4).
- Что читаем. Платформенную модель
EconomicModelConfig по её well-known-идентификатору. Отсутствие
строки допустимо: seed-настройка её создаёт, но до её применения ответ строится из дефолтов кода.
- Правила и маппинг. Если строка есть — все поля ответа берутся из агрегата. Если строки нет — ответ
формируется из дефолтов кода (таблица дефолтов — economic-model-config.md)
с
version = 0, updatedAt = null, updatedByUserId = null.
- Результат. Возвращаются девять коэффициентов, ревизия и штампы правки. Консистентность —
read-your-writes в рамках PostgreSQL: после сохранения (PUT) администратор сразу видит новую ревизию.
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|
ValidationError | 400 | Отсутствует/пустой X-Admin-User-Id | Ошибка валидации запроса | no retry |
FORBIDDEN | 403 | Клиент не pin-admin-system / нет policy | Доступ запрещён | no retry |
Отсутствие строки в БД — не ошибка: 200 с дефолтами кода и version = 0.
Совместимость и наблюдаемость
- Additive-поля ответа — без breaking; удаление/переименование — breaking. Легаси-поля
appreciationTaxMonthly/ebitdaTaxMonthly не удалять до deprecation-решения.
- Logs:
admin-model-config-read (adminUserId, version). Metrics:
invest_analytics_admin_operations_total{operation="get-model-config"}. Traces — сквозной trace через
traceparent.
Acceptance Criteria
- Given seed применён и модель сохранена (
Version = 3), When администратор шлёт GET с валидным
X-Admin-User-Id, Then 200 с девятью коэффициентами, version = 3, updatedAt/updatedByUserId
последней правки.
- Given строки модели в БД нет (seed не применён), When GET, Then
200 с дефолтами кода,
version = 0, updatedAt = null, updatedByUserId = null — не ошибка.
- Given администратор только что выполнил
PUT (ревизия n → n+1), When сразу шлёт GET, Then
version = n+1 (read-your-writes в рамках PostgreSQL).
- Given заголовок
X-Admin-User-Id отсутствует или пуст, When GET, Then 400 ValidationError.
- Given клиент не
pin-admin-system (нет policy AdminSystemOnly), When GET, Then 403 FORBIDDEN; модель наружу не раскрывается.
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные документы