Technology
SpaceFuel gRPC
SpacePOS talks to SpaceFuel over gRPC (local on the POS machine, with dev overrides).
Contract
- Proto lives in the
contracts/spacefuel-contractssubmodule. spacefuel.v1.protodefines:SpaceFuelBridge/ConnectStream(bidi stream)SpaceFuelBridge/GetForecourtState(unary)
SpacePOS client behavior
- SpaceFuel responds on connect with:
payload = "connected"(system)payload = { "type": "forecourt_state", "state": { ... } }
- SpacePOS parses that envelope and maps the response to
ForecourtState.
Transaction events
SpaceFuel also emits transaction events as JSON envelopes:
transaction_authorizedfueling_in_progresstransaction_saved
SpacePOS maps these into typed payloads and updates the dashboard state.
Endpoint resolution
SpacePOS resolves host/port in this order:
- Per-library config:
spacefuel_grpc_hostspacefuel_grpc_port
- Optional SpaceFuel state file (see below)
- Default:
127.0.0.1:5401
In production builds, host is forced to 127.0.0.1.
SpaceFuel state file (discovery)
If SpaceFuel is started outside SpacePOS, it can write a discovery file that SpacePOS will read on startup:
- Path (SpacePOS data dir):
extensions/spacefuel/grpc.json
- JSON schema:
{
"host": "127.0.0.1",
"port": 5401
}
SpacePOS uses this file as a fallback and persists the values into the library config when appropriate.
Auto-connect
On app startup, SpacePOS will auto-connect to SpaceFuel gRPC for any forecourt-master library. The gRPC client already has a retry loop, so connection failures back off and retry.
Dev overrides
In dev builds:
- The SpaceFuel page exposes host + port fields.
- Overrides are persisted to the library config for that library.
Event pipeline
The gRPC stream feeds fueling.events, which updates:
FuelingStateContextliveForecourtState- A capped debug event log (last 50 events)
The dashboard consumes the derived ForecourtState only, keeping UI logic clean.
Fueling panel UI (terminal + sessions)
- A compact fueling panel drawer is available in the terminal and terminal sessions top bar.
- Visibility is gated by
library.config.is_forecourt_master. - Width is resizable and persisted in
layoutStore.fuelingPanel. - The drawer renders the compact dispenser cards from the SpaceFuel dashboard.
TODO: ERP RabbitMQ emission (non-blocking)
If SpaceFuel events need to be mirrored to ERP via RabbitMQ, keep SpacePOS responsive by publishing asynchronously.
Planned approach:
- Define the ERP event set:
- Required:
transaction_authorized,fueling_started,transaction_saved - Optional:
fueling_in_progress(throttle or threshold)
- Required:
- Use a bounded async queue (e.g.
mpsc::channel(1000)) between the event bus and the RabbitMQ publisher. - Never publish inline on the event handler; always enqueue and return.
- If the queue is full, drop or merge only
fueling_in_progressevents. - Publish in a background task with retry/backoff (no blocking on POS).
- Log publish failures and dropped progress events (rate-limited).
