ADR 0073 — A backend-neutral taxonomy for rooms, functions and other enums¶
- Status: accepted
- Date: 2026-09-27
Context¶
On a CCU, rooms and functions ("Gewerke") are flat lists of ReGa objects, keyed by an integer id and shown by name. The whole north-bound surface — DeviceSummary.rooms, the channel summaries, MQTT suggested_area, the overview grouping, alarm and group pickers, areas (ADR 0056) — speaks in those names.
openccu-lite's metadata store organises devices in enums whose nodes nest: room/eg/wohnzimmer is the living room on the ground floor, and a box may carry enums beyond rooms and functions. Node ids are path segments, not integers; two nodes may share a display name ("Küche" on two floors); and the store has a revision counter and a change stream.
Flattening the tree into names loses the tree and merges the two kitchens. Flattening ancestors into rooms would give every device on a floor two rooms and break every consumer that expects a device's own room.
Decision¶
A backend-neutral taxonomy model, internal/model/taxonomy, holds a central's enums as trees of nodes. It is pure data and is not persisted: both sources are authoritative and cheap to re-read.
- Identity. A node is named by a reference
<enum>/<path>where the path joins node ids with/(room/eg/kueche). On a CCU every enum is one level deep and a node's path is the ReGa id of the room or function; the CCU's ISE-id joins stay inside the CCU adapter. - Mirror. The per-central device-details cache carries the taxonomy and, per address, the directly assigned references. The CCU adapter fills it from the same JSON-RPC reads as before; the lite adapter from one metadata snapshot before the devices load, then from the metadata change stream.
- Names stay names.
rooms,functionsand every name-based surface keep the display names of the directly assigned nodes. Ancestors are not flattened in. MQTTsuggested_areakeeps its rule (the room, when exactly one is assigned). Nothing changes for a CCU. - Paths are additive. Devices and channels on REST, WebSocket and the MQTT info payload gain a
taxonomyarray (enum,path,name,parent_path);GET /roomsandGET /functionsname the nodes behind each name (refs);GET /taxonomyserves every tree, empty nodes included. Writes can name a node (room_paths,function_paths), which is how one of two same-named rooms is chosen. Nodes are created, renamed, moved and deleted through/taxonomy/{central}/{enum}/nodes; on a CCU only flat root nodes of rooms and functions, nesting and moving are refused with thetaxonomy.treefeature (ADR 0074). - An ambiguous name is refused, not guessed: assigning by a name several nodes share answers
409with the candidate paths. - Areas stay keyed by (central, room name) (ADR 0056). On a box, a name several rooms share is one area assignment; the tree itself is the lite grouping. Documented limitation.
- The room/function create answer is corrected.
POST /roomsandPOST /functionsalways sentidas an integer while the specification said string; the specification now says integer,idis optional (absent on a box, whose nodes have no integer id) andpathnames the created node. The contract guard classifies the correction as breaking, so it carries REST API 12.0.0.
Alternatives considered¶
- Flatten ancestors into
rooms. Every device on a floor would be in two rooms;suggested_areaand every "the device's room" consumer break. - Replace names by paths on the existing fields. A breaking change for every client, for a structure a CCU does not have.
- Persist the taxonomy. A second truth to invalidate; the sources are cheap and authoritative.
- Key areas by node reference. Correct for boxes, a migration for every existing area on a CCU; deferred until a need is shown.
Consequences¶
- Clients that only know names keep working; clients that care about trees read
taxonomyandGET /taxonomy. - The SPA edits nested taxonomies as trees, picks assignments by path, and groups and filters the overview and alarm pickers by the path of a nested node. Heating-group candidates still carry names only.
- The CCU's ReGa ids no longer leak as a separate concept: they are a node's path on a CCU.