API Контракты (v1)

Содержание

API Контракты (v1)#

Source-of-truth спецификация:

  • docs/openapi.yaml

Runtime документация API:

  • /swagger (Swagger UI)

  • /openapi.yaml (OpenAPI YAML)

Базовая дисциплина#

  • Префикс API: /api/v1.

  • Имена ресурсов: kebab-case, множественное число (status-events, device-profiles).

  • Поля JSON: snake_case.

  • Временные метки: UTC, формат RFC3339.

  • Контрактные заголовки:

    • X-Route-Path

    • X-Route-Module

    • X-Route-Filter

    • X-Client-Version

    • X-Client-Build-Time

Канонические маршруты#

  • GET /api/v1/<resource>/list — выборка с фильтрацией, сортировкой, пагинацией.

  • GET /api/v1/<resource>/scheme — схема/метаданные ресурса для UI.

  • GET /api/v1/<resource>/{id} — получение одной сущности.

  • POST /api/v1/<resource> — создание сущности/команды.

  • PATCH /api/v1/<resource>/{id} — частичное изменение.

  • DELETE /api/v1/<resource>/{id} — архивирование или удаление по политике ресурса.

Параметры list#

  • limit, offset, sort, order, q

  • Дополнительные фильтры по бизнес-атрибутам (status, source, tenant_id, и т.д.)

Базовый успешный ответ list#

{
  "items": [],
  "offset": 0,
  "limit": 20,
  "total": 0,
  "has_more": false,
  "meta": {
    "request_id": "req-20260304-001",
    "timestamp": "2026-03-04T17:50:00Z"
  }
}

Ответ по одной сущности#

{
  "item": {},
  "meta": {
    "request_id": "req-20260304-002",
    "timestamp": "2026-03-04T17:50:03Z"
  }
}

Ошибка#

{
  "error": {
    "code": "validation_error",
    "message": "Некорректное значение поля status",
    "details": [{ "field": "status", "reason": "unsupported_value" }]
  },
  "meta": {
    "request_id": "req-20260304-003",
    "timestamp": "2026-03-04T17:50:05Z"
  }
}

Рекомендуемые HTTP-статусы: 200/201/204, 400/401/403/404/409/422, 500.

