5.8 KiB
Circuit List Editor API
Scope
The circuit-first editor uses tree, circuit, row and project-device endpoints.
All paths below are mounted below /api. There is no Consumer application API.
Project responses from GET /projects and GET /projects/:projectId include
currentRevision. Versioned project commands use this value for optimistic
concurrency checks.
Project Commands and History
GET /projects/:projectId/history- returns
currentRevision,undoDepth,redoDepthand the current top change-set id for both persistent stacks
- returns
POST /projects/:projectId/commands- executes a supported versioned command as a new user revision
- body:
{ "expectedRevision": 0, "command": { ... } }
POST /projects/:projectId/history/undoPOST /projects/:projectId/history/redo- body:
{ "expectedRevision": 1 } - executes the eligible inverse or forward command as a new auditable revision
- body:
The public dispatcher currently supports circuit.update and
circuit-device-row.update, both with schema version 1. Other command types
are rejected. The editor does not consume these endpoints yet.
Example:
{
"expectedRevision": 0,
"description": "Rename circuit",
"command": {
"schemaVersion": 1,
"type": "circuit.update",
"payload": {
"circuitId": "cir_1",
"changes": [
{ "field": "displayName", "value": "Sockets East" }
]
}
}
}
A stale expectedRevision returns HTTP 409 with
PROJECT_REVISION_CONFLICT. Undo or redo without an eligible stack entry
returns HTTP 409 with PROJECT_HISTORY_OPERATION_UNAVAILABLE.
Circuit-First Endpoints
Distribution Board Setup
POST /projects/:projectId/distribution-boards- atomically creates the distribution board, its circuit list and all default circuit sections
Tree Endpoint
GET /projects/:projectId/circuit-lists/:circuitListId/tree- Purpose: returns section/circuit/device-row tree with calculated row and circuit totals.
Response sketch:
{
"circuitListId": "cl_1",
"sections": [
{
"id": "sec_1",
"key": "lighting",
"prefix": "-1F",
"circuits": [
{
"id": "cir_1",
"equipmentIdentifier": "-1F1",
"circuitTotalPower": 4.2,
"deviceRows": [
{
"id": "row_1",
"displayName": "Office lights",
"rowTotalPower": 1.8
}
]
}
]
}
]
}
Circuit CRUD
POST /projects/:projectId/circuit-lists/:circuitListId/circuits- create circuit in list/section
POST /projects/:projectId/circuit-lists/:circuitListId/circuits-with-device-rows- atomically create one circuit and one or more initial device rows
PATCH /circuits/:circuitId- update circuit-level fields (BMK, protection, cable, reserve flag, etc.)
DELETE /circuits/:circuitId- delete circuit (and related rows via DB relations)
GET /circuit-sections/:sectionId/next-identifier- preview next identifier for section (
prefix + maxSuffix + 1)
- preview next identifier for section (
Request sketch (POST .../circuits):
{
"sectionId": "sec_1",
"equipmentIdentifier": "-2F14",
"displayName": "Sockets East",
"sortOrder": 140
}
Device Row CRUD
POST /circuits/:circuitId/device-rows- create row inside a circuit
PATCH /circuit-device-rows/:rowId- update row values
DELETE /circuit-device-rows/:rowId- delete row
Move Device Row
PATCH /circuit-device-rows/:rowId/move- Purpose: move one row to existing circuit or to newly created circuit in target section.
Request sketch:
{
"targetCircuitId": "cir_target"
}
or
{
"targetSectionId": "sec_target",
"createNewCircuit": true
}
Bulk Move Device Rows
PATCH /circuit-device-rows/move-bulk- Purpose: move multiple rows in one command flow.
Request sketch:
{
"rowIds": ["row_1", "row_2"],
"targetCircuitId": "cir_target"
}
Reorder Circuits
PATCH /circuit-sections/:sectionId/circuits/reorder- Purpose: persist explicit circuit order within one section.
Request sketch:
{
"orderedCircuitIds": ["cir_2", "cir_1", "cir_3"]
}
Renumber Section
POST /circuit-sections/:sectionId/renumber- Purpose: explicit renumbering by section prefix; never implicit on move/sort.
Safe Equipment Identifier Update
PATCH /circuit-sections/:sectionId/equipment-identifiers- Purpose: apply explicit per-circuit identifiers safely even with unique constraints.
Request sketch:
{
"identifiers": [
{ "circuitId": "cir_1", "equipmentIdentifier": "-2F1" },
{ "circuitId": "cir_2", "equipmentIdentifier": "-2F2" }
]
}
Removed Legacy Endpoints
The former /consumers read/write endpoints were removed after every retained
consumer had a verified Circuit-First migration mapping. Database upgrade tooling
reads retained legacy rows directly; application features must use the Circuit-First
endpoints above.
Linked Project Device Review
GET /project-devices/projects/:projectId/:projectDeviceId/links- returns all linked circuit device rows with distribution-board/circuit context and field differences
POST /project-devices/projects/:projectId/:projectDeviceId/synchronize- applies only explicitly selected fields to explicitly selected linked rows
POST /project-devices/projects/:projectId/:projectDeviceId/restore- restores the captured pre-sync values for session-local undo
POST /project-devices/projects/:projectId/:projectDeviceId/disconnect- disconnects explicitly selected rows without changing their local values
POST /project-devices/projects/:projectId/:projectDeviceId/reconnect- restores a disconnected link if the row has not been linked elsewhere meanwhile
displayName is included in the comparison but is not selected by default in the UI. Updating a
project device never triggers synchronization implicitly.