feat(provider): catalogue complete Gelios data surface

This commit is contained in:
Codex
2026-07-22 19:15:12 +03:00
parent fdda153595
commit 92070f21e8
7 changed files with 597 additions and 1 deletions
@@ -0,0 +1,28 @@
# Gelios capability catalog
`capability-catalog-v1.mjs` is the complete classified inventory for the
current `UnitModelOutput` surface and the adjacent object APIs that NODE.DC may
consume. Its authority is the official Gelios OpenAPI, checked on 2026-07-22.
The catalog is deliberately separate from an active L2 package. `implemented`
means a capability already has a governed collection and Data Product path;
`catalogued` means NODE.DC understands the surface but has not activated it;
`disabled` is mandatory for control and destructive operations.
The catalog accounts for every top-level Unit field and all twelve official
`/api/v1/units` include flags. It also records the separate read surfaces for
sensor metadata, latest sensor values, maintenance, filling, schedules and
command audit. Raw messages, decrypt material and command execution never
enter an operational UI projection.
Cadence is a product boundary:
- `hot`: current position, state, counters and classified latest readings;
- `warm`: slowly changing operational records such as maintenance plans;
- `cold`: unit, equipment and calculation profiles;
- `on_demand`: restricted or historical details that need explicit policy;
- `never`: secret, raw or command material outside the telemetry plane.
Provider packages may implement catalogued families incrementally, but they
must not move fields between classifications or cadences implicitly. A new
Data Product and its Foundry subject aspect must be explicit and versioned.
@@ -0,0 +1,332 @@
import { PROVIDER_CAPABILITY_CATALOG_SCHEMA_VERSION } from "../../src/provider-capability-catalog.mjs";
const unitCapabilityId = "gelios.units.current.read";
export const geliosCapabilityCatalogV1 = deepFreeze({
schemaVersion: PROVIDER_CAPABILITY_CATALOG_SCHEMA_VERSION,
providerId: "gelios",
version: "1.0.0",
authority: {
kind: "official-openapi",
url: "https://api.geliospro.com/openapi.json",
checkedAt: "2026-07-22T15:30:00Z",
},
coverage: {
schemaId: "UnitModelOutput",
sourceRoots: [
"activatedAt", "availableToUsers", "blockTime", "commands", "counters", "createdAt",
"creator", "currentUserAccess", "customFields", "driver", "extraInfo", "fuelParams",
"hwDecryptKey", "hwManufacturer", "hwType", "id", "imei", "imeiIsVisible", "isBlock",
"isFree", "lastMsg", "lastSensorsVal", "maintenancePlan", "name", "phone", "phone2",
"phone2IsVisible", "phoneIsVisible", "preSetCommandGroup", "removed", "removedAt", "sensors",
"stationaryLat", "stationaryLon", "storageInfo", "tripParams", "unblockTime", "unitType",
],
},
queryFlags: [
flag("inclextra", ["gelios.unit.asset_profile", "gelios.unit.asset_identifiers", "gelios.unit.extra_internal"]),
flag("incltrip", ["gelios.unit.trip_settings"]),
flag("inclfuel", ["gelios.unit.fuel_settings"]),
flag("inclcntrs", ["gelios.unit.counters"]),
flag("inclcstmflds", ["gelios.unit.custom_fields"]),
flag("inclsnsrs", ["gelios.unit.sensor_definitions", "gelios.unit.sensor_conversion"]),
flag("inclcmmnds", ["gelios.unit.command_catalog"]),
flag("incldrvrs", ["gelios.unit.driver"]),
flag("inclstinf", ["gelios.unit.storage"]),
flag("inclusersav", ["gelios.unit.access_metadata"]),
flag("incllsv", ["gelios.unit.latest_sensor_values"]),
flag("inclplan", ["gelios.unit.maintenance_plan"]),
],
dataFamilies: [
family({
id: "gelios.unit.identity",
title: "Stable unit identity and type",
sourcePaths: ["id", "name", "unitType.id", "unitType.name", "unitType.type"],
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.unit"], uiTab: "overview",
}),
family({
id: "gelios.unit.lifecycle",
title: "Activation, blocking and removal lifecycle",
sourcePaths: ["activatedAt", "blockTime", "createdAt", "isBlock", "isFree", "removed", "removedAt", "unblockTime"],
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.unit"], uiTab: "overview",
}),
family({
id: "gelios.unit.access_metadata",
title: "Provider ownership and access metadata",
sourcePaths: ["availableToUsers[]", "creator.id", "creator.login", "currentUserAccess"],
cadence: "cold", classification: "internal", disposition: "catalogue", status: "catalogued",
ontologyEntities: ["gelios.unit"],
}),
family({
id: "gelios.unit.equipment",
title: "Tracker hardware classification",
sourcePaths: ["hwManufacturer.id", "hwManufacturer.name", "hwType.id", "hwType.name"],
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.tracker_device"], uiTab: "equipment",
}),
family({
id: "gelios.unit.device_identifiers",
title: "Restricted device and phone identifiers",
sourcePaths: ["imei", "imeiIsVisible", "phone", "phone2", "phone2IsVisible", "phoneIsVisible"],
cadence: "on_demand", classification: "restricted", disposition: "profile", status: "catalogued",
ontologyEntities: ["gelios.tracker_device"], uiTab: "equipment",
}),
family({
id: "gelios.unit.cryptographic_material",
title: "Provider cryptographic material",
sourcePaths: ["hwDecryptKey"],
cadence: "never", classification: "secret", disposition: "forbid", status: "forbidden",
ontologyEntities: ["gelios.tracker_device"],
}),
family({
id: "gelios.unit.stationary_location",
title: "Restricted configured stationary location",
sourcePaths: ["stationaryLat", "stationaryLon"],
cadence: "on_demand", classification: "restricted", disposition: "profile", status: "catalogued",
ontologyEntities: ["gelios.unit"], uiTab: "position",
}),
family({
id: "gelios.unit.position_current",
title: "Current normalized position and movement sample",
sourcePaths: [
"lastMsg.course", "lastMsg.height", "lastMsg.lat", "lastMsg.lon", "lastMsg.receiveTime",
"lastMsg.sats", "lastMsg.speed", "lastMsg.time",
],
cadence: "hot", classification: "operational", disposition: "publish", status: "implemented",
ontologyEntities: ["gelios.telemetry_snapshot", "map.moving_object"], uiTab: "position",
dataProductIds: ["fleet.positions.current.v5"],
}),
family({
id: "gelios.unit.raw_message_parameters",
title: "Unclassified raw tracker message parameters",
sourcePaths: ["lastMsg.params"],
cadence: "never", classification: "unclassified", disposition: "forbid", status: "forbidden",
ontologyEntities: ["gelios.telemetry_snapshot"],
}),
family({
id: "gelios.unit.counters",
title: "Operational mileage and engine-hour counters",
sourcePaths: ["counters.engineHours.value", "counters.mileage.value"],
cadence: "hot", classification: "operational", disposition: "publish", status: "implemented",
ontologyEntities: ["gelios.telemetry_snapshot"], uiTab: "counters",
dataProductIds: ["fleet.positions.current.v5"],
}),
family({
id: "gelios.unit.latest_sensor_values",
title: "Latest values for explicitly classified sensors",
sourcePaths: ["lastSensorsVal[].tm", "lastSensorsVal[].val"],
cadence: "hot", classification: "unclassified", disposition: "profile", status: "implemented",
ontologyEntities: ["gelios.sensor_reading"], uiTab: "telemetry",
}),
family({
id: "gelios.unit.sensor_definitions",
title: "Sensor identity, units, visibility and limits",
sourcePaths: [
"sensors[].displayFuelTankVolume", "sensors[].fuelConsumptionRate", "sensors[].fuelTankVolume",
"sensors[].id", "sensors[].isVisible", "sensors[].maxValidParamValue", "sensors[].measure",
"sensors[].minValidParamValue", "sensors[].msgParam", "sensors[].name", "sensors[].type.id", "sensors[].type.name",
],
cadence: "cold", classification: "unclassified", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.sensor_definition"], uiTab: "equipment",
}),
family({
id: "gelios.unit.sensor_conversion",
title: "Raw sensor conversion tables",
sourcePaths: ["sensors[].conversionTable"],
cadence: "cold", classification: "internal", disposition: "catalogue", status: "catalogued",
ontologyEntities: ["gelios.sensor_definition"],
}),
family({
id: "gelios.unit.asset_profile",
title: "Vehicle and asset descriptive profile",
sourcePaths: [
"extraInfo.brand", "extraInfo.color", "extraInfo.engineCubicCapacity", "extraInfo.enginePower",
"extraInfo.fuelType", "extraInfo.iconLink", "extraInfo.model", "extraInfo.year",
],
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.unit"], uiTab: "equipment",
}),
family({
id: "gelios.unit.asset_identifiers",
title: "Restricted VIN and number plate",
sourcePaths: ["extraInfo.numberPlate", "extraInfo.vin"],
cadence: "on_demand", classification: "restricted", disposition: "profile", status: "catalogued",
ontologyEntities: ["gelios.unit"], uiTab: "equipment",
}),
family({
id: "gelios.unit.extra_internal",
title: "Provider autocomplete metadata",
sourcePaths: ["extraInfo.autocompleteParams"],
cadence: "cold", classification: "internal", disposition: "catalogue", status: "catalogued",
ontologyEntities: ["gelios.unit"],
}),
family({
id: "gelios.unit.trip_settings",
title: "Trip detection and movement policy",
sourcePaths: prefixed("tripParams", [
"correctedEngineHoursFactor", "correctedMileageFactor", "filterBySatellitesCountIsOn",
"filterBySatellitesCountValue", "filterEmissions", "limitAcceleration", "lostConnectionIsOn",
"lostConnectionTimeValue", "maximumPermissibleSpeed", "maximumValidHeight", "maximumValidSpeed",
"mileageByIgnition", "minimumMovementSpeed", "minimumMovementTime", "minimumParkingTime",
"minimumTimeStop", "minimumTripDistance", "minimumValidHeight", "speedMeasurementItemsId",
"speedParam", "tripDetectionType.id", "tripDetectionType.name", "useOdometer",
]),
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.unit"], uiTab: "settings",
}),
family({
id: "gelios.unit.fuel_settings",
title: "Fuel calculation and theft/filling policy",
sourcePaths: prefixed("fuelParams", [
"cityConsumptionSummer", "cityConsumptionWinter", "fillingByIgnOff", "fillingInterval",
"fillingSplitTimeout", "fillingTheftOnParkingOnly", "filterZeroFls", "idleConsumptionSummer",
"idleConsumptionWinter", "ignoreMsgsTimeAfterStart", "includeTheftsInConsumption",
"maximumConsumptionForPeriod", "minimumFilling", "minimumFuelTheft", "outOfTheCityConsumptionSummer",
"outOfTheCityConsumptionWinter", "secondsToIgnoreAfterMovementStart", "theftByIgnOff",
"theftSplitTimeout", "useAverageFlsValue", "useFilterIsOn", "useFilterValue",
"useNewFuelCalcAlgorithm", "useSeparateFls", "winterEnd", "winterStart",
]),
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.fuel_profile"], uiTab: "settings",
}),
family({
id: "gelios.unit.maintenance_plan",
title: "Maintenance thresholds and progress",
sourcePaths: prefixed("maintenancePlan[]", [
"created_at", "description", "id", "interval_day", "interval_mileage", "interval_motohour",
"is_day", "is_mileage", "is_motohour", "last_day", "last_mileage", "last_motohour",
"name", "repeat_count", "total_count", "unit_id", "updated_at",
]),
cadence: "warm", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.maintenance_plan"], uiTab: "maintenance",
}),
family({
id: "gelios.unit.custom_fields",
title: "Tenant-defined fields requiring explicit classification",
sourcePaths: ["customFields[].id", "customFields[].isVisible", "customFields[].name", "customFields[].value"],
cadence: "cold", classification: "unclassified", disposition: "profile", status: "catalogued",
ontologyEntities: ["gelios.custom_field"], uiTab: "diagnostics",
}),
family({
id: "gelios.unit.driver",
title: "Driver personal data",
sourcePaths: ["driver.name", "driver.phone"],
cadence: "on_demand", classification: "restricted", disposition: "profile", status: "catalogued",
ontologyEntities: ["gelios.unit"],
}),
family({
id: "gelios.unit.storage",
title: "Provider storage policy",
sourcePaths: [
"storageInfo.storagePeriod.description", "storageInfo.storagePeriod.id", "storageInfo.storagePeriod.name",
"storageInfo.storagePeriodLastUpdUtc",
],
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.unit"], uiTab: "equipment",
}),
family({
id: "gelios.unit.command_catalog",
title: "Command templates and preset groups",
sourcePaths: [
"commands[].id", "commands[].name", "commands[].text", "commands[].type",
"preSetCommandGroup.id", "preSetCommandGroup.name",
],
cadence: "never", classification: "control", disposition: "catalogue", status: "catalogued",
ontologyEntities: ["integration.command_capability"],
}),
family({
id: "gelios.unit.maintenance_events",
title: "Maintenance event history",
sourcePaths: ["maintenanceEvents[].id", "maintenanceEvents[].date", "maintenanceEvents[].description"],
cadence: "on_demand", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.maintenance_plan"], uiTab: "maintenance",
}),
family({
id: "gelios.unit.filling_events",
title: "Fuel filling event history",
sourcePaths: ["fillingEvents[].id", "fillingEvents[].date", "fillingEvents[].volume", "fillingEvents[].price"],
cadence: "on_demand", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.fuel_profile"], uiTab: "maintenance",
}),
family({
id: "gelios.unit.work_schedule",
title: "Shifts and work-time rules",
sourcePaths: ["shifts[].id", "shifts[].name", "workTime[].id", "workTime[].startDay", "workTime[].endDay"],
cadence: "cold", classification: "operational", disposition: "profile", status: "planned",
ontologyEntities: ["gelios.unit"], uiTab: "settings",
}),
family({
id: "gelios.unit.command_history",
title: "Command execution audit history",
sourcePaths: ["commandHistory[].id", "commandHistory[].status", "commandHistory[].timeCmd", "commandHistory[].timeSend"],
cadence: "on_demand", classification: "control", disposition: "catalogue", status: "catalogued",
ontologyEntities: ["integration.command_capability"],
}),
family({
id: "gelios.unit.raw_messages",
title: "Pure and raw tracker messages",
sourcePaths: ["rawMessages[].payload"],
cadence: "never", classification: "restricted", disposition: "forbid", status: "forbidden",
ontologyEntities: ["gelios.telemetry_snapshot"],
}),
family({
id: "gelios.geozones.current",
title: "Provider geozone catalogue",
sourcePaths: ["geozones[].geometry", "geozones[].id", "geozones[].name"],
cadence: "cold", classification: "operational", disposition: "publish", status: "implemented",
ontologyEntities: ["map.zone"], dataProductIds: ["map.gelios-geofences.current.v1"],
}),
],
capabilities: [
capability("gelios.units.current.read", "GET", "/api/v1/units", "read", "implemented", [
"gelios.unit.identity", "gelios.unit.lifecycle", "gelios.unit.access_metadata", "gelios.unit.equipment",
"gelios.unit.device_identifiers", "gelios.unit.cryptographic_material", "gelios.unit.stationary_location",
"gelios.unit.position_current", "gelios.unit.raw_message_parameters", "gelios.unit.counters",
"gelios.unit.latest_sensor_values", "gelios.unit.sensor_definitions", "gelios.unit.sensor_conversion",
"gelios.unit.asset_profile", "gelios.unit.asset_identifiers", "gelios.unit.extra_internal",
"gelios.unit.trip_settings", "gelios.unit.fuel_settings", "gelios.unit.maintenance_plan",
"gelios.unit.custom_fields", "gelios.unit.driver", "gelios.unit.storage", "gelios.unit.command_catalog",
]),
capability("gelios.unit.current.read", "GET", "/api/v1/units/{unit_id}", "read", "catalogued", ["gelios.unit.identity"]),
capability("gelios.units.last_messages.read", "POST", "/api/v1/units/last-msgs/full", "read", "catalogued", ["gelios.unit.position_current"]),
capability("gelios.unit.sensors.read", "GET", "/api/v1/units/{unit_id}/sensors", "metadata", "catalogued", ["gelios.unit.sensor_definitions", "gelios.unit.sensor_conversion"]),
capability("gelios.unit.sensor_values.read", "GET", "/api/v1/units/{unit_id}/sensors/values/last", "read", "catalogued", ["gelios.unit.latest_sensor_values"]),
capability("gelios.unit.maintenance_plan.read", "GET", "/api/v1/units/{unit_id}/maintenance/plan", "read", "catalogued", ["gelios.unit.maintenance_plan"]),
capability("gelios.unit.maintenance_events.read", "GET", "/api/v1/units/{unit_id}/maintenance/event", "read", "catalogued", ["gelios.unit.maintenance_events"]),
capability("gelios.unit.filling_events.read", "GET", "/api/v1/units/{unit_id}/filling/event", "read", "catalogued", ["gelios.unit.filling_events"]),
capability("gelios.unit.shifts.read", "GET", "/api/v1/units/{unit_id}/shifts", "read", "catalogued", ["gelios.unit.work_schedule"]),
capability("gelios.unit.work_time.read", "GET", "/api/v1/units/{unit_id}/work-time", "read", "catalogued", ["gelios.unit.work_schedule"]),
capability("gelios.unit.command_history.read", "GET", "/api/v1/units/{unit_id}/commands/history", "metadata", "catalogued", ["gelios.unit.command_history"]),
capability("gelios.unit.commands.read", "GET", "/api/v1/units/{unit_id}/commands", "metadata", "catalogued", ["gelios.unit.command_catalog"]),
capability("gelios.unit.last_message_params.read", "GET", "/api/v1/units/{unit_id}/last-msg-params", "metadata", "catalogued", ["gelios.unit.raw_message_parameters"]),
capability("gelios.unit.raw_message.read", "GET", "/api/v1/units/{unit_id}/last-msg/raw", "read", "disabled", ["gelios.unit.raw_messages"]),
capability("gelios.geozones.current.read", "GET", "/api/v1/geozones", "read", "implemented", ["gelios.geozones.current"]),
capability("gelios.unit.command.send", "POST", "/api/v1/units/{unit_id}/commands/send", "control", "disabled", ["gelios.unit.command_catalog"]),
capability("gelios.unit.update", "PATCH", "/api/v1/units/{unit_id}", "write", "disabled", ["gelios.unit.identity"]),
capability("gelios.unit.delete", "DELETE", "/api/v1/units/{unit_id}", "destructive", "disabled", ["gelios.unit.lifecycle"]),
],
});
function flag(id, familyIds) {
return { id, capabilityId: unitCapabilityId, familyIds };
}
function family({ dataProductIds = [], ...value }) {
return { ...value, dataProductIds };
}
function capability(id, method, path, classification, status, familyIds) {
return { id, method, path, classification, status, familyIds };
}
function prefixed(prefix, fields) {
return fields.map((field) => `${prefix}.${field}`);
}
function deepFreeze(input) {
if (!input || typeof input !== "object" || Object.isFrozen(input)) return input;
Object.freeze(input);
for (const child of Object.values(input)) deepFreeze(child);
return input;
}
@@ -0,0 +1,2 @@
export { geliosCapabilityCatalogV1 } from "./capability-catalog-v1.mjs";
export * from "./v7/index.mjs";