11 KiB
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 или тестирование. Для них позднее потребуется отдельный, ручной и аудируемый контур.
Решение
- Создать отдельный сервис
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.
- В 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.
- Выделить сервису собственную БД
gelios-postgres, не деля её с Tasker, Authentik, Notification Core или Ontology Core. В будущей multi-tenant форме эта БД обслуживает несколько Gelios connection instances, но все records разделеныtenant_idиconnection_id. - Базовый движок: PostgreSQL 16 с расширениями TimescaleDB и PostGIS.
- Timescale hypertable хранит временные ряды и автоматически делит их по времени.
- PostGIS хранит нормализованные точки и геометрии зон, а не renderer-объекты Cesium.
- Данный выбор покрывает транзакционную конфигурацию, realtime upsert, исторические запросы, SQL-аналитику и географию одним контуром.
- Не использовать RabbitMQ Tasker как общую шину Gelios. Если измерения покажут, что прямой writer или число независимых потребителей не справляются, добавить в Gelios-контур NATS JetStream с durable pull consumers. Он даст replay, acknowledgement и контролируемое удержание сообщений.
- 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 политиках.
Нулевая итерация без лишней инфраструктуры
- Зафиксировать owner-approved allowlist и видимые поля.
- Сделать только safe-read Engine Collector с ограничением по scope, rate limit, paging и cursor.
- В течение согласованного окна измерить: сообщений/сек, размер ответа, lag, дубликаты, задержку записи и нагрузку запросов карты.
- На фактах включить Timescale hypertables, PostGIS и retention policy; после этого решить, нужен ли JetStream сразу.
- Подать только
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 для новых масштабируемых обработчиков.