storeeslstatus¶
Version: v1 Scope: singleton per store ESL (one per physical ESL, keyed as a child of the storeesl path) Owning service: pricer-server
The storeeslstatus DTO records the real-time operational and lifecycle state of an individual ESL as reported by pricer-server (the on-premise gateway that drives the radio/IR network). It is intentionally kept separate from storeesl because its write frequency and write ownership differ fundamentally: pricer-server updates this record continuously as the device communicates, whereas storeesl is a relatively static configuration record owned by link-registry. Separating them keeps the writer-equals-owner invariant clean and lets consumers subscribe to status changes independently of configuration changes (see ADR-006).
In addition to the lifecycle state, this DTO embeds battery information, update timestamps, hardware properties, and (for IR devices) routing diagnostics — all data that PricerServer derives from device communication and that would otherwise need a secondary lookup.
ID pattern¶
t/{tenantid}/s/{storeid}/esls/{barcode}/status
t/{tenantid}/s/{storeid}/esls/{barcode}— the storeesl this status belongs to/status— singleton suffix; there is exactly one status record per storeesl
Schema¶
Top-level fields¶
| Field | Type | Description |
|---|---|---|
id |
string |
Primary ID; follows the pattern above |
state |
State (enum) |
Current operational and lifecycle state; see state machine below |
battery |
BatteryProperties |
Battery level, state, and timestamps |
last_display_update |
Timestamp |
When the display last received and acknowledged an image update |
last_ok_at |
Timestamp |
Last time the device was in OK state with a confirmed up-to-date image |
state_changed_at |
Timestamp |
When the current state was first entered |
first_onboarded_at |
Timestamp |
When the ESL first successfully completed onboarding; not reset on subsequent re-onboardings |
device_properties |
DeviceProperties |
Hardware-level properties as last reported by the device |
ir_properties |
IrProperties |
IR-specific communication status; absent for non-IR devices |
State enum — lifecycle states¶
| Value | Code | Description |
|---|---|---|
STATE_UNSPECIFIED |
0 | Default/unset; should not appear in practice |
ONBOARDING |
1 | Pairing in progress; device is reachable and work is underway. Entry point for all new ESLs |
ONBOARDING_PENDING |
2 | Pairing in progress but device timed out; reachable status unknown. Reached only via timeout from ONBOARDING |
OK |
3 | Fully operational: device is onboarded and its display shows the latest image |
UPDATING |
4 | An image or flash command has been queued and is in progress |
ROAMING |
5 | Device timed out during an update; PricerServer is periodically retrying. Reached only via timeout from UPDATING |
LOST |
6 | Device has been unreachable beyond the auto-reset threshold (30 days). Terminal: link-registry deletes the storeesl upon seeing this, which triggers PS to delete this DTO |
OFFBOARDING |
7 | Offboard command queued; device is reachable and work is underway. May transition to UPDATING if a new image arrives before offboard executes |
OFFBOARDING_PENDING |
8 | Offboard command queued but device timed out. May transition back to ROAMING if a new image/flash cancels the offboard |
OFFBOARDED |
9 | Device successfully offboarded. Terminal: same cleanup flow as LOST |
FAILED |
10 | Device is in a failed state, typically due to a configuration error |
State machine transitions¶
[*] ──────────────────────────────────────────── ONBOARDING
ONBOARDING ──(timeout)──────────────────► ONBOARDING_PENDING
ONBOARDING ──(handshake OK)─────────────► OK
ONBOARDING_PENDING ──(30 days)──────────────────► LOST
ONBOARDING_PENDING ──(new reason)───────────────► OFFBOARDING_PENDING
OK ──(image/flash queued)────────► UPDATING
UPDATING ──(ack received)─────────────► OK
UPDATING ──(timeout)──────────────────► ROAMING
ROAMING ──(device responds)──────────► OK
ROAMING ──(30 days)──────────────────► LOST
ROAMING ──(new reason)───────────────► OFFBOARDING_PENDING
OFFBOARDING_PENDING──(image/flash cancels)───────► ROAMING
OFFBOARDING_PENDING──(30 days)──────────────────► LOST
LOST ──(terminal)─────────────────► [storeesl deleted → DTO deleted]
OFFBOARDED ──(terminal)─────────────────► [storeesl deleted → DTO deleted]
The "30-day threshold" applies uniformly to ONBOARDING_PENDING, ROAMING, and OFFBOARDING_PENDING: if the device has been unreachable for 30 days, the firmware performs an automatic factory reset (the device and the gateway mutually forget each other), and the state transitions to LOST.
BatteryProperties message¶
| Field | Type | Description |
|---|---|---|
battery_state |
BatteryState (enum) |
Current battery state |
battery_state_changed_at |
Timestamp |
When the battery state last changed |
battery_first_low_at |
Timestamp |
Set on the first transition to LOW; cleared when battery recovers |
BatteryState values: BATTERY_STATE_UNSPECIFIED (0), OK (1), LOW (2), UNKNOWN (3 — not yet reported by device)
DeviceProperties message¶
| Field | Type | Description |
|---|---|---|
firmware_version |
string |
Firmware version as reported by the device. Example: "3.4.2" |
hardware_revision |
string |
Hardware revision as reported by the device. Example: "3" |
encryption_state |
EncryptionState (enum) |
Encryption state of the device communication channel |
EncryptionState values: ENCRYPTION_STATE_UNSPECIFIED (0), ENABLED (1), DISABLED (2), ACTIVATING (3), DEACTIVATING (4), ROTATING (5)
IrProperties message¶
Only populated for IR-based devices; absent for RF and other protocols.
| Field | Type | Description |
|---|---|---|
home_transceiver |
string |
Current home transceiver for this device. Example: "A1" |
last_trx_list |
string |
Last known transceiver route; diagnostic use. Example: "A1,A2,B3" |
roam_status |
RoamStatus |
Roaming diagnostics; only meaningful when state = ROAMING |
RoamStatus fields: roam_level (RoamLevel enum), roam_sweep (uint32 — retry sweeps since roaming began), roaming_since (Timestamp)
RoamLevel values: ROAM_LEVEL_UNSPECIFIED (0), FAST (1 — recently missed), NORMAL (2 — extended), SLOW (3 — critical, auto-reset imminent)
Why it is a separate DTO (ADR-006)¶
PricerServer writes the status record at high frequency as devices communicate — potentially multiple times per minute per device in a large store. The storeesl record is a configuration record written by link-registry when a device is assigned to a store, and changes infrequently. Merging the two would cause:
- Write ownership conflicts — two services would write to the same DTO key with incompatible cadences and partial updates.
- Consumer coupling — services like studio-renderer that only care about
esltype_idwould receive floods of irrelevant status updates. - Deletion race — the deletion flow requires link-registry to react to specific terminal states (LOST, OFFBOARDED) in the status record; a single merged record would create a circular dependency between the deleter and the deleted.
Keeping them separate allows each service to own exactly its slice of the data, and allows the deletion flow to be expressed cleanly: PS writes terminal state → link-registry deletes storeesl → that deletion signals PS to delete the status DTO.
Consumed by¶
| Service | Why |
|---|---|
| link-registry | Watches for LOST and OFFBOARDED states to trigger storeesl deletion and lifecycle cleanup |
| (internal dashboards) | Surfaces battery, firmware, and connectivity state for store operations teams |
Deletion cascade¶
pricer-server is the sole writer of storeeslstatus and is also responsible for deleting it — but only as the last step of the lifecycle:
- pricer-server PUTs
storeeslstatuswithstate = LOSTorOFFBOARDED. - link-registry deletes the parent storeesl.
- pricer-server observes the
storeesldeletion and then deletes the correspondingstoreeslstatus.
This ordering keeps the status DTO available to consumers throughout the terminal-cleanup window, and avoids leaving an orphaned status record when the ESL itself is gone.