Three related fixes:
1. Idle reverts (and any other kiosk-initiated layout switch) now POST
layout.changed to /api/kiosk/event. Previously the server only emitted
on admin-initiated switches, so Node-RED never saw the idle revert.
2. Server's /api/kiosk/event splays the payload to the top level when
the topic has a dedicated trigger node (layout.changed, kiosk.changed,
kiosk.status, display.power.changed, camera.changed). The trigger
nodes expect flat shapes matching the admin emit; the old wrapped
shape left every field undefined.
3. Auto-provisioning of bf-server-config in Node-RED: extend retry
window to ~5 min, log per attempt, force v2 API + full-deploy header
so credentials inline get accepted, surface response body on failure.
Kiosk heartbeat reports local display positions so the server can sync physical outputs without consuming global display indices.
Migrate displays.index away from global uniqueness because display numbering is only meaningful within a kiosk.
Bind native backend services and Node-RED to loopback so Angie remains the public auth boundary. Keep Docker on an internal compose network and stop kiosk fallback to a layout when display default is none.
Rust kiosk:
- web cells now use webkit6 WebView (load_uri)
- html cells use WebView.load_html (full HTML rendering)
- query_displays() reads /sys/class/drm/ for connected HDMI/DP outputs
- Heartbeat reports display geometry every 60s
Server:
- /api/kiosk/heartbeat accepts displays array
- Syncs kiosk-reported displays to display records
- Updates dimensions when changed, creates new displays for new ports