Контракты текущего этапа#

  • GET /health

  • GET /api/v1/modules/list

  • GET /api/v1/modules/scheme

  • GET /api/v1/modules/database/list

  • GET /api/v1/modules/permissions/list

  • POST /api/v1/modules/permissions/commands/update

  • GET /api/v1/modules/access-audit/scheme|list

  • GET /api/v1/modules/site-policy/scheme|list

  • POST /api/v1/modules/site-policy/commands/set

  • POST /api/v1/modules/commands/install

  • POST /api/v1/modules/commands/uninstall

  • GET /api/v1/status/list

  • GET /api/v1/status/stream (WebSocket)

  • GET /api/v1/alarms/scheme|list

  • POST /api/v1/alarms/commands/ack

  • GET /api/v1/tasks/scheme|list

  • POST /api/v1/tasks

  • GET /api/v1/tasks/{id}

  • POST /api/v1/tasks/commands/transition

  • GET /api/v1/audit/scheme|list

  • POST /api/v1/audit/commands/log

  • GET /api/v1/devices/telemetry/scheme|list

  • GET /api/v1/devices/telemetry/kpi

  • GET /api/v1/passkeys/scheme

  • GET /api/v1/passkeys/list

  • POST /api/v1/passkeys/commands/issue

  • POST /api/v1/passkeys/commands/revoke

  • POST /api/v1/auth/passkey/commands/start

  • POST /api/v1/auth/passkey/commands/complete

  • GET /api/v1/auth/passkey/status

  • GET /api/v1/auth/me

  • POST /api/v1/auth/commands/logout

  • GET /api/v1/industry-profiles/scheme|list

  • POST /api/v1/industry-profiles/commands/import

  • POST /api/v1/poultry-profiles/commands/import-yaml

  • POST /api/v1/industry-profiles/commands/export

  • POST /api/v1/poultry-profiles/commands/export-yaml

  • POST /api/v1/industry-profiles/commands/publish

  • POST /api/v1/poultry-profiles/commands/publish

  • POST /api/v1/industry-profiles/commands/rollback

  • POST /api/v1/poultry-profiles/commands/rollback

  • GET /api/v1/industry-alarms/scheme|list

  • POST /api/v1/industry-alarms/commands/publish

  • GET /api/v1/app/context

  • GET /api/v1/tables/scheme|list

  • POST /api/v1/tables

  • GET|PATCH|DELETE /api/v1/tables/{id}

  • GET /api/v1/forms/scheme|list

  • POST /api/v1/forms

  • GET|PATCH|DELETE /api/v1/forms/{id}

  • GET /api/v1/tenant-master/scheme|list

  • POST /api/v1/tenant-master/commands/publish

  • GET /api/v1/subscriptions/scheme|list

  • POST /api/v1/subscriptions/commands/set-status

  • GET /api/v1/sla-profiles/scheme|list

  • POST /api/v1/sla-profiles/commands/assign

  • GET /api/v1/version-policies/scheme|list

  • POST /api/v1/version-policies/commands/set

  • POST /api/v1/version-policies/commands/check

  • GET /api/v1/analytics/metrics/scheme|list

  • GET /api/v1/analytics/summary

  • GET /api/v1/tenant-master-sync/scheme|list

  • POST /api/v1/tenant-master-sync/commands/run

  • POST /api/v1/tenant-master-sync/commands/set-mode

  • GET /api/v1/melioration-field/scheme|list

  • GET /api/v1/melioration-alerts/scheme|list

  • GET /api/v1/melioration-irrigation-machine/scheme|list

  • GET /api/v1/melioration-irrigation-drip/scheme|list

  • GET /api/v1/melioration-soil-moisture/scheme|list

  • GET /api/v1/melioration-weather/scheme|list

  • POST /api/v1/melioration-irrigation-machine/commands/ingest

  • POST /api/v1/melioration-irrigation-drip/commands/ingest

  • POST /api/v1/melioration-soil-moisture/commands/ingest

  • POST /api/v1/melioration-weather/commands/ingest

  • POST /api/v1/melioration-weather/commands/telemetry

  • GET /api/v1/melioration-control-mode/scheme|list

  • POST /api/v1/melioration-control-mode/commands/set

  • POST /api/v1/melioration-control-mode/commands/degrade

  • GET /api/v1/poultry-climate/scheme|list

  • POST /api/v1/poultry-climate/commands/setpoint

  • POST /api/v1/poultry-climate/commands/ack

  • POST /api/v1/poultry-climate/commands/telemetry

  • POST /api/v1/poultry-climate/sensors/commands/ingest

  • GET /api/v1/poultry-flock/scheme|list

  • GET /api/v1/poultry-feedwater/scheme|list

  • POST /api/v1/poultry-feedwater/commands/ingest

  • GET /api/v1/poultry-production/scheme|list

  • GET /api/v1/poultry-production/kpi

  • GET /api/v1/poultry-alarms/scheme|list

  • POST /api/v1/poultry-alarms/commands/evaluate

  • POST /api/v1/poultry-alarms/commands/publish

  • POST /api/v1/poultry-alarms/commands/ack

  • POST /api/v1/poultry-alarms/commands/escalate

  • GET /api/v1/swine-climate/scheme|list

  • POST /api/v1/swine-climate/commands/setpoint

  • POST /api/v1/swine-climate/commands/telemetry

  • POST /api/v1/swine-climate/sensors/commands/ingest

  • GET /api/v1/swine-feeding/scheme|list

  • POST /api/v1/swine-feeding/commands/ingest

  • GET /api/v1/swine-water/scheme|list

  • POST /api/v1/swine-water/commands/ingest

  • GET /api/v1/swine-production/scheme|list

  • GET /api/v1/swine-production/kpi

  • POST /api/v1/swine-production/commands/ingest

  • GET /api/v1/swine-biosecurity/scheme|list

  • POST /api/v1/swine-biosecurity/commands/ingest

  • POST /api/v1/swine-biosecurity/commands/ack

Тело /health:

{ "status": "ok", "layer": "master-cloud" }

Контракт app/context#

Маршрут:

  • GET /api/v1/app/context

Ключевые правила:

  • endpoint возвращает bootstrap-контекст runtime (deployment_mode, industry_code, available_industries, tenant_id, site_id, feature_flags, user);

  • поле policy является source-of-truth для UI/API guard-слоя и содержит:

    • scope_type, role, effective_tenant_id;

    • permissions.ui и permissions.api (lookup id -> allowed);

    • capabilities (агрегированные флаги операций UI, включая switch_industry, sidebar_menu, sidebar_menu_update, module_install, module_permissions, master_*, tenant_*);

    • guards (master_scope, tenant_scope, allow_industry_switch);

  • feature_flags и policy.capabilities применяются совместно: при запрете capability UI должен блокировать операцию даже при наличии локального fallback по правам.

Контракт CRUD ресурсов (tables/forms)#

