diff --git a/wiki/concepts/position-record.md b/wiki/concepts/position-record.md index 4a26a70..d672bd5 100644 --- a/wiki/concepts/position-record.md +++ b/wiki/concepts/position-record.md @@ -2,7 +2,7 @@ title: Position Record type: concept created: 2026-04-30 -updated: 2026-05-03 +updated: 2026-05-04 sources: [gps-tracking-architecture, teltonika-ingestion-architecture, teltonika-data-sending-protocols] tags: [data-model, boundary-contract] --- @@ -94,4 +94,17 @@ Why store the IMEI rather than the uuid: - [[tcp-ingestion]] writes positions without any business-plane round-trip ([[plane-separation]]), so the only identifier it has at write time is the IMEI. - Devices can move between `entry_devices` rows across events; positions are an immutable per-IMEI record. -If/when a Phase 2 redesign moves to uuid-keyed positions, this is the section to revise — and `processor` `src/live/snapshot.ts` + `src/live/device-event-map.ts` both lose the translation hop. +If/when a Phase 2 redesign moves to uuid-keyed positions, this is the section to revise — and `processor` `src/live/snapshot.ts` + `src/live/device-event-map.ts` both lose the translation hop, alongside `react-spa`'s `src/data/devices.ts` (`useDevicesByImei` becomes `useDevicesById`). + +### Consumer-side join (SPA) + +The same translation hop applies in [[react-spa]] when the live channel's `position.deviceId` (IMEI) needs to resolve to a Device row's `model` / `serial_number` / vehicle / crew metadata. Implementation: + +```ts +// src/data/devices.ts +export function useDevicesByImei() { + // readItems('devices') -> Map +} +``` + +Used by ``, ``, and ``. Briefly drifted to keying by `devices.id` (uuid) between Phase 2 and Phase 3.2 — surfaced as device labels rendering 8-char id prefixes ("35042406") instead of model + IMEI tail ("FMB920 #3619"). Re-aligned with this contract on 2026-05-04 before Task 3.4's per-device detail panel started consuming the join. diff --git a/wiki/synthesis/processor-ws-contract.md b/wiki/synthesis/processor-ws-contract.md index b605863..cf0bbb6 100644 --- a/wiki/synthesis/processor-ws-contract.md +++ b/wiki/synthesis/processor-ws-contract.md @@ -2,7 +2,7 @@ title: Processor WebSocket contract type: synthesis created: 2026-05-02 -updated: 2026-05-03 +updated: 2026-05-04 sources: [gps-tracking-architecture, traccar-maps-architecture] tags: [websocket, protocol, contract, telemetry-plane, decision] --- @@ -161,7 +161,7 @@ Field semantics: |---|---|---|---| | `type` | `"position"` | yes | Discriminator. | | `topic` | string | yes | Echoes the subscription. Allows multiplexing on one connection. | -| `deviceId` | string | yes | **Phase 1: the IMEI** (vendor identifier, e.g. `"350424064163619"`) — same value as `Position.device_id` per [[position-record]]. Originally specified as `devices.id` (uuid) here; the implementation diverged because [[tcp-ingestion]] only knows the IMEI at write time and the live channel ships the same identifier through end-to-end. SPA joins `deviceId` → `devices.imei` to look up entry/vehicle/crew via TanStack Query against [[directus]]. Closing this divergence (uuid on the wire) is a Phase 2 question; not blocking dogfood. | +| `deviceId` | string | yes | **Phase 1: the IMEI** (vendor identifier, e.g. `"350424064163619"`) — same value as `Position.device_id` per [[position-record]]. Originally specified as `devices.id` (uuid) here; the implementation diverged because [[tcp-ingestion]] only knows the IMEI at write time and the live channel ships the same identifier through end-to-end. SPA joins `deviceId` → `devices.imei` to look up entry/vehicle/crew via TanStack Query against [[directus]]. Consumer-side implementation lives in [[react-spa]] at `src/data/devices.ts` (`useDevicesByImei()` — builds `Map`); used by ``, ``, and `` for label / metadata lookup. Closing this divergence (uuid on the wire) is a Phase 2 question; not blocking dogfood. | | `lat` / `lon` | number (degrees, WGS84) | yes | GPS coordinates. **Coordinate order in JSON is `lat`/`lon`** (not `[lon,lat]` GeoJSON ordering — that conversion happens in the SPA). | | `ts` | number (epoch milliseconds, UTC) | yes | Authoritative timestamp from the device's GPS fix. **Always use this, never `Date.now()` on the client.** | | `speed` | number (km/h) | optional | Omitted if device reports speed=0 with invalid GPS fix (per [[teltonika]] convention). |