Skip to content

Flow: ESL Hardware Lifecycle

Trigger: A link.v2 DTO is created for a barcode (onboarding begins), or the physical ESL communicates / stops communicating with the gateway Key services: link-registry, pricer-server Key DTOs: storeesl, storeeslstatus, link.v2, eslimage

This flow describes the complete operational lifecycle of an Electronic Shelf Label from the moment it is first associated with an item through its normal operation, temporary disconnection, intentional removal, and final deletion from the platform. The lifecycle is driven by two separate concerns that are deliberately kept in separate DTOs (per ADR-006):

  • storeesl — the logical identity and rendering anchor. Owned and written by link-registry. Exists while the ESL is part of the store's active label population.
  • storeeslstatus — the physical communication state. Owned and exclusively written by pricer-server. Reflects what pricer-server observes from the RF/IR network in real time.

This split keeps the owner-equals-writer invariant clean. Rendering services depend on storeesl without coupling to hardware state; pricer-server can update communication state at high frequency without touching the link/rendering data model. The deletion of an ESL is a multi-step coordination between the two writers.

Roles in the lifecycle

Service Writes Role
link-registry storeesl, link.v2 Creates storeesl when the first link.v2 is written for a barcode. Watches storeeslstatus and deletes storeesl when it sees a terminal state (LOST / OFFBOARDED).
pricer-server storeeslstatus Sole writer of storeeslstatus. Drives all state transitions from RF/IR feedback held in its internal per-ESL state DB. Deletes storeeslstatus only after the parent storeesl is gone.
pricer-server (consumer) eslimage, storeesl Subscribes to eslimage directly via CQS to transmit images, and to storeesl to register/unregister devices and to detect the deletion that triggers the storeeslstatus cleanup.

State machine

Authoritative state list and transitions are in esl-status.md (in-repo handover) and reflected on storeeslstatus.

stateDiagram-v2
    [*] --> ONBOARDING : link.v2 created for barcode\n(link-registry writes storeesl;\npricer-server starts pairing)

    ONBOARDING --> OK : Handshake OK\n(pricer-server writes status OK)
    ONBOARDING --> ONBOARDING_PENDING : Pairing timeout

    OK --> UPDATING : Image/flash queued
    UPDATING --> OK : ACK received
    UPDATING --> ROAMING : Delivery timeout

    ROAMING --> OK : Device responds
    ROAMING --> LOST : 30 days unreachable\n(firmware auto-reset)

    ONBOARDING_PENDING --> LOST : 30 days
    ONBOARDING_PENDING --> OFFBOARDING_PENDING : New reason

    OK --> OFFBOARDING : Operator offboard\n(reachable)
    OFFBOARDING --> OFFBOARDED : ACK
    OFFBOARDING --> OFFBOARDING_PENDING : Timeout
    OFFBOARDING_PENDING --> ROAMING : Image/flash cancels offboard
    OFFBOARDING_PENDING --> LOST : 30 days

    LOST --> [*] : storeesl deleted →\nstoreeslstatus deleted
    OFFBOARDED --> [*] : storeesl deleted →\nstoreeslstatus deleted

Walkthrough: onboarding → operation → terminal cleanup

1. Onboarding

A first link.v2 is created for a barcode (see Item–ESL Linking). link-registry writes the storeesl DTO. pricer-server's storeesl CQS subscription fires; it registers the device in its internal DB and begins pairing over RF/IR. pricer-server writes storeeslstatus with state ONBOARDING.

  • Handshake OKstoreeslstatus.state = OK.
  • Timeoutstoreeslstatus.state = ONBOARDING_PENDING; retries continue.

2. Steady state and image delivery

When eslimage is written (by eslimage-merger), pricer-server consumes it via CQS, reads the bytes from LFS, applies rotation, and transmits.

  • On queue/transmit: pricer-server writes storeeslstatus.state = UPDATING.
  • On ACK: back to OK. pricer-server also updates non-state telemetry on the same DTO (battery, firmware, IR diagnostics).
  • On delivery timeout: ROAMING. The previously delivered image remains on the e-ink display (non-volatile).

3. Terminal cleanup cascade

When the ESL is permanently gone — either operator-initiated (OFFBOARDED) or firmware-initiated factory reset after 30 days unreachable (LOST) — the cleanup is a three-step cascade across the two writers:

  1. pricer-server writes terminal status. storeeslstatus.state = LOST or OFFBOARDED. The internal state DB records the terminal event.
  2. link-registry deletes storeesl. Its storeeslstatus CQS subscription fires; it sees the terminal state and deletes the corresponding storeesl. Any remaining link.v2 records for that barcode are also cleaned up.
  3. pricer-server deletes storeeslstatus. Its storeesl CQS subscription fires on the deletion in step 2; it then deletes the storeeslstatus it wrote in step 1 and removes the device from its internal DB.

pricer-server never deletes storeeslstatus on its own initiative; the parent storeesl deletion is the sole trigger. This keeps the status DTO visible to other consumers (dashboards, link-registry) during the cleanup window.

sequenceDiagram
    participant PS as pricer-server
    participant DTOflow
    participant LR as link-registry

    Note over PS: ESL reaches terminal condition<br/>(operator offboard or 30-day timeout)
    PS->>DTOflow: PUT storeeslstatus<br/>state = LOST / OFFBOARDED
    DTOflow-->>LR: CQS: storeeslstatus changed
    LR->>DTOflow: Read storeeslstatus → terminal
    LR->>DTOflow: DELETE storeesl<br/>(and any remaining link.v2)
    DTOflow-->>PS: CQS: storeesl deleted
    PS->>DTOflow: DELETE storeeslstatus
    Note over PS,DTOflow: Cascade complete;<br/>no DTOs remain for this barcode

Roaming and queued updates

While an ESL is ROAMING, item updates and design changes continue to drive the upstream pipeline normally — studio-link-evaluator, studio-renderer, eslimage-merger and eslimage all keep producing the latest image. pricer-server stores the latest pending image in its internal DB; when the device re-appears it delivers the most recent image and writes storeeslstatus.state = OK. There is no separate retry queue at the DTO level — pricer-server is the queue.

  • Item–ESL Linking — the storeesl DTO created in step 3 of that flow is the anchor for this entire lifecycle; the ONBOARDING state begins there.
  • Item Update — during ROAMING, accumulated image updates are delivered when the ESL returns to OK.
  • ECC Rendering Pipeline — the parallel image-producing path; lifecycle of the ESL itself is identical regardless of which renderer produced the image.