Маршруты:

  • GET /api/v1/tables/scheme

  • GET /api/v1/tables/list

  • POST /api/v1/tables

  • GET /api/v1/tables/{id}

  • PATCH /api/v1/tables/{id}

  • DELETE /api/v1/tables/{id}

  • GET /api/v1/forms/scheme

  • GET /api/v1/forms/list

  • POST /api/v1/forms

  • GET /api/v1/forms/{id}

  • PATCH /api/v1/forms/{id}

  • DELETE /api/v1/forms/{id}

Ключевые правила:

  • POST и PATCH принимают объект в поле item и возвращают стандартный item envelope;

  • для list поддерживаются limit, offset, q;

  • при создании id может быть сгенерирован автоматически;

  • системные поля created_at, updated_at, resource выставляются runtime;

  • коды ошибок: validation_error (400), not_found (404), already_exists (409).

Контракт tenant-master exchange#

Маршруты:

  • GET /api/v1/tenant-master/scheme

  • GET /api/v1/tenant-master/list

  • POST /api/v1/tenant-master/commands/publish

Ключевые правила:

  • контур принимает только whitelisted служебные события (event_type) и статусы (status);

  • обязательные поля publish: tenant_id, event_type, status;

  • поддерживаются фильтры списка: tenant_id, event_type, status, limit, offset;

  • события хранят correlation_id и payload для сквозной трассировки обмена;

  • коды ошибок whitelist: event_not_whitelisted (409), status_not_whitelisted (409).

Контракт subscriptions + sla-profiles (master)#

Маршруты:

  • GET /api/v1/subscriptions/scheme

  • GET /api/v1/subscriptions/list

  • POST /api/v1/subscriptions/commands/set-status

  • GET /api/v1/sla-profiles/scheme

  • GET /api/v1/sla-profiles/list

  • POST /api/v1/sla-profiles/commands/assign

Ключевые правила:

  • контур поддерживает жизненный цикл подписки (trial|active|paused|canceled);

  • set-status изменяет состояние подписки и фиксирует updated_at;

  • sla-profiles содержит параметры SLA (response_minutes, resolution_minutes, escalation_policy);

  • assign связывает подписку с активным SLA-профилем;

  • фильтры списка подписок: tenant_id, status, sla_profile_id, q, limit, offset.

Контракт version-policies (master)#

Маршруты:

  • GET /api/v1/version-policies/scheme

  • GET /api/v1/version-policies/list

  • POST /api/v1/version-policies/commands/set

  • POST /api/v1/version-policies/commands/check

Ключевые правила:

  • policy-слой задает ограничения версии модуля (allowed_major, min_version, max_version, pinned_version);

  • поддерживаются scope: global, industry, tenant;

  • set создает/обновляет policy по id;

  • check валидирует версии установленных модулей и возвращает список нарушений (violations).

Контракт central analytics#

Маршруты:

  • GET /api/v1/analytics/metrics/scheme

  • GET /api/v1/analytics/metrics/list

  • GET /api/v1/analytics/summary

Ключевые правила:

  • metrics/list предоставляет агрегированные метрики master-контура по tenant/industry/window;

  • поддерживаются фильтры: tenant_id, industry_code, metric, window, q, limit, offset;

  • summary возвращает укрупненные показатели (tenants_count, industries_count, average_uptime_percent, average_latency_ms, open_alarms_total, open_tasks_total).

Контракт tenant-master-sync#

Маршруты:

  • GET /api/v1/tenant-master-sync/scheme

  • GET /api/v1/tenant-master-sync/list

  • POST /api/v1/tenant-master-sync/commands/run

  • POST /api/v1/tenant-master-sync/commands/set-mode

Ключевые правила:

  • модуль управляет состоянием синхронизации tenant -> master по каждому tenant_id;

  • статусы: live, degraded, stopped;

  • режимы: auto, manual, paused;

  • run запускает принудительную синхронизацию tenant и сбрасывает lag/pending;

  • set-mode переключает рабочий режим синхронизации.

Контракт alarms (tenant/master)#

Маршруты:

  • GET /api/v1/alarms/scheme

  • GET /api/v1/alarms/list

  • POST /api/v1/alarms/commands/ack

Ключевые правила:

  • единый контур тревог для master/tenant с состояниями open|acknowledged;

  • поддерживаются фильтры списка: q, severity, state, scope, limit, offset;

  • подтверждение тревоги выполняется через ack с полями id, acknowledged_by, comment;

  • ошибка отсутствующей тревоги: alarm_not_found (404);

  • при деинсталляции модуля возвращается module_not_installed (404).

Контракт tasks lifecycle#

Маршруты:

  • GET /api/v1/tasks/scheme

  • GET /api/v1/tasks/list

  • POST /api/v1/tasks

  • GET /api/v1/tasks/{id}

  • POST /api/v1/tasks/commands/transition

