Lets users wire the system end-to-end from the graph, and fixes the core
bug that made drag-to-wire silently fail.
- Fix drag-to-wire 422s across 5 entity kinds: updateConnection() now echoes
the target's discriminator (source_type/stream_type/target_type) into the
partial PUT, so value/colour-strip/audio/picture sources and output targets
all wire correctly. New contract test (54 cases) in test_graph_wiring_contract.py.
- Re-wire composite layers / mapped zones from the graph (right-click a
layer/zone source edge -> Re-wire). Whole-list write preserves every sibling
layer/zone setting, with an optimistic-concurrency guard and undo.
- Secret-safe /graph topology: project entities to id/name/subtype + reference
roots so the endpoint cannot leak webhook tokens or other credentials.
- Carry slot indices on list edges; node custom-icon + schema-drift refinements;
rewire i18n keys (en/ru/zh); wiring-control roadmap (TODO.md).
Backend
- snapshot: GET /api/v1/snapshot aggregates targets, devices, sources,
presets and system into one payload for the HA coordinator, collapsing
the prior ~2N+M request fan-out; per-section ?include= gating.
- graph: GET /api/v1/graph{,/schema,/dependents} backed by a pure,
unit-tested graph_schema engine — one authoritative connectable-field
registry so the editor no longer hard-codes topology in two places.
- devices: thread mqtt_source_id through DeviceCreate/Update/Response and
the routes for multi-broker MQTT; shared validate_mqtt_source_exists
(_mqtt_validation.py) reused by device + output-target routes; stop
update_device masking intentional 4xx as 500.
- shutdown: bound uvicorn graceful-shutdown via GRACEFUL_SHUTDOWN_TIMEOUT
(shared by __main__, android_entry, demo) so a lingering events WebSocket
can't strand LED targets or block process exit.
- access log: structured _access_log middleware attributing each request to
its authenticated token label (never the secret); uvicorn access_log off.
Frontend
- graph editor: generic schema-driven port/edge rendering, layout and
connection handling; service-worker refresh.
- device modals: MQTT broker EntitySelect for device_type=mqtt in add-device
and settings, wired into load/save/validate/dirty-check/clone.
- i18n: en/ru/zh keys.
Tests: graph routes + schema, snapshot routes, access log, mqtt_source_id
device regressions, bounded-shutdown entrypoint. 1614 passed.