Skip to content

Telemetry

Sergio Hernandez edited this page Jul 24, 2026 · 1 revision

Telemetry

The Telemetry service owns TrackHub's high-volume, append-heavy data: position fixes, position history, operator sync runs and operator health checks. It stores and serves this data; it never talks to GPS providers — that is the Router's job.

Related pages: Database · Router · Reporting


Schema boundary

Telemetry serves the telemetry schema but does not migrate it. The tables are created by the Manager migrations, which is why DB_CONNECTION_TELEMETRY must point at the same TrackHub database.

Access Tables
Read/write (telemetry) transporter_position, transporter_position_history, operator_sync_runs, operator_health_checks
Read-only (app) users, groups, user_group, transporters, transporter_group, transporter_device_assignments, devices, operators, accounts, account_features

The read-only app projections exist so the service can enforce account scoping and group visibility without a network hop per request. In production, connect with a role that has read/write on telemetry and read-only on those app tables.


Entities

Entity Purpose
TransporterPosition The latest-position projection — the freshest fix per transporter. This is what backs the live map.
TransporterPositionHistory The append-only track store, deduplicated by an idempotency key. Used for replay and reporting.
OperatorSyncRun One row per device or position sync attempt, with device and position counts, result and error.
OperatorHealthCheck Operator connectivity and health probe results.

Operator health is derived, not stored as a rollup. The operator row carries no health columns. Health status and sync summaries are computed at read time from these two tables — which is why every device-sync attempt records an observation, so accounts that only sync manually still get a meaningful Health status.


GraphQL operations

Queries

Operation Purpose
transporterPositionByOperator Latest positions for an operator, scoped to the caller's visibility
transporterPositionsByOperators Batched variant — the live-map hot path
positionHistory Stored position history, filtered by account / transporter / device
positionHistoryRange Replay read over a time range (ordered, point-capped), gated by gps.positionHistory
operatorSyncRuns Recorded sync-run telemetry
operatorHealth Current operator health snapshot, derived from the health-check and sync-run tables
operatorHealthHistory Recent health-check records for an operator
operatorHealthSummary Aggregated uptime, latency and failure counts over a lookback window
platformSyncActivity Platform-wide latest sync/health timestamps for the status page

Mutations

Operation Purpose
bulkTransporterPosition Upsert the latest-position projection (freshest fix per transporter)
appendPositionHistory / appendPositionHistoryBatch Append history rows — idempotent, gated by gps.positionHistory
persistResolvedAddress Write a reverse-geocoded address back onto stored position rows
recordOperatorSyncRun Record a sync attempt
recordOperatorHealth Record an operator health check

Visibility and gating

Visibility mirrors the rest of the platform: Administrator and Manager roles read account-wide; other users are scoped to their group membership, resolved through the transporter–group / user–group chain. Service clients read on behalf of already-authorized users.

Feature gating:

Surface Gate
Latest-position writes, health writes Core — authorization only
History writes and replay reads gps.positionHistory

Retention

PositionRetentionPurgeService is a hosted service inside the Telemetry web host. It deletes expired history per account, honouring each account's retention days (derived from the gps.positionHistory feature configuration).

It is an on-work-only recorder: an old BackgroundJobRun timestamp is the healthy steady state, not a stuck job.


Platform sync activity

PlatformSyncActivityReader supports the status page's SyncWorker tile. It is one of two deliberately unscoped readers on the platform — a documented platform-wide read gated by [Authorize(Administrative, Read)]. It returns timestamps and counts only, never an account id.

SyncWorker liveness is derived from data recency, because the worker is a plain Generic Host with no HTTP listener:

Signal State
Activity within 5 minutes Up
No account has gps.integration enabled Unknown — "nothing to sync" is not a failure
Otherwise Down

Telemetry can only see account-level enablement, never per-operator — that lives in Manager, and adding an inter-service call for it was deliberately rejected.


Gotchas

  • attributes is a PostgreSQL json column. json has no equality operator, so Distinct(), GroupBy() or set operations over an entity or projection including it fail at runtime with 42883. De-duplicate with EXISTS or key-based predicates. EF InMemory does not catch this — only real PostgreSQL does.
  • The extra attribute field is additive and schemaless. New provider signals flow through it with no migration and no cross-service schema change. See Router.
  • Telemetry has no migrations of its own. Do not add any — the schema belongs to Manager.

Clone this wiki locally