Ключевые правила:

  • состояния жизненного цикла: planned, in_progress, blocked, done, canceled;

  • поддерживаются фильтры списка: q, state, scope, assignee, limit, offset;

  • переходы выполняются через transition и валидируются по lifecycle policy;

  • недопустимый переход возвращает lifecycle_conflict (409);

  • для каждой задачи хранится история переходов (from_state, to_state, changed_by, changed_at, comment).

Контракт audit trail#

Маршруты:

  • GET /api/v1/audit/scheme

  • GET /api/v1/audit/list

  • POST /api/v1/audit/commands/log

Ключевые правила:

  • audit хранит историю действий и системных операций (actor, action, resource, result);

  • поддерживаются фильтры списка: q, actor, action, resource, result, limit, offset;

  • запись события выполняется через log c payload actor/action/resource/result/correlation_id/details;

  • поддерживаются результаты: success, denied, error;

  • история хранится в хронологическом порядке (новые записи сверху).

Контракт devices/telemetry#

Маршруты:

  • GET /api/v1/devices/telemetry/scheme

  • GET /api/v1/devices/telemetry/list

  • GET /api/v1/devices/telemetry/kpi

Ключевые правила:

  • list возвращает точки телеметрии устройств с фильтрами;

  • поддерживаются фильтры: q, device_id, site_id, status, metric, limit, offset;

  • kpi возвращает агрегаты по устройствам (online/warn/error, total points, average latency);

  • KPI рассчитываются по последнему известному состоянию каждого устройства в текущем фильтре.

Контракт ingest для melioration (MVP)#

  • POST /api/v1/melioration-irrigation-machine/commands/ingest

  • POST /api/v1/melioration-irrigation-drip/commands/ingest

  • POST /api/v1/melioration-soil-moisture/commands/ingest

  • POST /api/v1/melioration-weather/commands/ingest

  • POST /api/v1/melioration-weather/commands/telemetry

Ключевые правила:

  • ingest endpoint-ы принимают item-данные в request body и возвращают стандартный item envelope;

  • для irrigation событий поддерживаются обе единицы (mm primary, m3 derived);

  • для weather действует D-008 policy: station primary, service fallback при telemetry_healthy=false.

  • weather/telemetry поддерживает fallback_mode (A|B) и при healthy=false автоматически деградирует control_mode из C в fallback (auto_degraded=true).

  • /api/v1/melioration-alerts/list рассчитывает water_deficit|overwatering по связке soil + weather + irrigation.

Контракт poultry-climate (MVP, phase-1)#

Маршруты:

  • GET /api/v1/poultry-climate/scheme

  • GET /api/v1/poultry-climate/list

  • POST /api/v1/poultry-climate/commands/setpoint

  • POST /api/v1/poultry-climate/commands/ack

  • POST /api/v1/poultry-climate/commands/telemetry

  • POST /api/v1/poultry-climate/sensors/commands/ingest

Ключевые правила:

  • list возвращает климат-профили по house/batch/age-phase;

  • поддерживаются фильтры q, house_id, batch_id, age_phase_id, subtype, state, current_age_days, age_mode, limit, offset;

  • в ответе присутствует модель версий профиля (version_id, state, change_note, rollback_of).

  • setpoint применяет уставки к выбранному профилю (profile_id или селектор house+batch+age_phase), повышает version_id и переводит профиль в draft;

  • ack подтверждает профиль оператором и переводит его в published.

  • setpoint возвращает adapter_dispatch для климат-контроллера (adapter_profile_id, controller_id, transport, status).

  • telemetry принимает измерения адаптера (temp/humidity/co2/nh3/ventilation), сопоставляет с активным профилем и возвращает status + out_of_norm_flags.

  • sensors/ingest принимает показания датчиков среды (temperature|humidity|pressure|co2|nh3) и нормализует их в общий telemetry-контур climate.

  • при передаче current_age_days список вычисляет активную age-phase (active_by_age=true), а в режиме age_mode=active возвращает только текущий профиль фазы.

Контракт poultry-flock (MVP, phase-1)#

Маршруты:

  • GET /api/v1/poultry-flock/scheme

  • GET /api/v1/poultry-flock/list

Ключевые правила:

  • list возвращает партии выращивания по птичникам;

  • поддерживаются фильтры q, house_id, batch_id, subtype, status, limit, offset;

  • в ответе присутствуют поля жизненного цикла партии (start_date, planned_close_date, current_age_days, status).

Контракт poultry-feedwater (MVP, phase-1)#

Маршруты:

  • GET /api/v1/poultry-feedwater/scheme

  • GET /api/v1/poultry-feedwater/list

  • POST /api/v1/poultry-feedwater/commands/ingest

