Universal Tracking Chapter 1415

Chapter 14

3 min read Section 15 of 42

Chapter 14 - Latest State, Presence, and Movement

The live dashboard should not search billions of history rows to find one marker per subject. Maintain a compact latest_locations projection and update it conditionally.

Latest-location table

CREATE TABLE latest_locations (
    organization_id uuid NOT NULL,
    subject_id uuid NOT NULL,
    device_id uuid NOT NULL,
    session_id uuid,
    location_id uuid NOT NULL,
    recorded_at timestamptz NOT NULL,
    received_at timestamptz NOT NULL,
    position geography(Point, 4326) NOT NULL,
    accuracy_m double precision,
    speed_mps double precision,
    heading_deg double precision,
    battery_percent smallint,
    activity_type text,
    movement_status text NOT NULL,
    connection_status text NOT NULL,
    quality_flags text[] NOT NULL DEFAULT '{}',
    version bigint NOT NULL,
    updated_at timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (organization_id, subject_id)
);

Update only when the new observation wins a deterministic comparison:

INSERT INTO latest_locations (...)
VALUES (...)
ON CONFLICT (organization_id, subject_id)
DO UPDATE SET
    device_id = EXCLUDED.device_id,
    location_id = EXCLUDED.location_id,
    recorded_at = EXCLUDED.recorded_at,
    position = EXCLUDED.position,
    version = latest_locations.version + 1,
    updated_at = now()
WHERE (EXCLUDED.recorded_at, EXCLUDED.location_id)
    > (latest_locations.recorded_at,
       latest_locations.location_id);

The tie-breaker ensures deterministic behavior when timestamps are equal.

Current truth versus last observation

"Latest" does not mean "currently online." Store or calculate separate dimensions:

  • last observed location;
  • age of that observation;
  • last server contact;
  • active session status;
  • connection status;
  • movement status;
  • data quality.

A marker can be last seen moving but currently offline. The UI should not display it as live movement.

Presence

For phones using batched HTTP, presence is inferred from recent successful contact. For connected TCP trackers or WebSockets, the gateway may know connection state, but network connection is not proof of current GPS quality.

Define thresholds by device and use case:

online: last contact <= expected interval * tolerance
stale:  older than online threshold but within display window
offline: older than offline threshold
unknown: never contacted or policy cannot evaluate

The scheduler or worker transitions devices to offline and emits an event. The calculation must be idempotent because multiple workers may evaluate the same row.

Movement state

Reported speed alone is noisy. A movement detector can use hysteresis:

  • moving begins after speed or displacement exceeds a start threshold for a minimum duration;
  • stopped begins after speed remains below a lower threshold for a dwell period;
  • low-accuracy points do not cause rapid toggling;
  • activity type influences thresholds.

Store the algorithm version and transition time. A simple first implementation can be deterministic and explainable.

type MovementConfig struct {
    StartSpeedMPS float64
    StopSpeedMPS  float64
    StartDuration time.Duration
    StopDuration  time.Duration
    MaxAccuracyM  float64
}

Distance accumulation

Do not blindly sum every consecutive point. GPS jitter while stationary can create significant false distance. Consider:

  • minimum accuracy;
  • minimum displacement relative to accuracy radius;
  • maximum plausible speed;
  • activity-specific sampling;
  • gap boundaries;
  • map matching only when justified.

Keep raw points and calculate distance as a versioned derived metric. The latest state may contain a session distance estimate for immediate UI, later reconciled by a worker.

Snapshot query

The dashboard initial snapshot can retrieve authorized subjects and latest state in one bounded query. It should return freshness fields and policy-reduced coordinates when necessary.

{
  "subject_id": "0195...",
  "recorded_at": "2026-10-10T10:11:12Z",
  "received_at": "2026-10-10T10:11:13Z",
  "freshness_seconds": 3,
  "movement_status": "moving",
  "connection_status": "online",
  "position": {
    "latitude": 44.8123,
    "longitude": 20.4611
  },
  "quality": ["valid"],
  "version": 883
}

The version supports snapshot-plus-delta recovery.

Rebuilding projections

latest_locations is a projection, not the only source of truth. Provide a command that rebuilds it from accepted history and registry state. Rebuilds can target one subject, organization, partition interval, or all data.

A rebuild should write to a shadow table or use careful upserts so the live system remains available. Compare counts and sampled rows before switching.

Chapter checklist

A live-state projection should:

  • be separate from raw history;
  • update only for deterministically newer observations;
  • separate freshness, connection, movement, and quality;
  • use hysteresis for movement;
  • avoid summing GPS jitter as distance;
  • return a version for realtime recovery;
  • be rebuildable from durable facts.

Aleksandar Popovic · Copyright © 2026 Aleksandar Popovic · All rights reserved. Licensing and attribution