NODEDC_PLATFORM/docs/ADR_GELIOS_DATA_PLANE.md

11 KiB
Raw Permalink Blame History

ADR: Gelios adapter в External Provider Data Plane

Статус: superseded.
Дата: 2026-07-13.
Владелец решения: NODE.DC Platform.

Заменено 2026-07-14 документом ADR_L2_OWNED_EXTERNAL_CONNECTORS.md. Gelios остаётся domain/ontology примером, но не получает отдельный provider-owned gateway: fetch, mapping и collection policy живут в его L2 connector instance; Platform предоставляет нейтральный Data Plane.

Контекст

Gelios Pro поставляет непрерывную телеметрию, конфигурацию устройств и пространственные данные. В текущем доступе подтверждены 107 видимых units, из них 105 с lastMsg; окончательный connection scope должен быть зафиксирован allowlist-ом владельца. Это не данные Ontology Core и не данные Tasker. Они требуют отдельного контура для текущего состояния, истории, геозапросов, аналитики и будущих прогнозов.

Gelios является первым provider adapter, который подчиняется общему docs/ADR_EXTERNAL_PROVIDER_DATA_PLANE.md: connection instance хранит connection scope/policy, Engine Credentials владеет provider secret, gateway владеет storage/read-моделью, а ontology описывает значения, но не runtime data.

Физические trike-команды существуют в домене, но не входят в ingestion или тестирование. Для них позднее потребуется отдельный, ручной и аудируемый контур.

Решение

  1. Создать отдельный сервис platform/services/gelios-gateway как storage/read gateway:
    • не хранит и не получает provider token;
    • принимает только аутентифицированный safe-read intake от защищённого Engine L2 Collector workflow;
    • применяет allowlist и field policy до записи;
    • нормализует ответ в сущности пакета gelios;
    • публикует read-модель для Engine L2 workflow и Map View.
  2. В Engine появляется отдельный Gelios Credential и NDC Agent L2 collection profile:
    • credential скрывает access/refresh pair и его lifecycle;
    • credential привязан только к намеренно пошаренному Collector workflow;
    • Collector содержит allowlist read-capabilities и не имеет command transport;
    • ни секрет, ни provider response без нормализации не передаются в ontology, UI, Gateway или другие workflow.
  3. Выделить сервису собственную БД gelios-postgres, не деля её с Tasker, Authentik, Notification Core или Ontology Core. В будущей multi-tenant форме эта БД обслуживает несколько Gelios connection instances, но все records разделены tenant_id и connection_id.
  4. Базовый движок: PostgreSQL 16 с расширениями TimescaleDB и PostGIS.
    • Timescale hypertable хранит временные ряды и автоматически делит их по времени.
    • PostGIS хранит нормализованные точки и геометрии зон, а не renderer-объекты Cesium.
    • Данный выбор покрывает транзакционную конфигурацию, realtime upsert, исторические запросы, SQL-аналитику и географию одним контуром.
  5. Не использовать RabbitMQ Tasker как общую шину Gelios. Если измерения покажут, что прямой writer или число независимых потребителей не справляются, добавить в Gelios-контур NATS JetStream с durable pull consumers. Он даст replay, acknowledgement и контролируемое удержание сообщений.
  6. Engine level-2 Collector — единственная точка provider access; остальные workflow являются потребителями read-модели. Ontology Core остаётся только словарём и контрактами.

Целевой поток

Gelios REST (safe read only)
  -> NDC Agent L2 collection profile + protected credential
  -> authenticated normalized intake
  -> Gelios Gateway: scope -> field policy -> normalizer
  -> gelios-postgres: current state + immutable telemetry history
  -> [при необходимости] NATS JetStream
  -> `fleet.positions.current.v1` read API / realtime subscription
  -> NDC workflow level 2
  -> Map View semantic binding
  -> Cesium renderer adapter

Ни один шаг не получает права отправить команду устройству. Красный command-domain находится вне этого потока; metadata каталога команд сохраняется, но send transport не создаётся.

Модель хранения v0

Слой Назначение Минимальные записи
Контроль граница и повторяемость сбора access_scope, collection_run, ingestion_cursor, endpoint/response metrics
Каталог стабильные сущности и их конфигурация unit, unit_group, tracker_device, sensor/maintenance/custom-field definitions
Current state одна актуальная запись на unit для карты и интерфейса unit_current, position_fix, approved operational status
History неизменяемые события с временем наблюдения и получения telemetry_snapshot, selective sensor_reading, restricted raw payload reference
Spatial геометрии для запросов, не Cesium graphics point/track/geozone with SRID 4326
Analytics роллапы и признаки, не запросы по всему raw hourly/daily aggregates, feature sets, model runs
Audit попытки, ошибки, политика, будущие команды collection audit; separate command audit later

unit_current обновляется idempotently по unitSubjectId. История записывается append-only с ключом дедупликации, включающим provider unit id, observed time и fingerprint сообщения. Все временные таблицы имеют observed_at и received_at: задержка поставщика не должна переписывать фактическое время на карте.

Индексы и жизненный цикл

  • Основной путь истории: (unit_subject_id, observed_at DESC).
  • Пространственный индекс только для нормализованной geography/geometry; рендер-кэши в БД не храним.
  • Сырые params/raw messages — restricted, отдельно от публичной Studio read-model.
  • Политики retention, downsampling и резервного копирования должны быть утверждены до запуска history backfill. Они зависят от фактических msg/s, размера payload, нужной глубины истории, RPO/RTO и стоимости хранения.
  • Для предиктива держать recent/raw слой и отдельные часовые/дневные агрегаты. Timescale continuous aggregates позволяют сохранять длительную агрегированную историю после сокращения raw при корректно согласованных refresh и retention политиках.

Нулевая итерация без лишней инфраструктуры

  1. Зафиксировать owner-approved allowlist и видимые поля.
  2. Сделать только safe-read Engine Collector с ограничением по scope, rate limit, paging и cursor.
  3. В течение согласованного окна измерить: сообщений/сек, размер ответа, lag, дубликаты, задержку записи и нагрузку запросов карты.
  4. На фактах включить Timescale hypertables, PostGIS и retention policy; после этого решить, нужен ли JetStream сразу.
  5. Подать только fleet.positions.current.v1/approved current position в Map View. Историю и raw не отдавать в renderer напрямую.

Что не решено этим ADR

  • окончательное правило connection scope;
  • частота polling/возможность provider push;
  • сроки хранения raw, нормализованной истории и агрегатов;
  • RPO/RTO, репликация и production backup plan;
  • допуск к ручному command gateway. До отдельного решения отправка команд запрещена.

Обоснование и источники

  • Timescale hypertables — временные таблицы PostgreSQL автоматически партиционируются по времени.
  • Timescale self-hosted installation — расширение разворачивается как self-hosted PostgreSQL-контур; production требует backup/PITR и HA-плана.
  • Retention и continuous aggregates — raw и агрегаты требуют согласованных lifecycle-политик.
  • PostGIS — PostgreSQL-расширение для spatial types и GiST R-tree индексов.
  • NATS JetStream consumers — durable consumers дают acknowledgement, повторную доставку и recovery; рекомендуются pull consumers для новых масштабируемых обработчиков.