Ключевые правила:

  • list возвращает объединенный профиль кормления/водопотребления на age phase;

  • поддерживаются фильтры q, house_id, batch_id, age_phase_id, subtype, status, state, limit, offset;

  • в ответе присутствует модель версий профиля (version_id, state, change_note, rollback_of) и пороги аномалий расхода воды.

  • ingest принимает feed/water counters (+ pressure), рассчитывает отклонения и возвращает status=ok|warn|alarm с anomaly_flags.

  • ingest обновляет operational поля профиля (operational_status, last_*, *_deviation_pct, last_counter_at) для runtime-мониторинга.

Контракт poultry-production (MVP, phase-1)#

Маршруты:

  • GET /api/v1/poultry-production/scheme

  • GET /api/v1/poultry-production/list

  • GET /api/v1/poultry-production/kpi

Ключевые правила:

  • list возвращает производственные KPI по house/batch/date;

  • поддерживаются фильтры q, house_id, batch_id, subtype, metric_date, limit, offset;

  • в ответе доступны эксплуатационные отклонения (out_of_norm_flags) и KPI для broiler/layer.

  • kpi рассчитывает агрегированные отраслевые показатели по окну (window_days) для broiler/layer.

Контракт poultry-alarms (MVP, phase-1)#

Маршруты:

  • GET /api/v1/poultry-alarms/scheme

  • GET /api/v1/poultry-alarms/list

  • POST /api/v1/poultry-alarms/commands/evaluate

  • POST /api/v1/poultry-alarms/commands/publish

  • POST /api/v1/poultry-alarms/commands/ack

  • POST /api/v1/poultry-alarms/commands/escalate

Ключевые правила:

  • list возвращает отраслевые тревоги poultry с обязательным correlation_id;

  • поддерживаются фильтры q, house_id, batch_id, severity, priority, status, correlation_id, limit, offset;

  • структура события совпадает с poultry_alarm_event и готова к bridge в status.

  • publish создает событие с status=active и автоматически генерирует correlation_id, если не передан;

  • ack подтверждает событие по id, выставляет status=acked, acked_at, assignee.

  • для severity=critical|high poultry alarm-bus публикует bridge-событие в status с тем же correlation_id (bridged_to_status=true).

  • в status/list bridged-событие хранит correlation_id для сквозной трассировки poultry alarm -> status.

  • evaluate запускает rule-engine по телеметрии (temp/co2/ventilation/feed-water deviations) и создает события с приоритетами (P1/P2) согласно правилу.

  • для каждого события рассчитывается SLA (sla_target_sec, sla_deadline_at), а escalate помечает sla_breached=true и повышает escalation_level при нарушении SLA.

Контракт profile-service (D-003)#

Маршруты:

  • GET /api/v1/industry-profiles/scheme

  • GET /api/v1/industry-profiles/list

  • POST /api/v1/industry-profiles/commands/import

  • POST /api/v1/poultry-profiles/commands/import-yaml

  • POST /api/v1/industry-profiles/commands/export

  • POST /api/v1/poultry-profiles/commands/export-yaml

  • POST /api/v1/industry-profiles/commands/publish

  • POST /api/v1/poultry-profiles/commands/publish

  • POST /api/v1/industry-profiles/commands/rollback

  • POST /api/v1/poultry-profiles/commands/rollback

Ключевые правила:

  • перенос нормативов между хозяйствами через YAML (export/import);

  • версионирование профилей (draft/published/archived);

  • rollback на выбранную версию с аудитом действий;

  • совместимость import-профиля проверяется по industry_code и equipment_profile.

  • poultry-profiles/import-yaml принимает только профили с industry_code=poultry.

  • poultry-profiles/export-yaml экспортирует только industry_code=poultry и возвращает conflict при попытке экспорта профиля другой отрасли.

  • poultry-profiles/publish публикует только poultry-профили и выполняет ту же модель версионирования (draft -> published, предыдущая published -> archived).

  • poultry-profiles/rollback выполняет откат только для poultry-профилей и публикует указанную версию как активную.

Контракт industry alarm-bus (D-004)#

Маршруты:

  • GET /api/v1/industry-alarms/scheme

  • GET /api/v1/industry-alarms/list

  • POST /api/v1/industry-alarms/commands/publish

Ключевые правила:

  • отраслевые тревоги публикуются в отдельный контур industry-alarms;

  • изоляционные ключи tenant_id, industry_code, site_id передаются в отраслевых событиях и поддерживаются в фильтрах списка;

  • bridge в status выполняется для severity=critical|high;

  • mapping в status: critical|high -> error, medium -> warn, low|info -> ok;

  • для сквозной трассировки в обеих системах передается correlation_id.

