Appearance
Build a fuel management application
This walkthrough documents the fuel_management reference application. It coordinates a fuel pump and site gateway while treating timeout, partial dispense, and lost connectivity as expected operating conditions.
You finish with:
- Fuel Pump and Site Gateway Device Classes
pumpandgatewayapplication bindings- customer-managed credential records
- a
site_credentialsoffline dataset - an
authorise_dispensecommand - a durable
request_fuelprocess - walk-away release, partial settlement, and reconciliation paths
This proof does not certify a dispenser, meter, payment terminal, hazardous-area installation, tax calculation, or financial ledger. Physical and regulatory safety remains in the pump controller and the qualified site system.
Before you start
Use a simulator or non-dispensing test rig. You need:
- Product Applications beta access on Standard+
- a test customer instance and portal
- a Fuel Pump Device Class and representative test pump
- a Site Gateway Device Class and representative gateway
- a safe device bridge for pump authorisation and event reporting
- a test resource account with no real monetary value
Never test cloud workflow changes against an enabled production dispenser.
Part 1: Define the two hardware roles
Create or select:
| Device Class | Application role | Responsibility |
|---|---|---|
| Fuel Pump | pump | Enforce local interlocks, apply a bounded authorisation, meter dispense, and emit started/completed events |
| Site Gateway | gateway | Hold site credentials and offline authority material for the approved local runtime |
The pump must remain safe when cloud state is stale, duplicated, delayed, or unavailable. A cloud command requests authorisation; it does not bypass local emergency stop, meter, valve, overfill, or hazardous-area controls.

Part 2: Create and bind the application
- Open Developer > Product Applications.
- Create Fuel Management with key
fuel_management. - In Build > Hardware, bind Fuel Pump as
pump. - Bind Site Gateway as
gateway. - Confirm only staging devices from each class are eligible for the matching role.
Role aliases are stable application identifiers. Do not use device names such as Pump-4 as definition keys.
Part 3: Define customer credentials
In Build > Models, add a configuration model:
| Field | Value |
|---|---|
| Model key | credential |
| Label | Credential |
| Customer create/update | Enabled for authorised administrators |
| Customer delete | Disabled in the normative proof |
Add:
| Field key | Type | Meaning |
|---|---|---|
card_uid | String | Identifier consumed by the approved site runtime |
status | String | Active, suspended, revoked, or another explicit state |
Production designs normally need a separate vehicle or account reference, policy, limits, validity window, and audit identity. Do not put secrets, PINs, payment data, or unrestricted personal information into an offline projection.
Part 4: Project the site credential dataset
In the offline dataset section, add:
| Setting | Reference value |
|---|---|
| Key | site_credentials |
| Label | Site credentials |
| Projection | credential.card_uid, credential.status |
| Target selection | Device |
| Format | JSON |
| Delta limit | 1,000 changes or 5 MiB |
| Base rewrite ratio | 50 percent changed |
Generate a base after publishing, then use deltas for bounded changes. The device reports which generation it applied; desired generation is not proof of active local state.
Prelude Agent Product Runtime downloads the desired generation, verifies the payload, stages it, atomically activates it, keeps last-known-good, and reports the applied generation. Confirm the Customer Portal sync chip shows current after the agent has applied the payload; desired generation alone is not enough.

Part 5: Define the pump command
Add Authorise dispense with key authorise_dispense, binding pump, and a 30-second timeout. The normative proof supplies a maximum value and an authorisation identity.
The pump-side handler must:
- validate the correlation and authorisation IDs
- reject values outside local policy
- apply the maximum only once
- report a terminal command result
- emit
dispense.startedanddispense.completedwith the same domain identity - preserve completion for later upload if connectivity is lost
Do not infer dispensed value from command success. Settlement uses the measured completion event.
Part 6: Build the request process
Create Request Fuel with key request_fuel.
Happy path:
text
reserve requested credit
-> authorise pump and wait
-> wait up to 30 seconds for dispense.started
-> wait for dispense.completed
-> partially commit the measured amount
-> release the unused reservation
-> completeWalk-away path:
text
pump rejects, command expires, or no dispense.started event
-> release the full reservation
-> fail with walk_away_timeoutLost-connectivity path:
text
dispense started but completion does not arrive
-> enter reconciliation
-> wait for the durable completion event
-> settle measured amount
-> release the remainderThe normative proof uses a 10-second completion timeout to exercise reconciliation quickly. Set production timing from real dispenser behavior and network testing, not from this test value.
Part 7: Define customer access
Expose only deliberate customer operations:
- manage credentials for authorised customer administrators
- request fuel through a reviewed operation or external API
- view transaction state and customer-safe audit activity
Do not expose raw pump commands, offline authority controls, reconciliation internals, or OEM diagnostics to ordinary portal users.
If an ERP, card platform, or payment system is authoritative, bind it as an HTTPS integration with its own idempotency and reconciliation design.
Part 8: Publish and prove the online paths
- Validate and publish version 1.
- Attach it to the staging portal and provision Fleet Fuel.
- Create active and suspended test credentials.
- Preview and generate
site_credentials. - Report the generation applied by the test gateway.
- Create the bounded test credit account.
- Start
request_fuelwith a unique authorisation and correlation identity. - Report the pump command succeeded.
- emit
dispense.started - emit
dispense.completedwith a value below the reservation - confirm only the measured value is committed
- confirm the remainder is released
Repeat without dispense.started and confirm the full reservation is released with walk_away_timeout.
Part 9: Prove offline reconciliation
Issue a bounded authority grant tied to the current credential dataset generation. Replace it and confirm the old grant is no longer active.
While the test gateway is disconnected:
- consume only within the local grant and policy
- create a globally unique durable event ID
- preserve the event across restart
- upload after reconnection
- retry the same event deliberately
Confirm the server applies the event once, partially commits the correct amount, updates the grant, and acknowledges the durable event before local deletion. Test hard expiry and storage exhaustion as failure conditions.

Production handover gate
- [ ] Pump safety does not depend on cloud availability.
- [ ] Authorisations and completion events have durable unique identities.
- [ ] Walk-away releases the full reservation.
- [ ] Partial dispense commits only the measured amount.
- [ ] Lost completion enters reconciliation rather than guessing.
- [ ] Offline grants are bounded, generation-linked, replaceable, and hard-expiring.
- [ ] Duplicate offline events reconcile once.
- [ ] The gateway preserves unacknowledged events across restart.
- [ ] Suspended credentials disappear from the next applied generation.
- [ ] Customer roles cannot invoke raw pump or authority operations.
- [ ] Another customer cannot see credentials, transactions, devices, or activity.
- [ ] Regulatory, metrology, payment, and hazardous-area responsibilities are documented outside this proof.