Контракт модульного реестра#

GET /api/v1/modules/list возвращает список модулей с четырьмя контурами:

  • frontend: block_id, component;

  • backend: routes.

  • database: migrations, tables.

  • permissions: rules (role, resource, actions).

  • отраслевые метаданные: industry_code, industry_scope, key_entity, provides_enrichment_for.

  • поле version для отраслевых модулей следует политике MAJOR.MINOR.PATCH; в рамках одной отрасли активная major-линия должна быть единой.

Пример элемента:

{
  "id": "status",
  "name": "Status Stream",
  "description": "Поток статусов оборудования и событий в реальном времени",
  "version": "0.1.0",
  "core": false,
  "installed": true,
  "dependencies": [],
  "frontend": {
    "block_id": "status",
    "component": "status-table"
  },
  "backend": {
    "routes": ["/api/v1/status/list", "/api/v1/status/stream"]
  },
  "database": {
    "migrations": ["20260304_20_create_status_events"],
    "tables": [
      {
        "name": "status_events",
        "primary_key": "id",
        "columns": ["id", "source", "event", "status", "timestamp"]
      }
    ]
  },
  "permissions": {
    "rules": [
      {
        "role": "operator",
        "resource": "status",
        "actions": ["read", "stream"]
      }
    ]
  }
}

Контракт cross-industry access audit#

Маршруты:

  • GET /api/v1/modules/access-audit/scheme

  • GET /api/v1/modules/access-audit/list

Ключевые правила:

  • фиксируются решения отраслевых policy-check при modules/permissions/commands/update и modules/commands/install;

  • событие содержит: operation, decision (allow|deny), reason, module_id, requested_industry_code, module_industry_code, actor, timestamp;

  • хранение в runtime ограничено последними 200 событиями (in-memory, порядок desc);

  • фильтры списка: module_id, decision, requested_industry_code, module_industry_code.

Контракт модели БД по модулям#

GET /api/v1/modules/database/list возвращает модель БД модулей.

Параметры:

  • installed_only (true|false, по умолчанию true) — только установленные модули или полный каталог.

  • industry_code (опционально) — фильтрация permission-модели по отраслевой области доступа.

  • site_id (опционально) — фильтрация permission-модели с учетом site-policy (частичная активация модулей на площадке).

  • industry_code (опционально) — фильтрация permission-модели по отраслевой области доступа.

Элемент списка:

{
  "module_id": "tasks",
  "module_name": "Tasks",
  "installed": true,
  "migrations": ["20260305_20_create_tasks_lifecycle"],
  "tables": [
    {
      "name": "tasks",
      "primary_key": "id",
      "columns": ["id", "title", "priority", "status", "sla_minutes", "created_at"]
    }
  ]
}

Контракт модели прав по модулям#

GET /api/v1/modules/permissions/list возвращает роль-ресурсные правила модулей.

Параметры:

  • installed_only (true|false, по умолчанию true) — только установленные модули или полный каталог.

Элемент списка:

{
  "module_id": "tasks",
  "module_name": "Tasks",
  "installed": true,
  "rules": [
    {
      "role": "operator",
      "resource": "tasks",
      "actions": ["read", "create", "transition"]
    }
  ]
}

POST /api/v1/modules/permissions/commands/update обновляет правила конкретного модуля.

Тело запроса:

{
  "id": "status",
  "industry_code": "melioration",
  "rules": [
    { "role": "operator", "resource": "status", "actions": ["read"] },
    { "role": "admin", "resource": "status", "actions": ["read", "stream", "update"] }
  ]
}

Если industry_code задан, update разрешается только для модулей, доступных в рамках выбранной отрасли; при нарушении возвращается industry_policy_conflict.

Контракт установки/деинсталляции#

Тело запроса:

{ "id": "mqtt" }

Ошибки модульного API:

  • module_not_found

  • module_already_installed

  • module_not_installed

  • module_is_core

  • module_dependency_missing

  • module_has_dependents

  • industry_policy_conflict

Контракт site-policy (частичная активация модулей)#

Маршруты:

  • GET /api/v1/modules/site-policy/scheme

  • GET /api/v1/modules/site-policy/list

  • POST /api/v1/modules/site-policy/commands/set

Параметры site-policy/list:

  • site_id (обязательно)

  • limit, offset

Тело site-policy/set:

{
  "site_id": "site-a",
  "module_id": "melioration-field",
  "enabled": false
}

Правило:

  • modules/list, modules/database/list, modules/permissions/list поддерживают фильтр site_id и исключают модули, отключенные policy для этой площадки.

  • Source-of-truth для policy хранится в shared SQL persistence, а runtime in-memory map используется только как process cache.

Контракт Passkey (QR/RFID)#

Маршруты:

  • GET /api/v1/passkeys/scheme

  • GET /api/v1/passkeys/list

  • POST /api/v1/passkeys/commands/issue

  • POST /api/v1/passkeys/commands/revoke

Параметры passkeys/list:

  • limit, offset, sort, order, q

  • type (qr|rfid)

  • status (active|revoked)

Поддерживаемые поля сортировки:

  • id, type, holder, scope, status, issued_at, expires_at

Пример элемента passkeys/list:

{
  "id": "PK-QR-1001",
  "type": "qr",
  "holder": "Оператор смены",
  "scope": "Gate-A",
  "status": "active",
  "issued_at": "2026-03-04T14:00:00Z",
  "expires_at": "2036-03-05T14:00:00Z",
  "last_used_at": "2026-03-04T15:35:00Z"
}

Тело passkeys/commands/issue:

{
  "type": "rfid",
  "holder": "Test User",
  "scope": "Gate-B",
  "ttl_minutes": 60
}

Тело passkeys/commands/revoke:

{ "id": "PK-QR-1001" }

Если модуль passkey деинсталлирован, API возвращает 404 module_not_installed.

Контракт аутентификации Passkey#

Маршруты:

  • POST /api/v1/auth/passkey/commands/start

  • POST /api/v1/auth/passkey/commands/complete

  • GET /api/v1/auth/passkey/status

  • GET /api/v1/auth/me

  • POST /api/v1/auth/commands/logout

  • GET /api/v1/auth/permissions/scheme

  • GET /api/v1/auth/permissions/list

  • GET /api/v1/auth/ui-access/list

  • POST /api/v1/auth/ui-access/commands/update

  • GET /api/v1/auth/ui-preferences/list

  • POST /api/v1/auth/ui-preferences/commands/update

  • GET /api/v1/auth/shell-profile/list

  • POST /api/v1/auth/shell-profile/commands/export

  • POST /api/v1/auth/shell-profile/commands/import

  • POST /api/v1/auth/shell-profile/commands/rollback

  • GET /api/v1/auth/security-log/scheme

Практический канон для iP-1510:

  • локальный L1 path: RFID -> local auth bridge -> local session

  • phone-assisted path: QR challenge/response

  • BLE не считается обязательным transport contract и допустим только как ускоритель

  • для iPhone/Safari обязателен fallback QR -> 4-digit code

  • backend обязан фильтровать module projection по grants до рендера UI, а не только скрывать элементы на frontend

  • GET /api/v1/auth/security-log/list

Тело auth/passkey/start:

{ "method": "qr" }

Ответ:

  • challenge_id, method, status, expires_at

  • для method=qr дополнительно qr_payload

Тело auth/passkey/complete:

{
  "challenge_id": "CH-...",
  "credential": "PK-QR-1001"
}

credential может быть как id ключа (PK-*), так и внутренним credential (QR-*/RF-*).

POST /api/v1/auth/passkey/commands/complete:

  • по успешному завершению выставляет HttpOnly cookie ioot_session с JWT (HMAC-SHA256).

  • JWT также может передаваться через Authorization: Bearer <token>.

GET /api/v1/auth/me:

  • возвращает authenticated=true и user при валидном JWT;

  • возвращает authenticated=false, если токен отсутствует/невалиден.

  • user включает: role, scope, scope_type, tenant_id (для tenant-scope).

GET /api/v1/auth/permissions/list:

  • возвращает объединенную матрицу api + ui операций с расчетным флагом allowed;

  • поддерживает фильтры:

    • layer=api|ui;

    • allowed=true|false.

GET /api/v1/auth/ui-access/list:

  • возвращает role/action правила для UI-shell ресурса;

  • текущий runtime-ресурс: ui.sidebar.menu;

  • id можно передать query-параметром, по умолчанию используется ui.sidebar.menu.

  • backend source-of-truth хранится в shared SQL persistence.

POST /api/v1/auth/ui-access/commands/update:

  • обновляет правила UI-access для shell-ресурса;

  • используется для доступа к burger-меню и прав на его редактирование;

  • допустимые actions текущего runtime: read, update.

GET /api/v1/auth/ui-preferences/list:

  • возвращает пользовательские shell-настройки для текущего контекста tenant/site/industry;

  • читает theme, dashboard_layout, quick_module_ids с флагами наличия has_*;

  • при отсутствии сохраненных значений frontend использует локальный fallback.

  • backend source-of-truth хранится в shared SQL persistence.

POST /api/v1/auth/ui-preferences/commands/update:

  • сохраняет пользовательские shell-настройки для текущего контекста;

  • доступен всем аутентифицированным ролям как self-service ресурс;

  • текущий payload включает theme, dashboard_layout, quick_module_ids, industry_code, site_id;

  • при каждом обновлении пишет versioned snapshot в shell-profile для текущего tenant/site/industry.

GET /api/v1/auth/shell-profile/list:

  • возвращает историю versioned shell-profile для текущего tenant с optional фильтрами site_id, industry_code;

  • запись включает current_version, versions[], audit[], updated_at.

  • backend source-of-truth хранится в shared SQL persistence; legacy JSON sidecars допустимы только как bootstrap import path.

POST /api/v1/auth/shell-profile/commands/export:

  • экспортирует текущий shell-profile snapshot в JSON payload со schema_version=v1;

  • поддерживает выбор конкретной version; если история еще не создана, экспортирует live-снимок из ui-preferences + ui-access.

POST /api/v1/auth/shell-profile/commands/import:

  • импортирует shell-profile snapshot в выбранный site_id / industry_code;

  • payload включает theme, dashboard_layout, quick_module_ids, ui_access;

  • применяет snapshot к ui-preferences и ui-access, затем создает новую версию с audit entry.

POST /api/v1/auth/shell-profile/commands/rollback:

  • откатывает shell-profile к выбранной to_version;

  • повторно применяет сохраненный snapshot и пишет новую версию с rollback_of=<to_version>;

  • доступен только admin, так как изменяет общие UI access rules.

GET /api/v1/auth/security-log/list:

  • возвращает security-журнал по событиям auth/action (allow|deny) с route-контекстом;

  • поддерживает фильтры category, result, event, method, path, tenant_id;

  • доступен только ролям admin|security (иначе 403 rbac_forbidden).

Защита API#

  • Все маршруты /api/* защищены middleware, кроме публичных auth-маршрутов:

    • POST /api/v1/auth/passkey/commands/start

    • POST /api/v1/auth/passkey/commands/complete

    • GET /api/v1/auth/passkey/status

    • GET /api/v1/auth/me

    • POST /api/v1/auth/commands/logout

  • При отсутствии валидного JWT возвращается:

{
  "error": {
    "code": "auth_required",
    "message": "Требуется вход в приложение"
  }
}
  • RBAC и scope-гварды применяются на уровне middleware:

    • master endpoint-группы (tenant-master*, subscriptions/sla, version-policies, analytics) требуют scope_type=master;

    • tenant endpoint-группы (industry-*, melioration-*, poultry-*, swine-*) требуют scope_type=tenant;

    • для tenant scope включена boundary-проверка tenant_id / target_tenant_id в query и JSON body;

    • при нарушении границ возвращаются 403 с кодами scope_boundary_denied/tenant_boundary_denied/rbac_forbidden.

Pilot process composition (runtime facts)#

Существующие API-контракты используются process-утилитами reference runtime без введения новых endpoint-ов:

  • scripts/pilot-bootstrap.py использует GET /api/v1/app/context, GET /api/v1/modules/list, GET /api/v1/modules/site-policy/list, POST /api/v1/auth/shell-profile/commands/export, POST /api/v1/auth/shell-profile/commands/import, POST /api/v1/modules/commands/install, POST /api/v1/modules/commands/uninstall, POST /api/v1/modules/site-policy/commands/set;

  • scripts/pilot-evidence-bundle.py использует GET /api/v1/app/context, GET /ready, GET /api/v1/modules/list, GET /api/v1/modules/site-policy/list, POST /api/v1/auth/shell-profile/commands/export, GET /api/v1/auth/security-log/list;

  • scripts/pilot-rollback-drill.py оркестрирует baseline export/apply/evidence/restore поверх двух контуров выше.

Синхронизация с ../green-robot#

  • При дальнейшем развитии:

    • modules/scheme должен возвращать display_module, show_filters, module_view, catalog_enrichment (sidebar_fields, infobar_fields).

    • Shell должен поддерживать отдельный UI-access ресурс ui.sidebar.menu для role-gated burger-меню и конфигурации быстрых fullscreen-кнопок.

    • Shell persistence должен поддерживать backend-хранение theme, dashboard_layout, quick_module_ids с изоляцией по tenant/site/industry и локальным fallback.

    • Shell должен поддерживать versioned export/import/rollback profile для theme, dashboard_layout, quick_module_ids, ui-access, а также pilot preset-артефакты cloud-multi и edge-single.

    • Ввести единый envelope ответа со meta для всех новых list/get endpointов.

    • Применять kebab-case имена ресурсов и idempotency для критичных POST-операций.